winex11: Forward AlphaBlend with a DIB section as source to the null driver.
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blobe3fa09a5ebec06eecb3a5b67b650be64aa7348f8
1 /*
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
8 * Some parts also:
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
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <stdlib.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "x11drv.h"
36 #include "winternl.h"
37 #include "wine/library.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 int using_client_side_fonts = FALSE;
43 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
45 #ifdef SONAME_LIBXRENDER
47 static BOOL X11DRV_XRender_Installed = FALSE;
49 #include <X11/Xlib.h>
50 #include <X11/extensions/Xrender.h>
52 #ifndef RepeatNone /* added in 0.10 */
53 #define RepeatNone 0
54 #define RepeatNormal 1
55 #define RepeatPad 2
56 #define RepeatReflect 3
57 #endif
59 enum wxr_format
61 WXR_FORMAT_MONO,
62 WXR_FORMAT_GRAY,
63 WXR_FORMAT_X1R5G5B5,
64 WXR_FORMAT_X1B5G5R5,
65 WXR_FORMAT_R5G6B5,
66 WXR_FORMAT_B5G6R5,
67 WXR_FORMAT_R8G8B8,
68 WXR_FORMAT_B8G8R8,
69 WXR_FORMAT_A8R8G8B8,
70 WXR_FORMAT_B8G8R8A8,
71 WXR_FORMAT_X8R8G8B8,
72 WXR_FORMAT_B8G8R8X8,
73 WXR_NB_FORMATS,
74 WXR_INVALID_FORMAT = WXR_NB_FORMATS
77 typedef struct wine_xrender_format_template
79 unsigned int depth;
80 unsigned int alpha;
81 unsigned int alphaMask;
82 unsigned int red;
83 unsigned int redMask;
84 unsigned int green;
85 unsigned int greenMask;
86 unsigned int blue;
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 enum wxr_format default_format;
108 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
110 typedef struct
112 LOGFONTW lf;
113 XFORM xform;
114 SIZE devsize; /* size in device coords */
115 DWORD hash;
116 } LFANDSIZE;
118 #define INITIAL_REALIZED_BUF_SIZE 128
120 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
122 typedef struct
124 GlyphSet glyphset;
125 XRenderPictFormat *font_format;
126 int nrealized;
127 BOOL *realized;
128 void **bitmaps;
129 XGlyphInfo *gis;
130 } gsCacheEntryFormat;
132 typedef struct
134 LFANDSIZE lfsz;
135 AA_Type aa_default;
136 gsCacheEntryFormat * format[AA_MAXVALUE];
137 INT count;
138 INT next;
139 } gsCacheEntry;
141 struct xrender_physdev
143 struct gdi_physdev dev;
144 X11DRV_PDEVICE *x11dev;
145 enum wxr_format format;
146 int cache_index;
147 BOOL update_clip;
148 Picture pict;
149 Picture pict_src;
150 XRenderPictFormat *pict_format;
153 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
155 return (struct xrender_physdev *)dev;
158 static const struct gdi_dc_funcs xrender_funcs;
160 static gsCacheEntry *glyphsetCache = NULL;
161 static DWORD glyphsetCacheSize = 0;
162 static INT lastfree = -1;
163 static INT mru = -1;
165 #define INIT_CACHE_SIZE 10
167 static int antialias = 1;
169 static void *xrender_handle;
171 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
172 MAKE_FUNCPTR(XRenderAddGlyphs)
173 MAKE_FUNCPTR(XRenderComposite)
174 MAKE_FUNCPTR(XRenderCompositeString8)
175 MAKE_FUNCPTR(XRenderCompositeString16)
176 MAKE_FUNCPTR(XRenderCompositeString32)
177 MAKE_FUNCPTR(XRenderCompositeText16)
178 MAKE_FUNCPTR(XRenderCreateGlyphSet)
179 MAKE_FUNCPTR(XRenderCreatePicture)
180 MAKE_FUNCPTR(XRenderFillRectangle)
181 MAKE_FUNCPTR(XRenderFindFormat)
182 MAKE_FUNCPTR(XRenderFindVisualFormat)
183 MAKE_FUNCPTR(XRenderFreeGlyphSet)
184 MAKE_FUNCPTR(XRenderFreePicture)
185 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
186 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
187 MAKE_FUNCPTR(XRenderSetPictureTransform)
188 #endif
189 MAKE_FUNCPTR(XRenderQueryExtension)
191 #ifdef SONAME_LIBFONTCONFIG
192 #include <fontconfig/fontconfig.h>
193 MAKE_FUNCPTR(FcConfigSubstitute)
194 MAKE_FUNCPTR(FcDefaultSubstitute)
195 MAKE_FUNCPTR(FcFontMatch)
196 MAKE_FUNCPTR(FcInit)
197 MAKE_FUNCPTR(FcPatternCreate)
198 MAKE_FUNCPTR(FcPatternDestroy)
199 MAKE_FUNCPTR(FcPatternAddInteger)
200 MAKE_FUNCPTR(FcPatternAddString)
201 MAKE_FUNCPTR(FcPatternGetBool)
202 MAKE_FUNCPTR(FcPatternGetInteger)
203 MAKE_FUNCPTR(FcPatternGetString)
204 static void *fontconfig_handle;
205 static BOOL fontconfig_installed;
206 #endif
208 #undef MAKE_FUNCPTR
210 static CRITICAL_SECTION xrender_cs;
211 static CRITICAL_SECTION_DEBUG critsect_debug =
213 0, 0, &xrender_cs,
214 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
215 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
217 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
219 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
220 ( ( (ULONG)_x4 << 24 ) | \
221 ( (ULONG)_x3 << 16 ) | \
222 ( (ULONG)_x2 << 8 ) | \
223 (ULONG)_x1 )
225 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
227 #define GASP_GRIDFIT 0x01
228 #define GASP_DOGRAY 0x02
230 #ifdef WORDS_BIGENDIAN
231 #define get_be_word(x) (x)
232 #define NATIVE_BYTE_ORDER MSBFirst
233 #else
234 #define get_be_word(x) RtlUshortByteSwap(x)
235 #define NATIVE_BYTE_ORDER LSBFirst
236 #endif
238 static enum wxr_format get_format_without_alpha( enum wxr_format format )
240 switch (format)
242 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
243 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
244 default: return format;
248 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
250 templ->id = 0;
251 templ->type = PictTypeDirect;
252 templ->depth = fmt->depth;
253 templ->direct.alpha = fmt->alpha;
254 templ->direct.alphaMask = fmt->alphaMask;
255 templ->direct.red = fmt->red;
256 templ->direct.redMask = fmt->redMask;
257 templ->direct.green = fmt->green;
258 templ->direct.greenMask = fmt->greenMask;
259 templ->direct.blue = fmt->blue;
260 templ->direct.blueMask = fmt->blueMask;
261 templ->colormap = 0;
263 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
265 return TRUE;
268 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
270 if(fmt->depth != screen_depth)
271 return FALSE;
272 if( (fmt->redMask << fmt->red) != visual->red_mask)
273 return FALSE;
274 if( (fmt->greenMask << fmt->green) != visual->green_mask)
275 return FALSE;
276 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
277 return FALSE;
279 /* We never select a default ARGB visual */
280 if(fmt->alphaMask)
281 return FALSE;
283 return TRUE;
286 static int load_xrender_formats(void)
288 int count = 0;
289 unsigned int i;
291 for (i = 0; i < WXR_NB_FORMATS; i++)
293 XRenderPictFormat templ;
295 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
297 wine_tsx11_lock();
298 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
299 if (!pict_formats[i])
301 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
302 if (visual->class == DirectColor)
304 XVisualInfo info;
305 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
306 screen_depth, TrueColor, &info ))
308 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
309 if (pict_formats[i]) visual = info.visual;
313 wine_tsx11_unlock();
314 if (pict_formats[i]) default_format = i;
316 else
318 unsigned long mask = 0;
319 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
321 wine_tsx11_lock();
322 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
323 wine_tsx11_unlock();
325 if (pict_formats[i])
327 count++;
328 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
331 return count;
334 /***********************************************************************
335 * X11DRV_XRender_Init
337 * Let's see if our XServer has the extension available
340 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
342 int event_base, i;
344 if (client_side_with_render &&
345 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
348 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
349 LOAD_FUNCPTR(XRenderAddGlyphs)
350 LOAD_FUNCPTR(XRenderComposite)
351 LOAD_FUNCPTR(XRenderCompositeString8)
352 LOAD_FUNCPTR(XRenderCompositeString16)
353 LOAD_FUNCPTR(XRenderCompositeString32)
354 LOAD_FUNCPTR(XRenderCompositeText16)
355 LOAD_FUNCPTR(XRenderCreateGlyphSet)
356 LOAD_FUNCPTR(XRenderCreatePicture)
357 LOAD_FUNCPTR(XRenderFillRectangle)
358 LOAD_FUNCPTR(XRenderFindFormat)
359 LOAD_FUNCPTR(XRenderFindVisualFormat)
360 LOAD_FUNCPTR(XRenderFreeGlyphSet)
361 LOAD_FUNCPTR(XRenderFreePicture)
362 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
363 LOAD_FUNCPTR(XRenderQueryExtension)
364 #undef LOAD_FUNCPTR
365 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
366 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
367 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
368 #undef LOAD_OPTIONAL_FUNCPTR
369 #endif
371 wine_tsx11_lock();
372 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
373 wine_tsx11_unlock();
374 if(X11DRV_XRender_Installed) {
375 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
376 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
378 wine_tsx11_unlock();
379 WINE_MESSAGE(
380 "Wine has detected that you probably have a buggy version\n"
381 "of libXrender.so . Because of this client side font rendering\n"
382 "will be disabled. Please upgrade this library.\n");
383 X11DRV_XRender_Installed = FALSE;
384 return NULL;
387 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
388 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
389 X11DRV_XRender_Installed = FALSE;
394 #ifdef SONAME_LIBFONTCONFIG
395 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
397 #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;}
398 LOAD_FUNCPTR(FcConfigSubstitute);
399 LOAD_FUNCPTR(FcDefaultSubstitute);
400 LOAD_FUNCPTR(FcFontMatch);
401 LOAD_FUNCPTR(FcInit);
402 LOAD_FUNCPTR(FcPatternCreate);
403 LOAD_FUNCPTR(FcPatternDestroy);
404 LOAD_FUNCPTR(FcPatternAddInteger);
405 LOAD_FUNCPTR(FcPatternAddString);
406 LOAD_FUNCPTR(FcPatternGetBool);
407 LOAD_FUNCPTR(FcPatternGetInteger);
408 LOAD_FUNCPTR(FcPatternGetString);
409 #undef LOAD_FUNCPTR
410 fontconfig_installed = pFcInit();
412 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
413 #endif
415 sym_not_found:
416 if(X11DRV_XRender_Installed || client_side_with_core)
418 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
419 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
421 glyphsetCacheSize = INIT_CACHE_SIZE;
422 lastfree = 0;
423 for(i = 0; i < INIT_CACHE_SIZE; i++) {
424 glyphsetCache[i].next = i + 1;
425 glyphsetCache[i].count = -1;
427 glyphsetCache[i-1].next = -1;
428 using_client_side_fonts = 1;
430 if(!X11DRV_XRender_Installed) {
431 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
432 if(screen_depth <= 8 || !client_side_antialias_with_core)
433 antialias = 0;
434 } else {
435 if(screen_depth <= 8 || !client_side_antialias_with_render)
436 antialias = 0;
438 return &xrender_funcs;
440 TRACE("Using X11 core fonts\n");
441 return NULL;
444 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
445 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
447 if(pf->direct.redMask)
448 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
449 else
450 dst_color->red = 0;
452 if(pf->direct.greenMask)
453 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
454 else
455 dst_color->green = 0;
457 if(pf->direct.blueMask)
458 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
459 else
460 dst_color->blue = 0;
462 dst_color->alpha = 0xffff;
465 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
467 int redMask, greenMask, blueMask;
468 unsigned int i;
470 if (depth == 1) return WXR_FORMAT_MONO;
472 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
473 if (!shifts) return default_format;
475 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
476 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
477 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
479 /* Try to locate a format which matches the specification of the dibsection. */
480 for(i = 0; i < WXR_NB_FORMATS; i++)
482 if( depth == wxr_formats_template[i].depth &&
483 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
484 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
485 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
486 return i;
489 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
490 ERR("No XRender format found!\n");
491 return WXR_INVALID_FORMAT;
494 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info, BOOL use_alpha )
496 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
498 switch (info->bmiHeader.biBitCount)
500 case 1:
501 return WXR_FORMAT_MONO;
502 case 4:
503 case 8:
504 break;
505 case 24:
506 if (info->bmiHeader.biCompression != BI_RGB) break;
507 return WXR_FORMAT_R8G8B8;
508 case 16:
509 case 32:
510 if (info->bmiHeader.biCompression == BI_BITFIELDS)
512 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
513 unsigned int i;
515 for (i = 0; i < WXR_NB_FORMATS; i++)
517 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
518 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
519 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
520 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
521 return i;
523 break;
525 if (info->bmiHeader.biCompression != BI_RGB) break;
526 if (info->bmiHeader.biBitCount == 16) return WXR_FORMAT_X1R5G5B5;
527 return use_alpha ? WXR_FORMAT_A8R8G8B8 : WXR_FORMAT_X8R8G8B8;
529 return WXR_INVALID_FORMAT;
532 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
533 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
535 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
536 XTransform xform = {{
537 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
538 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
539 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
542 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
543 #endif
546 /* check if we can use repeating instead of scaling for the specified source DC */
547 static BOOL use_source_repeat( struct xrender_physdev *dev )
549 return (dev->x11dev->bitmap &&
550 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
551 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
554 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
556 if (!dev->pict && dev->pict_format)
558 XRenderPictureAttributes pa;
560 wine_tsx11_lock();
561 pa.subwindow_mode = IncludeInferiors;
562 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
563 dev->pict_format, CPSubwindowMode, &pa );
564 wine_tsx11_unlock();
565 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
566 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
567 dev->update_clip = TRUE;
570 if (dev->update_clip)
572 RGNDATA *clip_data;
573 HRGN rgn = 0;
575 if (clip_rect)
577 rgn = CreateRectRgnIndirect( clip_rect );
578 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
579 CombineRgn( rgn, rgn, dev->x11dev->region, RGN_AND );
581 else if (clip_rgn)
583 rgn = CreateRectRgn( 0, 0, 0, 0 );
584 CombineRgn( rgn, clip_rgn, dev->x11dev->region, RGN_AND );
587 if ((clip_data = X11DRV_GetRegionData( rgn ? rgn : dev->x11dev->region, 0 )))
589 wine_tsx11_lock();
590 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
591 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
592 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
593 wine_tsx11_unlock();
594 HeapFree( GetProcessHeap(), 0, clip_data );
596 dev->update_clip = (rgn != 0); /* have to update again if we are using a custom region */
597 if (rgn) DeleteObject( rgn );
599 return dev->pict;
602 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
604 if (!dev->pict_src && dev->pict_format)
606 XRenderPictureAttributes pa;
608 wine_tsx11_lock();
609 pa.subwindow_mode = IncludeInferiors;
610 pa.repeat = repeat ? RepeatNormal : RepeatNone;
611 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
612 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
613 wine_tsx11_unlock();
615 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
616 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
619 return dev->pict_src;
622 static void free_xrender_picture( struct xrender_physdev *dev )
624 if (dev->pict || dev->pict_src)
626 wine_tsx11_lock();
627 XFlush( gdi_display );
628 if (dev->pict)
630 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
631 pXRenderFreePicture(gdi_display, dev->pict);
632 dev->pict = 0;
634 if(dev->pict_src)
636 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
637 pXRenderFreePicture(gdi_display, dev->pict_src);
638 dev->pict_src = 0;
640 wine_tsx11_unlock();
642 dev->pict_format = NULL;
645 static void update_xrender_drawable( struct xrender_physdev *dev )
647 free_xrender_picture( dev );
648 dev->format = get_xrender_format_from_color_shifts( dev->x11dev->depth, dev->x11dev->color_shifts );
649 dev->pict_format = pict_formats[dev->format];
652 /* return a mask picture used to force alpha to 0 */
653 static Picture get_no_alpha_mask(void)
655 static Pixmap pixmap;
656 static Picture pict;
658 wine_tsx11_lock();
659 if (!pict)
661 XRenderPictureAttributes pa;
662 XRenderColor col;
664 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
665 pa.repeat = RepeatNormal;
666 pa.component_alpha = True;
667 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
668 CPRepeat|CPComponentAlpha, &pa );
669 col.red = col.green = col.blue = 0xffff;
670 col.alpha = 0;
671 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
673 wine_tsx11_unlock();
674 return pict;
677 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
679 if(p1->hash != p2->hash) return TRUE;
680 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
681 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
682 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
683 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
686 #if 0
687 static void walk_cache(void)
689 int i;
691 EnterCriticalSection(&xrender_cs);
692 for(i=mru; i >= 0; i = glyphsetCache[i].next)
693 TRACE("item %d\n", i);
694 LeaveCriticalSection(&xrender_cs);
696 #endif
698 static int LookupEntry(LFANDSIZE *plfsz)
700 int i, prev_i = -1;
702 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
703 TRACE("%d\n", i);
704 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
706 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
707 glyphsetCache[i].count++;
708 if(prev_i >= 0) {
709 glyphsetCache[prev_i].next = glyphsetCache[i].next;
710 glyphsetCache[i].next = mru;
711 mru = i;
713 TRACE("found font in cache %d\n", i);
714 return i;
716 prev_i = i;
718 TRACE("font not in cache\n");
719 return -1;
722 static void FreeEntry(int entry)
724 int i, format;
726 for(format = 0; format < AA_MAXVALUE; format++) {
727 gsCacheEntryFormat * formatEntry;
729 if( !glyphsetCache[entry].format[format] )
730 continue;
732 formatEntry = glyphsetCache[entry].format[format];
734 if(formatEntry->glyphset) {
735 wine_tsx11_lock();
736 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
737 wine_tsx11_unlock();
738 formatEntry->glyphset = 0;
740 if(formatEntry->nrealized) {
741 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
742 formatEntry->realized = NULL;
743 if(formatEntry->bitmaps) {
744 for(i = 0; i < formatEntry->nrealized; i++)
745 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
746 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
747 formatEntry->bitmaps = NULL;
749 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
750 formatEntry->gis = NULL;
751 formatEntry->nrealized = 0;
754 HeapFree(GetProcessHeap(), 0, formatEntry);
755 glyphsetCache[entry].format[format] = NULL;
759 static int AllocEntry(void)
761 int best = -1, prev_best = -1, i, prev_i = -1;
763 if(lastfree >= 0) {
764 assert(glyphsetCache[lastfree].count == -1);
765 glyphsetCache[lastfree].count = 1;
766 best = lastfree;
767 lastfree = glyphsetCache[lastfree].next;
768 assert(best != mru);
769 glyphsetCache[best].next = mru;
770 mru = best;
772 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
773 return mru;
776 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
777 if(glyphsetCache[i].count == 0) {
778 best = i;
779 prev_best = prev_i;
781 prev_i = i;
784 if(best >= 0) {
785 TRACE("freeing unused glyphset at cache %d\n", best);
786 FreeEntry(best);
787 glyphsetCache[best].count = 1;
788 if(prev_best >= 0) {
789 glyphsetCache[prev_best].next = glyphsetCache[best].next;
790 glyphsetCache[best].next = mru;
791 mru = best;
792 } else {
793 assert(mru == best);
795 return mru;
798 TRACE("Growing cache\n");
800 if (glyphsetCache)
801 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
802 glyphsetCache,
803 (glyphsetCacheSize + INIT_CACHE_SIZE)
804 * sizeof(*glyphsetCache));
805 else
806 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
807 (glyphsetCacheSize + INIT_CACHE_SIZE)
808 * sizeof(*glyphsetCache));
810 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
811 i++) {
812 glyphsetCache[i].next = i + 1;
813 glyphsetCache[i].count = -1;
815 glyphsetCache[i-1].next = -1;
816 glyphsetCacheSize += INIT_CACHE_SIZE;
818 lastfree = glyphsetCache[best].next;
819 glyphsetCache[best].count = 1;
820 glyphsetCache[best].next = mru;
821 mru = best;
822 TRACE("new free cache slot at %d\n", mru);
823 return mru;
826 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
828 DWORD size;
829 WORD *gasp, *buffer;
830 WORD num_recs;
831 DWORD ppem;
832 TEXTMETRICW tm;
834 *flags = 0;
836 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
837 if(size == GDI_ERROR)
838 return FALSE;
840 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
841 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
843 GetTextMetricsW(hdc, &tm);
844 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
846 gasp++;
847 num_recs = get_be_word(*gasp);
848 gasp++;
849 while(num_recs--)
851 *flags = get_be_word(*(gasp + 1));
852 if(ppem <= get_be_word(*gasp))
853 break;
854 gasp += 2;
856 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
858 HeapFree(GetProcessHeap(), 0, buffer);
859 return TRUE;
862 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
864 AA_Type ret;
865 WORD flags;
866 UINT font_smoothing_type, font_smoothing_orientation;
868 if (X11DRV_XRender_Installed && subpixel &&
869 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
870 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
872 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
873 &font_smoothing_orientation, 0) &&
874 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
876 ret = AA_BGR;
878 else
879 ret = AA_RGB;
880 /*FIXME
881 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
882 But, Wine's subpixel rendering can support the portrait mode.
885 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
886 ret = AA_Grey;
887 else
888 ret = AA_None;
890 return ret;
893 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
895 int ret;
896 int format;
897 gsCacheEntry *entry;
898 static int hinter = -1;
899 static int subpixel = -1;
900 BOOL font_smoothing;
902 if((ret = LookupEntry(plfsz)) != -1) return ret;
904 ret = AllocEntry();
905 entry = glyphsetCache + ret;
906 entry->lfsz = *plfsz;
907 for( format = 0; format < AA_MAXVALUE; format++ ) {
908 assert( !entry->format[format] );
911 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
913 if(hinter == -1 || subpixel == -1)
915 RASTERIZER_STATUS status;
916 GetRasterizerCaps(&status, sizeof(status));
917 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
918 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
921 switch (plfsz->lf.lfQuality)
923 case ANTIALIASED_QUALITY:
924 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
925 return ret; /* ignore further configuration */
926 case CLEARTYPE_QUALITY:
927 case CLEARTYPE_NATURAL_QUALITY:
928 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
929 break;
930 case DEFAULT_QUALITY:
931 case DRAFT_QUALITY:
932 case PROOF_QUALITY:
933 default:
934 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
935 font_smoothing)
937 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
939 else
940 entry->aa_default = AA_None;
941 break;
944 font_smoothing = TRUE; /* default to enabled */
945 #ifdef SONAME_LIBFONTCONFIG
946 if (fontconfig_installed)
948 FcPattern *match, *pattern = pFcPatternCreate();
949 FcResult result;
950 char family[LF_FACESIZE * 4];
952 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
953 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
954 if (plfsz->lf.lfWeight != FW_DONTCARE)
956 int weight;
957 switch (plfsz->lf.lfWeight)
959 case FW_THIN: weight = FC_WEIGHT_THIN; break;
960 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
961 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
962 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
963 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
964 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
965 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
966 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
967 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
968 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
970 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
972 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
973 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
974 pFcDefaultSubstitute( pattern );
975 if ((match = pFcFontMatch( NULL, pattern, &result )))
977 int rgba;
978 FcBool antialias;
980 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
981 antialias = TRUE;
982 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
984 FcChar8 *file;
985 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
987 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
988 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
990 switch (rgba)
992 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
993 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
994 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
995 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
996 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
999 if (!antialias) font_smoothing = FALSE;
1000 pFcPatternDestroy( match );
1002 pFcPatternDestroy( pattern );
1004 #endif /* SONAME_LIBFONTCONFIG */
1006 /* now check Xft resources */
1008 char *value;
1009 BOOL antialias = TRUE;
1011 wine_tsx11_lock();
1012 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1014 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1015 value[0] == '0' || !strcasecmp( value, "off" ))
1016 antialias = FALSE;
1018 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1020 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1021 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1022 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1023 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1024 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1025 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1027 wine_tsx11_unlock();
1028 if (!antialias) font_smoothing = FALSE;
1031 if (!font_smoothing) entry->aa_default = AA_None;
1033 /* we can't support subpixel without xrender */
1034 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1036 else
1037 entry->aa_default = AA_None;
1039 return ret;
1042 static void dec_ref_cache(int index)
1044 assert(index >= 0);
1045 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1046 assert(glyphsetCache[index].count > 0);
1047 glyphsetCache[index].count--;
1050 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1052 DWORD hash = 0, *ptr, two_chars;
1053 WORD *pwc;
1054 int i;
1056 hash ^= plfsz->devsize.cx;
1057 hash ^= plfsz->devsize.cy;
1058 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1059 hash ^= *ptr;
1060 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1061 hash ^= *ptr;
1062 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1063 two_chars = *ptr;
1064 pwc = (WCHAR *)&two_chars;
1065 if(!*pwc) break;
1066 *pwc = toupperW(*pwc);
1067 pwc++;
1068 *pwc = toupperW(*pwc);
1069 hash ^= two_chars;
1070 if(!*pwc) break;
1072 plfsz->hash = hash;
1073 return;
1076 /***********************************************************************
1077 * X11DRV_XRender_Finalize
1079 void X11DRV_XRender_Finalize(void)
1081 int i;
1083 EnterCriticalSection(&xrender_cs);
1084 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1085 FreeEntry(i);
1086 LeaveCriticalSection(&xrender_cs);
1089 /**********************************************************************
1090 * xrenderdrv_SelectFont
1092 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
1094 struct xrender_physdev *physdev = get_xrender_dev( dev );
1095 LFANDSIZE lfsz;
1097 if (!GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf )) return HGDI_ERROR;
1099 if (!gdiFont)
1101 dev = GET_NEXT_PHYSDEV( dev, pSelectFont );
1102 return dev->funcs->pSelectFont( dev, hfont, gdiFont );
1105 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1106 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1107 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1108 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1109 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1110 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1112 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1113 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1114 lfsz.xform.eM21, lfsz.xform.eM22);
1116 /* Not used fields, would break hashing */
1117 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1119 lfsz_calc_hash(&lfsz);
1121 EnterCriticalSection(&xrender_cs);
1122 if (physdev->cache_index != -1)
1123 dec_ref_cache( physdev->cache_index );
1124 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1125 LeaveCriticalSection(&xrender_cs);
1126 physdev->x11dev->has_gdi_font = TRUE;
1127 return 0;
1130 static BOOL create_xrender_dc( PHYSDEV *pdev )
1132 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1133 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1135 if (!physdev) return FALSE;
1136 physdev->x11dev = x11dev;
1137 physdev->cache_index = -1;
1138 physdev->format = get_xrender_format_from_color_shifts( x11dev->depth, x11dev->color_shifts );
1139 physdev->pict_format = pict_formats[physdev->format];
1140 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1141 return TRUE;
1144 /* store the color mask data in the bitmap info structure */
1145 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1147 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1149 info->bmiHeader.biPlanes = 1;
1150 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1151 info->bmiHeader.biCompression = BI_RGB;
1152 info->bmiHeader.biClrUsed = 0;
1154 switch (info->bmiHeader.biBitCount)
1156 case 16:
1157 colors[0] = format->direct.redMask << format->direct.red;
1158 colors[1] = format->direct.greenMask << format->direct.green;
1159 colors[2] = format->direct.blueMask << format->direct.blue;
1160 info->bmiHeader.biCompression = BI_BITFIELDS;
1161 break;
1162 case 32:
1163 colors[0] = format->direct.redMask << format->direct.red;
1164 colors[1] = format->direct.greenMask << format->direct.green;
1165 colors[2] = format->direct.blueMask << format->direct.blue;
1166 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1167 info->bmiHeader.biCompression = BI_BITFIELDS;
1168 break;
1173 /**********************************************************************
1174 * xrenderdrv_CreateDC
1176 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1177 LPCWSTR output, const DEVMODEW* initData )
1179 return create_xrender_dc( pdev );
1182 /**********************************************************************
1183 * xrenderdrv_CreateCompatibleDC
1185 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1187 if (orig) /* chain to x11drv first */
1189 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1190 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1192 /* otherwise we have been called by x11drv */
1194 return create_xrender_dc( pdev );
1197 /**********************************************************************
1198 * xrenderdrv_DeleteDC
1200 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1202 struct xrender_physdev *physdev = get_xrender_dev( dev );
1204 free_xrender_picture( physdev );
1206 EnterCriticalSection( &xrender_cs );
1207 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1208 LeaveCriticalSection( &xrender_cs );
1210 HeapFree( GetProcessHeap(), 0, physdev );
1211 return TRUE;
1214 /**********************************************************************
1215 * xrenderdrv_ExtEscape
1217 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1218 INT out_count, LPVOID out_data )
1220 struct xrender_physdev *physdev = get_xrender_dev( dev );
1222 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1224 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1226 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1228 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1229 if (ret) update_xrender_drawable( physdev );
1230 return ret;
1233 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1236 /****************************************************************************
1237 * xrenderdrv_CreateBitmap
1239 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1241 XRenderPictFormat *pict_format = NULL;
1242 ColorShifts shifts;
1243 BITMAP bitmap;
1245 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1247 if (bitmap.bmPlanes == 1 && bitmap.bmBitsPixel == screen_bpp)
1249 switch (bitmap.bmBitsPixel)
1251 case 16: pict_format = pict_formats[WXR_FORMAT_R5G6B5]; break;
1252 case 24: pict_format = pict_formats[WXR_FORMAT_R8G8B8]; break;
1253 case 32: pict_format = pict_formats[WXR_FORMAT_A8R8G8B8]; break;
1257 if (pict_format)
1259 X11DRV_PALETTE_ComputeColorShifts( &shifts,
1260 pict_format->direct.redMask << pict_format->direct.red,
1261 pict_format->direct.greenMask << pict_format->direct.green,
1262 pict_format->direct.blueMask << pict_format->direct.blue );
1263 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_format->depth, TRUE, &shifts );
1266 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1267 return dev->funcs->pCreateBitmap( dev, hbitmap );
1270 /****************************************************************************
1271 * xrenderdrv_DeleteBitmap
1273 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1275 return X11DRV_DeleteBitmap( hbitmap );
1278 /***********************************************************************
1279 * xrenderdrv_SelectBitmap
1281 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1283 HBITMAP ret;
1284 struct xrender_physdev *physdev = get_xrender_dev( dev );
1286 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1287 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1288 if (ret) update_xrender_drawable( physdev );
1289 return ret;
1292 /***********************************************************************
1293 * xrenderdrv_GetImage
1295 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1296 struct gdi_image_bits *bits, struct bitblt_coords *src )
1298 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1299 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1300 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1303 /***********************************************************************
1304 * xrenderdrv_SetDeviceClipping
1306 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1308 struct xrender_physdev *physdev = get_xrender_dev( dev );
1310 physdev->update_clip = TRUE;
1312 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1313 dev->funcs->pSetDeviceClipping( dev, vis_rgn, clip_rgn );
1317 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1319 XRenderPictFormat *pict_format;
1320 ColorShifts shifts;
1321 const DWORD *bitfields;
1322 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1323 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1326 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1327 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1328 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1329 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1330 return FALSE;
1332 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1333 bitfields = dib->dsBitfields;
1334 else if(bits_pixel == 24 || bits_pixel == 32)
1335 bitfields = bitfields_32;
1336 else
1337 bitfields = bitfields_16;
1339 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1340 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1342 /* Common formats should be in our picture format table. */
1343 if (!pict_format)
1345 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1346 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1347 return FALSE;
1350 physBitmap->pixmap_depth = pict_format->depth;
1351 physBitmap->trueColor = TRUE;
1352 physBitmap->pixmap_color_shifts = shifts;
1353 return TRUE;
1356 /************************************************************************
1357 * UploadGlyph
1359 * Helper to ExtTextOut. Must be called inside xrender_cs
1361 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1363 unsigned int buflen;
1364 char *buf;
1365 Glyph gid;
1366 GLYPHMETRICS gm;
1367 XGlyphInfo gi;
1368 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1369 gsCacheEntryFormat *formatEntry;
1370 UINT ggo_format = GGO_GLYPH_INDEX;
1371 enum wxr_format wxr_format;
1372 static const char zero[4];
1373 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1375 switch(format) {
1376 case AA_Grey:
1377 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1378 break;
1379 case AA_RGB:
1380 ggo_format |= WINE_GGO_HRGB_BITMAP;
1381 break;
1382 case AA_BGR:
1383 ggo_format |= WINE_GGO_HBGR_BITMAP;
1384 break;
1385 case AA_VRGB:
1386 ggo_format |= WINE_GGO_VRGB_BITMAP;
1387 break;
1388 case AA_VBGR:
1389 ggo_format |= WINE_GGO_VBGR_BITMAP;
1390 break;
1392 default:
1393 ERR("aa = %d - not implemented\n", format);
1394 case AA_None:
1395 ggo_format |= GGO_BITMAP;
1396 break;
1399 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1400 if(buflen == GDI_ERROR) {
1401 if(format != AA_None) {
1402 format = AA_None;
1403 entry->aa_default = AA_None;
1404 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1405 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1407 if(buflen == GDI_ERROR) {
1408 WARN("GetGlyphOutlineW failed using default glyph\n");
1409 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1410 if(buflen == GDI_ERROR) {
1411 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1412 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1413 if(buflen == GDI_ERROR) {
1414 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1415 return;
1419 TRACE("Turning off antialiasing for this monochrome font\n");
1422 /* If there is nothing for the current type, we create the entry. */
1423 if( !entry->format[format] ) {
1424 entry->format[format] = HeapAlloc(GetProcessHeap(),
1425 HEAP_ZERO_MEMORY,
1426 sizeof(gsCacheEntryFormat));
1428 formatEntry = entry->format[format];
1430 if(formatEntry->nrealized <= glyph) {
1431 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1433 if (formatEntry->realized)
1434 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1435 HEAP_ZERO_MEMORY,
1436 formatEntry->realized,
1437 formatEntry->nrealized * sizeof(BOOL));
1438 else
1439 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1440 HEAP_ZERO_MEMORY,
1441 formatEntry->nrealized * sizeof(BOOL));
1443 if(!X11DRV_XRender_Installed) {
1444 if (formatEntry->bitmaps)
1445 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1446 HEAP_ZERO_MEMORY,
1447 formatEntry->bitmaps,
1448 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1449 else
1450 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1451 HEAP_ZERO_MEMORY,
1452 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1454 if (formatEntry->gis)
1455 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1456 HEAP_ZERO_MEMORY,
1457 formatEntry->gis,
1458 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1459 else
1460 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1461 HEAP_ZERO_MEMORY,
1462 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1466 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1467 switch(format) {
1468 case AA_Grey:
1469 wxr_format = WXR_FORMAT_GRAY;
1470 break;
1472 case AA_RGB:
1473 case AA_BGR:
1474 case AA_VRGB:
1475 case AA_VBGR:
1476 wxr_format = WXR_FORMAT_A8R8G8B8;
1477 break;
1479 default:
1480 ERR("aa = %d - not implemented\n", format);
1481 case AA_None:
1482 wxr_format = WXR_FORMAT_MONO;
1483 break;
1486 wine_tsx11_lock();
1487 formatEntry->font_format = pict_formats[wxr_format];
1488 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1489 wine_tsx11_unlock();
1493 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1494 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1495 formatEntry->realized[glyph] = TRUE;
1497 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1498 buflen,
1499 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1500 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1502 gi.width = gm.gmBlackBoxX;
1503 gi.height = gm.gmBlackBoxY;
1504 gi.x = -gm.gmptGlyphOrigin.x;
1505 gi.y = gm.gmptGlyphOrigin.y;
1506 gi.xOff = gm.gmCellIncX;
1507 gi.yOff = gm.gmCellIncY;
1509 if(TRACE_ON(xrender)) {
1510 int pitch, i, j;
1511 char output[300];
1512 unsigned char *line;
1514 if(format == AA_None) {
1515 pitch = ((gi.width + 31) / 32) * 4;
1516 for(i = 0; i < gi.height; i++) {
1517 line = (unsigned char*) buf + i * pitch;
1518 output[0] = '\0';
1519 for(j = 0; j < pitch * 8; j++) {
1520 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1522 TRACE("%s\n", output);
1524 } else {
1525 static const char blks[] = " .:;!o*#";
1526 char str[2];
1528 str[1] = '\0';
1529 pitch = ((gi.width + 3) / 4) * 4;
1530 for(i = 0; i < gi.height; i++) {
1531 line = (unsigned char*) buf + i * pitch;
1532 output[0] = '\0';
1533 for(j = 0; j < pitch; j++) {
1534 str[0] = blks[line[j] >> 5];
1535 strcat(output, str);
1537 TRACE("%s\n", output);
1543 if(formatEntry->glyphset) {
1544 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1545 unsigned char *byte = (unsigned char*) buf, c;
1546 int i = buflen;
1548 while(i--) {
1549 c = *byte;
1551 /* magic to flip bit order */
1552 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1553 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1554 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1556 *byte++ = c;
1559 else if ( format != AA_Grey &&
1560 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1562 unsigned int i, *data = (unsigned int *)buf;
1563 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1565 gid = glyph;
1568 XRenderCompositeText seems to ignore 0x0 glyphs when
1569 AA_None, which means we lose the advance width of glyphs
1570 like the space. We'll pretend that such glyphs are 1x1
1571 bitmaps.
1574 if(buflen == 0)
1575 gi.width = gi.height = 1;
1577 wine_tsx11_lock();
1578 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1579 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1580 wine_tsx11_unlock();
1581 HeapFree(GetProcessHeap(), 0, buf);
1582 } else {
1583 formatEntry->bitmaps[glyph] = buf;
1586 formatEntry->gis[glyph] = gi;
1589 static void SharpGlyphMono(struct xrender_physdev *physDev, INT x, INT y,
1590 void *bitmap, XGlyphInfo *gi)
1592 unsigned char *srcLine = bitmap, *src;
1593 unsigned char bits, bitsMask;
1594 int width = gi->width;
1595 int stride = ((width + 31) & ~31) >> 3;
1596 int height = gi->height;
1597 int w;
1598 int xspan, lenspan;
1600 TRACE("%d, %d\n", x, y);
1601 x -= gi->x;
1602 y -= gi->y;
1603 while (height--)
1605 src = srcLine;
1606 srcLine += stride;
1607 w = width;
1609 bitsMask = 0x80; /* FreeType is always MSB first */
1610 bits = *src++;
1612 xspan = x;
1613 while (w)
1615 if (bits & bitsMask)
1617 lenspan = 0;
1620 lenspan++;
1621 if (lenspan == w)
1622 break;
1623 bitsMask = bitsMask >> 1;
1624 if (!bitsMask)
1626 bits = *src++;
1627 bitsMask = 0x80;
1629 } while (bits & bitsMask);
1630 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1631 physDev->x11dev->gc, xspan, y, lenspan, 1);
1632 xspan += lenspan;
1633 w -= lenspan;
1635 else
1639 w--;
1640 xspan++;
1641 if (!w)
1642 break;
1643 bitsMask = bitsMask >> 1;
1644 if (!bitsMask)
1646 bits = *src++;
1647 bitsMask = 0x80;
1649 } while (!(bits & bitsMask));
1652 y++;
1656 static void SharpGlyphGray(struct xrender_physdev *physDev, INT x, INT y,
1657 void *bitmap, XGlyphInfo *gi)
1659 unsigned char *srcLine = bitmap, *src, bits;
1660 int width = gi->width;
1661 int stride = ((width + 3) & ~3);
1662 int height = gi->height;
1663 int w;
1664 int xspan, lenspan;
1666 x -= gi->x;
1667 y -= gi->y;
1668 while (height--)
1670 src = srcLine;
1671 srcLine += stride;
1672 w = width;
1674 bits = *src++;
1675 xspan = x;
1676 while (w)
1678 if (bits >= 0x80)
1680 lenspan = 0;
1683 lenspan++;
1684 if (lenspan == w)
1685 break;
1686 bits = *src++;
1687 } while (bits >= 0x80);
1688 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1689 physDev->x11dev->gc, xspan, y, lenspan, 1);
1690 xspan += lenspan;
1691 w -= lenspan;
1693 else
1697 w--;
1698 xspan++;
1699 if (!w)
1700 break;
1701 bits = *src++;
1702 } while (bits < 0x80);
1705 y++;
1710 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1712 int s, l;
1714 s = 0;
1715 while ((mask & 1) == 0)
1717 mask >>= 1;
1718 s++;
1720 l = 0;
1721 while ((mask & 1) == 1)
1723 mask >>= 1;
1724 l++;
1726 *shift = s;
1727 *len = l;
1730 static DWORD GetField (DWORD pixel, int shift, int len)
1732 pixel = pixel & (((1 << (len)) - 1) << shift);
1733 pixel = pixel << (32 - (shift + len)) >> 24;
1734 while (len < 8)
1736 pixel |= (pixel >> len);
1737 len <<= 1;
1739 return pixel;
1743 static DWORD PutField (DWORD pixel, int shift, int len)
1745 shift = shift - (8 - len);
1746 if (len <= 8)
1747 pixel &= (((1 << len) - 1) << (8 - len));
1748 if (shift < 0)
1749 pixel >>= -shift;
1750 else
1751 pixel <<= shift;
1752 return pixel;
1755 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1756 int color)
1758 int r_shift, r_len;
1759 int g_shift, g_len;
1760 int b_shift, b_len;
1761 BYTE *maskLine, *mask, m;
1762 int maskStride;
1763 DWORD pixel;
1764 int width, height;
1765 int w, tx;
1766 BYTE src_r, src_g, src_b;
1768 x -= gi->x;
1769 y -= gi->y;
1770 width = gi->width;
1771 height = gi->height;
1773 maskLine = bitmap;
1774 maskStride = (width + 3) & ~3;
1776 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1777 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1778 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1780 src_r = GetField(color, r_shift, r_len);
1781 src_g = GetField(color, g_shift, g_len);
1782 src_b = GetField(color, b_shift, b_len);
1784 for(; height--; y++)
1786 mask = maskLine;
1787 maskLine += maskStride;
1788 w = width;
1789 tx = x;
1791 if(y < 0) continue;
1792 if(y >= image->height) break;
1794 for(; w--; tx++)
1796 if(tx >= image->width) break;
1798 m = *mask++;
1799 if(tx < 0) continue;
1801 if (m == 0xff)
1802 XPutPixel (image, tx, y, color);
1803 else if (m)
1805 BYTE r, g, b;
1807 pixel = XGetPixel (image, tx, y);
1809 r = GetField(pixel, r_shift, r_len);
1810 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1811 g = GetField(pixel, g_shift, g_len);
1812 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1813 b = GetField(pixel, b_shift, b_len);
1814 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1816 pixel = (PutField (r, r_shift, r_len) |
1817 PutField (g, g_shift, g_len) |
1818 PutField (b, b_shift, b_len));
1819 XPutPixel (image, tx, y, pixel);
1825 /*************************************************************
1826 * get_tile_pict
1828 * Returns an appropriate Picture for tiling the text colour.
1829 * Call and use result within the xrender_cs
1831 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1833 static struct
1835 Pixmap xpm;
1836 Picture pict;
1837 XRenderColor current_color;
1838 } tiles[WXR_NB_FORMATS], *tile;
1840 tile = &tiles[wxr_format];
1842 if(!tile->xpm)
1844 XRenderPictureAttributes pa;
1845 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1847 wine_tsx11_lock();
1848 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1850 pa.repeat = RepeatNormal;
1851 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1852 wine_tsx11_unlock();
1854 /* init current_color to something different from text_pixel */
1855 tile->current_color = *color;
1856 tile->current_color.red ^= 0xffff;
1858 if (wxr_format == WXR_FORMAT_MONO)
1860 /* for a 1bpp bitmap we always need a 1 in the tile */
1861 XRenderColor col;
1862 col.red = col.green = col.blue = 0;
1863 col.alpha = 0xffff;
1864 wine_tsx11_lock();
1865 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1866 wine_tsx11_unlock();
1870 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1872 wine_tsx11_lock();
1873 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1874 wine_tsx11_unlock();
1875 tile->current_color = *color;
1877 return tile->pict;
1880 /*************************************************************
1881 * get_mask_pict
1883 * Returns an appropriate Picture for masking with the specified alpha.
1884 * Call and use result within the xrender_cs
1886 static Picture get_mask_pict( int alpha )
1888 static Pixmap pixmap;
1889 static Picture pict;
1890 static int current_alpha;
1892 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1894 if (!pixmap)
1896 XRenderPictureAttributes pa;
1898 wine_tsx11_lock();
1899 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1900 pa.repeat = RepeatNormal;
1901 pict = pXRenderCreatePicture( gdi_display, pixmap,
1902 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1903 wine_tsx11_unlock();
1904 current_alpha = -1;
1907 if (alpha != current_alpha)
1909 XRenderColor col;
1910 col.red = col.green = col.blue = 0;
1911 col.alpha = current_alpha = alpha;
1912 wine_tsx11_lock();
1913 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1914 wine_tsx11_unlock();
1916 return pict;
1919 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1921 return 1;
1924 /********************************************************************
1925 * is_dib_with_colortable
1927 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1929 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1931 DIBSECTION dib;
1933 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1934 dib.dsBmih.biBitCount <= 8 )
1935 return TRUE;
1937 return FALSE;
1940 /***********************************************************************
1941 * xrenderdrv_ExtTextOut
1943 BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1944 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1946 struct xrender_physdev *physdev = get_xrender_dev( dev );
1947 XGCValues xgcval;
1948 gsCacheEntry *entry;
1949 gsCacheEntryFormat *formatEntry;
1950 BOOL retv = FALSE;
1951 int textPixel, backgroundPixel;
1952 RGNDATA *saved_region = NULL;
1953 BOOL disable_antialias = FALSE;
1954 AA_Type aa_type = AA_None;
1955 unsigned int idx;
1956 Picture tile_pict = 0;
1958 if (!physdev->x11dev->has_gdi_font)
1960 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1961 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1964 if(is_dib_with_colortable( physdev->x11dev ))
1966 TRACE("Disabling antialiasing\n");
1967 disable_antialias = TRUE;
1970 xgcval.function = GXcopy;
1971 xgcval.background = physdev->x11dev->backgroundPixel;
1972 xgcval.fill_style = FillSolid;
1973 wine_tsx11_lock();
1974 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1975 wine_tsx11_unlock();
1977 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
1979 if(physdev->x11dev->depth == 1) {
1980 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1981 textPixel = 0;
1982 backgroundPixel = 1;
1983 } else {
1984 textPixel = 1;
1985 backgroundPixel = 0;
1987 } else {
1988 textPixel = physdev->x11dev->textPixel;
1989 backgroundPixel = physdev->x11dev->backgroundPixel;
1992 if(flags & ETO_OPAQUE)
1994 wine_tsx11_lock();
1995 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
1996 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
1997 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
1998 lprect->right - lprect->left, lprect->bottom - lprect->top );
1999 wine_tsx11_unlock();
2002 if(count == 0)
2004 retv = TRUE;
2005 goto done_unlock;
2008 EnterCriticalSection(&xrender_cs);
2010 entry = glyphsetCache + physdev->cache_index;
2011 if( disable_antialias == FALSE )
2012 aa_type = entry->aa_default;
2013 formatEntry = entry->format[aa_type];
2015 for(idx = 0; idx < count; idx++) {
2016 if( !formatEntry ) {
2017 UploadGlyph(physdev, wstr[idx], aa_type);
2018 /* re-evaluate antialias since aa_default may have changed */
2019 if( disable_antialias == FALSE )
2020 aa_type = entry->aa_default;
2021 formatEntry = entry->format[aa_type];
2022 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
2023 UploadGlyph(physdev, wstr[idx], aa_type);
2026 if (!formatEntry)
2028 WARN("could not upload requested glyphs\n");
2029 LeaveCriticalSection(&xrender_cs);
2030 goto done_unlock;
2033 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
2034 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2036 if(X11DRV_XRender_Installed)
2038 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
2039 POINT offset = {0, 0};
2040 POINT desired, current;
2041 int render_op = PictOpOver;
2042 Picture pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
2043 XRenderColor col;
2045 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
2046 So we pass zeros to the function and move to our starting position using the first
2047 element of the elts array. */
2049 desired.x = physdev->x11dev->dc_rect.left + x;
2050 desired.y = physdev->x11dev->dc_rect.top + y;
2051 current.x = current.y = 0;
2053 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
2054 tile_pict = get_tile_pict(physdev->format, &col);
2056 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
2058 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
2059 render_op = PictOpOutReverse; /* This gives us 'black' text */
2061 for(idx = 0; idx < count; idx++)
2063 elts[idx].glyphset = formatEntry->glyphset;
2064 elts[idx].chars = wstr + idx;
2065 elts[idx].nchars = 1;
2066 elts[idx].xOff = desired.x - current.x;
2067 elts[idx].yOff = desired.y - current.y;
2069 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
2070 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
2072 if(!lpDx)
2074 desired.x += formatEntry->gis[wstr[idx]].xOff;
2075 desired.y += formatEntry->gis[wstr[idx]].yOff;
2077 else
2079 if(flags & ETO_PDY)
2081 offset.x += lpDx[idx * 2];
2082 offset.y += lpDx[idx * 2 + 1];
2084 else
2085 offset.x += lpDx[idx];
2086 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
2087 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
2091 wine_tsx11_lock();
2092 /* Make sure we don't have any transforms set from a previous call */
2093 set_xrender_transformation(pict, 1, 1, 0, 0);
2094 pXRenderCompositeText16(gdi_display, render_op,
2095 tile_pict,
2096 pict,
2097 formatEntry->font_format,
2098 0, 0, 0, 0, elts, count);
2099 wine_tsx11_unlock();
2100 HeapFree(GetProcessHeap(), 0, elts);
2101 } else {
2102 POINT offset = {0, 0};
2104 if (flags & ETO_CLIPPED)
2106 HRGN clip_region = CreateRectRgnIndirect( lprect );
2107 saved_region = add_extra_clipping_region( physdev->x11dev, clip_region );
2108 DeleteObject( clip_region );
2111 wine_tsx11_lock();
2112 XSetForeground( gdi_display, physdev->x11dev->gc, textPixel );
2114 if(aa_type == AA_None || physdev->x11dev->depth == 1)
2116 void (* sharp_glyph_fn)(struct xrender_physdev *, INT, INT, void *, XGlyphInfo *);
2118 if(aa_type == AA_None)
2119 sharp_glyph_fn = SharpGlyphMono;
2120 else
2121 sharp_glyph_fn = SharpGlyphGray;
2123 for(idx = 0; idx < count; idx++) {
2124 sharp_glyph_fn(physdev,
2125 physdev->x11dev->dc_rect.left + x + offset.x,
2126 physdev->x11dev->dc_rect.top + y + offset.y,
2127 formatEntry->bitmaps[wstr[idx]],
2128 &formatEntry->gis[wstr[idx]]);
2129 if(lpDx)
2131 if(flags & ETO_PDY)
2133 offset.x += lpDx[idx * 2];
2134 offset.y += lpDx[idx * 2 + 1];
2136 else
2137 offset.x += lpDx[idx];
2139 else
2141 offset.x += formatEntry->gis[wstr[idx]].xOff;
2142 offset.y += formatEntry->gis[wstr[idx]].yOff;
2145 } else {
2146 XImage *image;
2147 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2148 RECT extents = {0, 0, 0, 0};
2149 POINT cur = {0, 0};
2150 int w = physdev->x11dev->drawable_rect.right - physdev->x11dev->drawable_rect.left;
2151 int h = physdev->x11dev->drawable_rect.bottom - physdev->x11dev->drawable_rect.top;
2153 TRACE("drawable %dx%d\n", w, h);
2155 for(idx = 0; idx < count; idx++) {
2156 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2157 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2158 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2159 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2160 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2161 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2162 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2163 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2165 if(lpDx)
2167 if(flags & ETO_PDY)
2169 cur.x += lpDx[idx * 2];
2170 cur.y += lpDx[idx * 2 + 1];
2172 else
2173 cur.x += lpDx[idx];
2175 else
2177 cur.x += formatEntry->gis[wstr[idx]].xOff;
2178 cur.y += formatEntry->gis[wstr[idx]].yOff;
2181 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2182 extents.right, extents.bottom, physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2184 if(physdev->x11dev->dc_rect.left + x + extents.left >= 0) {
2185 image_x = physdev->x11dev->dc_rect.left + x + extents.left;
2186 image_off_x = 0;
2187 } else {
2188 image_x = 0;
2189 image_off_x = physdev->x11dev->dc_rect.left + x + extents.left;
2191 if(physdev->x11dev->dc_rect.top + y + extents.top >= 0) {
2192 image_y = physdev->x11dev->dc_rect.top + y + extents.top;
2193 image_off_y = 0;
2194 } else {
2195 image_y = 0;
2196 image_off_y = physdev->x11dev->dc_rect.top + y + extents.top;
2198 if(physdev->x11dev->dc_rect.left + x + extents.right < w)
2199 image_w = physdev->x11dev->dc_rect.left + x + extents.right - image_x;
2200 else
2201 image_w = w - image_x;
2202 if(physdev->x11dev->dc_rect.top + y + extents.bottom < h)
2203 image_h = physdev->x11dev->dc_rect.top + y + extents.bottom - image_y;
2204 else
2205 image_h = h - image_y;
2207 if(image_w <= 0 || image_h <= 0) goto no_image;
2209 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2210 image = XGetImage(gdi_display, physdev->x11dev->drawable,
2211 image_x, image_y, image_w, image_h,
2212 AllPlanes, ZPixmap);
2213 X11DRV_check_error();
2215 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2216 gdi_display, (int)physdev->x11dev->drawable, image_x, image_y,
2217 image_w, image_h, AllPlanes, ZPixmap,
2218 physdev->x11dev->depth, image);
2219 if(!image) {
2220 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2221 physdev->x11dev->depth);
2222 GC gc;
2223 XGCValues gcv;
2225 gcv.graphics_exposures = False;
2226 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2227 XCopyArea(gdi_display, physdev->x11dev->drawable, xpm, gc, image_x, image_y,
2228 image_w, image_h, 0, 0);
2229 XFreeGC(gdi_display, gc);
2230 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2231 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2232 ZPixmap);
2233 X11DRV_check_error();
2234 XFreePixmap(gdi_display, xpm);
2236 if(!image) goto no_image;
2238 image->red_mask = visual->red_mask;
2239 image->green_mask = visual->green_mask;
2240 image->blue_mask = visual->blue_mask;
2242 for(idx = 0; idx < count; idx++) {
2243 SmoothGlyphGray(image,
2244 offset.x + image_off_x - extents.left,
2245 offset.y + image_off_y - extents.top,
2246 formatEntry->bitmaps[wstr[idx]],
2247 &formatEntry->gis[wstr[idx]],
2248 physdev->x11dev->textPixel);
2249 if(lpDx)
2251 if(flags & ETO_PDY)
2253 offset.x += lpDx[idx * 2];
2254 offset.y += lpDx[idx * 2 + 1];
2256 else
2257 offset.x += lpDx[idx];
2259 else
2261 offset.x += formatEntry->gis[wstr[idx]].xOff;
2262 offset.y += formatEntry->gis[wstr[idx]].yOff;
2265 XPutImage(gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc, image, 0, 0,
2266 image_x, image_y, image_w, image_h);
2267 XDestroyImage(image);
2269 no_image:
2270 wine_tsx11_unlock();
2271 restore_clipping_region( physdev->x11dev, saved_region );
2273 LeaveCriticalSection(&xrender_cs);
2274 retv = TRUE;
2276 done_unlock:
2277 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2278 return retv;
2281 /* Helper function for (stretched) blitting using xrender */
2282 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2283 int x_src, int y_src, int x_dst, int y_dst,
2284 double xscale, double yscale, int width, int height )
2286 int x_offset, y_offset;
2288 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2289 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2290 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2291 wine_tsx11_lock();
2292 if(xscale != 1.0 || yscale != 1.0)
2294 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2295 * in the wrong quadrant of the x-y plane.
2297 x_offset = (xscale < 0) ? -width : 0;
2298 y_offset = (yscale < 0) ? -height : 0;
2299 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2301 else
2303 x_offset = x_src;
2304 y_offset = y_src;
2305 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2307 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2308 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2309 wine_tsx11_unlock();
2312 /* Helper function for (stretched) mono->color blitting using xrender */
2313 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
2314 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
2315 int x_src, int y_src, int x_dst, int y_dst,
2316 double xscale, double yscale, int width, int height )
2318 Picture tile_pict;
2319 int x_offset, y_offset;
2321 /* When doing a mono->color blit, the source data is used as mask, and the source picture
2322 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
2323 * the tile data.
2325 EnterCriticalSection( &xrender_cs );
2326 tile_pict = get_tile_pict( dst_format, bg );
2328 wine_tsx11_lock();
2329 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
2331 if (xscale != 1.0 || yscale != 1.0)
2333 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2334 * in the wrong quadrant of the x-y plane.
2336 x_offset = (xscale < 0) ? -width : 0;
2337 y_offset = (yscale < 0) ? -height : 0;
2338 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2340 else
2342 x_offset = x_src;
2343 y_offset = y_src;
2344 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2346 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
2347 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
2348 wine_tsx11_unlock();
2349 LeaveCriticalSection( &xrender_cs );
2352 static void get_colors( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2353 XRenderColor *fg, XRenderColor *bg )
2355 if (physdev_src->format == WXR_FORMAT_MONO)
2357 RGBQUAD rgb[2];
2358 int pixel;
2360 if (GetDIBColorTable( physdev_src->dev.hdc, 0, 2, rgb ) == 2)
2362 pixel = X11DRV_PALETTE_ToPhysical( physdev_dst->x11dev,
2363 RGB( rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue ));
2364 get_xrender_color( physdev_dst->pict_format, pixel, fg );
2365 pixel = X11DRV_PALETTE_ToPhysical( physdev_dst->x11dev,
2366 RGB( rgb[1].rgbRed, rgb[1].rgbGreen, rgb[1].rgbBlue ));
2367 get_xrender_color( physdev_dst->pict_format, pixel, bg );
2368 return;
2371 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, fg );
2372 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, bg );
2375 /* create a pixmap and render picture for an image */
2376 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
2377 struct bitblt_coords *src, enum wxr_format format,
2378 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
2380 DWORD ret;
2381 int width = src->visrect.right - src->visrect.left;
2382 int height = src->visrect.bottom - src->visrect.top;
2383 int depth = pict_formats[format]->depth;
2384 struct gdi_image_bits dst_bits;
2385 XRenderPictureAttributes pa;
2386 XImage *image;
2388 wine_tsx11_lock();
2389 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
2390 info->bmiHeader.biWidth, height, 32, 0 );
2391 wine_tsx11_unlock();
2392 if (!image) return ERROR_OUTOFMEMORY;
2394 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
2395 if (ret) return ret;
2397 image->data = dst_bits.ptr;
2398 /* hack: make sure the bits are readable if we are reading from a DIB section */
2399 /* to be removed once we get rid of DIB access protections */
2400 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2402 *use_repeat = (width == 1 && height == 1);
2403 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2405 wine_tsx11_lock();
2406 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2407 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2408 src->visrect.left, 0, 0, 0, width, height );
2409 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2410 wine_tsx11_unlock();
2412 /* make coordinates relative to the pixmap */
2413 src->x -= src->visrect.left;
2414 src->y -= src->visrect.top;
2415 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2417 image->data = NULL;
2418 wine_tsx11_lock();
2419 XDestroyImage( image );
2420 wine_tsx11_unlock();
2421 if (dst_bits.free) dst_bits.free( &dst_bits );
2422 return ret;
2425 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2426 Drawable drawable, const struct bitblt_coords *src,
2427 const struct bitblt_coords *dst )
2429 int width = abs( dst->width );
2430 int height = abs( dst->height );
2431 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2432 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2433 int x_dst, y_dst;
2434 Picture src_pict = 0, dst_pict, mask_pict = 0;
2435 BOOL use_repeat;
2436 double xscale, yscale;
2438 use_repeat = use_source_repeat( physdev_src );
2439 if (!use_repeat)
2441 xscale = src->width / (double)dst->width;
2442 yscale = src->height / (double)dst->height;
2444 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2446 if (drawable) /* using an intermediate pixmap */
2448 XRenderPictureAttributes pa;
2450 x_dst = dst->x;
2451 y_dst = dst->y;
2452 pa.repeat = RepeatNone;
2453 wine_tsx11_lock();
2454 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2455 wine_tsx11_unlock();
2457 else
2459 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2460 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2461 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2464 if (src->width < 0) x_src += src->width + 1;
2465 if (src->height < 0) y_src += src->height + 1;
2466 if (dst->width < 0) x_dst += dst->width + 1;
2467 if (dst->height < 0) y_dst += dst->height + 1;
2469 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2471 /* mono -> color */
2472 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2474 XRenderColor fg, bg;
2476 get_colors( physdev_src, physdev_dst, &fg, &bg );
2477 fg.alpha = bg.alpha = 0;
2479 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2480 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2482 else /* color -> color (can be at different depths) or mono -> mono */
2484 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2485 mask_pict = get_no_alpha_mask();
2487 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2488 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2491 if (drawable)
2493 wine_tsx11_lock();
2494 pXRenderFreePicture( gdi_display, dst_pict );
2495 wine_tsx11_unlock();
2500 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, HRGN clip,
2501 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2502 Drawable drawable, struct bitblt_coords *src,
2503 struct bitblt_coords *dst, BOOL use_repeat )
2505 int x_src, y_src, x_dst, y_dst;
2506 Picture dst_pict;
2507 XRenderPictureAttributes pa;
2508 double xscale, yscale;
2510 if (drawable) /* using an intermediate pixmap */
2512 RGNDATA *clip_data = NULL;
2514 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2515 x_dst = dst->x;
2516 y_dst = dst->y;
2517 pa.repeat = RepeatNone;
2518 wine_tsx11_lock();
2519 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2520 if (clip_data)
2521 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2522 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2523 wine_tsx11_unlock();
2524 HeapFree( GetProcessHeap(), 0, clip_data );
2526 else
2528 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2529 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2530 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2533 if (!use_repeat)
2535 xscale = src->width / (double)dst->width;
2536 yscale = src->height / (double)dst->height;
2538 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2540 x_src = src->x;
2541 y_src = src->y;
2542 if (src->width < 0) x_src += src->width + 1;
2543 if (src->height < 0) y_src += src->height + 1;
2544 if (dst->width < 0) x_dst += dst->width + 1;
2545 if (dst->height < 0) y_dst += dst->height + 1;
2547 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, x_src, y_src, x_dst, y_dst,
2548 xscale, yscale, abs( dst->width ), abs( dst->height ));
2550 if (drawable)
2552 wine_tsx11_lock();
2553 pXRenderFreePicture( gdi_display, dst_pict );
2554 wine_tsx11_unlock();
2559 /***********************************************************************
2560 * xrenderdrv_StretchBlt
2562 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2563 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2565 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2566 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2567 INT sSrc, sDst;
2568 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2570 if (src_dev->funcs != dst_dev->funcs)
2572 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2573 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2576 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2578 /* XRender is of no use for color -> mono */
2579 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2580 goto x11drv_fallback;
2582 /* if not stretching, we only need to handle format conversion */
2583 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2585 sSrc = sDst = X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_None );
2586 if (physdev_dst != physdev_src) sSrc = X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_None );
2588 /* try client-side DIB copy */
2589 if (!stretch && sSrc == DIB_Status_AppMod)
2591 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2592 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2593 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2594 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2597 X11DRV_CoerceDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2598 if (physdev_dst != physdev_src) X11DRV_CoerceDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2600 if (rop != SRCCOPY)
2602 GC tmpGC;
2603 Pixmap tmp_pixmap;
2604 struct bitblt_coords tmp;
2606 /* make coordinates relative to tmp pixmap */
2607 tmp = *dst;
2608 tmp.x -= tmp.visrect.left;
2609 tmp.y -= tmp.visrect.top;
2610 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2612 wine_tsx11_lock();
2613 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2614 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2615 XSetGraphicsExposures( gdi_display, tmpGC, False );
2616 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2617 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2618 wine_tsx11_unlock();
2620 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2621 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2623 wine_tsx11_lock();
2624 XFreePixmap( gdi_display, tmp_pixmap );
2625 XFreeGC( gdi_display, tmpGC );
2626 wine_tsx11_unlock();
2628 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2630 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2631 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2632 return TRUE;
2634 x11drv_fallback:
2635 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2639 /***********************************************************************
2640 * xrenderdrv_PutImage
2642 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2643 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2644 struct bitblt_coords *dst, DWORD rop )
2646 struct xrender_physdev *physdev;
2647 X_PHYSBITMAP *bitmap;
2648 DWORD ret;
2649 Pixmap tmp_pixmap;
2650 GC gc;
2651 enum wxr_format src_format, dst_format;
2652 XRenderPictFormat *pict_format;
2653 Pixmap src_pixmap;
2654 Picture src_pict;
2655 BOOL use_repeat;
2657 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2659 if (hbitmap)
2661 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2662 physdev = NULL;
2663 dst_format = get_xrender_format_from_color_shifts( bitmap->pixmap_depth,
2664 &bitmap->pixmap_color_shifts );
2666 else
2668 physdev = get_xrender_dev( dev );
2669 bitmap = NULL;
2670 dst_format = physdev->format;
2673 src_format = get_xrender_format_from_bitmapinfo( info, TRUE );
2674 if (!(pict_format = pict_formats[src_format])) goto update_format;
2676 /* make sure we can create an image with the same bpp */
2677 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2678 goto update_format;
2680 /* mono <-> color conversions not supported */
2681 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2682 goto x11drv_fallback;
2684 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2686 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2687 if (!ret)
2689 struct bitblt_coords tmp;
2691 if (bitmap)
2693 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2694 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2696 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2698 xrender_put_image( src_pixmap, src_pict, rgn, pict_formats[dst_format],
2699 NULL, bitmap->pixmap, src, dst, use_repeat );
2701 X11DRV_DIB_Unlock( bitmap, TRUE );
2702 DeleteObject( rgn );
2704 else
2706 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2708 if (rop != SRCCOPY)
2710 RGNDATA *clip_data = NULL;
2712 /* make coordinates relative to tmp pixmap */
2713 tmp = *dst;
2714 tmp.x -= tmp.visrect.left;
2715 tmp.y -= tmp.visrect.top;
2716 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2718 if (clip) clip_data = add_extra_clipping_region( physdev->x11dev, clip );
2720 wine_tsx11_lock();
2721 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2722 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2723 XSetGraphicsExposures( gdi_display, gc, False );
2724 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2725 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2726 wine_tsx11_unlock();
2728 xrender_put_image( src_pixmap, src_pict, NULL, physdev->pict_format,
2729 NULL, tmp_pixmap, src, &tmp, use_repeat );
2730 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2732 wine_tsx11_lock();
2733 XFreePixmap( gdi_display, tmp_pixmap );
2734 XFreeGC( gdi_display, gc );
2735 wine_tsx11_unlock();
2737 restore_clipping_region( physdev->x11dev, clip_data );
2739 else xrender_put_image( src_pixmap, src_pict, clip,
2740 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2742 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2745 wine_tsx11_lock();
2746 pXRenderFreePicture( gdi_display, src_pict );
2747 XFreePixmap( gdi_display, src_pixmap );
2748 wine_tsx11_unlock();
2750 return ret;
2752 update_format:
2753 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2754 set_color_info( pict_formats[dst_format], info );
2755 return ERROR_BAD_FORMAT;
2757 x11drv_fallback:
2758 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2759 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2760 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2764 /***********************************************************************
2765 * xrenderdrv_BlendImage
2767 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2768 struct bitblt_coords *src, struct bitblt_coords *dst,
2769 BLENDFUNCTION func )
2771 struct xrender_physdev *physdev = get_xrender_dev( dev );
2772 DWORD ret;
2773 enum wxr_format format;
2774 XRenderPictFormat *pict_format;
2775 Picture dst_pict, src_pict, mask_pict;
2776 Pixmap src_pixmap;
2777 BOOL use_repeat;
2779 if (!X11DRV_XRender_Installed)
2781 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2782 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2785 format = get_xrender_format_from_bitmapinfo( info, func.AlphaFormat & AC_SRC_ALPHA );
2786 if (!(pict_format = pict_formats[format])) goto update_format;
2788 /* make sure we can create an image with the same bpp */
2789 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2790 goto update_format;
2792 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2793 goto update_format;
2795 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2797 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2798 if (!ret)
2800 double xscale, yscale;
2802 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2804 if (!use_repeat)
2806 xscale = src->width / (double)dst->width;
2807 yscale = src->height / (double)dst->height;
2809 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2811 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2813 EnterCriticalSection( &xrender_cs );
2814 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2816 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2817 physdev->x11dev->dc_rect.left + dst->x,
2818 physdev->x11dev->dc_rect.top + dst->y,
2819 xscale, yscale, dst->width, dst->height );
2821 wine_tsx11_lock();
2822 pXRenderFreePicture( gdi_display, src_pict );
2823 XFreePixmap( gdi_display, src_pixmap );
2824 wine_tsx11_unlock();
2826 LeaveCriticalSection( &xrender_cs );
2828 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2830 return ret;
2832 update_format:
2833 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2834 set_color_info( physdev->pict_format, info );
2835 return ERROR_BAD_FORMAT;
2839 /***********************************************************************
2840 * xrenderdrv_AlphaBlend
2842 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2843 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2845 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2846 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2847 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2848 XRenderPictureAttributes pa;
2849 Pixmap tmp_pixmap = 0;
2850 double xscale, yscale;
2851 BOOL use_repeat;
2853 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2855 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2856 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2859 if (physdev_dst != physdev_src)
2861 int status = X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_None );
2862 if (status == DIB_Status_AppMod || status == DIB_Status_InSync)
2864 X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2865 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2866 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2868 X11DRV_CoerceDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2870 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2872 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2874 use_repeat = use_source_repeat( physdev_src );
2875 if (!use_repeat)
2877 xscale = src->width / (double)dst->width;
2878 yscale = src->height / (double)dst->height;
2880 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2882 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2884 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2886 /* mono -> color blending needs an intermediate color pixmap */
2887 XRenderColor fg, bg;
2888 int width = src->visrect.right - src->visrect.left;
2889 int height = src->visrect.bottom - src->visrect.top;
2891 /* blending doesn't use the destination DC colors */
2892 fg.red = fg.green = fg.blue = 0;
2893 bg.red = bg.green = bg.blue = 0xffff;
2894 fg.alpha = bg.alpha = 0xffff;
2896 wine_tsx11_lock();
2897 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2898 physdev_dst->pict_format->depth );
2899 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2900 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2901 CPRepeat, &pa );
2902 wine_tsx11_unlock();
2904 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2905 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2907 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2909 /* we need a source picture with no alpha */
2910 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2911 if (format != physdev_src->format)
2913 wine_tsx11_lock();
2914 pa.subwindow_mode = IncludeInferiors;
2915 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2916 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2917 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2918 wine_tsx11_unlock();
2922 if (tmp_pict) src_pict = tmp_pict;
2924 EnterCriticalSection( &xrender_cs );
2925 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2927 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2928 physdev_src->x11dev->dc_rect.left + src->x,
2929 physdev_src->x11dev->dc_rect.top + src->y,
2930 physdev_dst->x11dev->dc_rect.left + dst->x,
2931 physdev_dst->x11dev->dc_rect.top + dst->y,
2932 xscale, yscale, dst->width, dst->height );
2934 wine_tsx11_lock();
2935 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2936 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2937 wine_tsx11_unlock();
2939 LeaveCriticalSection( &xrender_cs );
2940 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2941 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2942 return TRUE;
2946 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2948 /* At depths >1, the depth of physBitmap and physDev might not be the same e.g. the physbitmap might be a 16-bit DIB while the physdev uses 24-bit */
2949 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2950 enum wxr_format src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2951 enum wxr_format dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2953 wine_tsx11_lock();
2954 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2956 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2957 if( (physBitmap->pixmap_depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->pixmap_depth) ||
2958 (src_format == dst_format) )
2960 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2961 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2963 else /* We need depth conversion */
2965 Picture src_pict, dst_pict;
2966 XRenderPictureAttributes pa;
2967 pa.subwindow_mode = IncludeInferiors;
2968 pa.repeat = RepeatNone;
2970 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap,
2971 pict_formats[src_format], CPSubwindowMode|CPRepeat, &pa);
2972 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap,
2973 pict_formats[dst_format], CPSubwindowMode|CPRepeat, &pa);
2975 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2976 pXRenderFreePicture(gdi_display, src_pict);
2977 pXRenderFreePicture(gdi_display, dst_pict);
2979 wine_tsx11_unlock();
2982 static const struct gdi_dc_funcs xrender_funcs =
2984 NULL, /* pAbortDoc */
2985 NULL, /* pAbortPath */
2986 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2987 NULL, /* pAngleArc */
2988 NULL, /* pArc */
2989 NULL, /* pArcTo */
2990 NULL, /* pBeginPath */
2991 xrenderdrv_BlendImage, /* pBlendImage */
2992 NULL, /* pChoosePixelFormat */
2993 NULL, /* pChord */
2994 NULL, /* pCloseFigure */
2995 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2996 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2997 xrenderdrv_CreateDC, /* pCreateDC */
2998 NULL, /* pCreateDIBSection */
2999 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
3000 xrenderdrv_DeleteDC, /* pDeleteDC */
3001 NULL, /* pDeleteObject */
3002 NULL, /* pDescribePixelFormat */
3003 NULL, /* pDeviceCapabilities */
3004 NULL, /* pEllipse */
3005 NULL, /* pEndDoc */
3006 NULL, /* pEndPage */
3007 NULL, /* pEndPath */
3008 NULL, /* pEnumDeviceFonts */
3009 NULL, /* pEnumICMProfiles */
3010 NULL, /* pExcludeClipRect */
3011 NULL, /* pExtDeviceMode */
3012 xrenderdrv_ExtEscape, /* pExtEscape */
3013 NULL, /* pExtFloodFill */
3014 NULL, /* pExtSelectClipRgn */
3015 xrenderdrv_ExtTextOut, /* pExtTextOut */
3016 NULL, /* pFillPath */
3017 NULL, /* pFillRgn */
3018 NULL, /* pFlattenPath */
3019 NULL, /* pFrameRgn */
3020 NULL, /* pGdiComment */
3021 NULL, /* pGetCharWidth */
3022 NULL, /* pGetDeviceCaps */
3023 NULL, /* pGetDeviceGammaRamp */
3024 NULL, /* pGetICMProfile */
3025 xrenderdrv_GetImage, /* pGetImage */
3026 NULL, /* pGetNearestColor */
3027 NULL, /* pGetPixel */
3028 NULL, /* pGetPixelFormat */
3029 NULL, /* pGetSystemPaletteEntries */
3030 NULL, /* pGetTextExtentExPoint */
3031 NULL, /* pGetTextMetrics */
3032 NULL, /* pIntersectClipRect */
3033 NULL, /* pInvertRgn */
3034 NULL, /* pLineTo */
3035 NULL, /* pModifyWorldTransform */
3036 NULL, /* pMoveTo */
3037 NULL, /* pOffsetClipRgn */
3038 NULL, /* pOffsetViewportOrg */
3039 NULL, /* pOffsetWindowOrg */
3040 NULL, /* pPaintRgn */
3041 NULL, /* pPatBlt */
3042 NULL, /* pPie */
3043 NULL, /* pPolyBezier */
3044 NULL, /* pPolyBezierTo */
3045 NULL, /* pPolyDraw */
3046 NULL, /* pPolyPolygon */
3047 NULL, /* pPolyPolyline */
3048 NULL, /* pPolygon */
3049 NULL, /* pPolyline */
3050 NULL, /* pPolylineTo */
3051 xrenderdrv_PutImage, /* pPutImage */
3052 NULL, /* pRealizeDefaultPalette */
3053 NULL, /* pRealizePalette */
3054 NULL, /* pRectangle */
3055 NULL, /* pResetDC */
3056 NULL, /* pRestoreDC */
3057 NULL, /* pRoundRect */
3058 NULL, /* pSaveDC */
3059 NULL, /* pScaleViewportExt */
3060 NULL, /* pScaleWindowExt */
3061 xrenderdrv_SelectBitmap, /* pSelectBitmap */
3062 NULL, /* pSelectBrush */
3063 NULL, /* pSelectClipPath */
3064 xrenderdrv_SelectFont, /* pSelectFont */
3065 NULL, /* pSelectPalette */
3066 NULL, /* pSelectPen */
3067 NULL, /* pSetArcDirection */
3068 NULL, /* pSetBkColor */
3069 NULL, /* pSetBkMode */
3070 NULL, /* pSetDCBrushColor */
3071 NULL, /* pSetDCPenColor */
3072 NULL, /* pSetDIBColorTable */
3073 NULL, /* pSetDIBitsToDevice */
3074 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
3075 NULL, /* pSetDeviceGammaRamp */
3076 NULL, /* pSetLayout */
3077 NULL, /* pSetMapMode */
3078 NULL, /* pSetMapperFlags */
3079 NULL, /* pSetPixel */
3080 NULL, /* pSetPixelFormat */
3081 NULL, /* pSetPolyFillMode */
3082 NULL, /* pSetROP2 */
3083 NULL, /* pSetRelAbs */
3084 NULL, /* pSetStretchBltMode */
3085 NULL, /* pSetTextAlign */
3086 NULL, /* pSetTextCharacterExtra */
3087 NULL, /* pSetTextColor */
3088 NULL, /* pSetTextJustification */
3089 NULL, /* pSetViewportExt */
3090 NULL, /* pSetViewportOrg */
3091 NULL, /* pSetWindowExt */
3092 NULL, /* pSetWindowOrg */
3093 NULL, /* pSetWorldTransform */
3094 NULL, /* pStartDoc */
3095 NULL, /* pStartPage */
3096 xrenderdrv_StretchBlt, /* pStretchBlt */
3097 NULL, /* pStretchDIBits */
3098 NULL, /* pStrokeAndFillPath */
3099 NULL, /* pStrokePath */
3100 NULL, /* pSwapBuffers */
3101 NULL, /* pUnrealizePalette */
3102 NULL, /* pWidenPath */
3103 /* OpenGL not supported */
3106 #else /* SONAME_LIBXRENDER */
3108 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
3110 TRACE("XRender support not compiled in.\n");
3111 return NULL;
3114 void X11DRV_XRender_Finalize(void)
3118 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
3120 wine_tsx11_lock();
3121 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
3123 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
3124 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
3125 wine_tsx11_unlock();
3128 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
3130 return FALSE;
3133 #endif /* SONAME_LIBXRENDER */