winex11: Remove some unused function ptrs.
[wine.git] / dlls / winex11.drv / xrender.c
blobde469e280096967c335ae95ce2d88f915785273c
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 const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
109 /* format phys red phys green phys blue log red log green log blue */
110 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
111 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
112 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
113 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
114 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
115 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
116 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
117 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
118 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
120 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
121 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
124 static enum wxr_format default_format = WXR_INVALID_FORMAT;
125 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
127 typedef struct
129 LOGFONTW lf;
130 XFORM xform;
131 SIZE devsize; /* size in device coords */
132 DWORD hash;
133 } LFANDSIZE;
135 #define INITIAL_REALIZED_BUF_SIZE 128
137 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
139 typedef struct
141 GlyphSet glyphset;
142 XRenderPictFormat *font_format;
143 int nrealized;
144 BOOL *realized;
145 void **bitmaps;
146 XGlyphInfo *gis;
147 } gsCacheEntryFormat;
149 typedef struct
151 LFANDSIZE lfsz;
152 AA_Type aa_default;
153 gsCacheEntryFormat * format[AA_MAXVALUE];
154 INT count;
155 INT next;
156 } gsCacheEntry;
158 struct xrender_physdev
160 struct gdi_physdev dev;
161 X11DRV_PDEVICE *x11dev;
162 enum wxr_format format;
163 int cache_index;
164 BOOL update_clip;
165 Picture pict;
166 Picture pict_src;
167 XRenderPictFormat *pict_format;
170 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
172 return (struct xrender_physdev *)dev;
175 static const struct gdi_dc_funcs xrender_funcs;
177 static gsCacheEntry *glyphsetCache = NULL;
178 static DWORD glyphsetCacheSize = 0;
179 static INT lastfree = -1;
180 static INT mru = -1;
182 #define INIT_CACHE_SIZE 10
184 static int antialias = 1;
186 static void *xrender_handle;
188 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
189 MAKE_FUNCPTR(XRenderAddGlyphs)
190 MAKE_FUNCPTR(XRenderComposite)
191 MAKE_FUNCPTR(XRenderCompositeText16)
192 MAKE_FUNCPTR(XRenderCreateGlyphSet)
193 MAKE_FUNCPTR(XRenderCreatePicture)
194 MAKE_FUNCPTR(XRenderFillRectangle)
195 MAKE_FUNCPTR(XRenderFindFormat)
196 MAKE_FUNCPTR(XRenderFindVisualFormat)
197 MAKE_FUNCPTR(XRenderFreeGlyphSet)
198 MAKE_FUNCPTR(XRenderFreePicture)
199 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
200 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
201 MAKE_FUNCPTR(XRenderSetPictureTransform)
202 #endif
203 MAKE_FUNCPTR(XRenderQueryExtension)
205 #ifdef SONAME_LIBFONTCONFIG
206 #include <fontconfig/fontconfig.h>
207 MAKE_FUNCPTR(FcConfigSubstitute)
208 MAKE_FUNCPTR(FcDefaultSubstitute)
209 MAKE_FUNCPTR(FcFontMatch)
210 MAKE_FUNCPTR(FcInit)
211 MAKE_FUNCPTR(FcPatternCreate)
212 MAKE_FUNCPTR(FcPatternDestroy)
213 MAKE_FUNCPTR(FcPatternAddInteger)
214 MAKE_FUNCPTR(FcPatternAddString)
215 MAKE_FUNCPTR(FcPatternGetBool)
216 MAKE_FUNCPTR(FcPatternGetInteger)
217 MAKE_FUNCPTR(FcPatternGetString)
218 static void *fontconfig_handle;
219 static BOOL fontconfig_installed;
220 #endif
222 #undef MAKE_FUNCPTR
224 static CRITICAL_SECTION xrender_cs;
225 static CRITICAL_SECTION_DEBUG critsect_debug =
227 0, 0, &xrender_cs,
228 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
229 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
231 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
233 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
234 ( ( (ULONG)_x4 << 24 ) | \
235 ( (ULONG)_x3 << 16 ) | \
236 ( (ULONG)_x2 << 8 ) | \
237 (ULONG)_x1 )
239 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
241 #define GASP_GRIDFIT 0x01
242 #define GASP_DOGRAY 0x02
244 #ifdef WORDS_BIGENDIAN
245 #define get_be_word(x) (x)
246 #define NATIVE_BYTE_ORDER MSBFirst
247 #else
248 #define get_be_word(x) RtlUshortByteSwap(x)
249 #define NATIVE_BYTE_ORDER LSBFirst
250 #endif
252 static enum wxr_format get_format_without_alpha( enum wxr_format format )
254 switch (format)
256 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
257 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
258 default: return format;
262 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
264 templ->id = 0;
265 templ->type = PictTypeDirect;
266 templ->depth = fmt->depth;
267 templ->direct.alpha = fmt->alpha;
268 templ->direct.alphaMask = fmt->alphaMask;
269 templ->direct.red = fmt->red;
270 templ->direct.redMask = fmt->redMask;
271 templ->direct.green = fmt->green;
272 templ->direct.greenMask = fmt->greenMask;
273 templ->direct.blue = fmt->blue;
274 templ->direct.blueMask = fmt->blueMask;
275 templ->colormap = 0;
277 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
279 return TRUE;
282 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
284 if(fmt->depth != screen_depth)
285 return FALSE;
286 if( (fmt->redMask << fmt->red) != visual->red_mask)
287 return FALSE;
288 if( (fmt->greenMask << fmt->green) != visual->green_mask)
289 return FALSE;
290 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
291 return FALSE;
293 /* We never select a default ARGB visual */
294 if(fmt->alphaMask)
295 return FALSE;
297 return TRUE;
300 static int load_xrender_formats(void)
302 int count = 0;
303 unsigned int i;
305 for (i = 0; i < WXR_NB_FORMATS; i++)
307 XRenderPictFormat templ;
309 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
311 wine_tsx11_lock();
312 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
313 if (!pict_formats[i])
315 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
316 if (visual->class == DirectColor)
318 XVisualInfo info;
319 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
320 screen_depth, TrueColor, &info ))
322 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
323 if (pict_formats[i]) visual = info.visual;
327 wine_tsx11_unlock();
328 if (pict_formats[i]) default_format = i;
330 else
332 unsigned long mask = 0;
333 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
335 wine_tsx11_lock();
336 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
337 wine_tsx11_unlock();
339 if (pict_formats[i])
341 count++;
342 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
345 return count;
348 /***********************************************************************
349 * X11DRV_XRender_Init
351 * Let's see if our XServer has the extension available
354 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
356 int event_base, i;
358 if (client_side_with_render &&
359 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
362 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
363 LOAD_FUNCPTR(XRenderAddGlyphs)
364 LOAD_FUNCPTR(XRenderComposite)
365 LOAD_FUNCPTR(XRenderCompositeText16)
366 LOAD_FUNCPTR(XRenderCreateGlyphSet)
367 LOAD_FUNCPTR(XRenderCreatePicture)
368 LOAD_FUNCPTR(XRenderFillRectangle)
369 LOAD_FUNCPTR(XRenderFindFormat)
370 LOAD_FUNCPTR(XRenderFindVisualFormat)
371 LOAD_FUNCPTR(XRenderFreeGlyphSet)
372 LOAD_FUNCPTR(XRenderFreePicture)
373 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
374 LOAD_FUNCPTR(XRenderQueryExtension)
375 #undef LOAD_FUNCPTR
376 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
377 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
378 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
379 #undef LOAD_OPTIONAL_FUNCPTR
380 #endif
382 wine_tsx11_lock();
383 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
384 wine_tsx11_unlock();
385 if(X11DRV_XRender_Installed) {
386 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
387 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
389 wine_tsx11_unlock();
390 WINE_MESSAGE(
391 "Wine has detected that you probably have a buggy version\n"
392 "of libXrender.so . Because of this client side font rendering\n"
393 "will be disabled. Please upgrade this library.\n");
394 X11DRV_XRender_Installed = FALSE;
395 return NULL;
398 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
399 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
400 X11DRV_XRender_Installed = FALSE;
405 #ifdef SONAME_LIBFONTCONFIG
406 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
408 #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;}
409 LOAD_FUNCPTR(FcConfigSubstitute);
410 LOAD_FUNCPTR(FcDefaultSubstitute);
411 LOAD_FUNCPTR(FcFontMatch);
412 LOAD_FUNCPTR(FcInit);
413 LOAD_FUNCPTR(FcPatternCreate);
414 LOAD_FUNCPTR(FcPatternDestroy);
415 LOAD_FUNCPTR(FcPatternAddInteger);
416 LOAD_FUNCPTR(FcPatternAddString);
417 LOAD_FUNCPTR(FcPatternGetBool);
418 LOAD_FUNCPTR(FcPatternGetInteger);
419 LOAD_FUNCPTR(FcPatternGetString);
420 #undef LOAD_FUNCPTR
421 fontconfig_installed = pFcInit();
423 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
424 #endif
426 sym_not_found:
427 if(X11DRV_XRender_Installed || client_side_with_core)
429 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
430 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
432 glyphsetCacheSize = INIT_CACHE_SIZE;
433 lastfree = 0;
434 for(i = 0; i < INIT_CACHE_SIZE; i++) {
435 glyphsetCache[i].next = i + 1;
436 glyphsetCache[i].count = -1;
438 glyphsetCache[i-1].next = -1;
439 using_client_side_fonts = 1;
441 if(!X11DRV_XRender_Installed) {
442 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
443 if(screen_depth <= 8 || !client_side_antialias_with_core)
444 antialias = 0;
445 } else {
446 if(screen_depth <= 8 || !client_side_antialias_with_render)
447 antialias = 0;
449 return &xrender_funcs;
451 TRACE("Using X11 core fonts\n");
452 return NULL;
455 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
456 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
458 if(pf->direct.redMask)
459 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
460 else
461 dst_color->red = 0;
463 if(pf->direct.greenMask)
464 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
465 else
466 dst_color->green = 0;
468 if(pf->direct.blueMask)
469 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
470 else
471 dst_color->blue = 0;
473 dst_color->alpha = 0xffff;
476 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
478 int redMask, greenMask, blueMask;
479 unsigned int i;
481 if (depth == 1) return WXR_FORMAT_MONO;
483 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
484 if (!shifts) return default_format;
486 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
487 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
488 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
490 /* Try to locate a format which matches the specification of the dibsection. */
491 for(i = 0; i < WXR_NB_FORMATS; i++)
493 if( depth == wxr_formats_template[i].depth &&
494 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
495 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
496 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
497 return i;
500 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
501 ERR("No XRender format found for %u %08x/%08x/%08x\n", depth, redMask, greenMask, blueMask);
502 return WXR_INVALID_FORMAT;
505 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info, BOOL use_alpha )
507 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
509 switch (info->bmiHeader.biBitCount)
511 case 1:
512 return WXR_FORMAT_MONO;
513 case 4:
514 case 8:
515 break;
516 case 24:
517 if (info->bmiHeader.biCompression != BI_RGB) break;
518 return WXR_FORMAT_R8G8B8;
519 case 16:
520 case 32:
521 if (info->bmiHeader.biCompression == BI_BITFIELDS)
523 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
524 unsigned int i;
526 for (i = 0; i < WXR_NB_FORMATS; i++)
528 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
529 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
530 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
531 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
532 return i;
534 break;
536 if (info->bmiHeader.biCompression != BI_RGB) break;
537 if (info->bmiHeader.biBitCount == 16) return WXR_FORMAT_X1R5G5B5;
538 return use_alpha ? WXR_FORMAT_A8R8G8B8 : WXR_FORMAT_X8R8G8B8;
540 return WXR_INVALID_FORMAT;
543 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
544 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
546 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
547 XTransform xform = {{
548 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
549 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
550 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
553 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
554 #endif
557 /* check if we can use repeating instead of scaling for the specified source DC */
558 static BOOL use_source_repeat( struct xrender_physdev *dev )
560 return (dev->x11dev->bitmap &&
561 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
562 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
565 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
567 if (!dev->pict && dev->pict_format)
569 XRenderPictureAttributes pa;
571 wine_tsx11_lock();
572 pa.subwindow_mode = IncludeInferiors;
573 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
574 dev->pict_format, CPSubwindowMode, &pa );
575 wine_tsx11_unlock();
576 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
577 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
578 dev->update_clip = TRUE;
581 if (dev->update_clip)
583 RGNDATA *clip_data;
584 HRGN rgn = 0;
586 if (clip_rect)
588 rgn = CreateRectRgnIndirect( clip_rect );
589 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
590 CombineRgn( rgn, rgn, dev->x11dev->region, RGN_AND );
592 else if (clip_rgn)
594 rgn = CreateRectRgn( 0, 0, 0, 0 );
595 CombineRgn( rgn, clip_rgn, dev->x11dev->region, RGN_AND );
598 if ((clip_data = X11DRV_GetRegionData( rgn ? rgn : dev->x11dev->region, 0 )))
600 wine_tsx11_lock();
601 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
602 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
603 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
604 wine_tsx11_unlock();
605 HeapFree( GetProcessHeap(), 0, clip_data );
607 dev->update_clip = (rgn != 0); /* have to update again if we are using a custom region */
608 if (rgn) DeleteObject( rgn );
610 return dev->pict;
613 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
615 if (!dev->pict_src && dev->pict_format)
617 XRenderPictureAttributes pa;
619 wine_tsx11_lock();
620 pa.subwindow_mode = IncludeInferiors;
621 pa.repeat = repeat ? RepeatNormal : RepeatNone;
622 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
623 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
624 wine_tsx11_unlock();
626 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
627 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
630 return dev->pict_src;
633 static void free_xrender_picture( struct xrender_physdev *dev )
635 if (dev->pict || dev->pict_src)
637 wine_tsx11_lock();
638 XFlush( gdi_display );
639 if (dev->pict)
641 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
642 pXRenderFreePicture(gdi_display, dev->pict);
643 dev->pict = 0;
645 if(dev->pict_src)
647 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
648 pXRenderFreePicture(gdi_display, dev->pict_src);
649 dev->pict_src = 0;
651 wine_tsx11_unlock();
655 /* return a mask picture used to force alpha to 0 */
656 static Picture get_no_alpha_mask(void)
658 static Pixmap pixmap;
659 static Picture pict;
661 wine_tsx11_lock();
662 if (!pict)
664 XRenderPictureAttributes pa;
665 XRenderColor col;
667 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
668 pa.repeat = RepeatNormal;
669 pa.component_alpha = True;
670 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
671 CPRepeat|CPComponentAlpha, &pa );
672 col.red = col.green = col.blue = 0xffff;
673 col.alpha = 0;
674 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
676 wine_tsx11_unlock();
677 return pict;
680 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
682 if(p1->hash != p2->hash) return TRUE;
683 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
684 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
685 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
686 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
689 #if 0
690 static void walk_cache(void)
692 int i;
694 EnterCriticalSection(&xrender_cs);
695 for(i=mru; i >= 0; i = glyphsetCache[i].next)
696 TRACE("item %d\n", i);
697 LeaveCriticalSection(&xrender_cs);
699 #endif
701 static int LookupEntry(LFANDSIZE *plfsz)
703 int i, prev_i = -1;
705 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
706 TRACE("%d\n", i);
707 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
709 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
710 glyphsetCache[i].count++;
711 if(prev_i >= 0) {
712 glyphsetCache[prev_i].next = glyphsetCache[i].next;
713 glyphsetCache[i].next = mru;
714 mru = i;
716 TRACE("found font in cache %d\n", i);
717 return i;
719 prev_i = i;
721 TRACE("font not in cache\n");
722 return -1;
725 static void FreeEntry(int entry)
727 int i, format;
729 for(format = 0; format < AA_MAXVALUE; format++) {
730 gsCacheEntryFormat * formatEntry;
732 if( !glyphsetCache[entry].format[format] )
733 continue;
735 formatEntry = glyphsetCache[entry].format[format];
737 if(formatEntry->glyphset) {
738 wine_tsx11_lock();
739 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
740 wine_tsx11_unlock();
741 formatEntry->glyphset = 0;
743 if(formatEntry->nrealized) {
744 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
745 formatEntry->realized = NULL;
746 if(formatEntry->bitmaps) {
747 for(i = 0; i < formatEntry->nrealized; i++)
748 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
749 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
750 formatEntry->bitmaps = NULL;
752 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
753 formatEntry->gis = NULL;
754 formatEntry->nrealized = 0;
757 HeapFree(GetProcessHeap(), 0, formatEntry);
758 glyphsetCache[entry].format[format] = NULL;
762 static int AllocEntry(void)
764 int best = -1, prev_best = -1, i, prev_i = -1;
766 if(lastfree >= 0) {
767 assert(glyphsetCache[lastfree].count == -1);
768 glyphsetCache[lastfree].count = 1;
769 best = lastfree;
770 lastfree = glyphsetCache[lastfree].next;
771 assert(best != mru);
772 glyphsetCache[best].next = mru;
773 mru = best;
775 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
776 return mru;
779 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
780 if(glyphsetCache[i].count == 0) {
781 best = i;
782 prev_best = prev_i;
784 prev_i = i;
787 if(best >= 0) {
788 TRACE("freeing unused glyphset at cache %d\n", best);
789 FreeEntry(best);
790 glyphsetCache[best].count = 1;
791 if(prev_best >= 0) {
792 glyphsetCache[prev_best].next = glyphsetCache[best].next;
793 glyphsetCache[best].next = mru;
794 mru = best;
795 } else {
796 assert(mru == best);
798 return mru;
801 TRACE("Growing cache\n");
803 if (glyphsetCache)
804 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
805 glyphsetCache,
806 (glyphsetCacheSize + INIT_CACHE_SIZE)
807 * sizeof(*glyphsetCache));
808 else
809 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
810 (glyphsetCacheSize + INIT_CACHE_SIZE)
811 * sizeof(*glyphsetCache));
813 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
814 i++) {
815 glyphsetCache[i].next = i + 1;
816 glyphsetCache[i].count = -1;
818 glyphsetCache[i-1].next = -1;
819 glyphsetCacheSize += INIT_CACHE_SIZE;
821 lastfree = glyphsetCache[best].next;
822 glyphsetCache[best].count = 1;
823 glyphsetCache[best].next = mru;
824 mru = best;
825 TRACE("new free cache slot at %d\n", mru);
826 return mru;
829 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
831 DWORD size;
832 WORD *gasp, *buffer;
833 WORD num_recs;
834 DWORD ppem;
835 TEXTMETRICW tm;
837 *flags = 0;
839 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
840 if(size == GDI_ERROR)
841 return FALSE;
843 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
844 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
846 GetTextMetricsW(hdc, &tm);
847 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
849 gasp++;
850 num_recs = get_be_word(*gasp);
851 gasp++;
852 while(num_recs--)
854 *flags = get_be_word(*(gasp + 1));
855 if(ppem <= get_be_word(*gasp))
856 break;
857 gasp += 2;
859 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
861 HeapFree(GetProcessHeap(), 0, buffer);
862 return TRUE;
865 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
867 AA_Type ret;
868 WORD flags;
869 UINT font_smoothing_type, font_smoothing_orientation;
871 if (X11DRV_XRender_Installed && subpixel &&
872 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
873 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
875 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
876 &font_smoothing_orientation, 0) &&
877 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
879 ret = AA_BGR;
881 else
882 ret = AA_RGB;
883 /*FIXME
884 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
885 But, Wine's subpixel rendering can support the portrait mode.
888 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
889 ret = AA_Grey;
890 else
891 ret = AA_None;
893 return ret;
896 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
898 int ret;
899 int format;
900 gsCacheEntry *entry;
901 static int hinter = -1;
902 static int subpixel = -1;
903 BOOL font_smoothing;
905 if((ret = LookupEntry(plfsz)) != -1) return ret;
907 ret = AllocEntry();
908 entry = glyphsetCache + ret;
909 entry->lfsz = *plfsz;
910 for( format = 0; format < AA_MAXVALUE; format++ ) {
911 assert( !entry->format[format] );
914 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
916 if(hinter == -1 || subpixel == -1)
918 RASTERIZER_STATUS status;
919 GetRasterizerCaps(&status, sizeof(status));
920 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
921 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
924 switch (plfsz->lf.lfQuality)
926 case ANTIALIASED_QUALITY:
927 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
928 return ret; /* ignore further configuration */
929 case CLEARTYPE_QUALITY:
930 case CLEARTYPE_NATURAL_QUALITY:
931 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
932 break;
933 case DEFAULT_QUALITY:
934 case DRAFT_QUALITY:
935 case PROOF_QUALITY:
936 default:
937 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
938 font_smoothing)
940 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
942 else
943 entry->aa_default = AA_None;
944 break;
947 font_smoothing = TRUE; /* default to enabled */
948 #ifdef SONAME_LIBFONTCONFIG
949 if (fontconfig_installed)
951 FcPattern *match, *pattern = pFcPatternCreate();
952 FcResult result;
953 char family[LF_FACESIZE * 4];
955 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
956 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
957 if (plfsz->lf.lfWeight != FW_DONTCARE)
959 int weight;
960 switch (plfsz->lf.lfWeight)
962 case FW_THIN: weight = FC_WEIGHT_THIN; break;
963 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
964 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
965 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
966 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
967 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
968 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
969 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
970 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
971 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
973 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
975 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
976 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
977 pFcDefaultSubstitute( pattern );
978 if ((match = pFcFontMatch( NULL, pattern, &result )))
980 int rgba;
981 FcBool antialias;
983 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
984 antialias = TRUE;
985 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
987 FcChar8 *file;
988 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
990 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
991 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
993 switch (rgba)
995 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
996 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
997 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
998 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
999 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1002 if (!antialias) font_smoothing = FALSE;
1003 pFcPatternDestroy( match );
1005 pFcPatternDestroy( pattern );
1007 #endif /* SONAME_LIBFONTCONFIG */
1009 /* now check Xft resources */
1011 char *value;
1012 BOOL antialias = TRUE;
1014 wine_tsx11_lock();
1015 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1017 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1018 value[0] == '0' || !strcasecmp( value, "off" ))
1019 antialias = FALSE;
1021 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1023 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1024 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1025 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1026 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1027 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1028 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1030 wine_tsx11_unlock();
1031 if (!antialias) font_smoothing = FALSE;
1034 if (!font_smoothing) entry->aa_default = AA_None;
1036 /* we can't support subpixel without xrender */
1037 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1039 else
1040 entry->aa_default = AA_None;
1042 return ret;
1045 static void dec_ref_cache(int index)
1047 assert(index >= 0);
1048 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1049 assert(glyphsetCache[index].count > 0);
1050 glyphsetCache[index].count--;
1053 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1055 DWORD hash = 0, *ptr, two_chars;
1056 WORD *pwc;
1057 int i;
1059 hash ^= plfsz->devsize.cx;
1060 hash ^= plfsz->devsize.cy;
1061 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1062 hash ^= *ptr;
1063 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1064 hash ^= *ptr;
1065 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1066 two_chars = *ptr;
1067 pwc = (WCHAR *)&two_chars;
1068 if(!*pwc) break;
1069 *pwc = toupperW(*pwc);
1070 pwc++;
1071 *pwc = toupperW(*pwc);
1072 hash ^= two_chars;
1073 if(!*pwc) break;
1075 plfsz->hash = hash;
1076 return;
1079 /***********************************************************************
1080 * X11DRV_XRender_Finalize
1082 void X11DRV_XRender_Finalize(void)
1084 int i;
1086 EnterCriticalSection(&xrender_cs);
1087 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1088 FreeEntry(i);
1089 LeaveCriticalSection(&xrender_cs);
1092 /**********************************************************************
1093 * xrenderdrv_SelectFont
1095 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
1097 struct xrender_physdev *physdev = get_xrender_dev( dev );
1098 LFANDSIZE lfsz;
1100 if (!GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf )) return HGDI_ERROR;
1102 if (!gdiFont)
1104 dev = GET_NEXT_PHYSDEV( dev, pSelectFont );
1105 return dev->funcs->pSelectFont( dev, hfont, gdiFont );
1108 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1109 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1110 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1111 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1112 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1113 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1115 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1116 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1117 lfsz.xform.eM21, lfsz.xform.eM22);
1119 /* Not used fields, would break hashing */
1120 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1122 lfsz_calc_hash(&lfsz);
1124 EnterCriticalSection(&xrender_cs);
1125 if (physdev->cache_index != -1)
1126 dec_ref_cache( physdev->cache_index );
1127 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1128 LeaveCriticalSection(&xrender_cs);
1129 physdev->x11dev->has_gdi_font = TRUE;
1130 return 0;
1133 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1135 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1136 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1138 if (!physdev) return FALSE;
1139 physdev->x11dev = x11dev;
1140 physdev->cache_index = -1;
1141 physdev->format = format;
1142 physdev->pict_format = pict_formats[format];
1143 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1144 return TRUE;
1147 /* store the color mask data in the bitmap info structure */
1148 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1150 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1152 info->bmiHeader.biPlanes = 1;
1153 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1154 info->bmiHeader.biCompression = BI_RGB;
1155 info->bmiHeader.biClrUsed = 0;
1157 switch (info->bmiHeader.biBitCount)
1159 case 16:
1160 colors[0] = format->direct.redMask << format->direct.red;
1161 colors[1] = format->direct.greenMask << format->direct.green;
1162 colors[2] = format->direct.blueMask << format->direct.blue;
1163 info->bmiHeader.biCompression = BI_BITFIELDS;
1164 break;
1165 case 32:
1166 colors[0] = format->direct.redMask << format->direct.red;
1167 colors[1] = format->direct.greenMask << format->direct.green;
1168 colors[2] = format->direct.blueMask << format->direct.blue;
1169 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1170 info->bmiHeader.biCompression = BI_BITFIELDS;
1171 break;
1176 /**********************************************************************
1177 * xrenderdrv_CreateDC
1179 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1180 LPCWSTR output, const DEVMODEW* initData )
1182 return create_xrender_dc( pdev, default_format );
1185 /**********************************************************************
1186 * xrenderdrv_CreateCompatibleDC
1188 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1190 if (orig) /* chain to x11drv first */
1192 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1193 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1195 /* otherwise we have been called by x11drv */
1197 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1200 /**********************************************************************
1201 * xrenderdrv_DeleteDC
1203 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1205 struct xrender_physdev *physdev = get_xrender_dev( dev );
1207 free_xrender_picture( physdev );
1209 EnterCriticalSection( &xrender_cs );
1210 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1211 LeaveCriticalSection( &xrender_cs );
1213 HeapFree( GetProcessHeap(), 0, physdev );
1214 return TRUE;
1217 /**********************************************************************
1218 * xrenderdrv_ExtEscape
1220 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1221 INT out_count, LPVOID out_data )
1223 struct xrender_physdev *physdev = get_xrender_dev( dev );
1225 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1227 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1229 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1231 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1232 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1233 return ret;
1236 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1239 /****************************************************************************
1240 * xrenderdrv_CreateBitmap
1242 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1244 enum wxr_format format = WXR_INVALID_FORMAT;
1245 BITMAP bitmap;
1247 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1249 if (bitmap.bmPlanes == 1 && bitmap.bmBitsPixel == screen_bpp)
1251 switch (bitmap.bmBitsPixel)
1253 case 16: format = WXR_FORMAT_R5G6B5; break;
1254 case 24: format = WXR_FORMAT_R8G8B8; break;
1255 case 32: format = WXR_FORMAT_A8R8G8B8; break;
1259 if (pict_formats[format])
1260 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth,
1261 TRUE, &wxr_color_shifts[format] );
1263 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1264 return dev->funcs->pCreateBitmap( dev, hbitmap );
1267 /****************************************************************************
1268 * xrenderdrv_DeleteBitmap
1270 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1272 return X11DRV_DeleteBitmap( hbitmap );
1275 /***********************************************************************
1276 * xrenderdrv_SelectBitmap
1278 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1280 HBITMAP ret;
1281 struct xrender_physdev *physdev = get_xrender_dev( dev );
1283 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1284 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1285 if (ret)
1287 free_xrender_picture( physdev );
1288 physdev->format = get_xrender_format_from_color_shifts( physdev->x11dev->depth,
1289 physdev->x11dev->color_shifts );
1290 physdev->pict_format = pict_formats[physdev->format];
1292 return ret;
1295 /***********************************************************************
1296 * xrenderdrv_GetImage
1298 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1299 struct gdi_image_bits *bits, struct bitblt_coords *src )
1301 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1302 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1303 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1306 /***********************************************************************
1307 * xrenderdrv_SetDeviceClipping
1309 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1311 struct xrender_physdev *physdev = get_xrender_dev( dev );
1313 physdev->update_clip = TRUE;
1315 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1316 dev->funcs->pSetDeviceClipping( dev, vis_rgn, clip_rgn );
1320 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1322 XRenderPictFormat *pict_format;
1323 ColorShifts shifts;
1324 const DWORD *bitfields;
1325 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1326 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1329 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1330 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1331 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1332 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1333 return FALSE;
1335 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1336 bitfields = dib->dsBitfields;
1337 else if(bits_pixel == 24 || bits_pixel == 32)
1338 bitfields = bitfields_32;
1339 else
1340 bitfields = bitfields_16;
1342 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1343 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1345 /* Common formats should be in our picture format table. */
1346 if (!pict_format)
1348 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1349 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1350 return FALSE;
1353 physBitmap->depth = pict_format->depth;
1354 physBitmap->trueColor = TRUE;
1355 physBitmap->color_shifts = shifts;
1356 return TRUE;
1359 /************************************************************************
1360 * UploadGlyph
1362 * Helper to ExtTextOut. Must be called inside xrender_cs
1364 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1366 unsigned int buflen;
1367 char *buf;
1368 Glyph gid;
1369 GLYPHMETRICS gm;
1370 XGlyphInfo gi;
1371 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1372 gsCacheEntryFormat *formatEntry;
1373 UINT ggo_format = GGO_GLYPH_INDEX;
1374 enum wxr_format wxr_format;
1375 static const char zero[4];
1376 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1378 switch(format) {
1379 case AA_Grey:
1380 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1381 break;
1382 case AA_RGB:
1383 ggo_format |= WINE_GGO_HRGB_BITMAP;
1384 break;
1385 case AA_BGR:
1386 ggo_format |= WINE_GGO_HBGR_BITMAP;
1387 break;
1388 case AA_VRGB:
1389 ggo_format |= WINE_GGO_VRGB_BITMAP;
1390 break;
1391 case AA_VBGR:
1392 ggo_format |= WINE_GGO_VBGR_BITMAP;
1393 break;
1395 default:
1396 ERR("aa = %d - not implemented\n", format);
1397 case AA_None:
1398 ggo_format |= GGO_BITMAP;
1399 break;
1402 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1403 if(buflen == GDI_ERROR) {
1404 if(format != AA_None) {
1405 format = AA_None;
1406 entry->aa_default = AA_None;
1407 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1408 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1410 if(buflen == GDI_ERROR) {
1411 WARN("GetGlyphOutlineW failed using default glyph\n");
1412 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1413 if(buflen == GDI_ERROR) {
1414 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1415 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1416 if(buflen == GDI_ERROR) {
1417 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1418 return;
1422 TRACE("Turning off antialiasing for this monochrome font\n");
1425 /* If there is nothing for the current type, we create the entry. */
1426 if( !entry->format[format] ) {
1427 entry->format[format] = HeapAlloc(GetProcessHeap(),
1428 HEAP_ZERO_MEMORY,
1429 sizeof(gsCacheEntryFormat));
1431 formatEntry = entry->format[format];
1433 if(formatEntry->nrealized <= glyph) {
1434 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1436 if (formatEntry->realized)
1437 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1438 HEAP_ZERO_MEMORY,
1439 formatEntry->realized,
1440 formatEntry->nrealized * sizeof(BOOL));
1441 else
1442 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1443 HEAP_ZERO_MEMORY,
1444 formatEntry->nrealized * sizeof(BOOL));
1446 if(!X11DRV_XRender_Installed) {
1447 if (formatEntry->bitmaps)
1448 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1449 HEAP_ZERO_MEMORY,
1450 formatEntry->bitmaps,
1451 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1452 else
1453 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1454 HEAP_ZERO_MEMORY,
1455 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1457 if (formatEntry->gis)
1458 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1459 HEAP_ZERO_MEMORY,
1460 formatEntry->gis,
1461 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1462 else
1463 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1464 HEAP_ZERO_MEMORY,
1465 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1469 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1470 switch(format) {
1471 case AA_Grey:
1472 wxr_format = WXR_FORMAT_GRAY;
1473 break;
1475 case AA_RGB:
1476 case AA_BGR:
1477 case AA_VRGB:
1478 case AA_VBGR:
1479 wxr_format = WXR_FORMAT_A8R8G8B8;
1480 break;
1482 default:
1483 ERR("aa = %d - not implemented\n", format);
1484 case AA_None:
1485 wxr_format = WXR_FORMAT_MONO;
1486 break;
1489 wine_tsx11_lock();
1490 formatEntry->font_format = pict_formats[wxr_format];
1491 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1492 wine_tsx11_unlock();
1496 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1497 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1498 formatEntry->realized[glyph] = TRUE;
1500 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1501 buflen,
1502 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1503 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1505 gi.width = gm.gmBlackBoxX;
1506 gi.height = gm.gmBlackBoxY;
1507 gi.x = -gm.gmptGlyphOrigin.x;
1508 gi.y = gm.gmptGlyphOrigin.y;
1509 gi.xOff = gm.gmCellIncX;
1510 gi.yOff = gm.gmCellIncY;
1512 if(TRACE_ON(xrender)) {
1513 int pitch, i, j;
1514 char output[300];
1515 unsigned char *line;
1517 if(format == AA_None) {
1518 pitch = ((gi.width + 31) / 32) * 4;
1519 for(i = 0; i < gi.height; i++) {
1520 line = (unsigned char*) buf + i * pitch;
1521 output[0] = '\0';
1522 for(j = 0; j < pitch * 8; j++) {
1523 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1525 TRACE("%s\n", output);
1527 } else {
1528 static const char blks[] = " .:;!o*#";
1529 char str[2];
1531 str[1] = '\0';
1532 pitch = ((gi.width + 3) / 4) * 4;
1533 for(i = 0; i < gi.height; i++) {
1534 line = (unsigned char*) buf + i * pitch;
1535 output[0] = '\0';
1536 for(j = 0; j < pitch; j++) {
1537 str[0] = blks[line[j] >> 5];
1538 strcat(output, str);
1540 TRACE("%s\n", output);
1546 if(formatEntry->glyphset) {
1547 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1548 unsigned char *byte = (unsigned char*) buf, c;
1549 int i = buflen;
1551 while(i--) {
1552 c = *byte;
1554 /* magic to flip bit order */
1555 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1556 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1557 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1559 *byte++ = c;
1562 else if ( format != AA_Grey &&
1563 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1565 unsigned int i, *data = (unsigned int *)buf;
1566 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1568 gid = glyph;
1571 XRenderCompositeText seems to ignore 0x0 glyphs when
1572 AA_None, which means we lose the advance width of glyphs
1573 like the space. We'll pretend that such glyphs are 1x1
1574 bitmaps.
1577 if(buflen == 0)
1578 gi.width = gi.height = 1;
1580 wine_tsx11_lock();
1581 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1582 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1583 wine_tsx11_unlock();
1584 HeapFree(GetProcessHeap(), 0, buf);
1585 } else {
1586 formatEntry->bitmaps[glyph] = buf;
1589 formatEntry->gis[glyph] = gi;
1592 static void SharpGlyphMono(struct xrender_physdev *physDev, INT x, INT y,
1593 void *bitmap, XGlyphInfo *gi)
1595 unsigned char *srcLine = bitmap, *src;
1596 unsigned char bits, bitsMask;
1597 int width = gi->width;
1598 int stride = ((width + 31) & ~31) >> 3;
1599 int height = gi->height;
1600 int w;
1601 int xspan, lenspan;
1603 TRACE("%d, %d\n", x, y);
1604 x -= gi->x;
1605 y -= gi->y;
1606 while (height--)
1608 src = srcLine;
1609 srcLine += stride;
1610 w = width;
1612 bitsMask = 0x80; /* FreeType is always MSB first */
1613 bits = *src++;
1615 xspan = x;
1616 while (w)
1618 if (bits & bitsMask)
1620 lenspan = 0;
1623 lenspan++;
1624 if (lenspan == w)
1625 break;
1626 bitsMask = bitsMask >> 1;
1627 if (!bitsMask)
1629 bits = *src++;
1630 bitsMask = 0x80;
1632 } while (bits & bitsMask);
1633 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1634 physDev->x11dev->gc, xspan, y, lenspan, 1);
1635 xspan += lenspan;
1636 w -= lenspan;
1638 else
1642 w--;
1643 xspan++;
1644 if (!w)
1645 break;
1646 bitsMask = bitsMask >> 1;
1647 if (!bitsMask)
1649 bits = *src++;
1650 bitsMask = 0x80;
1652 } while (!(bits & bitsMask));
1655 y++;
1659 static void SharpGlyphGray(struct xrender_physdev *physDev, INT x, INT y,
1660 void *bitmap, XGlyphInfo *gi)
1662 unsigned char *srcLine = bitmap, *src, bits;
1663 int width = gi->width;
1664 int stride = ((width + 3) & ~3);
1665 int height = gi->height;
1666 int w;
1667 int xspan, lenspan;
1669 x -= gi->x;
1670 y -= gi->y;
1671 while (height--)
1673 src = srcLine;
1674 srcLine += stride;
1675 w = width;
1677 bits = *src++;
1678 xspan = x;
1679 while (w)
1681 if (bits >= 0x80)
1683 lenspan = 0;
1686 lenspan++;
1687 if (lenspan == w)
1688 break;
1689 bits = *src++;
1690 } while (bits >= 0x80);
1691 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1692 physDev->x11dev->gc, xspan, y, lenspan, 1);
1693 xspan += lenspan;
1694 w -= lenspan;
1696 else
1700 w--;
1701 xspan++;
1702 if (!w)
1703 break;
1704 bits = *src++;
1705 } while (bits < 0x80);
1708 y++;
1713 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1715 int s, l;
1717 s = 0;
1718 while ((mask & 1) == 0)
1720 mask >>= 1;
1721 s++;
1723 l = 0;
1724 while ((mask & 1) == 1)
1726 mask >>= 1;
1727 l++;
1729 *shift = s;
1730 *len = l;
1733 static DWORD GetField (DWORD pixel, int shift, int len)
1735 pixel = pixel & (((1 << (len)) - 1) << shift);
1736 pixel = pixel << (32 - (shift + len)) >> 24;
1737 while (len < 8)
1739 pixel |= (pixel >> len);
1740 len <<= 1;
1742 return pixel;
1746 static DWORD PutField (DWORD pixel, int shift, int len)
1748 shift = shift - (8 - len);
1749 if (len <= 8)
1750 pixel &= (((1 << len) - 1) << (8 - len));
1751 if (shift < 0)
1752 pixel >>= -shift;
1753 else
1754 pixel <<= shift;
1755 return pixel;
1758 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1759 int color)
1761 int r_shift, r_len;
1762 int g_shift, g_len;
1763 int b_shift, b_len;
1764 BYTE *maskLine, *mask, m;
1765 int maskStride;
1766 DWORD pixel;
1767 int width, height;
1768 int w, tx;
1769 BYTE src_r, src_g, src_b;
1771 x -= gi->x;
1772 y -= gi->y;
1773 width = gi->width;
1774 height = gi->height;
1776 maskLine = bitmap;
1777 maskStride = (width + 3) & ~3;
1779 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1780 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1781 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1783 src_r = GetField(color, r_shift, r_len);
1784 src_g = GetField(color, g_shift, g_len);
1785 src_b = GetField(color, b_shift, b_len);
1787 for(; height--; y++)
1789 mask = maskLine;
1790 maskLine += maskStride;
1791 w = width;
1792 tx = x;
1794 if(y < 0) continue;
1795 if(y >= image->height) break;
1797 for(; w--; tx++)
1799 if(tx >= image->width) break;
1801 m = *mask++;
1802 if(tx < 0) continue;
1804 if (m == 0xff)
1805 XPutPixel (image, tx, y, color);
1806 else if (m)
1808 BYTE r, g, b;
1810 pixel = XGetPixel (image, tx, y);
1812 r = GetField(pixel, r_shift, r_len);
1813 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1814 g = GetField(pixel, g_shift, g_len);
1815 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1816 b = GetField(pixel, b_shift, b_len);
1817 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1819 pixel = (PutField (r, r_shift, r_len) |
1820 PutField (g, g_shift, g_len) |
1821 PutField (b, b_shift, b_len));
1822 XPutPixel (image, tx, y, pixel);
1828 /*************************************************************
1829 * get_tile_pict
1831 * Returns an appropriate Picture for tiling the text colour.
1832 * Call and use result within the xrender_cs
1834 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1836 static struct
1838 Pixmap xpm;
1839 Picture pict;
1840 XRenderColor current_color;
1841 } tiles[WXR_NB_FORMATS], *tile;
1843 tile = &tiles[wxr_format];
1845 if(!tile->xpm)
1847 XRenderPictureAttributes pa;
1848 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1850 wine_tsx11_lock();
1851 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1853 pa.repeat = RepeatNormal;
1854 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1855 wine_tsx11_unlock();
1857 /* init current_color to something different from text_pixel */
1858 tile->current_color = *color;
1859 tile->current_color.red ^= 0xffff;
1861 if (wxr_format == WXR_FORMAT_MONO)
1863 /* for a 1bpp bitmap we always need a 1 in the tile */
1864 XRenderColor col;
1865 col.red = col.green = col.blue = 0;
1866 col.alpha = 0xffff;
1867 wine_tsx11_lock();
1868 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1869 wine_tsx11_unlock();
1873 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1875 wine_tsx11_lock();
1876 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1877 wine_tsx11_unlock();
1878 tile->current_color = *color;
1880 return tile->pict;
1883 /*************************************************************
1884 * get_mask_pict
1886 * Returns an appropriate Picture for masking with the specified alpha.
1887 * Call and use result within the xrender_cs
1889 static Picture get_mask_pict( int alpha )
1891 static Pixmap pixmap;
1892 static Picture pict;
1893 static int current_alpha;
1895 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1897 if (!pixmap)
1899 XRenderPictureAttributes pa;
1901 wine_tsx11_lock();
1902 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1903 pa.repeat = RepeatNormal;
1904 pict = pXRenderCreatePicture( gdi_display, pixmap,
1905 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1906 wine_tsx11_unlock();
1907 current_alpha = -1;
1910 if (alpha != current_alpha)
1912 XRenderColor col;
1913 col.red = col.green = col.blue = 0;
1914 col.alpha = current_alpha = alpha;
1915 wine_tsx11_lock();
1916 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1917 wine_tsx11_unlock();
1919 return pict;
1922 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1924 return 1;
1927 /********************************************************************
1928 * is_dib_with_colortable
1930 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1932 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1934 DIBSECTION dib;
1936 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1937 dib.dsBmih.biBitCount <= 8 )
1938 return TRUE;
1940 return FALSE;
1943 /***********************************************************************
1944 * xrenderdrv_ExtTextOut
1946 BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1947 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1949 struct xrender_physdev *physdev = get_xrender_dev( dev );
1950 XGCValues xgcval;
1951 gsCacheEntry *entry;
1952 gsCacheEntryFormat *formatEntry;
1953 BOOL retv = FALSE;
1954 int textPixel, backgroundPixel;
1955 RGNDATA *saved_region = NULL;
1956 BOOL disable_antialias = FALSE;
1957 AA_Type aa_type = AA_None;
1958 unsigned int idx;
1959 Picture tile_pict = 0;
1961 if (!physdev->x11dev->has_gdi_font)
1963 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1964 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1967 if(is_dib_with_colortable( physdev->x11dev ))
1969 TRACE("Disabling antialiasing\n");
1970 disable_antialias = TRUE;
1973 xgcval.function = GXcopy;
1974 xgcval.background = physdev->x11dev->backgroundPixel;
1975 xgcval.fill_style = FillSolid;
1976 wine_tsx11_lock();
1977 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1978 wine_tsx11_unlock();
1980 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
1982 if(physdev->x11dev->depth == 1) {
1983 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1984 textPixel = 0;
1985 backgroundPixel = 1;
1986 } else {
1987 textPixel = 1;
1988 backgroundPixel = 0;
1990 } else {
1991 textPixel = physdev->x11dev->textPixel;
1992 backgroundPixel = physdev->x11dev->backgroundPixel;
1995 if(flags & ETO_OPAQUE)
1997 wine_tsx11_lock();
1998 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
1999 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
2000 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
2001 lprect->right - lprect->left, lprect->bottom - lprect->top );
2002 wine_tsx11_unlock();
2005 if(count == 0)
2007 retv = TRUE;
2008 goto done_unlock;
2011 EnterCriticalSection(&xrender_cs);
2013 entry = glyphsetCache + physdev->cache_index;
2014 if( disable_antialias == FALSE )
2015 aa_type = entry->aa_default;
2016 formatEntry = entry->format[aa_type];
2018 for(idx = 0; idx < count; idx++) {
2019 if( !formatEntry ) {
2020 UploadGlyph(physdev, wstr[idx], aa_type);
2021 /* re-evaluate antialias since aa_default may have changed */
2022 if( disable_antialias == FALSE )
2023 aa_type = entry->aa_default;
2024 formatEntry = entry->format[aa_type];
2025 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
2026 UploadGlyph(physdev, wstr[idx], aa_type);
2029 if (!formatEntry)
2031 WARN("could not upload requested glyphs\n");
2032 LeaveCriticalSection(&xrender_cs);
2033 goto done_unlock;
2036 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
2037 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2039 if(X11DRV_XRender_Installed)
2041 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
2042 POINT offset = {0, 0};
2043 POINT desired, current;
2044 int render_op = PictOpOver;
2045 Picture pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
2046 XRenderColor col;
2048 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
2049 So we pass zeros to the function and move to our starting position using the first
2050 element of the elts array. */
2052 desired.x = physdev->x11dev->dc_rect.left + x;
2053 desired.y = physdev->x11dev->dc_rect.top + y;
2054 current.x = current.y = 0;
2056 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
2057 tile_pict = get_tile_pict(physdev->format, &col);
2059 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
2061 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
2062 render_op = PictOpOutReverse; /* This gives us 'black' text */
2064 for(idx = 0; idx < count; idx++)
2066 elts[idx].glyphset = formatEntry->glyphset;
2067 elts[idx].chars = wstr + idx;
2068 elts[idx].nchars = 1;
2069 elts[idx].xOff = desired.x - current.x;
2070 elts[idx].yOff = desired.y - current.y;
2072 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
2073 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
2075 if(!lpDx)
2077 desired.x += formatEntry->gis[wstr[idx]].xOff;
2078 desired.y += formatEntry->gis[wstr[idx]].yOff;
2080 else
2082 if(flags & ETO_PDY)
2084 offset.x += lpDx[idx * 2];
2085 offset.y += lpDx[idx * 2 + 1];
2087 else
2088 offset.x += lpDx[idx];
2089 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
2090 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
2094 wine_tsx11_lock();
2095 /* Make sure we don't have any transforms set from a previous call */
2096 set_xrender_transformation(pict, 1, 1, 0, 0);
2097 pXRenderCompositeText16(gdi_display, render_op,
2098 tile_pict,
2099 pict,
2100 formatEntry->font_format,
2101 0, 0, 0, 0, elts, count);
2102 wine_tsx11_unlock();
2103 HeapFree(GetProcessHeap(), 0, elts);
2104 } else {
2105 POINT offset = {0, 0};
2107 if (flags & ETO_CLIPPED)
2109 HRGN clip_region = CreateRectRgnIndirect( lprect );
2110 saved_region = add_extra_clipping_region( physdev->x11dev, clip_region );
2111 DeleteObject( clip_region );
2114 wine_tsx11_lock();
2115 XSetForeground( gdi_display, physdev->x11dev->gc, textPixel );
2117 if(aa_type == AA_None || physdev->x11dev->depth == 1)
2119 void (* sharp_glyph_fn)(struct xrender_physdev *, INT, INT, void *, XGlyphInfo *);
2121 if(aa_type == AA_None)
2122 sharp_glyph_fn = SharpGlyphMono;
2123 else
2124 sharp_glyph_fn = SharpGlyphGray;
2126 for(idx = 0; idx < count; idx++) {
2127 sharp_glyph_fn(physdev,
2128 physdev->x11dev->dc_rect.left + x + offset.x,
2129 physdev->x11dev->dc_rect.top + y + offset.y,
2130 formatEntry->bitmaps[wstr[idx]],
2131 &formatEntry->gis[wstr[idx]]);
2132 if(lpDx)
2134 if(flags & ETO_PDY)
2136 offset.x += lpDx[idx * 2];
2137 offset.y += lpDx[idx * 2 + 1];
2139 else
2140 offset.x += lpDx[idx];
2142 else
2144 offset.x += formatEntry->gis[wstr[idx]].xOff;
2145 offset.y += formatEntry->gis[wstr[idx]].yOff;
2148 } else {
2149 XImage *image;
2150 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2151 RECT extents = {0, 0, 0, 0};
2152 POINT cur = {0, 0};
2153 int w = physdev->x11dev->drawable_rect.right - physdev->x11dev->drawable_rect.left;
2154 int h = physdev->x11dev->drawable_rect.bottom - physdev->x11dev->drawable_rect.top;
2156 TRACE("drawable %dx%d\n", w, h);
2158 for(idx = 0; idx < count; idx++) {
2159 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2160 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2161 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2162 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2163 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2164 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2165 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2166 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2168 if(lpDx)
2170 if(flags & ETO_PDY)
2172 cur.x += lpDx[idx * 2];
2173 cur.y += lpDx[idx * 2 + 1];
2175 else
2176 cur.x += lpDx[idx];
2178 else
2180 cur.x += formatEntry->gis[wstr[idx]].xOff;
2181 cur.y += formatEntry->gis[wstr[idx]].yOff;
2184 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2185 extents.right, extents.bottom, physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2187 if(physdev->x11dev->dc_rect.left + x + extents.left >= 0) {
2188 image_x = physdev->x11dev->dc_rect.left + x + extents.left;
2189 image_off_x = 0;
2190 } else {
2191 image_x = 0;
2192 image_off_x = physdev->x11dev->dc_rect.left + x + extents.left;
2194 if(physdev->x11dev->dc_rect.top + y + extents.top >= 0) {
2195 image_y = physdev->x11dev->dc_rect.top + y + extents.top;
2196 image_off_y = 0;
2197 } else {
2198 image_y = 0;
2199 image_off_y = physdev->x11dev->dc_rect.top + y + extents.top;
2201 if(physdev->x11dev->dc_rect.left + x + extents.right < w)
2202 image_w = physdev->x11dev->dc_rect.left + x + extents.right - image_x;
2203 else
2204 image_w = w - image_x;
2205 if(physdev->x11dev->dc_rect.top + y + extents.bottom < h)
2206 image_h = physdev->x11dev->dc_rect.top + y + extents.bottom - image_y;
2207 else
2208 image_h = h - image_y;
2210 if(image_w <= 0 || image_h <= 0) goto no_image;
2212 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2213 image = XGetImage(gdi_display, physdev->x11dev->drawable,
2214 image_x, image_y, image_w, image_h,
2215 AllPlanes, ZPixmap);
2216 X11DRV_check_error();
2218 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2219 gdi_display, (int)physdev->x11dev->drawable, image_x, image_y,
2220 image_w, image_h, AllPlanes, ZPixmap,
2221 physdev->x11dev->depth, image);
2222 if(!image) {
2223 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2224 physdev->x11dev->depth);
2225 GC gc;
2226 XGCValues gcv;
2228 gcv.graphics_exposures = False;
2229 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2230 XCopyArea(gdi_display, physdev->x11dev->drawable, xpm, gc, image_x, image_y,
2231 image_w, image_h, 0, 0);
2232 XFreeGC(gdi_display, gc);
2233 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2234 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2235 ZPixmap);
2236 X11DRV_check_error();
2237 XFreePixmap(gdi_display, xpm);
2239 if(!image) goto no_image;
2241 image->red_mask = visual->red_mask;
2242 image->green_mask = visual->green_mask;
2243 image->blue_mask = visual->blue_mask;
2245 for(idx = 0; idx < count; idx++) {
2246 SmoothGlyphGray(image,
2247 offset.x + image_off_x - extents.left,
2248 offset.y + image_off_y - extents.top,
2249 formatEntry->bitmaps[wstr[idx]],
2250 &formatEntry->gis[wstr[idx]],
2251 physdev->x11dev->textPixel);
2252 if(lpDx)
2254 if(flags & ETO_PDY)
2256 offset.x += lpDx[idx * 2];
2257 offset.y += lpDx[idx * 2 + 1];
2259 else
2260 offset.x += lpDx[idx];
2262 else
2264 offset.x += formatEntry->gis[wstr[idx]].xOff;
2265 offset.y += formatEntry->gis[wstr[idx]].yOff;
2268 XPutImage(gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc, image, 0, 0,
2269 image_x, image_y, image_w, image_h);
2270 XDestroyImage(image);
2272 no_image:
2273 wine_tsx11_unlock();
2274 restore_clipping_region( physdev->x11dev, saved_region );
2276 LeaveCriticalSection(&xrender_cs);
2277 retv = TRUE;
2279 done_unlock:
2280 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2281 return retv;
2284 /* multiply the alpha channel of a picture */
2285 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
2286 int x, int y, int width, int height )
2288 XRenderPictureAttributes pa;
2289 Pixmap src_pixmap, mask_pixmap;
2290 Picture src_pict, mask_pict;
2291 XRenderColor color;
2293 wine_tsx11_lock();
2294 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2295 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2296 pa.repeat = RepeatNormal;
2297 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
2298 pa.component_alpha = True;
2299 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
2300 color.red = color.green = color.blue = color.alpha = 0xffff;
2301 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
2302 color.alpha = alpha;
2303 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
2304 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
2305 0, 0, 0, 0, x, y, width, height );
2306 pXRenderFreePicture( gdi_display, src_pict );
2307 pXRenderFreePicture( gdi_display, mask_pict );
2308 XFreePixmap( gdi_display, src_pixmap );
2309 XFreePixmap( gdi_display, mask_pixmap );
2310 wine_tsx11_unlock();
2313 /* Helper function for (stretched) blitting using xrender */
2314 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2315 int x_src, int y_src, int x_dst, int y_dst,
2316 double xscale, double yscale, int width, int height )
2318 int x_offset, y_offset;
2320 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2321 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2322 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2323 wine_tsx11_lock();
2324 if(xscale != 1.0 || yscale != 1.0)
2326 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2327 * in the wrong quadrant of the x-y plane.
2329 x_offset = (xscale < 0) ? -width : 0;
2330 y_offset = (yscale < 0) ? -height : 0;
2331 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2333 else
2335 x_offset = x_src;
2336 y_offset = y_src;
2337 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2339 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2340 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2341 wine_tsx11_unlock();
2344 /* Helper function for (stretched) mono->color blitting using xrender */
2345 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
2346 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
2347 int x_src, int y_src, int x_dst, int y_dst,
2348 double xscale, double yscale, int width, int height )
2350 Picture tile_pict;
2351 int x_offset, y_offset;
2352 XRenderColor color;
2354 /* When doing a mono->color blit, the source data is used as mask, and the source picture
2355 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
2356 * the tile data.
2358 EnterCriticalSection( &xrender_cs );
2359 color = *bg;
2360 color.alpha = 0xffff; /* tile pict needs 100% alpha */
2361 tile_pict = get_tile_pict( dst_format, &color );
2363 wine_tsx11_lock();
2364 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
2366 if (xscale != 1.0 || yscale != 1.0)
2368 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2369 * in the wrong quadrant of the x-y plane.
2371 x_offset = (xscale < 0) ? -width : 0;
2372 y_offset = (yscale < 0) ? -height : 0;
2373 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2375 else
2377 x_offset = x_src;
2378 y_offset = y_src;
2379 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2381 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
2382 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
2383 wine_tsx11_unlock();
2384 LeaveCriticalSection( &xrender_cs );
2386 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
2387 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
2388 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
2391 static void get_colors( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2392 XRenderColor *fg, XRenderColor *bg )
2394 if (physdev_src->format == WXR_FORMAT_MONO)
2396 RGBQUAD rgb[2];
2397 int pixel;
2399 if (GetDIBColorTable( physdev_src->dev.hdc, 0, 2, rgb ) == 2)
2401 pixel = X11DRV_PALETTE_ToPhysical( physdev_dst->x11dev,
2402 RGB( rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue ));
2403 get_xrender_color( physdev_dst->pict_format, pixel, fg );
2404 pixel = X11DRV_PALETTE_ToPhysical( physdev_dst->x11dev,
2405 RGB( rgb[1].rgbRed, rgb[1].rgbGreen, rgb[1].rgbBlue ));
2406 get_xrender_color( physdev_dst->pict_format, pixel, bg );
2407 return;
2410 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, fg );
2411 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, bg );
2414 /* create a pixmap and render picture for an image */
2415 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
2416 struct bitblt_coords *src, enum wxr_format format,
2417 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
2419 DWORD ret;
2420 int width = src->visrect.right - src->visrect.left;
2421 int height = src->visrect.bottom - src->visrect.top;
2422 int depth = pict_formats[format]->depth;
2423 struct gdi_image_bits dst_bits;
2424 XRenderPictureAttributes pa;
2425 XImage *image;
2427 wine_tsx11_lock();
2428 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
2429 info->bmiHeader.biWidth, height, 32, 0 );
2430 wine_tsx11_unlock();
2431 if (!image) return ERROR_OUTOFMEMORY;
2433 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
2434 if (ret) return ret;
2436 image->data = dst_bits.ptr;
2437 /* hack: make sure the bits are readable if we are reading from a DIB section */
2438 /* to be removed once we get rid of DIB access protections */
2439 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2441 *use_repeat = (width == 1 && height == 1);
2442 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2444 wine_tsx11_lock();
2445 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2446 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2447 src->visrect.left, 0, 0, 0, width, height );
2448 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2449 wine_tsx11_unlock();
2451 /* make coordinates relative to the pixmap */
2452 src->x -= src->visrect.left;
2453 src->y -= src->visrect.top;
2454 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2456 image->data = NULL;
2457 wine_tsx11_lock();
2458 XDestroyImage( image );
2459 wine_tsx11_unlock();
2460 if (dst_bits.free) dst_bits.free( &dst_bits );
2461 return ret;
2464 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2465 Drawable drawable, const struct bitblt_coords *src,
2466 const struct bitblt_coords *dst )
2468 int width = abs( dst->width );
2469 int height = abs( dst->height );
2470 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2471 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2472 int x_dst, y_dst;
2473 Picture src_pict = 0, dst_pict, mask_pict = 0;
2474 BOOL use_repeat;
2475 double xscale, yscale;
2477 use_repeat = use_source_repeat( physdev_src );
2478 if (!use_repeat)
2480 xscale = src->width / (double)dst->width;
2481 yscale = src->height / (double)dst->height;
2483 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2485 if (drawable) /* using an intermediate pixmap */
2487 XRenderPictureAttributes pa;
2489 x_dst = dst->x;
2490 y_dst = dst->y;
2491 pa.repeat = RepeatNone;
2492 wine_tsx11_lock();
2493 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2494 wine_tsx11_unlock();
2496 else
2498 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2499 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2500 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2503 if (src->width < 0) x_src += src->width + 1;
2504 if (src->height < 0) y_src += src->height + 1;
2505 if (dst->width < 0) x_dst += dst->width + 1;
2506 if (dst->height < 0) y_dst += dst->height + 1;
2508 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2510 /* mono -> color */
2511 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2513 XRenderColor fg, bg;
2515 get_colors( physdev_src, physdev_dst, &fg, &bg );
2516 fg.alpha = bg.alpha = 0;
2518 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2519 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2521 else /* color -> color (can be at different depths) or mono -> mono */
2523 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2524 mask_pict = get_no_alpha_mask();
2526 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2527 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2530 if (drawable)
2532 wine_tsx11_lock();
2533 pXRenderFreePicture( gdi_display, dst_pict );
2534 wine_tsx11_unlock();
2539 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, HRGN clip,
2540 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2541 Drawable drawable, struct bitblt_coords *src,
2542 struct bitblt_coords *dst, BOOL use_repeat )
2544 int x_src, y_src, x_dst, y_dst;
2545 Picture dst_pict;
2546 XRenderPictureAttributes pa;
2547 double xscale, yscale;
2549 if (drawable) /* using an intermediate pixmap */
2551 RGNDATA *clip_data = NULL;
2553 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2554 x_dst = dst->x;
2555 y_dst = dst->y;
2556 pa.repeat = RepeatNone;
2557 wine_tsx11_lock();
2558 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2559 if (clip_data)
2560 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2561 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2562 wine_tsx11_unlock();
2563 HeapFree( GetProcessHeap(), 0, clip_data );
2565 else
2567 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2568 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2569 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2572 if (!use_repeat)
2574 xscale = src->width / (double)dst->width;
2575 yscale = src->height / (double)dst->height;
2577 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2579 x_src = src->x;
2580 y_src = src->y;
2581 if (src->width < 0) x_src += src->width + 1;
2582 if (src->height < 0) y_src += src->height + 1;
2583 if (dst->width < 0) x_dst += dst->width + 1;
2584 if (dst->height < 0) y_dst += dst->height + 1;
2586 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, x_src, y_src, x_dst, y_dst,
2587 xscale, yscale, abs( dst->width ), abs( dst->height ));
2589 if (drawable)
2591 wine_tsx11_lock();
2592 pXRenderFreePicture( gdi_display, dst_pict );
2593 wine_tsx11_unlock();
2598 /***********************************************************************
2599 * xrenderdrv_StretchBlt
2601 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2602 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2604 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2605 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2606 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2608 if (src_dev->funcs != dst_dev->funcs)
2610 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2611 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2614 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2616 /* XRender is of no use for color -> mono */
2617 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2618 goto x11drv_fallback;
2620 /* if not stretching, we only need to handle format conversion */
2621 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2623 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2624 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2626 if (rop != SRCCOPY)
2628 GC tmpGC;
2629 Pixmap tmp_pixmap;
2630 struct bitblt_coords tmp;
2632 /* make coordinates relative to tmp pixmap */
2633 tmp = *dst;
2634 tmp.x -= tmp.visrect.left;
2635 tmp.y -= tmp.visrect.top;
2636 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2638 wine_tsx11_lock();
2639 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2640 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2641 XSetGraphicsExposures( gdi_display, tmpGC, False );
2642 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2643 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2644 wine_tsx11_unlock();
2646 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2647 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2649 wine_tsx11_lock();
2650 XFreePixmap( gdi_display, tmp_pixmap );
2651 XFreeGC( gdi_display, tmpGC );
2652 wine_tsx11_unlock();
2654 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2656 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2657 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2658 return TRUE;
2660 x11drv_fallback:
2661 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2665 /***********************************************************************
2666 * xrenderdrv_PutImage
2668 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2669 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2670 struct bitblt_coords *dst, DWORD rop )
2672 struct xrender_physdev *physdev;
2673 X_PHYSBITMAP *bitmap;
2674 DWORD ret;
2675 Pixmap tmp_pixmap;
2676 GC gc;
2677 enum wxr_format src_format, dst_format;
2678 XRenderPictFormat *pict_format;
2679 Pixmap src_pixmap;
2680 Picture src_pict;
2681 BOOL use_repeat;
2683 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2685 if (hbitmap)
2687 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2688 physdev = NULL;
2689 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2691 else
2693 physdev = get_xrender_dev( dev );
2694 bitmap = NULL;
2695 dst_format = physdev->format;
2698 src_format = get_xrender_format_from_bitmapinfo( info, TRUE );
2699 if (!(pict_format = pict_formats[src_format])) goto update_format;
2701 /* make sure we can create an image with the same bpp */
2702 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2703 goto update_format;
2705 /* mono <-> color conversions not supported */
2706 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2707 goto x11drv_fallback;
2709 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2711 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2712 if (!ret)
2714 struct bitblt_coords tmp;
2716 if (bitmap)
2718 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2719 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2721 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2723 xrender_put_image( src_pixmap, src_pict, rgn, pict_formats[dst_format],
2724 NULL, bitmap->pixmap, src, dst, use_repeat );
2726 X11DRV_DIB_Unlock( bitmap, TRUE );
2727 DeleteObject( rgn );
2729 else
2731 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2733 if (rop != SRCCOPY)
2735 RGNDATA *clip_data = NULL;
2737 /* make coordinates relative to tmp pixmap */
2738 tmp = *dst;
2739 tmp.x -= tmp.visrect.left;
2740 tmp.y -= tmp.visrect.top;
2741 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2743 if (clip) clip_data = add_extra_clipping_region( physdev->x11dev, clip );
2745 wine_tsx11_lock();
2746 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2747 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2748 XSetGraphicsExposures( gdi_display, gc, False );
2749 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2750 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2751 wine_tsx11_unlock();
2753 xrender_put_image( src_pixmap, src_pict, NULL, physdev->pict_format,
2754 NULL, tmp_pixmap, src, &tmp, use_repeat );
2755 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2757 wine_tsx11_lock();
2758 XFreePixmap( gdi_display, tmp_pixmap );
2759 XFreeGC( gdi_display, gc );
2760 wine_tsx11_unlock();
2762 restore_clipping_region( physdev->x11dev, clip_data );
2764 else xrender_put_image( src_pixmap, src_pict, clip,
2765 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2767 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2770 wine_tsx11_lock();
2771 pXRenderFreePicture( gdi_display, src_pict );
2772 XFreePixmap( gdi_display, src_pixmap );
2773 wine_tsx11_unlock();
2775 return ret;
2777 update_format:
2778 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2779 set_color_info( pict_formats[dst_format], info );
2780 return ERROR_BAD_FORMAT;
2782 x11drv_fallback:
2783 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2784 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2785 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2789 /***********************************************************************
2790 * xrenderdrv_BlendImage
2792 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2793 struct bitblt_coords *src, struct bitblt_coords *dst,
2794 BLENDFUNCTION func )
2796 struct xrender_physdev *physdev = get_xrender_dev( dev );
2797 DWORD ret;
2798 enum wxr_format format;
2799 XRenderPictFormat *pict_format;
2800 Picture dst_pict, src_pict, mask_pict;
2801 Pixmap src_pixmap;
2802 BOOL use_repeat;
2804 if (!X11DRV_XRender_Installed)
2806 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2807 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2810 format = get_xrender_format_from_bitmapinfo( info, func.AlphaFormat & AC_SRC_ALPHA );
2811 if (!(pict_format = pict_formats[format])) goto update_format;
2813 /* make sure we can create an image with the same bpp */
2814 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2815 goto update_format;
2817 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2818 goto update_format;
2820 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2822 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2823 if (!ret)
2825 double xscale, yscale;
2827 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2829 if (!use_repeat)
2831 xscale = src->width / (double)dst->width;
2832 yscale = src->height / (double)dst->height;
2834 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2836 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2838 EnterCriticalSection( &xrender_cs );
2839 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2841 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2842 physdev->x11dev->dc_rect.left + dst->x,
2843 physdev->x11dev->dc_rect.top + dst->y,
2844 xscale, yscale, dst->width, dst->height );
2846 wine_tsx11_lock();
2847 pXRenderFreePicture( gdi_display, src_pict );
2848 XFreePixmap( gdi_display, src_pixmap );
2849 wine_tsx11_unlock();
2851 LeaveCriticalSection( &xrender_cs );
2853 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2855 return ret;
2857 update_format:
2858 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2859 set_color_info( physdev->pict_format, info );
2860 return ERROR_BAD_FORMAT;
2864 /***********************************************************************
2865 * xrenderdrv_AlphaBlend
2867 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2868 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2870 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2871 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2872 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2873 XRenderPictureAttributes pa;
2874 Pixmap tmp_pixmap = 0;
2875 double xscale, yscale;
2876 BOOL use_repeat;
2878 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2880 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2881 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2884 if (physdev_dst != physdev_src)
2886 int status = X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_None );
2887 if (status == DIB_Status_AppMod || status == DIB_Status_InSync)
2889 X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2890 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2891 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2893 X11DRV_CoerceDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2895 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2897 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2899 use_repeat = use_source_repeat( physdev_src );
2900 if (!use_repeat)
2902 xscale = src->width / (double)dst->width;
2903 yscale = src->height / (double)dst->height;
2905 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2907 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2909 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2911 /* mono -> color blending needs an intermediate color pixmap */
2912 XRenderColor fg, bg;
2913 int width = src->visrect.right - src->visrect.left;
2914 int height = src->visrect.bottom - src->visrect.top;
2916 /* blending doesn't use the destination DC colors */
2917 fg.red = fg.green = fg.blue = 0;
2918 bg.red = bg.green = bg.blue = 0xffff;
2919 fg.alpha = bg.alpha = 0xffff;
2921 wine_tsx11_lock();
2922 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2923 physdev_dst->pict_format->depth );
2924 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2925 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2926 CPRepeat, &pa );
2927 wine_tsx11_unlock();
2929 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2930 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2932 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2934 /* we need a source picture with no alpha */
2935 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2936 if (format != physdev_src->format)
2938 wine_tsx11_lock();
2939 pa.subwindow_mode = IncludeInferiors;
2940 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2941 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2942 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2943 wine_tsx11_unlock();
2947 if (tmp_pict) src_pict = tmp_pict;
2949 EnterCriticalSection( &xrender_cs );
2950 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2952 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2953 physdev_src->x11dev->dc_rect.left + src->x,
2954 physdev_src->x11dev->dc_rect.top + src->y,
2955 physdev_dst->x11dev->dc_rect.left + dst->x,
2956 physdev_dst->x11dev->dc_rect.top + dst->y,
2957 xscale, yscale, dst->width, dst->height );
2959 wine_tsx11_lock();
2960 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2961 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2962 wine_tsx11_unlock();
2964 LeaveCriticalSection( &xrender_cs );
2965 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2966 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2967 return TRUE;
2971 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2973 /* 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 */
2974 int depth = physBitmap->depth == 1 ? 1 : physDev->depth;
2975 enum wxr_format src_format = get_xrender_format_from_color_shifts(physBitmap->depth, &physBitmap->color_shifts);
2976 enum wxr_format dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2978 wine_tsx11_lock();
2979 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2981 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2982 if( (physBitmap->depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->depth) ||
2983 (src_format == dst_format) )
2985 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2986 get_bitmap_gc(physBitmap->depth), 0, 0, width, height, 0, 0 );
2988 else /* We need depth conversion */
2990 Picture src_pict, dst_pict;
2991 XRenderPictureAttributes pa;
2992 pa.subwindow_mode = IncludeInferiors;
2993 pa.repeat = RepeatNone;
2995 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap,
2996 pict_formats[src_format], CPSubwindowMode|CPRepeat, &pa);
2997 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap,
2998 pict_formats[dst_format], CPSubwindowMode|CPRepeat, &pa);
3000 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
3001 pXRenderFreePicture(gdi_display, src_pict);
3002 pXRenderFreePicture(gdi_display, dst_pict);
3004 wine_tsx11_unlock();
3007 static const struct gdi_dc_funcs xrender_funcs =
3009 NULL, /* pAbortDoc */
3010 NULL, /* pAbortPath */
3011 xrenderdrv_AlphaBlend, /* pAlphaBlend */
3012 NULL, /* pAngleArc */
3013 NULL, /* pArc */
3014 NULL, /* pArcTo */
3015 NULL, /* pBeginPath */
3016 xrenderdrv_BlendImage, /* pBlendImage */
3017 NULL, /* pChoosePixelFormat */
3018 NULL, /* pChord */
3019 NULL, /* pCloseFigure */
3020 xrenderdrv_CreateBitmap, /* pCreateBitmap */
3021 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
3022 xrenderdrv_CreateDC, /* pCreateDC */
3023 NULL, /* pCreateDIBSection */
3024 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
3025 xrenderdrv_DeleteDC, /* pDeleteDC */
3026 NULL, /* pDeleteObject */
3027 NULL, /* pDescribePixelFormat */
3028 NULL, /* pDeviceCapabilities */
3029 NULL, /* pEllipse */
3030 NULL, /* pEndDoc */
3031 NULL, /* pEndPage */
3032 NULL, /* pEndPath */
3033 NULL, /* pEnumDeviceFonts */
3034 NULL, /* pEnumICMProfiles */
3035 NULL, /* pExcludeClipRect */
3036 NULL, /* pExtDeviceMode */
3037 xrenderdrv_ExtEscape, /* pExtEscape */
3038 NULL, /* pExtFloodFill */
3039 NULL, /* pExtSelectClipRgn */
3040 xrenderdrv_ExtTextOut, /* pExtTextOut */
3041 NULL, /* pFillPath */
3042 NULL, /* pFillRgn */
3043 NULL, /* pFlattenPath */
3044 NULL, /* pFrameRgn */
3045 NULL, /* pGdiComment */
3046 NULL, /* pGetCharWidth */
3047 NULL, /* pGetDeviceCaps */
3048 NULL, /* pGetDeviceGammaRamp */
3049 NULL, /* pGetICMProfile */
3050 xrenderdrv_GetImage, /* pGetImage */
3051 NULL, /* pGetNearestColor */
3052 NULL, /* pGetPixel */
3053 NULL, /* pGetPixelFormat */
3054 NULL, /* pGetSystemPaletteEntries */
3055 NULL, /* pGetTextExtentExPoint */
3056 NULL, /* pGetTextMetrics */
3057 NULL, /* pIntersectClipRect */
3058 NULL, /* pInvertRgn */
3059 NULL, /* pLineTo */
3060 NULL, /* pModifyWorldTransform */
3061 NULL, /* pMoveTo */
3062 NULL, /* pOffsetClipRgn */
3063 NULL, /* pOffsetViewportOrg */
3064 NULL, /* pOffsetWindowOrg */
3065 NULL, /* pPaintRgn */
3066 NULL, /* pPatBlt */
3067 NULL, /* pPie */
3068 NULL, /* pPolyBezier */
3069 NULL, /* pPolyBezierTo */
3070 NULL, /* pPolyDraw */
3071 NULL, /* pPolyPolygon */
3072 NULL, /* pPolyPolyline */
3073 NULL, /* pPolygon */
3074 NULL, /* pPolyline */
3075 NULL, /* pPolylineTo */
3076 xrenderdrv_PutImage, /* pPutImage */
3077 NULL, /* pRealizeDefaultPalette */
3078 NULL, /* pRealizePalette */
3079 NULL, /* pRectangle */
3080 NULL, /* pResetDC */
3081 NULL, /* pRestoreDC */
3082 NULL, /* pRoundRect */
3083 NULL, /* pSaveDC */
3084 NULL, /* pScaleViewportExt */
3085 NULL, /* pScaleWindowExt */
3086 xrenderdrv_SelectBitmap, /* pSelectBitmap */
3087 NULL, /* pSelectBrush */
3088 NULL, /* pSelectClipPath */
3089 xrenderdrv_SelectFont, /* pSelectFont */
3090 NULL, /* pSelectPalette */
3091 NULL, /* pSelectPen */
3092 NULL, /* pSetArcDirection */
3093 NULL, /* pSetBkColor */
3094 NULL, /* pSetBkMode */
3095 NULL, /* pSetDCBrushColor */
3096 NULL, /* pSetDCPenColor */
3097 NULL, /* pSetDIBColorTable */
3098 NULL, /* pSetDIBitsToDevice */
3099 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
3100 NULL, /* pSetDeviceGammaRamp */
3101 NULL, /* pSetLayout */
3102 NULL, /* pSetMapMode */
3103 NULL, /* pSetMapperFlags */
3104 NULL, /* pSetPixel */
3105 NULL, /* pSetPixelFormat */
3106 NULL, /* pSetPolyFillMode */
3107 NULL, /* pSetROP2 */
3108 NULL, /* pSetRelAbs */
3109 NULL, /* pSetStretchBltMode */
3110 NULL, /* pSetTextAlign */
3111 NULL, /* pSetTextCharacterExtra */
3112 NULL, /* pSetTextColor */
3113 NULL, /* pSetTextJustification */
3114 NULL, /* pSetViewportExt */
3115 NULL, /* pSetViewportOrg */
3116 NULL, /* pSetWindowExt */
3117 NULL, /* pSetWindowOrg */
3118 NULL, /* pSetWorldTransform */
3119 NULL, /* pStartDoc */
3120 NULL, /* pStartPage */
3121 xrenderdrv_StretchBlt, /* pStretchBlt */
3122 NULL, /* pStretchDIBits */
3123 NULL, /* pStrokeAndFillPath */
3124 NULL, /* pStrokePath */
3125 NULL, /* pSwapBuffers */
3126 NULL, /* pUnrealizePalette */
3127 NULL, /* pWidenPath */
3128 /* OpenGL not supported */
3131 #else /* SONAME_LIBXRENDER */
3133 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
3135 TRACE("XRender support not compiled in.\n");
3136 return NULL;
3139 void X11DRV_XRender_Finalize(void)
3143 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
3145 wine_tsx11_lock();
3146 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
3148 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
3149 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
3150 wine_tsx11_unlock();
3153 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
3155 return FALSE;
3158 #endif /* SONAME_LIBXRENDER */