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);
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;
146 } gsCacheEntryFormat;
152 gsCacheEntryFormat * format[AA_MAXVALUE];
157 struct xrender_physdev
159 struct gdi_physdev dev;
160 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(XRenderChangePicture)
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_XRENDERCREATELINEARGRADIENT
202 MAKE_FUNCPTR(XRenderCreateLinearGradient)
204 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
205 MAKE_FUNCPTR(XRenderSetPictureTransform)
207 MAKE_FUNCPTR(XRenderQueryExtension)
209 #ifdef SONAME_LIBFONTCONFIG
210 #include <fontconfig/fontconfig.h>
211 MAKE_FUNCPTR(FcConfigSubstitute)
212 MAKE_FUNCPTR(FcDefaultSubstitute)
213 MAKE_FUNCPTR(FcFontMatch)
215 MAKE_FUNCPTR(FcPatternCreate)
216 MAKE_FUNCPTR(FcPatternDestroy)
217 MAKE_FUNCPTR(FcPatternAddInteger)
218 MAKE_FUNCPTR(FcPatternAddString)
219 MAKE_FUNCPTR(FcPatternGetBool)
220 MAKE_FUNCPTR(FcPatternGetInteger)
221 MAKE_FUNCPTR(FcPatternGetString)
222 static void *fontconfig_handle;
223 static BOOL fontconfig_installed;
228 static CRITICAL_SECTION xrender_cs;
229 static CRITICAL_SECTION_DEBUG critsect_debug =
232 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
233 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
235 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
237 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
238 ( ( (ULONG)_x4 << 24 ) | \
239 ( (ULONG)_x3 << 16 ) | \
240 ( (ULONG)_x2 << 8 ) | \
243 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
245 #define GASP_GRIDFIT 0x01
246 #define GASP_DOGRAY 0x02
248 #ifdef WORDS_BIGENDIAN
249 #define get_be_word(x) (x)
250 #define NATIVE_BYTE_ORDER MSBFirst
252 #define get_be_word(x) RtlUshortByteSwap(x)
253 #define NATIVE_BYTE_ORDER LSBFirst
256 static BOOL has_alpha( enum wxr_format format )
258 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
261 static enum wxr_format get_format_without_alpha( enum wxr_format format )
265 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
266 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
267 default: return format;
271 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
274 templ->type = PictTypeDirect;
275 templ->depth = fmt->depth;
276 templ->direct.alpha = fmt->alpha;
277 templ->direct.alphaMask = fmt->alphaMask;
278 templ->direct.red = fmt->red;
279 templ->direct.redMask = fmt->redMask;
280 templ->direct.green = fmt->green;
281 templ->direct.greenMask = fmt->greenMask;
282 templ->direct.blue = fmt->blue;
283 templ->direct.blueMask = fmt->blueMask;
286 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
291 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
293 if(fmt->depth != screen_depth)
295 if( (fmt->redMask << fmt->red) != visual->red_mask)
297 if( (fmt->greenMask << fmt->green) != visual->green_mask)
299 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
302 /* We never select a default ARGB visual */
309 static int load_xrender_formats(void)
314 for (i = 0; i < WXR_NB_FORMATS; i++)
316 XRenderPictFormat templ;
318 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
321 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
322 if (!pict_formats[i])
324 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
325 if (visual->class == DirectColor)
328 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
329 screen_depth, TrueColor, &info ))
331 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
332 if (pict_formats[i]) visual = info.visual;
337 if (pict_formats[i]) default_format = i;
341 unsigned long mask = 0;
342 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
345 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
351 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
357 /***********************************************************************
358 * X11DRV_XRender_Init
360 * Let's see if our XServer has the extension available
363 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
368 using_client_side_fonts = client_side_with_render || client_side_with_core;
370 if (!client_side_with_render) return NULL;
371 if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
373 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
374 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
375 LOAD_FUNCPTR(XRenderAddGlyphs);
376 LOAD_FUNCPTR(XRenderChangePicture);
377 LOAD_FUNCPTR(XRenderComposite);
378 LOAD_FUNCPTR(XRenderCompositeText16);
379 LOAD_FUNCPTR(XRenderCreateGlyphSet);
380 LOAD_FUNCPTR(XRenderCreatePicture);
381 LOAD_FUNCPTR(XRenderFillRectangle);
382 LOAD_FUNCPTR(XRenderFindFormat);
383 LOAD_FUNCPTR(XRenderFindVisualFormat);
384 LOAD_FUNCPTR(XRenderFreeGlyphSet);
385 LOAD_FUNCPTR(XRenderFreePicture);
386 LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
387 LOAD_FUNCPTR(XRenderQueryExtension);
388 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
389 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
391 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
392 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
394 #undef LOAD_OPTIONAL_FUNCPTR
398 ok = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
400 if (!ok) return NULL;
402 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
403 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
405 ERR_(winediag)("Wine has detected that you probably have a buggy version "
406 "of libXrender. Because of this client side font rendering "
407 "will be disabled. Please upgrade this library.\n");
411 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask)
413 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
417 #ifdef SONAME_LIBFONTCONFIG
418 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
420 #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;}
421 LOAD_FUNCPTR(FcConfigSubstitute);
422 LOAD_FUNCPTR(FcDefaultSubstitute);
423 LOAD_FUNCPTR(FcFontMatch);
424 LOAD_FUNCPTR(FcInit);
425 LOAD_FUNCPTR(FcPatternCreate);
426 LOAD_FUNCPTR(FcPatternDestroy);
427 LOAD_FUNCPTR(FcPatternAddInteger);
428 LOAD_FUNCPTR(FcPatternAddString);
429 LOAD_FUNCPTR(FcPatternGetBool);
430 LOAD_FUNCPTR(FcPatternGetInteger);
431 LOAD_FUNCPTR(FcPatternGetString);
433 fontconfig_installed = pFcInit();
435 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
440 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
441 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
443 glyphsetCacheSize = INIT_CACHE_SIZE;
445 for(i = 0; i < INIT_CACHE_SIZE; i++) {
446 glyphsetCache[i].next = i + 1;
447 glyphsetCache[i].count = -1;
449 glyphsetCache[i-1].next = -1;
451 if(screen_depth <= 8 || !client_side_antialias_with_render) antialias = 0;
453 return &xrender_funcs;
456 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
457 static void get_xrender_color( struct xrender_physdev *physdev, COLORREF src_color, XRenderColor *dst_color )
459 if (src_color & (1 << 24)) /* PALETTEINDEX */
461 HPALETTE pal = GetCurrentObject( physdev->dev.hdc, OBJ_PAL );
462 PALETTEENTRY pal_ent;
464 if (!GetPaletteEntries( pal, LOWORD(src_color), 1, &pal_ent ))
465 GetPaletteEntries( pal, 0, 1, &pal_ent );
466 dst_color->red = pal_ent.peRed * 257;
467 dst_color->green = pal_ent.peGreen * 257;
468 dst_color->blue = pal_ent.peBlue * 257;
472 if (src_color >> 16 == 0x10ff) src_color = 0; /* DIBINDEX */
474 dst_color->red = GetRValue( src_color ) * 257;
475 dst_color->green = GetGValue( src_color ) * 257;
476 dst_color->blue = GetBValue( src_color ) * 257;
479 if (physdev->format == WXR_FORMAT_MONO && !dst_color->red && !dst_color->green && !dst_color->blue)
480 dst_color->alpha = 0;
482 dst_color->alpha = 0xffff;
485 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
487 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
489 switch (info->bmiHeader.biBitCount)
492 return WXR_FORMAT_MONO;
497 if (info->bmiHeader.biCompression != BI_RGB) break;
498 return WXR_FORMAT_R8G8B8;
501 if (info->bmiHeader.biCompression == BI_BITFIELDS)
503 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
506 for (i = 0; i < WXR_NB_FORMATS; i++)
508 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
509 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
510 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
511 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
516 if (info->bmiHeader.biCompression != BI_RGB) break;
517 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
519 return WXR_INVALID_FORMAT;
522 static enum wxr_format get_bitmap_format( int bpp )
524 enum wxr_format format = WXR_INVALID_FORMAT;
526 if (bpp == screen_bpp)
530 case 16: format = WXR_FORMAT_R5G6B5; break;
531 case 24: format = WXR_FORMAT_R8G8B8; break;
532 case 32: format = WXR_FORMAT_A8R8G8B8; break;
538 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
539 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
541 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
542 XTransform xform = {{
543 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
544 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
545 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
548 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
552 /* check if we can use repeating instead of scaling for the specified source DC */
553 static BOOL use_source_repeat( struct xrender_physdev *dev )
555 return (dev->x11dev->bitmap &&
556 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
557 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
560 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
562 XRenderPictureAttributes pa;
569 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
572 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
575 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
576 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
577 (XRectangle *)data->Buffer, data->rdh.nCount );
579 HeapFree( GetProcessHeap(), 0, data );
584 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
586 if (!dev->pict && dev->pict_format)
588 XRenderPictureAttributes pa;
591 pa.subwindow_mode = IncludeInferiors;
592 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
593 dev->pict_format, CPSubwindowMode, &pa );
595 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
596 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
597 dev->update_clip = (dev->region != 0);
602 HRGN rgn = CreateRectRgnIndirect( clip_rect );
603 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
604 if (dev->region) CombineRgn( rgn, rgn, dev->region, RGN_AND );
605 update_xrender_clipping( dev, rgn );
612 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
613 CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
614 update_xrender_clipping( dev, rgn );
617 else update_xrender_clipping( dev, clip_rgn );
619 else if (dev->update_clip) update_xrender_clipping( dev, dev->region );
621 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
625 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
627 if (!dev->pict_src && dev->pict_format)
629 XRenderPictureAttributes pa;
632 pa.subwindow_mode = IncludeInferiors;
633 pa.repeat = repeat ? RepeatNormal : RepeatNone;
634 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
635 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
638 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
639 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
642 return dev->pict_src;
645 static void free_xrender_picture( struct xrender_physdev *dev )
647 if (dev->pict || dev->pict_src)
650 XFlush( gdi_display );
653 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
654 pXRenderFreePicture(gdi_display, dev->pict);
659 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
660 pXRenderFreePicture(gdi_display, dev->pict_src);
667 /* return a mask picture used to force alpha to 0 */
668 static Picture get_no_alpha_mask(void)
670 static Pixmap pixmap;
676 XRenderPictureAttributes pa;
679 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
680 pa.repeat = RepeatNormal;
681 pa.component_alpha = True;
682 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
683 CPRepeat|CPComponentAlpha, &pa );
684 col.red = col.green = col.blue = 0xffff;
686 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
692 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
694 if(p1->hash != p2->hash) return TRUE;
695 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
696 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
697 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
698 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
702 static void walk_cache(void)
706 EnterCriticalSection(&xrender_cs);
707 for(i=mru; i >= 0; i = glyphsetCache[i].next)
708 TRACE("item %d\n", i);
709 LeaveCriticalSection(&xrender_cs);
713 static int LookupEntry(LFANDSIZE *plfsz)
717 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
719 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
721 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
722 glyphsetCache[i].count++;
724 glyphsetCache[prev_i].next = glyphsetCache[i].next;
725 glyphsetCache[i].next = mru;
728 TRACE("found font in cache %d\n", i);
733 TRACE("font not in cache\n");
737 static void FreeEntry(int entry)
741 for(format = 0; format < AA_MAXVALUE; format++) {
742 gsCacheEntryFormat * formatEntry;
744 if( !glyphsetCache[entry].format[format] )
747 formatEntry = glyphsetCache[entry].format[format];
749 if(formatEntry->glyphset) {
751 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
753 formatEntry->glyphset = 0;
755 if(formatEntry->nrealized) {
756 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
757 formatEntry->realized = NULL;
758 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
759 formatEntry->gis = NULL;
760 formatEntry->nrealized = 0;
763 HeapFree(GetProcessHeap(), 0, formatEntry);
764 glyphsetCache[entry].format[format] = NULL;
768 static int AllocEntry(void)
770 int best = -1, prev_best = -1, i, prev_i = -1;
773 assert(glyphsetCache[lastfree].count == -1);
774 glyphsetCache[lastfree].count = 1;
776 lastfree = glyphsetCache[lastfree].next;
778 glyphsetCache[best].next = mru;
781 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
785 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
786 if(glyphsetCache[i].count == 0) {
794 TRACE("freeing unused glyphset at cache %d\n", best);
796 glyphsetCache[best].count = 1;
798 glyphsetCache[prev_best].next = glyphsetCache[best].next;
799 glyphsetCache[best].next = mru;
807 TRACE("Growing cache\n");
810 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
812 (glyphsetCacheSize + INIT_CACHE_SIZE)
813 * sizeof(*glyphsetCache));
815 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
816 (glyphsetCacheSize + INIT_CACHE_SIZE)
817 * sizeof(*glyphsetCache));
819 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
821 glyphsetCache[i].next = i + 1;
822 glyphsetCache[i].count = -1;
824 glyphsetCache[i-1].next = -1;
825 glyphsetCacheSize += INIT_CACHE_SIZE;
827 lastfree = glyphsetCache[best].next;
828 glyphsetCache[best].count = 1;
829 glyphsetCache[best].next = mru;
831 TRACE("new free cache slot at %d\n", mru);
835 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
845 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
846 if(size == GDI_ERROR)
849 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
850 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
852 GetTextMetricsW(hdc, &tm);
853 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
856 num_recs = get_be_word(*gasp);
860 *flags = get_be_word(*(gasp + 1));
861 if(ppem <= get_be_word(*gasp))
865 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
867 HeapFree(GetProcessHeap(), 0, buffer);
871 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
875 UINT font_smoothing_type, font_smoothing_orientation;
878 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
879 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
881 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
882 &font_smoothing_orientation, 0) &&
883 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
890 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
891 But, Wine's subpixel rendering can support the portrait mode.
894 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
902 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
907 static int hinter = -1;
908 static int subpixel = -1;
911 if((ret = LookupEntry(plfsz)) != -1) return ret;
914 entry = glyphsetCache + ret;
915 entry->lfsz = *plfsz;
916 for( format = 0; format < AA_MAXVALUE; format++ ) {
917 assert( !entry->format[format] );
920 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
922 if(hinter == -1 || subpixel == -1)
924 RASTERIZER_STATUS status;
925 GetRasterizerCaps(&status, sizeof(status));
926 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
927 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
930 switch (plfsz->lf.lfQuality)
932 case ANTIALIASED_QUALITY:
933 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
934 return ret; /* ignore further configuration */
935 case CLEARTYPE_QUALITY:
936 case CLEARTYPE_NATURAL_QUALITY:
937 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
939 case DEFAULT_QUALITY:
943 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
946 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
949 entry->aa_default = AA_None;
953 font_smoothing = TRUE; /* default to enabled */
954 #ifdef SONAME_LIBFONTCONFIG
955 if (fontconfig_installed)
957 FcPattern *match, *pattern;
959 char family[LF_FACESIZE * 4];
961 #if defined(__i386__) && defined(__GNUC__)
962 /* fontconfig generates floating point exceptions, mask them */
963 WORD cw, default_cw = 0x37f;
964 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
967 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
968 pattern = pFcPatternCreate();
969 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
970 if (plfsz->lf.lfWeight != FW_DONTCARE)
973 switch (plfsz->lf.lfWeight)
975 case FW_THIN: weight = FC_WEIGHT_THIN; break;
976 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
977 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
978 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
979 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
980 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
981 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
982 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
983 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
984 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
986 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
988 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
989 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
990 pFcDefaultSubstitute( pattern );
991 if ((match = pFcFontMatch( NULL, pattern, &result )))
996 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
998 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
1001 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
1003 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
1004 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
1008 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
1009 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
1010 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1011 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1012 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1015 if (!antialias) font_smoothing = FALSE;
1016 pFcPatternDestroy( match );
1018 pFcPatternDestroy( pattern );
1020 #if defined(__i386__) && defined(__GNUC__)
1021 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
1024 #endif /* SONAME_LIBFONTCONFIG */
1026 /* now check Xft resources */
1029 BOOL antialias = TRUE;
1032 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1034 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1035 value[0] == '0' || !strcasecmp( value, "off" ))
1038 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1040 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1041 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1042 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1043 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1044 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1045 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1047 wine_tsx11_unlock();
1048 if (!antialias) font_smoothing = FALSE;
1051 if (!font_smoothing) entry->aa_default = AA_None;
1054 entry->aa_default = AA_None;
1059 static void dec_ref_cache(int index)
1062 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1063 assert(glyphsetCache[index].count > 0);
1064 glyphsetCache[index].count--;
1067 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1069 DWORD hash = 0, *ptr, two_chars;
1073 hash ^= plfsz->devsize.cx;
1074 hash ^= plfsz->devsize.cy;
1075 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1077 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1079 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1081 pwc = (WCHAR *)&two_chars;
1083 *pwc = toupperW(*pwc);
1085 *pwc = toupperW(*pwc);
1093 /***********************************************************************
1094 * X11DRV_XRender_Finalize
1096 void X11DRV_XRender_Finalize(void)
1100 EnterCriticalSection(&xrender_cs);
1101 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1103 LeaveCriticalSection(&xrender_cs);
1104 DeleteCriticalSection(&xrender_cs);
1107 /**********************************************************************
1108 * xrenderdrv_SelectFont
1110 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1112 struct xrender_physdev *physdev = get_xrender_dev( dev );
1113 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1114 HFONT ret = next->funcs->pSelectFont( next, hfont );
1118 if (physdev->x11dev->has_gdi_font)
1122 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1124 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1125 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1126 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1127 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1128 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1129 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1131 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1132 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1133 lfsz.xform.eM21, lfsz.xform.eM22);
1135 /* Not used fields, would break hashing */
1136 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1138 lfsz_calc_hash(&lfsz);
1140 EnterCriticalSection(&xrender_cs);
1141 if (physdev->cache_index != -1)
1142 dec_ref_cache( physdev->cache_index );
1143 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1144 LeaveCriticalSection(&xrender_cs);
1148 EnterCriticalSection( &xrender_cs );
1149 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1150 physdev->cache_index = -1;
1151 LeaveCriticalSection( &xrender_cs );
1156 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1158 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1159 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1161 if (!physdev) return FALSE;
1162 physdev->x11dev = x11dev;
1163 physdev->cache_index = -1;
1164 physdev->format = format;
1165 physdev->pict_format = pict_formats[format];
1166 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1170 /* store the color mask data in the bitmap info structure */
1171 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1173 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1175 info->bmiHeader.biPlanes = 1;
1176 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1177 info->bmiHeader.biCompression = BI_RGB;
1178 info->bmiHeader.biClrUsed = 0;
1180 switch (info->bmiHeader.biBitCount)
1183 colors[0] = format->direct.redMask << format->direct.red;
1184 colors[1] = format->direct.greenMask << format->direct.green;
1185 colors[2] = format->direct.blueMask << format->direct.blue;
1186 info->bmiHeader.biCompression = BI_BITFIELDS;
1189 colors[0] = format->direct.redMask << format->direct.red;
1190 colors[1] = format->direct.greenMask << format->direct.green;
1191 colors[2] = format->direct.blueMask << format->direct.blue;
1192 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1193 info->bmiHeader.biCompression = BI_BITFIELDS;
1199 /**********************************************************************
1200 * xrenderdrv_CreateDC
1202 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1203 LPCWSTR output, const DEVMODEW* initData )
1205 return create_xrender_dc( pdev, default_format );
1208 /**********************************************************************
1209 * xrenderdrv_CreateCompatibleDC
1211 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1213 if (orig) /* chain to x11drv first */
1215 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1216 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1218 /* otherwise we have been called by x11drv */
1220 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1223 /**********************************************************************
1224 * xrenderdrv_DeleteDC
1226 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1228 struct xrender_physdev *physdev = get_xrender_dev( dev );
1230 free_xrender_picture( physdev );
1232 EnterCriticalSection( &xrender_cs );
1233 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1234 LeaveCriticalSection( &xrender_cs );
1236 HeapFree( GetProcessHeap(), 0, physdev );
1240 /**********************************************************************
1241 * xrenderdrv_ExtEscape
1243 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1244 INT out_count, LPVOID out_data )
1246 struct xrender_physdev *physdev = get_xrender_dev( dev );
1248 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1250 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1252 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1254 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1255 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1259 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1262 /****************************************************************************
1263 * xrenderdrv_CopyBitmap
1265 static BOOL xrenderdrv_CopyBitmap( HBITMAP src, HBITMAP dst )
1267 return X11DRV_CopyBitmap( src, dst );
1270 /****************************************************************************
1271 * xrenderdrv_CreateBitmap
1273 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1275 enum wxr_format format = WXR_INVALID_FORMAT;
1276 X_PHYSBITMAP *phys_bitmap;
1279 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1281 if (bitmap.bmBitsPixel == 1)
1283 if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, 1 ))) return FALSE;
1284 phys_bitmap->format = WXR_FORMAT_MONO;
1285 phys_bitmap->trueColor = FALSE;
1289 format = get_bitmap_format( bitmap.bmBitsPixel );
1291 if (pict_formats[format])
1293 if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth )))
1295 phys_bitmap->format = format;
1296 phys_bitmap->trueColor = TRUE;
1297 phys_bitmap->color_shifts = wxr_color_shifts[format];
1301 if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, screen_depth )))
1303 phys_bitmap->format = WXR_INVALID_FORMAT;
1304 phys_bitmap->trueColor = (visual->class == TrueColor || visual->class == DirectColor);
1305 phys_bitmap->color_shifts = X11DRV_PALETTE_default_shifts;
1311 /****************************************************************************
1312 * xrenderdrv_DeleteBitmap
1314 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1316 return X11DRV_DeleteBitmap( hbitmap );
1319 /***********************************************************************
1320 * xrenderdrv_SelectBitmap
1322 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1325 struct xrender_physdev *physdev = get_xrender_dev( dev );
1327 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1328 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1331 free_xrender_picture( physdev );
1332 if (hbitmap == BITMAP_stock_phys_bitmap.hbitmap) physdev->format = WXR_FORMAT_MONO;
1333 else physdev->format = X11DRV_get_phys_bitmap(hbitmap)->format;
1334 physdev->pict_format = pict_formats[physdev->format];
1339 /***********************************************************************
1340 * xrenderdrv_GetImage
1342 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1343 struct gdi_image_bits *bits, struct bitblt_coords *src )
1345 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1346 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1347 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1350 /***********************************************************************
1351 * xrenderdrv_SetDeviceClipping
1353 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1355 struct xrender_physdev *physdev = get_xrender_dev( dev );
1357 physdev->region = rgn;
1358 physdev->update_clip = TRUE;
1360 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1361 dev->funcs->pSetDeviceClipping( dev, rgn );
1365 /************************************************************************
1368 * Helper to ExtTextOut. Must be called inside xrender_cs
1370 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1372 unsigned int buflen;
1377 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1378 gsCacheEntryFormat *formatEntry;
1379 UINT ggo_format = GGO_GLYPH_INDEX;
1380 enum wxr_format wxr_format;
1381 static const char zero[4];
1382 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1386 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1389 ggo_format |= WINE_GGO_HRGB_BITMAP;
1392 ggo_format |= WINE_GGO_HBGR_BITMAP;
1395 ggo_format |= WINE_GGO_VRGB_BITMAP;
1398 ggo_format |= WINE_GGO_VBGR_BITMAP;
1402 ERR("aa = %d - not implemented\n", format);
1404 ggo_format |= GGO_BITMAP;
1408 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1409 if(buflen == GDI_ERROR) {
1410 if(format != AA_None) {
1412 entry->aa_default = AA_None;
1413 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1414 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1416 if(buflen == GDI_ERROR) {
1417 WARN("GetGlyphOutlineW failed using default glyph\n");
1418 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1419 if(buflen == GDI_ERROR) {
1420 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1421 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1422 if(buflen == GDI_ERROR) {
1423 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1428 TRACE("Turning off antialiasing for this monochrome font\n");
1431 /* If there is nothing for the current type, we create the entry. */
1432 if( !entry->format[format] ) {
1433 entry->format[format] = HeapAlloc(GetProcessHeap(),
1435 sizeof(gsCacheEntryFormat));
1437 formatEntry = entry->format[format];
1439 if(formatEntry->nrealized <= glyph) {
1440 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1442 if (formatEntry->realized)
1443 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1445 formatEntry->realized,
1446 formatEntry->nrealized * sizeof(BOOL));
1448 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1450 formatEntry->nrealized * sizeof(BOOL));
1452 if (formatEntry->gis)
1453 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1456 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1458 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1460 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1464 if(formatEntry->glyphset == 0) {
1467 wxr_format = WXR_FORMAT_GRAY;
1474 wxr_format = WXR_FORMAT_A8R8G8B8;
1478 ERR("aa = %d - not implemented\n", format);
1480 wxr_format = WXR_FORMAT_MONO;
1485 formatEntry->font_format = pict_formats[wxr_format];
1486 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1487 wine_tsx11_unlock();
1491 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1492 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1493 formatEntry->realized[glyph] = TRUE;
1495 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1497 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1498 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1500 gi.width = gm.gmBlackBoxX;
1501 gi.height = gm.gmBlackBoxY;
1502 gi.x = -gm.gmptGlyphOrigin.x;
1503 gi.y = gm.gmptGlyphOrigin.y;
1504 gi.xOff = gm.gmCellIncX;
1505 gi.yOff = gm.gmCellIncY;
1507 if(TRACE_ON(xrender)) {
1510 unsigned char *line;
1512 if(format == AA_None) {
1513 pitch = ((gi.width + 31) / 32) * 4;
1514 for(i = 0; i < gi.height; i++) {
1515 line = (unsigned char*) buf + i * pitch;
1517 for(j = 0; j < pitch * 8; j++) {
1518 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1520 TRACE("%s\n", output);
1523 static const char blks[] = " .:;!o*#";
1527 pitch = ((gi.width + 3) / 4) * 4;
1528 for(i = 0; i < gi.height; i++) {
1529 line = (unsigned char*) buf + i * pitch;
1531 for(j = 0; j < pitch; j++) {
1532 str[0] = blks[line[j] >> 5];
1533 strcat(output, str);
1535 TRACE("%s\n", output);
1541 if(formatEntry->glyphset) {
1542 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1543 unsigned char *byte = (unsigned char*) buf, c;
1549 /* magic to flip bit order */
1550 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1551 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1552 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1557 else if ( format != AA_Grey &&
1558 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1560 unsigned int i, *data = (unsigned int *)buf;
1561 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1566 XRenderCompositeText seems to ignore 0x0 glyphs when
1567 AA_None, which means we lose the advance width of glyphs
1568 like the space. We'll pretend that such glyphs are 1x1
1573 gi.width = gi.height = 1;
1576 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1577 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1578 wine_tsx11_unlock();
1579 HeapFree(GetProcessHeap(), 0, buf);
1582 formatEntry->gis[glyph] = gi;
1585 /*************************************************************
1588 * Returns an appropriate Picture for tiling the text colour.
1589 * Call and use result within the xrender_cs
1591 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1597 XRenderColor current_color;
1598 } tiles[WXR_NB_FORMATS], *tile;
1600 tile = &tiles[wxr_format];
1604 XRenderPictureAttributes pa;
1605 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1608 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1610 pa.repeat = RepeatNormal;
1611 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1612 wine_tsx11_unlock();
1614 /* init current_color to something different from text_pixel */
1615 tile->current_color = *color;
1616 tile->current_color.red ^= 0xffff;
1618 if (wxr_format == WXR_FORMAT_MONO)
1620 /* for a 1bpp bitmap we always need a 1 in the tile */
1622 col.red = col.green = col.blue = 0;
1625 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1626 wine_tsx11_unlock();
1630 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1633 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1634 wine_tsx11_unlock();
1635 tile->current_color = *color;
1640 /*************************************************************
1643 * Returns an appropriate Picture for masking with the specified alpha.
1644 * Call and use result within the xrender_cs
1646 static Picture get_mask_pict( int alpha )
1648 static Pixmap pixmap;
1649 static Picture pict;
1650 static int current_alpha;
1652 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1656 XRenderPictureAttributes pa;
1659 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1660 pa.repeat = RepeatNormal;
1661 pict = pXRenderCreatePicture( gdi_display, pixmap,
1662 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1663 wine_tsx11_unlock();
1667 if (alpha != current_alpha)
1670 col.red = col.green = col.blue = 0;
1671 col.alpha = current_alpha = alpha;
1673 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1674 wine_tsx11_unlock();
1679 /***********************************************************************
1680 * xrenderdrv_ExtTextOut
1682 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1683 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1685 struct xrender_physdev *physdev = get_xrender_dev( dev );
1686 gsCacheEntry *entry;
1687 gsCacheEntryFormat *formatEntry;
1688 AA_Type aa_type = AA_None;
1690 Picture pict, tile_pict = 0;
1692 POINT offset, desired, current;
1693 int render_op = PictOpOver;
1696 if (!physdev->x11dev->has_gdi_font)
1698 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1699 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1702 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1703 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1705 if(flags & ETO_OPAQUE)
1709 if (physdev->format == WXR_FORMAT_MONO)
1710 /* use the inverse of the text color */
1711 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1713 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1716 set_xrender_transformation( pict, 1, 1, 0, 0 );
1717 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1718 physdev->x11dev->dc_rect.left + lprect->left,
1719 physdev->x11dev->dc_rect.top + lprect->top,
1720 lprect->right - lprect->left,
1721 lprect->bottom - lprect->top );
1722 wine_tsx11_unlock();
1725 if(count == 0) return TRUE;
1727 EnterCriticalSection(&xrender_cs);
1729 entry = glyphsetCache + physdev->cache_index;
1730 aa_type = entry->aa_default;
1731 formatEntry = entry->format[aa_type];
1733 for(idx = 0; idx < count; idx++) {
1734 if( !formatEntry ) {
1735 UploadGlyph(physdev, wstr[idx], aa_type);
1736 /* re-evaluate antialias since aa_default may have changed */
1737 aa_type = entry->aa_default;
1738 formatEntry = entry->format[aa_type];
1739 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1740 UploadGlyph(physdev, wstr[idx], aa_type);
1745 WARN("could not upload requested glyphs\n");
1746 LeaveCriticalSection(&xrender_cs);
1750 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1751 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1753 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1755 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1756 So we pass zeros to the function and move to our starting position using the first
1757 element of the elts array. */
1759 desired.x = physdev->x11dev->dc_rect.left + x;
1760 desired.y = physdev->x11dev->dc_rect.top + y;
1761 offset.x = offset.y = 0;
1762 current.x = current.y = 0;
1764 tile_pict = get_tile_pict(physdev->format, &col);
1766 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1768 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1769 render_op = PictOpOutReverse; /* This gives us 'black' text */
1771 for(idx = 0; idx < count; idx++)
1773 elts[idx].glyphset = formatEntry->glyphset;
1774 elts[idx].chars = wstr + idx;
1775 elts[idx].nchars = 1;
1776 elts[idx].xOff = desired.x - current.x;
1777 elts[idx].yOff = desired.y - current.y;
1779 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1780 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1784 desired.x += formatEntry->gis[wstr[idx]].xOff;
1785 desired.y += formatEntry->gis[wstr[idx]].yOff;
1791 offset.x += lpDx[idx * 2];
1792 offset.y += lpDx[idx * 2 + 1];
1795 offset.x += lpDx[idx];
1796 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1797 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1802 /* Make sure we don't have any transforms set from a previous call */
1803 set_xrender_transformation(pict, 1, 1, 0, 0);
1804 pXRenderCompositeText16(gdi_display, render_op,
1807 formatEntry->font_format,
1808 0, 0, 0, 0, elts, count);
1809 wine_tsx11_unlock();
1810 HeapFree(GetProcessHeap(), 0, elts);
1812 LeaveCriticalSection(&xrender_cs);
1816 /* multiply the alpha channel of a picture */
1817 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1818 int x, int y, int width, int height )
1820 XRenderPictureAttributes pa;
1821 Pixmap src_pixmap, mask_pixmap;
1822 Picture src_pict, mask_pict;
1826 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1827 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1828 pa.repeat = RepeatNormal;
1829 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1830 pa.component_alpha = True;
1831 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1832 color.red = color.green = color.blue = color.alpha = 0xffff;
1833 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1834 color.alpha = alpha;
1835 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1836 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1837 0, 0, 0, 0, x, y, width, height );
1838 pXRenderFreePicture( gdi_display, src_pict );
1839 pXRenderFreePicture( gdi_display, mask_pict );
1840 XFreePixmap( gdi_display, src_pixmap );
1841 XFreePixmap( gdi_display, mask_pixmap );
1842 wine_tsx11_unlock();
1845 /* Helper function for (stretched) blitting using xrender */
1846 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1847 int x_src, int y_src, int x_dst, int y_dst,
1848 double xscale, double yscale, int width, int height )
1850 int x_offset, y_offset;
1852 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1853 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1854 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1856 if(xscale != 1.0 || yscale != 1.0)
1858 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1859 * in the wrong quadrant of the x-y plane.
1861 x_offset = (xscale < 0) ? -width : 0;
1862 y_offset = (yscale < 0) ? -height : 0;
1863 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1869 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1871 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1872 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
1873 wine_tsx11_unlock();
1876 /* Helper function for (stretched) mono->color blitting using xrender */
1877 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1878 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1879 int x_src, int y_src, int x_dst, int y_dst,
1880 double xscale, double yscale, int width, int height )
1883 int x_offset, y_offset;
1886 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1887 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1890 EnterCriticalSection( &xrender_cs );
1892 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1893 tile_pict = get_tile_pict( dst_format, &color );
1896 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
1898 if (xscale != 1.0 || yscale != 1.0)
1900 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1901 * in the wrong quadrant of the x-y plane.
1903 x_offset = (xscale < 0) ? -width : 0;
1904 y_offset = (yscale < 0) ? -height : 0;
1905 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1911 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1913 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1914 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
1915 wine_tsx11_unlock();
1916 LeaveCriticalSection( &xrender_cs );
1918 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1919 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1920 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
1923 /* create a pixmap and render picture for an image */
1924 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1925 struct bitblt_coords *src, enum wxr_format format,
1926 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1929 int width = src->visrect.right - src->visrect.left;
1930 int height = src->visrect.bottom - src->visrect.top;
1931 int depth = pict_formats[format]->depth;
1932 struct gdi_image_bits dst_bits;
1933 XRenderPictureAttributes pa;
1937 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1938 info->bmiHeader.biWidth, height, 32, 0 );
1939 wine_tsx11_unlock();
1940 if (!image) return ERROR_OUTOFMEMORY;
1942 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1943 if (ret) return ret;
1945 image->data = dst_bits.ptr;
1947 *use_repeat = (width == 1 && height == 1);
1948 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1951 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1952 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
1953 src->visrect.left, 0, 0, 0, width, height );
1954 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1955 wine_tsx11_unlock();
1957 /* make coordinates relative to the pixmap */
1958 src->x -= src->visrect.left;
1959 src->y -= src->visrect.top;
1960 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1964 XDestroyImage( image );
1965 wine_tsx11_unlock();
1966 if (dst_bits.free) dst_bits.free( &dst_bits );
1970 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
1971 Drawable drawable, const struct bitblt_coords *src,
1972 const struct bitblt_coords *dst )
1974 int width = abs( dst->width );
1975 int height = abs( dst->height );
1976 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
1977 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
1979 Picture src_pict = 0, dst_pict, mask_pict = 0;
1981 double xscale, yscale;
1983 use_repeat = use_source_repeat( physdev_src );
1986 xscale = src->width / (double)dst->width;
1987 yscale = src->height / (double)dst->height;
1989 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1991 if (drawable) /* using an intermediate pixmap */
1993 XRenderPictureAttributes pa;
1997 pa.repeat = RepeatNone;
1999 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2000 wine_tsx11_unlock();
2004 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2005 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2006 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2009 if (src->width < 0) x_src += src->width + 1;
2010 if (src->height < 0) y_src += src->height + 1;
2011 if (dst->width < 0) x_dst += dst->width + 1;
2012 if (dst->height < 0) y_dst += dst->height + 1;
2014 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2017 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2019 XRenderColor fg, bg;
2021 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
2022 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
2023 fg.alpha = bg.alpha = 0;
2025 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2026 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2028 else /* color -> color (can be at different depths) or mono -> mono */
2030 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
2031 mask_pict = get_no_alpha_mask();
2033 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2034 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2040 pXRenderFreePicture( gdi_display, dst_pict );
2041 wine_tsx11_unlock();
2046 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2047 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2048 Drawable drawable, struct bitblt_coords *src,
2049 struct bitblt_coords *dst, BOOL use_repeat )
2051 int x_src, y_src, x_dst, y_dst;
2053 XRenderPictureAttributes pa;
2054 double xscale, yscale;
2056 if (drawable) /* using an intermediate pixmap */
2058 RGNDATA *clip_data = NULL;
2060 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2063 pa.repeat = RepeatNone;
2065 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2067 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2068 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2069 wine_tsx11_unlock();
2070 HeapFree( GetProcessHeap(), 0, clip_data );
2074 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2075 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2076 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2081 xscale = src->width / (double)dst->width;
2082 yscale = src->height / (double)dst->height;
2084 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2088 if (src->width < 0) x_src += src->width + 1;
2089 if (src->height < 0) y_src += src->height + 1;
2090 if (dst->width < 0) x_dst += dst->width + 1;
2091 if (dst->height < 0) y_dst += dst->height + 1;
2093 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2094 xscale, yscale, abs( dst->width ), abs( dst->height ));
2099 pXRenderFreePicture( gdi_display, dst_pict );
2100 wine_tsx11_unlock();
2105 /***********************************************************************
2106 * xrenderdrv_StretchBlt
2108 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2109 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2111 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2112 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2113 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2115 if (src_dev->funcs != dst_dev->funcs)
2117 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2118 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2121 /* XRender is of no use for color -> mono */
2122 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2123 goto x11drv_fallback;
2125 /* if not stretching, we only need to handle format conversion */
2126 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2132 struct bitblt_coords tmp;
2134 /* make coordinates relative to tmp pixmap */
2136 tmp.x -= tmp.visrect.left;
2137 tmp.y -= tmp.visrect.top;
2138 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2141 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2142 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2143 XSetGraphicsExposures( gdi_display, tmpGC, False );
2144 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2145 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
2146 wine_tsx11_unlock();
2148 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2149 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2152 XFreePixmap( gdi_display, tmp_pixmap );
2153 XFreeGC( gdi_display, tmpGC );
2154 wine_tsx11_unlock();
2156 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2161 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2165 /***********************************************************************
2166 * xrenderdrv_PutImage
2168 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2169 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2170 struct bitblt_coords *dst, DWORD rop )
2172 struct xrender_physdev *physdev;
2173 X_PHYSBITMAP *bitmap;
2177 enum wxr_format src_format, dst_format;
2178 XRenderPictFormat *pict_format;
2180 Picture src_pict, mask_pict = 0;
2185 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2187 dst_format = bitmap->format;
2191 physdev = get_xrender_dev( dev );
2193 dst_format = physdev->format;
2196 src_format = get_xrender_format_from_bitmapinfo( info );
2197 if (!(pict_format = pict_formats[src_format])) goto update_format;
2199 /* make sure we can create an image with the same bpp */
2200 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2203 /* mono <-> color conversions not supported */
2204 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2205 goto x11drv_fallback;
2207 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2209 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2211 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2214 struct bitblt_coords tmp;
2218 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2219 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2221 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2222 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2223 DeleteObject( rgn );
2229 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2231 /* make coordinates relative to tmp pixmap */
2233 tmp.x -= tmp.visrect.left;
2234 tmp.y -= tmp.visrect.top;
2235 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2238 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2239 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2240 XSetGraphicsExposures( gdi_display, gc, False );
2241 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
2242 tmp.visrect.right - tmp.visrect.left,
2243 tmp.visrect.bottom - tmp.visrect.top,
2244 physdev->pict_format->depth );
2245 wine_tsx11_unlock();
2247 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2248 NULL, tmp_pixmap, src, &tmp, use_repeat );
2249 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2252 XFreePixmap( gdi_display, tmp_pixmap );
2253 XFreeGC( gdi_display, gc );
2254 wine_tsx11_unlock();
2256 if (restore_region) restore_clipping_region( physdev->x11dev );
2258 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2259 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2263 pXRenderFreePicture( gdi_display, src_pict );
2264 XFreePixmap( gdi_display, src_pixmap );
2265 wine_tsx11_unlock();
2270 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2271 set_color_info( pict_formats[dst_format], info );
2272 return ERROR_BAD_FORMAT;
2275 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2276 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2277 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2281 /***********************************************************************
2282 * xrenderdrv_BlendImage
2284 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2285 struct bitblt_coords *src, struct bitblt_coords *dst,
2286 BLENDFUNCTION func )
2288 struct xrender_physdev *physdev = get_xrender_dev( dev );
2290 enum wxr_format format;
2291 XRenderPictFormat *pict_format;
2292 Picture dst_pict, src_pict, mask_pict;
2296 format = get_xrender_format_from_bitmapinfo( info );
2297 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2298 format = get_format_without_alpha( format );
2299 else if (format != WXR_FORMAT_A8R8G8B8)
2300 return ERROR_INVALID_PARAMETER;
2302 if (!(pict_format = pict_formats[format])) goto update_format;
2304 /* make sure we can create an image with the same bpp */
2305 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2308 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2311 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2313 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2316 double xscale, yscale;
2320 xscale = src->width / (double)dst->width;
2321 yscale = src->height / (double)dst->height;
2323 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2325 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2327 EnterCriticalSection( &xrender_cs );
2328 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2330 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2331 physdev->x11dev->dc_rect.left + dst->x,
2332 physdev->x11dev->dc_rect.top + dst->y,
2333 xscale, yscale, dst->width, dst->height );
2336 pXRenderFreePicture( gdi_display, src_pict );
2337 XFreePixmap( gdi_display, src_pixmap );
2338 wine_tsx11_unlock();
2340 LeaveCriticalSection( &xrender_cs );
2345 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2346 set_color_info( physdev->pict_format, info );
2347 return ERROR_BAD_FORMAT;
2351 /***********************************************************************
2352 * xrenderdrv_AlphaBlend
2354 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2355 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2357 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2358 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2359 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2360 XRenderPictureAttributes pa;
2361 Pixmap tmp_pixmap = 0;
2362 double xscale, yscale;
2365 if (src_dev->funcs != dst_dev->funcs)
2367 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2368 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2371 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2373 SetLastError( ERROR_INVALID_PARAMETER );
2377 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2379 use_repeat = use_source_repeat( physdev_src );
2382 xscale = src->width / (double)dst->width;
2383 yscale = src->height / (double)dst->height;
2385 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2387 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2389 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2391 /* mono -> color blending needs an intermediate color pixmap */
2392 XRenderColor fg, bg;
2393 int width = src->visrect.right - src->visrect.left;
2394 int height = src->visrect.bottom - src->visrect.top;
2396 /* blending doesn't use the destination DC colors */
2397 fg.red = fg.green = fg.blue = 0;
2398 bg.red = bg.green = bg.blue = 0xffff;
2399 fg.alpha = bg.alpha = 0xffff;
2402 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2403 physdev_dst->pict_format->depth );
2404 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2405 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2407 wine_tsx11_unlock();
2409 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2410 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2412 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2414 /* we need a source picture with no alpha */
2415 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2416 if (format != physdev_src->format)
2419 pa.subwindow_mode = IncludeInferiors;
2420 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2421 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2422 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2423 wine_tsx11_unlock();
2427 if (tmp_pict) src_pict = tmp_pict;
2429 EnterCriticalSection( &xrender_cs );
2430 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2432 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2433 physdev_src->x11dev->dc_rect.left + src->x,
2434 physdev_src->x11dev->dc_rect.top + src->y,
2435 physdev_dst->x11dev->dc_rect.left + dst->x,
2436 physdev_dst->x11dev->dc_rect.top + dst->y,
2437 xscale, yscale, dst->width, dst->height );
2440 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2441 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2442 wine_tsx11_unlock();
2444 LeaveCriticalSection( &xrender_cs );
2448 /***********************************************************************
2449 * xrenderdrv_GradientFill
2451 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2452 void * grad_array, ULONG ngrad, ULONG mode )
2454 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2455 static const XFixed stops[2] = { 0, 1 << 16 };
2456 struct xrender_physdev *physdev = get_xrender_dev( dev );
2457 XLinearGradient gradient;
2458 XRenderColor colors[2];
2459 Picture src_pict, dst_pict;
2461 const GRADIENT_RECT *rect = grad_array;
2464 if (!pXRenderCreateLinearGradient) goto fallback;
2466 /* <= 16-bpp uses dithering */
2467 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2471 case GRADIENT_FILL_RECT_H:
2472 case GRADIENT_FILL_RECT_V:
2473 for (i = 0; i < ngrad; i++, rect++)
2475 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2476 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2478 colors[0].red = v1->Red * 257 / 256;
2479 colors[0].green = v1->Green * 257 / 256;
2480 colors[0].blue = v1->Blue * 257 / 256;
2481 colors[1].red = v2->Red * 257 / 256;
2482 colors[1].green = v2->Green * 257 / 256;
2483 colors[1].blue = v2->Blue * 257 / 256;
2484 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2485 colors[0].alpha = colors[1].alpha = 65535;
2491 LPtoDP( dev->hdc, pt, 2 );
2492 if (mode == GRADIENT_FILL_RECT_H)
2494 gradient.p1.y = gradient.p2.y = 0;
2495 if (pt[1].x > pt[0].x)
2498 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2502 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2508 gradient.p1.x = gradient.p2.x = 0;
2509 if (pt[1].y > pt[0].y)
2512 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2516 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2521 TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2522 mode, pt[0].x, pt[0].y, pt[1].x, pt[1].y,
2523 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2524 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2526 dst_pict = get_xrender_picture( physdev, 0, NULL );
2529 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2530 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0,
2531 physdev->x11dev->dc_rect.left + min( pt[0].x, pt[1].x ),
2532 physdev->x11dev->dc_rect.top + min( pt[0].y, pt[1].y ),
2533 1, 1, abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y) );
2534 pXRenderFreePicture( gdi_display, src_pict );
2535 wine_tsx11_unlock();
2542 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2543 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2546 /***********************************************************************
2547 * xrenderdrv_SelectBrush
2549 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2551 struct xrender_physdev *physdev = get_xrender_dev( dev );
2552 X_PHYSBITMAP *physbitmap;
2553 BOOL delete_bitmap = FALSE;
2557 XRenderPictFormat *pict_format;
2558 Picture src_pict, dst_pict;
2559 XRenderPictureAttributes pa;
2561 if (!pattern) goto x11drv_fallback;
2562 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2564 bitmap = pattern->bitmap;
2565 if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2567 if (!(bitmap = create_brush_bitmap( physdev->x11dev, pattern ))) return 0;
2568 physbitmap = X11DRV_get_phys_bitmap( bitmap );
2569 delete_bitmap = TRUE;
2572 if (physbitmap->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2573 if (!(pict_format = pict_formats[physbitmap->format])) goto x11drv_fallback;
2575 GetObjectW( bitmap, sizeof(bm), &bm );
2578 pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
2579 physdev->pict_format->depth );
2581 pa.repeat = RepeatNone;
2582 src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_format, CPRepeat, &pa);
2583 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
2585 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, bm.bmWidth, bm.bmHeight );
2586 pXRenderFreePicture( gdi_display, src_pict );
2587 pXRenderFreePicture( gdi_display, dst_pict );
2589 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2590 physdev->x11dev->brush.pixmap = pixmap;
2591 physdev->x11dev->brush.fillStyle = FillTiled;
2592 physdev->x11dev->brush.pixel = 0; /* ignored */
2593 physdev->x11dev->brush.style = BS_PATTERN;
2594 wine_tsx11_unlock();
2596 if (delete_bitmap) DeleteObject( bitmap );
2600 if (delete_bitmap) DeleteObject( bitmap );
2601 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2602 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2606 static const struct gdi_dc_funcs xrender_funcs =
2608 NULL, /* pAbortDoc */
2609 NULL, /* pAbortPath */
2610 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2611 NULL, /* pAngleArc */
2614 NULL, /* pBeginPath */
2615 xrenderdrv_BlendImage, /* pBlendImage */
2616 NULL, /* pChoosePixelFormat */
2618 NULL, /* pCloseFigure */
2619 xrenderdrv_CopyBitmap, /* pCopyBitmap */
2620 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2621 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2622 xrenderdrv_CreateDC, /* pCreateDC */
2623 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
2624 xrenderdrv_DeleteDC, /* pDeleteDC */
2625 NULL, /* pDeleteObject */
2626 NULL, /* pDescribePixelFormat */
2627 NULL, /* pDeviceCapabilities */
2628 NULL, /* pEllipse */
2630 NULL, /* pEndPage */
2631 NULL, /* pEndPath */
2632 NULL, /* pEnumFonts */
2633 NULL, /* pEnumICMProfiles */
2634 NULL, /* pExcludeClipRect */
2635 NULL, /* pExtDeviceMode */
2636 xrenderdrv_ExtEscape, /* pExtEscape */
2637 NULL, /* pExtFloodFill */
2638 NULL, /* pExtSelectClipRgn */
2639 xrenderdrv_ExtTextOut, /* pExtTextOut */
2640 NULL, /* pFillPath */
2641 NULL, /* pFillRgn */
2642 NULL, /* pFlattenPath */
2643 NULL, /* pFontIsLinked */
2644 NULL, /* pFrameRgn */
2645 NULL, /* pGdiComment */
2646 NULL, /* pGdiRealizationInfo */
2647 NULL, /* pGetCharABCWidths */
2648 NULL, /* pGetCharABCWidthsI */
2649 NULL, /* pGetCharWidth */
2650 NULL, /* pGetDeviceCaps */
2651 NULL, /* pGetDeviceGammaRamp */
2652 NULL, /* pGetFontData */
2653 NULL, /* pGetFontUnicodeRanges */
2654 NULL, /* pGetGlyphIndices */
2655 NULL, /* pGetGlyphOutline */
2656 NULL, /* pGetICMProfile */
2657 xrenderdrv_GetImage, /* pGetImage */
2658 NULL, /* pGetKerningPairs */
2659 NULL, /* pGetNearestColor */
2660 NULL, /* pGetOutlineTextMetrics */
2661 NULL, /* pGetPixel */
2662 NULL, /* pGetPixelFormat */
2663 NULL, /* pGetSystemPaletteEntries */
2664 NULL, /* pGetTextCharsetInfo */
2665 NULL, /* pGetTextExtentExPoint */
2666 NULL, /* pGetTextExtentExPointI */
2667 NULL, /* pGetTextFace */
2668 NULL, /* pGetTextMetrics */
2669 xrenderdrv_GradientFill, /* pGradientFill */
2670 NULL, /* pIntersectClipRect */
2671 NULL, /* pInvertRgn */
2673 NULL, /* pModifyWorldTransform */
2675 NULL, /* pOffsetClipRgn */
2676 NULL, /* pOffsetViewportOrg */
2677 NULL, /* pOffsetWindowOrg */
2678 NULL, /* pPaintRgn */
2681 NULL, /* pPolyBezier */
2682 NULL, /* pPolyBezierTo */
2683 NULL, /* pPolyDraw */
2684 NULL, /* pPolyPolygon */
2685 NULL, /* pPolyPolyline */
2686 NULL, /* pPolygon */
2687 NULL, /* pPolyline */
2688 NULL, /* pPolylineTo */
2689 xrenderdrv_PutImage, /* pPutImage */
2690 NULL, /* pRealizeDefaultPalette */
2691 NULL, /* pRealizePalette */
2692 NULL, /* pRectangle */
2693 NULL, /* pResetDC */
2694 NULL, /* pRestoreDC */
2695 NULL, /* pRoundRect */
2697 NULL, /* pScaleViewportExt */
2698 NULL, /* pScaleWindowExt */
2699 xrenderdrv_SelectBitmap, /* pSelectBitmap */
2700 xrenderdrv_SelectBrush, /* pSelectBrush */
2701 NULL, /* pSelectClipPath */
2702 xrenderdrv_SelectFont, /* pSelectFont */
2703 NULL, /* pSelectPalette */
2704 NULL, /* pSelectPen */
2705 NULL, /* pSetArcDirection */
2706 NULL, /* pSetBkColor */
2707 NULL, /* pSetBkMode */
2708 NULL, /* pSetDCBrushColor */
2709 NULL, /* pSetDCPenColor */
2710 NULL, /* pSetDIBitsToDevice */
2711 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2712 NULL, /* pSetDeviceGammaRamp */
2713 NULL, /* pSetLayout */
2714 NULL, /* pSetMapMode */
2715 NULL, /* pSetMapperFlags */
2716 NULL, /* pSetPixel */
2717 NULL, /* pSetPixelFormat */
2718 NULL, /* pSetPolyFillMode */
2719 NULL, /* pSetROP2 */
2720 NULL, /* pSetRelAbs */
2721 NULL, /* pSetStretchBltMode */
2722 NULL, /* pSetTextAlign */
2723 NULL, /* pSetTextCharacterExtra */
2724 NULL, /* pSetTextColor */
2725 NULL, /* pSetTextJustification */
2726 NULL, /* pSetViewportExt */
2727 NULL, /* pSetViewportOrg */
2728 NULL, /* pSetWindowExt */
2729 NULL, /* pSetWindowOrg */
2730 NULL, /* pSetWorldTransform */
2731 NULL, /* pStartDoc */
2732 NULL, /* pStartPage */
2733 xrenderdrv_StretchBlt, /* pStretchBlt */
2734 NULL, /* pStretchDIBits */
2735 NULL, /* pStrokeAndFillPath */
2736 NULL, /* pStrokePath */
2737 NULL, /* pSwapBuffers */
2738 NULL, /* pUnrealizePalette */
2739 NULL, /* pWidenPath */
2740 /* OpenGL not supported */
2743 #else /* SONAME_LIBXRENDER */
2745 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2747 TRACE("XRender support not compiled in.\n");
2751 void X11DRV_XRender_Finalize(void)
2755 #endif /* SONAME_LIBXRENDER */