winex11: Always refresh the picture clipping when we have an additional clip region.
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blob1c15d2af9113a75e90347cfa84753fb0e6b72b02
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 WINE_DECLARE_DEBUG_CHANNEL(winediag);
49 static BOOL X11DRV_XRender_Installed = FALSE;
51 #include <X11/Xlib.h>
52 #include <X11/extensions/Xrender.h>
54 #ifndef RepeatNone /* added in 0.10 */
55 #define RepeatNone 0
56 #define RepeatNormal 1
57 #define RepeatPad 2
58 #define RepeatReflect 3
59 #endif
61 enum wxr_format
63 WXR_FORMAT_MONO,
64 WXR_FORMAT_GRAY,
65 WXR_FORMAT_X1R5G5B5,
66 WXR_FORMAT_X1B5G5R5,
67 WXR_FORMAT_R5G6B5,
68 WXR_FORMAT_B5G6R5,
69 WXR_FORMAT_R8G8B8,
70 WXR_FORMAT_B8G8R8,
71 WXR_FORMAT_A8R8G8B8,
72 WXR_FORMAT_B8G8R8A8,
73 WXR_FORMAT_X8R8G8B8,
74 WXR_FORMAT_B8G8R8X8,
75 WXR_NB_FORMATS,
76 WXR_INVALID_FORMAT = WXR_NB_FORMATS
79 typedef struct wine_xrender_format_template
81 unsigned int depth;
82 unsigned int alpha;
83 unsigned int alphaMask;
84 unsigned int red;
85 unsigned int redMask;
86 unsigned int green;
87 unsigned int greenMask;
88 unsigned int blue;
89 unsigned int blueMask;
90 } WineXRenderFormatTemplate;
92 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
94 /* Format depth alpha mask red mask green mask blue mask*/
95 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
96 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
97 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
98 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
99 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
100 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
101 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
103 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
105 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
106 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
109 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
111 /* format phys red phys green phys blue log red log green log blue */
112 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
113 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
114 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
115 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
116 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
117 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
118 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
120 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
121 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
122 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
123 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
126 static enum wxr_format default_format = WXR_INVALID_FORMAT;
127 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
129 typedef struct
131 LOGFONTW lf;
132 XFORM xform;
133 SIZE devsize; /* size in device coords */
134 DWORD hash;
135 } LFANDSIZE;
137 #define INITIAL_REALIZED_BUF_SIZE 128
139 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
141 typedef struct
143 GlyphSet glyphset;
144 XRenderPictFormat *font_format;
145 int nrealized;
146 BOOL *realized;
147 XGlyphInfo *gis;
148 } gsCacheEntryFormat;
150 typedef struct
152 LFANDSIZE lfsz;
153 AA_Type aa_default;
154 gsCacheEntryFormat * format[AA_MAXVALUE];
155 INT count;
156 INT next;
157 } gsCacheEntry;
159 struct xrender_physdev
161 struct gdi_physdev dev;
162 X11DRV_PDEVICE *x11dev;
163 enum wxr_format format;
164 int cache_index;
165 BOOL update_clip;
166 Picture pict;
167 Picture pict_src;
168 XRenderPictFormat *pict_format;
171 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
173 return (struct xrender_physdev *)dev;
176 static const struct gdi_dc_funcs xrender_funcs;
178 static gsCacheEntry *glyphsetCache = NULL;
179 static DWORD glyphsetCacheSize = 0;
180 static INT lastfree = -1;
181 static INT mru = -1;
183 #define INIT_CACHE_SIZE 10
185 static int antialias = 1;
187 static void *xrender_handle;
189 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
190 MAKE_FUNCPTR(XRenderAddGlyphs)
191 MAKE_FUNCPTR(XRenderComposite)
192 MAKE_FUNCPTR(XRenderCompositeText16)
193 MAKE_FUNCPTR(XRenderCreateGlyphSet)
194 MAKE_FUNCPTR(XRenderCreatePicture)
195 MAKE_FUNCPTR(XRenderFillRectangle)
196 MAKE_FUNCPTR(XRenderFindFormat)
197 MAKE_FUNCPTR(XRenderFindVisualFormat)
198 MAKE_FUNCPTR(XRenderFreeGlyphSet)
199 MAKE_FUNCPTR(XRenderFreePicture)
200 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
201 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
202 MAKE_FUNCPTR(XRenderCreateLinearGradient)
203 #endif
204 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
205 MAKE_FUNCPTR(XRenderSetPictureTransform)
206 #endif
207 MAKE_FUNCPTR(XRenderQueryExtension)
209 #ifdef SONAME_LIBFONTCONFIG
210 #include <fontconfig/fontconfig.h>
211 MAKE_FUNCPTR(FcConfigSubstitute)
212 MAKE_FUNCPTR(FcDefaultSubstitute)
213 MAKE_FUNCPTR(FcFontMatch)
214 MAKE_FUNCPTR(FcInit)
215 MAKE_FUNCPTR(FcPatternCreate)
216 MAKE_FUNCPTR(FcPatternDestroy)
217 MAKE_FUNCPTR(FcPatternAddInteger)
218 MAKE_FUNCPTR(FcPatternAddString)
219 MAKE_FUNCPTR(FcPatternGetBool)
220 MAKE_FUNCPTR(FcPatternGetInteger)
221 MAKE_FUNCPTR(FcPatternGetString)
222 static void *fontconfig_handle;
223 static BOOL fontconfig_installed;
224 #endif
226 #undef MAKE_FUNCPTR
228 static CRITICAL_SECTION xrender_cs;
229 static CRITICAL_SECTION_DEBUG critsect_debug =
231 0, 0, &xrender_cs,
232 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
233 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
235 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
237 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
238 ( ( (ULONG)_x4 << 24 ) | \
239 ( (ULONG)_x3 << 16 ) | \
240 ( (ULONG)_x2 << 8 ) | \
241 (ULONG)_x1 )
243 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
245 #define GASP_GRIDFIT 0x01
246 #define GASP_DOGRAY 0x02
248 #ifdef WORDS_BIGENDIAN
249 #define get_be_word(x) (x)
250 #define NATIVE_BYTE_ORDER MSBFirst
251 #else
252 #define get_be_word(x) RtlUshortByteSwap(x)
253 #define NATIVE_BYTE_ORDER LSBFirst
254 #endif
256 static BOOL has_alpha( enum wxr_format format )
258 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
261 static enum wxr_format get_format_without_alpha( enum wxr_format format )
263 switch (format)
265 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
266 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
267 default: return format;
271 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
273 templ->id = 0;
274 templ->type = PictTypeDirect;
275 templ->depth = fmt->depth;
276 templ->direct.alpha = fmt->alpha;
277 templ->direct.alphaMask = fmt->alphaMask;
278 templ->direct.red = fmt->red;
279 templ->direct.redMask = fmt->redMask;
280 templ->direct.green = fmt->green;
281 templ->direct.greenMask = fmt->greenMask;
282 templ->direct.blue = fmt->blue;
283 templ->direct.blueMask = fmt->blueMask;
284 templ->colormap = 0;
286 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
288 return TRUE;
291 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
293 if(fmt->depth != screen_depth)
294 return FALSE;
295 if( (fmt->redMask << fmt->red) != visual->red_mask)
296 return FALSE;
297 if( (fmt->greenMask << fmt->green) != visual->green_mask)
298 return FALSE;
299 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
300 return FALSE;
302 /* We never select a default ARGB visual */
303 if(fmt->alphaMask)
304 return FALSE;
306 return TRUE;
309 static int load_xrender_formats(void)
311 int count = 0;
312 unsigned int i;
314 for (i = 0; i < WXR_NB_FORMATS; i++)
316 XRenderPictFormat templ;
318 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
320 wine_tsx11_lock();
321 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
322 if (!pict_formats[i])
324 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
325 if (visual->class == DirectColor)
327 XVisualInfo info;
328 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
329 screen_depth, TrueColor, &info ))
331 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
332 if (pict_formats[i]) visual = info.visual;
336 wine_tsx11_unlock();
337 if (pict_formats[i]) default_format = i;
339 else
341 unsigned long mask = 0;
342 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
344 wine_tsx11_lock();
345 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
346 wine_tsx11_unlock();
348 if (pict_formats[i])
350 count++;
351 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
354 return count;
357 /***********************************************************************
358 * X11DRV_XRender_Init
360 * Let's see if our XServer has the extension available
363 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
365 int event_base, i;
367 using_client_side_fonts = client_side_with_render || client_side_with_core;
369 if (!client_side_with_render) return NULL;
370 if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
372 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
373 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
374 LOAD_FUNCPTR(XRenderAddGlyphs);
375 LOAD_FUNCPTR(XRenderComposite);
376 LOAD_FUNCPTR(XRenderCompositeText16);
377 LOAD_FUNCPTR(XRenderCreateGlyphSet);
378 LOAD_FUNCPTR(XRenderCreatePicture);
379 LOAD_FUNCPTR(XRenderFillRectangle);
380 LOAD_FUNCPTR(XRenderFindFormat);
381 LOAD_FUNCPTR(XRenderFindVisualFormat);
382 LOAD_FUNCPTR(XRenderFreeGlyphSet);
383 LOAD_FUNCPTR(XRenderFreePicture);
384 LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
385 LOAD_FUNCPTR(XRenderQueryExtension);
386 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
387 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
388 #endif
389 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
390 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
391 #endif
392 #undef LOAD_OPTIONAL_FUNCPTR
393 #undef LOAD_FUNCPTR
395 wine_tsx11_lock();
396 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
397 wine_tsx11_unlock();
398 if (!X11DRV_XRender_Installed) return NULL;
400 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
401 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
403 ERR_(winediag)("Wine has detected that you probably have a buggy version "
404 "of libXrender. Because of this client side font rendering "
405 "will be disabled. Please upgrade this library.\n");
406 X11DRV_XRender_Installed = FALSE;
407 return NULL;
410 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask)
412 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
413 X11DRV_XRender_Installed = FALSE;
414 return NULL;
417 #ifdef SONAME_LIBFONTCONFIG
418 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
420 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fontconfig_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
421 LOAD_FUNCPTR(FcConfigSubstitute);
422 LOAD_FUNCPTR(FcDefaultSubstitute);
423 LOAD_FUNCPTR(FcFontMatch);
424 LOAD_FUNCPTR(FcInit);
425 LOAD_FUNCPTR(FcPatternCreate);
426 LOAD_FUNCPTR(FcPatternDestroy);
427 LOAD_FUNCPTR(FcPatternAddInteger);
428 LOAD_FUNCPTR(FcPatternAddString);
429 LOAD_FUNCPTR(FcPatternGetBool);
430 LOAD_FUNCPTR(FcPatternGetInteger);
431 LOAD_FUNCPTR(FcPatternGetString);
432 #undef LOAD_FUNCPTR
433 fontconfig_installed = pFcInit();
435 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
437 sym_not_found:
438 #endif
440 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
441 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
443 glyphsetCacheSize = INIT_CACHE_SIZE;
444 lastfree = 0;
445 for(i = 0; i < INIT_CACHE_SIZE; i++) {
446 glyphsetCache[i].next = i + 1;
447 glyphsetCache[i].count = -1;
449 glyphsetCache[i-1].next = -1;
451 if(screen_depth <= 8 || !client_side_antialias_with_render) antialias = 0;
453 return &xrender_funcs;
456 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
457 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
459 if(pf->direct.redMask)
460 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
461 else
462 dst_color->red = 0;
464 if(pf->direct.greenMask)
465 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
466 else
467 dst_color->green = 0;
469 if(pf->direct.blueMask)
470 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
471 else
472 dst_color->blue = 0;
474 dst_color->alpha = 0xffff;
477 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
479 int redMask, greenMask, blueMask;
480 unsigned int i;
482 if (depth == 1) return WXR_FORMAT_MONO;
484 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
485 if (!shifts) return default_format;
487 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
488 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
489 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
491 /* Try to locate a format which matches the specification of the dibsection. */
492 for(i = 0; i < WXR_NB_FORMATS; i++)
494 if( depth == wxr_formats_template[i].depth &&
495 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
496 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
497 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
498 return i;
501 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
502 ERR("No XRender format found for %u %08x/%08x/%08x\n", depth, redMask, greenMask, blueMask);
503 return WXR_INVALID_FORMAT;
506 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
508 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
510 switch (info->bmiHeader.biBitCount)
512 case 1:
513 return WXR_FORMAT_MONO;
514 case 4:
515 case 8:
516 break;
517 case 24:
518 if (info->bmiHeader.biCompression != BI_RGB) break;
519 return WXR_FORMAT_R8G8B8;
520 case 16:
521 case 32:
522 if (info->bmiHeader.biCompression == BI_BITFIELDS)
524 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
525 unsigned int i;
527 for (i = 0; i < WXR_NB_FORMATS; i++)
529 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
530 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
531 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
532 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
533 return i;
535 break;
537 if (info->bmiHeader.biCompression != BI_RGB) break;
538 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
540 return WXR_INVALID_FORMAT;
543 static enum wxr_format get_bitmap_format( int bpp )
545 enum wxr_format format = WXR_INVALID_FORMAT;
547 if (bpp == screen_bpp)
549 switch (bpp)
551 case 16: format = WXR_FORMAT_R5G6B5; break;
552 case 24: format = WXR_FORMAT_R8G8B8; break;
553 case 32: format = WXR_FORMAT_A8R8G8B8; break;
556 return format;
559 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
560 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
562 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
563 XTransform xform = {{
564 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
565 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
566 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
569 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
570 #endif
573 /* check if we can use repeating instead of scaling for the specified source DC */
574 static BOOL use_source_repeat( struct xrender_physdev *dev )
576 return (dev->x11dev->bitmap &&
577 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
578 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
581 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
583 if (!dev->pict && dev->pict_format)
585 XRenderPictureAttributes pa;
587 wine_tsx11_lock();
588 pa.subwindow_mode = IncludeInferiors;
589 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
590 dev->pict_format, CPSubwindowMode, &pa );
591 wine_tsx11_unlock();
592 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
593 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
594 dev->update_clip = TRUE;
597 if (dev->update_clip || clip_rect || clip_rgn)
599 RGNDATA *clip_data;
600 HRGN rgn = 0;
602 if (clip_rect)
604 rgn = CreateRectRgnIndirect( clip_rect );
605 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
606 CombineRgn( rgn, rgn, dev->x11dev->region, RGN_AND );
608 else if (clip_rgn)
610 rgn = CreateRectRgn( 0, 0, 0, 0 );
611 CombineRgn( rgn, clip_rgn, dev->x11dev->region, RGN_AND );
614 if ((clip_data = X11DRV_GetRegionData( rgn ? rgn : dev->x11dev->region, 0 )))
616 wine_tsx11_lock();
617 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
618 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
619 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
620 wine_tsx11_unlock();
621 HeapFree( GetProcessHeap(), 0, clip_data );
623 dev->update_clip = (rgn != 0); /* have to update again if we are using a custom region */
624 if (rgn) DeleteObject( rgn );
626 return dev->pict;
629 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
631 if (!dev->pict_src && dev->pict_format)
633 XRenderPictureAttributes pa;
635 wine_tsx11_lock();
636 pa.subwindow_mode = IncludeInferiors;
637 pa.repeat = repeat ? RepeatNormal : RepeatNone;
638 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
639 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
640 wine_tsx11_unlock();
642 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
643 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
646 return dev->pict_src;
649 static void free_xrender_picture( struct xrender_physdev *dev )
651 if (dev->pict || dev->pict_src)
653 wine_tsx11_lock();
654 XFlush( gdi_display );
655 if (dev->pict)
657 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
658 pXRenderFreePicture(gdi_display, dev->pict);
659 dev->pict = 0;
661 if(dev->pict_src)
663 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
664 pXRenderFreePicture(gdi_display, dev->pict_src);
665 dev->pict_src = 0;
667 wine_tsx11_unlock();
671 /* return a mask picture used to force alpha to 0 */
672 static Picture get_no_alpha_mask(void)
674 static Pixmap pixmap;
675 static Picture pict;
677 wine_tsx11_lock();
678 if (!pict)
680 XRenderPictureAttributes pa;
681 XRenderColor col;
683 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
684 pa.repeat = RepeatNormal;
685 pa.component_alpha = True;
686 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
687 CPRepeat|CPComponentAlpha, &pa );
688 col.red = col.green = col.blue = 0xffff;
689 col.alpha = 0;
690 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
692 wine_tsx11_unlock();
693 return pict;
696 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
698 if(p1->hash != p2->hash) return TRUE;
699 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
700 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
701 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
702 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
705 #if 0
706 static void walk_cache(void)
708 int i;
710 EnterCriticalSection(&xrender_cs);
711 for(i=mru; i >= 0; i = glyphsetCache[i].next)
712 TRACE("item %d\n", i);
713 LeaveCriticalSection(&xrender_cs);
715 #endif
717 static int LookupEntry(LFANDSIZE *plfsz)
719 int i, prev_i = -1;
721 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
722 TRACE("%d\n", i);
723 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
725 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
726 glyphsetCache[i].count++;
727 if(prev_i >= 0) {
728 glyphsetCache[prev_i].next = glyphsetCache[i].next;
729 glyphsetCache[i].next = mru;
730 mru = i;
732 TRACE("found font in cache %d\n", i);
733 return i;
735 prev_i = i;
737 TRACE("font not in cache\n");
738 return -1;
741 static void FreeEntry(int entry)
743 int format;
745 for(format = 0; format < AA_MAXVALUE; format++) {
746 gsCacheEntryFormat * formatEntry;
748 if( !glyphsetCache[entry].format[format] )
749 continue;
751 formatEntry = glyphsetCache[entry].format[format];
753 if(formatEntry->glyphset) {
754 wine_tsx11_lock();
755 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
756 wine_tsx11_unlock();
757 formatEntry->glyphset = 0;
759 if(formatEntry->nrealized) {
760 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
761 formatEntry->realized = NULL;
762 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
763 formatEntry->gis = NULL;
764 formatEntry->nrealized = 0;
767 HeapFree(GetProcessHeap(), 0, formatEntry);
768 glyphsetCache[entry].format[format] = NULL;
772 static int AllocEntry(void)
774 int best = -1, prev_best = -1, i, prev_i = -1;
776 if(lastfree >= 0) {
777 assert(glyphsetCache[lastfree].count == -1);
778 glyphsetCache[lastfree].count = 1;
779 best = lastfree;
780 lastfree = glyphsetCache[lastfree].next;
781 assert(best != mru);
782 glyphsetCache[best].next = mru;
783 mru = best;
785 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
786 return mru;
789 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
790 if(glyphsetCache[i].count == 0) {
791 best = i;
792 prev_best = prev_i;
794 prev_i = i;
797 if(best >= 0) {
798 TRACE("freeing unused glyphset at cache %d\n", best);
799 FreeEntry(best);
800 glyphsetCache[best].count = 1;
801 if(prev_best >= 0) {
802 glyphsetCache[prev_best].next = glyphsetCache[best].next;
803 glyphsetCache[best].next = mru;
804 mru = best;
805 } else {
806 assert(mru == best);
808 return mru;
811 TRACE("Growing cache\n");
813 if (glyphsetCache)
814 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
815 glyphsetCache,
816 (glyphsetCacheSize + INIT_CACHE_SIZE)
817 * sizeof(*glyphsetCache));
818 else
819 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
820 (glyphsetCacheSize + INIT_CACHE_SIZE)
821 * sizeof(*glyphsetCache));
823 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
824 i++) {
825 glyphsetCache[i].next = i + 1;
826 glyphsetCache[i].count = -1;
828 glyphsetCache[i-1].next = -1;
829 glyphsetCacheSize += INIT_CACHE_SIZE;
831 lastfree = glyphsetCache[best].next;
832 glyphsetCache[best].count = 1;
833 glyphsetCache[best].next = mru;
834 mru = best;
835 TRACE("new free cache slot at %d\n", mru);
836 return mru;
839 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
841 DWORD size;
842 WORD *gasp, *buffer;
843 WORD num_recs;
844 DWORD ppem;
845 TEXTMETRICW tm;
847 *flags = 0;
849 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
850 if(size == GDI_ERROR)
851 return FALSE;
853 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
854 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
856 GetTextMetricsW(hdc, &tm);
857 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
859 gasp++;
860 num_recs = get_be_word(*gasp);
861 gasp++;
862 while(num_recs--)
864 *flags = get_be_word(*(gasp + 1));
865 if(ppem <= get_be_word(*gasp))
866 break;
867 gasp += 2;
869 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
871 HeapFree(GetProcessHeap(), 0, buffer);
872 return TRUE;
875 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
877 AA_Type ret;
878 WORD flags;
879 UINT font_smoothing_type, font_smoothing_orientation;
881 if (X11DRV_XRender_Installed && subpixel &&
882 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
883 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
885 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
886 &font_smoothing_orientation, 0) &&
887 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
889 ret = AA_BGR;
891 else
892 ret = AA_RGB;
893 /*FIXME
894 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
895 But, Wine's subpixel rendering can support the portrait mode.
898 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
899 ret = AA_Grey;
900 else
901 ret = AA_None;
903 return ret;
906 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
908 int ret;
909 int format;
910 gsCacheEntry *entry;
911 static int hinter = -1;
912 static int subpixel = -1;
913 BOOL font_smoothing;
915 if((ret = LookupEntry(plfsz)) != -1) return ret;
917 ret = AllocEntry();
918 entry = glyphsetCache + ret;
919 entry->lfsz = *plfsz;
920 for( format = 0; format < AA_MAXVALUE; format++ ) {
921 assert( !entry->format[format] );
924 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
926 if(hinter == -1 || subpixel == -1)
928 RASTERIZER_STATUS status;
929 GetRasterizerCaps(&status, sizeof(status));
930 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
931 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
934 switch (plfsz->lf.lfQuality)
936 case ANTIALIASED_QUALITY:
937 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
938 return ret; /* ignore further configuration */
939 case CLEARTYPE_QUALITY:
940 case CLEARTYPE_NATURAL_QUALITY:
941 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
942 break;
943 case DEFAULT_QUALITY:
944 case DRAFT_QUALITY:
945 case PROOF_QUALITY:
946 default:
947 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
948 font_smoothing)
950 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
952 else
953 entry->aa_default = AA_None;
954 break;
957 font_smoothing = TRUE; /* default to enabled */
958 #ifdef SONAME_LIBFONTCONFIG
959 if (fontconfig_installed)
961 FcPattern *match, *pattern;
962 FcResult result;
963 char family[LF_FACESIZE * 4];
965 #if defined(__i386__) && defined(__GNUC__)
966 /* fontconfig generates floating point exceptions, mask them */
967 WORD cw, default_cw = 0x37f;
968 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
969 #endif
971 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
972 pattern = pFcPatternCreate();
973 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
974 if (plfsz->lf.lfWeight != FW_DONTCARE)
976 int weight;
977 switch (plfsz->lf.lfWeight)
979 case FW_THIN: weight = FC_WEIGHT_THIN; break;
980 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
981 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
982 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
983 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
984 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
985 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
986 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
987 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
988 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
990 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
992 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
993 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
994 pFcDefaultSubstitute( pattern );
995 if ((match = pFcFontMatch( NULL, pattern, &result )))
997 int rgba;
998 FcBool antialias;
1000 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
1001 antialias = TRUE;
1002 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
1004 FcChar8 *file;
1005 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
1007 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
1008 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
1010 switch (rgba)
1012 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
1013 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
1014 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1015 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1016 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1019 if (!antialias) font_smoothing = FALSE;
1020 pFcPatternDestroy( match );
1022 pFcPatternDestroy( pattern );
1024 #if defined(__i386__) && defined(__GNUC__)
1025 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
1026 #endif
1028 #endif /* SONAME_LIBFONTCONFIG */
1030 /* now check Xft resources */
1032 char *value;
1033 BOOL antialias = TRUE;
1035 wine_tsx11_lock();
1036 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1038 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1039 value[0] == '0' || !strcasecmp( value, "off" ))
1040 antialias = FALSE;
1042 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1044 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1045 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1046 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1047 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1048 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1049 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1051 wine_tsx11_unlock();
1052 if (!antialias) font_smoothing = FALSE;
1055 if (!font_smoothing) entry->aa_default = AA_None;
1057 /* we can't support subpixel without xrender */
1058 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1060 else
1061 entry->aa_default = AA_None;
1063 return ret;
1066 static void dec_ref_cache(int index)
1068 assert(index >= 0);
1069 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1070 assert(glyphsetCache[index].count > 0);
1071 glyphsetCache[index].count--;
1074 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1076 DWORD hash = 0, *ptr, two_chars;
1077 WORD *pwc;
1078 int i;
1080 hash ^= plfsz->devsize.cx;
1081 hash ^= plfsz->devsize.cy;
1082 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1083 hash ^= *ptr;
1084 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1085 hash ^= *ptr;
1086 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1087 two_chars = *ptr;
1088 pwc = (WCHAR *)&two_chars;
1089 if(!*pwc) break;
1090 *pwc = toupperW(*pwc);
1091 pwc++;
1092 *pwc = toupperW(*pwc);
1093 hash ^= two_chars;
1094 if(!*pwc) break;
1096 plfsz->hash = hash;
1097 return;
1100 /***********************************************************************
1101 * X11DRV_XRender_Finalize
1103 void X11DRV_XRender_Finalize(void)
1105 int i;
1107 EnterCriticalSection(&xrender_cs);
1108 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1109 FreeEntry(i);
1110 LeaveCriticalSection(&xrender_cs);
1111 DeleteCriticalSection(&xrender_cs);
1114 /**********************************************************************
1115 * xrenderdrv_SelectFont
1117 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1119 struct xrender_physdev *physdev = get_xrender_dev( dev );
1120 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1121 HFONT ret = next->funcs->pSelectFont( next, hfont );
1123 if (!ret) return 0;
1125 if (physdev->x11dev->has_gdi_font)
1127 LFANDSIZE lfsz;
1129 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1131 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1132 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1133 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1134 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1135 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1136 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1138 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1139 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1140 lfsz.xform.eM21, lfsz.xform.eM22);
1142 /* Not used fields, would break hashing */
1143 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1145 lfsz_calc_hash(&lfsz);
1147 EnterCriticalSection(&xrender_cs);
1148 if (physdev->cache_index != -1)
1149 dec_ref_cache( physdev->cache_index );
1150 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1151 LeaveCriticalSection(&xrender_cs);
1153 else
1155 EnterCriticalSection( &xrender_cs );
1156 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1157 physdev->cache_index = -1;
1158 LeaveCriticalSection( &xrender_cs );
1160 return ret;
1163 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1165 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1166 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1168 if (!physdev) return FALSE;
1169 physdev->x11dev = x11dev;
1170 physdev->cache_index = -1;
1171 physdev->format = format;
1172 physdev->pict_format = pict_formats[format];
1173 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1174 return TRUE;
1177 /* store the color mask data in the bitmap info structure */
1178 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1180 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1182 info->bmiHeader.biPlanes = 1;
1183 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1184 info->bmiHeader.biCompression = BI_RGB;
1185 info->bmiHeader.biClrUsed = 0;
1187 switch (info->bmiHeader.biBitCount)
1189 case 16:
1190 colors[0] = format->direct.redMask << format->direct.red;
1191 colors[1] = format->direct.greenMask << format->direct.green;
1192 colors[2] = format->direct.blueMask << format->direct.blue;
1193 info->bmiHeader.biCompression = BI_BITFIELDS;
1194 break;
1195 case 32:
1196 colors[0] = format->direct.redMask << format->direct.red;
1197 colors[1] = format->direct.greenMask << format->direct.green;
1198 colors[2] = format->direct.blueMask << format->direct.blue;
1199 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1200 info->bmiHeader.biCompression = BI_BITFIELDS;
1201 break;
1206 /**********************************************************************
1207 * xrenderdrv_CreateDC
1209 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1210 LPCWSTR output, const DEVMODEW* initData )
1212 return create_xrender_dc( pdev, default_format );
1215 /**********************************************************************
1216 * xrenderdrv_CreateCompatibleDC
1218 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1220 if (orig) /* chain to x11drv first */
1222 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1223 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1225 /* otherwise we have been called by x11drv */
1227 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1230 /**********************************************************************
1231 * xrenderdrv_DeleteDC
1233 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1235 struct xrender_physdev *physdev = get_xrender_dev( dev );
1237 free_xrender_picture( physdev );
1239 EnterCriticalSection( &xrender_cs );
1240 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1241 LeaveCriticalSection( &xrender_cs );
1243 HeapFree( GetProcessHeap(), 0, physdev );
1244 return TRUE;
1247 /**********************************************************************
1248 * xrenderdrv_ExtEscape
1250 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1251 INT out_count, LPVOID out_data )
1253 struct xrender_physdev *physdev = get_xrender_dev( dev );
1255 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1257 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1259 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1261 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1262 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1263 return ret;
1266 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1269 /****************************************************************************
1270 * xrenderdrv_CopyBitmap
1272 static BOOL xrenderdrv_CopyBitmap( HBITMAP src, HBITMAP dst )
1274 return X11DRV_CopyBitmap( src, dst );
1277 /****************************************************************************
1278 * xrenderdrv_CreateBitmap
1280 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1282 enum wxr_format format;
1283 BITMAP bitmap;
1285 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1287 if (bitmap.bmPlanes != 1) return FALSE;
1288 format = get_bitmap_format( bitmap.bmBitsPixel );
1290 if (pict_formats[format])
1291 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth,
1292 TRUE, &wxr_color_shifts[format] );
1294 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1295 return dev->funcs->pCreateBitmap( dev, hbitmap );
1298 /****************************************************************************
1299 * xrenderdrv_DeleteBitmap
1301 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1303 return X11DRV_DeleteBitmap( hbitmap );
1306 /***********************************************************************
1307 * xrenderdrv_SelectBitmap
1309 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1311 HBITMAP ret;
1312 struct xrender_physdev *physdev = get_xrender_dev( dev );
1314 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1315 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1316 if (ret)
1318 free_xrender_picture( physdev );
1319 physdev->format = get_xrender_format_from_color_shifts( physdev->x11dev->depth,
1320 physdev->x11dev->color_shifts );
1321 physdev->pict_format = pict_formats[physdev->format];
1323 return ret;
1326 /***********************************************************************
1327 * xrenderdrv_GetImage
1329 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1330 struct gdi_image_bits *bits, struct bitblt_coords *src )
1332 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1333 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1334 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1337 /***********************************************************************
1338 * xrenderdrv_SetDeviceClipping
1340 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1342 struct xrender_physdev *physdev = get_xrender_dev( dev );
1344 physdev->update_clip = TRUE;
1346 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1347 dev->funcs->pSetDeviceClipping( dev, vis_rgn, clip_rgn );
1351 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1353 XRenderPictFormat *pict_format;
1354 ColorShifts shifts;
1355 const DWORD *bitfields;
1356 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1357 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1360 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1361 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1362 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1363 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1364 return FALSE;
1366 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1367 bitfields = dib->dsBitfields;
1368 else if(bits_pixel == 24 || bits_pixel == 32)
1369 bitfields = bitfields_32;
1370 else
1371 bitfields = bitfields_16;
1373 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1374 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1376 /* Common formats should be in our picture format table. */
1377 if (!pict_format)
1379 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1380 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1381 return FALSE;
1384 physBitmap->depth = pict_format->depth;
1385 physBitmap->trueColor = TRUE;
1386 physBitmap->color_shifts = shifts;
1387 return TRUE;
1390 /************************************************************************
1391 * UploadGlyph
1393 * Helper to ExtTextOut. Must be called inside xrender_cs
1395 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1397 unsigned int buflen;
1398 char *buf;
1399 Glyph gid;
1400 GLYPHMETRICS gm;
1401 XGlyphInfo gi;
1402 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1403 gsCacheEntryFormat *formatEntry;
1404 UINT ggo_format = GGO_GLYPH_INDEX;
1405 enum wxr_format wxr_format;
1406 static const char zero[4];
1407 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1409 switch(format) {
1410 case AA_Grey:
1411 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1412 break;
1413 case AA_RGB:
1414 ggo_format |= WINE_GGO_HRGB_BITMAP;
1415 break;
1416 case AA_BGR:
1417 ggo_format |= WINE_GGO_HBGR_BITMAP;
1418 break;
1419 case AA_VRGB:
1420 ggo_format |= WINE_GGO_VRGB_BITMAP;
1421 break;
1422 case AA_VBGR:
1423 ggo_format |= WINE_GGO_VBGR_BITMAP;
1424 break;
1426 default:
1427 ERR("aa = %d - not implemented\n", format);
1428 case AA_None:
1429 ggo_format |= GGO_BITMAP;
1430 break;
1433 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1434 if(buflen == GDI_ERROR) {
1435 if(format != AA_None) {
1436 format = AA_None;
1437 entry->aa_default = AA_None;
1438 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1439 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1441 if(buflen == GDI_ERROR) {
1442 WARN("GetGlyphOutlineW failed using default glyph\n");
1443 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1444 if(buflen == GDI_ERROR) {
1445 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1446 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1447 if(buflen == GDI_ERROR) {
1448 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1449 return;
1453 TRACE("Turning off antialiasing for this monochrome font\n");
1456 /* If there is nothing for the current type, we create the entry. */
1457 if( !entry->format[format] ) {
1458 entry->format[format] = HeapAlloc(GetProcessHeap(),
1459 HEAP_ZERO_MEMORY,
1460 sizeof(gsCacheEntryFormat));
1462 formatEntry = entry->format[format];
1464 if(formatEntry->nrealized <= glyph) {
1465 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1467 if (formatEntry->realized)
1468 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1469 HEAP_ZERO_MEMORY,
1470 formatEntry->realized,
1471 formatEntry->nrealized * sizeof(BOOL));
1472 else
1473 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1474 HEAP_ZERO_MEMORY,
1475 formatEntry->nrealized * sizeof(BOOL));
1477 if (formatEntry->gis)
1478 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1479 HEAP_ZERO_MEMORY,
1480 formatEntry->gis,
1481 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1482 else
1483 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1484 HEAP_ZERO_MEMORY,
1485 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1489 if(formatEntry->glyphset == 0) {
1490 switch(format) {
1491 case AA_Grey:
1492 wxr_format = WXR_FORMAT_GRAY;
1493 break;
1495 case AA_RGB:
1496 case AA_BGR:
1497 case AA_VRGB:
1498 case AA_VBGR:
1499 wxr_format = WXR_FORMAT_A8R8G8B8;
1500 break;
1502 default:
1503 ERR("aa = %d - not implemented\n", format);
1504 case AA_None:
1505 wxr_format = WXR_FORMAT_MONO;
1506 break;
1509 wine_tsx11_lock();
1510 formatEntry->font_format = pict_formats[wxr_format];
1511 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1512 wine_tsx11_unlock();
1516 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1517 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1518 formatEntry->realized[glyph] = TRUE;
1520 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1521 buflen,
1522 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1523 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1525 gi.width = gm.gmBlackBoxX;
1526 gi.height = gm.gmBlackBoxY;
1527 gi.x = -gm.gmptGlyphOrigin.x;
1528 gi.y = gm.gmptGlyphOrigin.y;
1529 gi.xOff = gm.gmCellIncX;
1530 gi.yOff = gm.gmCellIncY;
1532 if(TRACE_ON(xrender)) {
1533 int pitch, i, j;
1534 char output[300];
1535 unsigned char *line;
1537 if(format == AA_None) {
1538 pitch = ((gi.width + 31) / 32) * 4;
1539 for(i = 0; i < gi.height; i++) {
1540 line = (unsigned char*) buf + i * pitch;
1541 output[0] = '\0';
1542 for(j = 0; j < pitch * 8; j++) {
1543 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1545 TRACE("%s\n", output);
1547 } else {
1548 static const char blks[] = " .:;!o*#";
1549 char str[2];
1551 str[1] = '\0';
1552 pitch = ((gi.width + 3) / 4) * 4;
1553 for(i = 0; i < gi.height; i++) {
1554 line = (unsigned char*) buf + i * pitch;
1555 output[0] = '\0';
1556 for(j = 0; j < pitch; j++) {
1557 str[0] = blks[line[j] >> 5];
1558 strcat(output, str);
1560 TRACE("%s\n", output);
1566 if(formatEntry->glyphset) {
1567 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1568 unsigned char *byte = (unsigned char*) buf, c;
1569 int i = buflen;
1571 while(i--) {
1572 c = *byte;
1574 /* magic to flip bit order */
1575 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1576 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1577 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1579 *byte++ = c;
1582 else if ( format != AA_Grey &&
1583 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1585 unsigned int i, *data = (unsigned int *)buf;
1586 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1588 gid = glyph;
1591 XRenderCompositeText seems to ignore 0x0 glyphs when
1592 AA_None, which means we lose the advance width of glyphs
1593 like the space. We'll pretend that such glyphs are 1x1
1594 bitmaps.
1597 if(buflen == 0)
1598 gi.width = gi.height = 1;
1600 wine_tsx11_lock();
1601 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1602 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1603 wine_tsx11_unlock();
1604 HeapFree(GetProcessHeap(), 0, buf);
1607 formatEntry->gis[glyph] = gi;
1610 /*************************************************************
1611 * get_tile_pict
1613 * Returns an appropriate Picture for tiling the text colour.
1614 * Call and use result within the xrender_cs
1616 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1618 static struct
1620 Pixmap xpm;
1621 Picture pict;
1622 XRenderColor current_color;
1623 } tiles[WXR_NB_FORMATS], *tile;
1625 tile = &tiles[wxr_format];
1627 if(!tile->xpm)
1629 XRenderPictureAttributes pa;
1630 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1632 wine_tsx11_lock();
1633 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1635 pa.repeat = RepeatNormal;
1636 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1637 wine_tsx11_unlock();
1639 /* init current_color to something different from text_pixel */
1640 tile->current_color = *color;
1641 tile->current_color.red ^= 0xffff;
1643 if (wxr_format == WXR_FORMAT_MONO)
1645 /* for a 1bpp bitmap we always need a 1 in the tile */
1646 XRenderColor col;
1647 col.red = col.green = col.blue = 0;
1648 col.alpha = 0xffff;
1649 wine_tsx11_lock();
1650 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1651 wine_tsx11_unlock();
1655 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1657 wine_tsx11_lock();
1658 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1659 wine_tsx11_unlock();
1660 tile->current_color = *color;
1662 return tile->pict;
1665 /*************************************************************
1666 * get_mask_pict
1668 * Returns an appropriate Picture for masking with the specified alpha.
1669 * Call and use result within the xrender_cs
1671 static Picture get_mask_pict( int alpha )
1673 static Pixmap pixmap;
1674 static Picture pict;
1675 static int current_alpha;
1677 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1679 if (!pixmap)
1681 XRenderPictureAttributes pa;
1683 wine_tsx11_lock();
1684 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1685 pa.repeat = RepeatNormal;
1686 pict = pXRenderCreatePicture( gdi_display, pixmap,
1687 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1688 wine_tsx11_unlock();
1689 current_alpha = -1;
1692 if (alpha != current_alpha)
1694 XRenderColor col;
1695 col.red = col.green = col.blue = 0;
1696 col.alpha = current_alpha = alpha;
1697 wine_tsx11_lock();
1698 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1699 wine_tsx11_unlock();
1701 return pict;
1704 /***********************************************************************
1705 * xrenderdrv_ExtTextOut
1707 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1708 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1710 struct xrender_physdev *physdev = get_xrender_dev( dev );
1711 XGCValues xgcval;
1712 gsCacheEntry *entry;
1713 gsCacheEntryFormat *formatEntry;
1714 int textPixel, backgroundPixel;
1715 AA_Type aa_type = AA_None;
1716 unsigned int idx;
1717 Picture pict, tile_pict = 0;
1718 XGlyphElt16 *elts;
1719 POINT offset, desired, current;
1720 int render_op = PictOpOver;
1721 XRenderColor col;
1723 if (!X11DRV_XRender_Installed || !physdev->x11dev->has_gdi_font)
1725 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1726 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1729 xgcval.function = GXcopy;
1730 xgcval.background = physdev->x11dev->backgroundPixel;
1731 xgcval.fill_style = FillSolid;
1732 wine_tsx11_lock();
1733 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1734 wine_tsx11_unlock();
1736 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
1738 if(physdev->x11dev->depth == 1) {
1739 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1740 textPixel = 0;
1741 backgroundPixel = 1;
1742 } else {
1743 textPixel = 1;
1744 backgroundPixel = 0;
1746 } else {
1747 textPixel = physdev->x11dev->textPixel;
1748 backgroundPixel = physdev->x11dev->backgroundPixel;
1751 if(flags & ETO_OPAQUE)
1753 wine_tsx11_lock();
1754 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
1755 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
1756 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
1757 lprect->right - lprect->left, lprect->bottom - lprect->top );
1758 wine_tsx11_unlock();
1761 if(count == 0)
1763 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1764 return TRUE;
1767 EnterCriticalSection(&xrender_cs);
1769 entry = glyphsetCache + physdev->cache_index;
1770 aa_type = entry->aa_default;
1771 formatEntry = entry->format[aa_type];
1773 for(idx = 0; idx < count; idx++) {
1774 if( !formatEntry ) {
1775 UploadGlyph(physdev, wstr[idx], aa_type);
1776 /* re-evaluate antialias since aa_default may have changed */
1777 aa_type = entry->aa_default;
1778 formatEntry = entry->format[aa_type];
1779 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1780 UploadGlyph(physdev, wstr[idx], aa_type);
1783 if (!formatEntry)
1785 WARN("could not upload requested glyphs\n");
1786 LeaveCriticalSection(&xrender_cs);
1787 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1788 return FALSE;
1791 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1792 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1794 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1795 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1797 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1798 So we pass zeros to the function and move to our starting position using the first
1799 element of the elts array. */
1801 desired.x = physdev->x11dev->dc_rect.left + x;
1802 desired.y = physdev->x11dev->dc_rect.top + y;
1803 offset.x = offset.y = 0;
1804 current.x = current.y = 0;
1806 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
1807 tile_pict = get_tile_pict(physdev->format, &col);
1809 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1811 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
1812 render_op = PictOpOutReverse; /* This gives us 'black' text */
1814 for(idx = 0; idx < count; idx++)
1816 elts[idx].glyphset = formatEntry->glyphset;
1817 elts[idx].chars = wstr + idx;
1818 elts[idx].nchars = 1;
1819 elts[idx].xOff = desired.x - current.x;
1820 elts[idx].yOff = desired.y - current.y;
1822 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1823 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1825 if(!lpDx)
1827 desired.x += formatEntry->gis[wstr[idx]].xOff;
1828 desired.y += formatEntry->gis[wstr[idx]].yOff;
1830 else
1832 if(flags & ETO_PDY)
1834 offset.x += lpDx[idx * 2];
1835 offset.y += lpDx[idx * 2 + 1];
1837 else
1838 offset.x += lpDx[idx];
1839 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1840 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1844 wine_tsx11_lock();
1845 /* Make sure we don't have any transforms set from a previous call */
1846 set_xrender_transformation(pict, 1, 1, 0, 0);
1847 pXRenderCompositeText16(gdi_display, render_op,
1848 tile_pict,
1849 pict,
1850 formatEntry->font_format,
1851 0, 0, 0, 0, elts, count);
1852 wine_tsx11_unlock();
1853 HeapFree(GetProcessHeap(), 0, elts);
1855 LeaveCriticalSection(&xrender_cs);
1856 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1857 return TRUE;
1860 /* multiply the alpha channel of a picture */
1861 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1862 int x, int y, int width, int height )
1864 XRenderPictureAttributes pa;
1865 Pixmap src_pixmap, mask_pixmap;
1866 Picture src_pict, mask_pict;
1867 XRenderColor color;
1869 wine_tsx11_lock();
1870 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1871 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1872 pa.repeat = RepeatNormal;
1873 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1874 pa.component_alpha = True;
1875 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1876 color.red = color.green = color.blue = color.alpha = 0xffff;
1877 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1878 color.alpha = alpha;
1879 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1880 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1881 0, 0, 0, 0, x, y, width, height );
1882 pXRenderFreePicture( gdi_display, src_pict );
1883 pXRenderFreePicture( gdi_display, mask_pict );
1884 XFreePixmap( gdi_display, src_pixmap );
1885 XFreePixmap( gdi_display, mask_pixmap );
1886 wine_tsx11_unlock();
1889 /* Helper function for (stretched) blitting using xrender */
1890 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1891 int x_src, int y_src, int x_dst, int y_dst,
1892 double xscale, double yscale, int width, int height )
1894 int x_offset, y_offset;
1896 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1897 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1898 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1899 wine_tsx11_lock();
1900 if(xscale != 1.0 || yscale != 1.0)
1902 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1903 * in the wrong quadrant of the x-y plane.
1905 x_offset = (xscale < 0) ? -width : 0;
1906 y_offset = (yscale < 0) ? -height : 0;
1907 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1909 else
1911 x_offset = x_src;
1912 y_offset = y_src;
1913 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1915 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1916 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
1917 wine_tsx11_unlock();
1920 /* Helper function for (stretched) mono->color blitting using xrender */
1921 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1922 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1923 int x_src, int y_src, int x_dst, int y_dst,
1924 double xscale, double yscale, int width, int height )
1926 Picture tile_pict;
1927 int x_offset, y_offset;
1928 XRenderColor color;
1930 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1931 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1932 * the tile data.
1934 EnterCriticalSection( &xrender_cs );
1935 color = *bg;
1936 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1937 tile_pict = get_tile_pict( dst_format, &color );
1939 wine_tsx11_lock();
1940 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
1942 if (xscale != 1.0 || yscale != 1.0)
1944 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1945 * in the wrong quadrant of the x-y plane.
1947 x_offset = (xscale < 0) ? -width : 0;
1948 y_offset = (yscale < 0) ? -height : 0;
1949 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1951 else
1953 x_offset = x_src;
1954 y_offset = y_src;
1955 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1957 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1958 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
1959 wine_tsx11_unlock();
1960 LeaveCriticalSection( &xrender_cs );
1962 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1963 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1964 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
1967 /* create a pixmap and render picture for an image */
1968 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1969 struct bitblt_coords *src, enum wxr_format format,
1970 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1972 DWORD ret;
1973 int width = src->visrect.right - src->visrect.left;
1974 int height = src->visrect.bottom - src->visrect.top;
1975 int depth = pict_formats[format]->depth;
1976 struct gdi_image_bits dst_bits;
1977 XRenderPictureAttributes pa;
1978 XImage *image;
1980 wine_tsx11_lock();
1981 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1982 info->bmiHeader.biWidth, height, 32, 0 );
1983 wine_tsx11_unlock();
1984 if (!image) return ERROR_OUTOFMEMORY;
1986 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1987 if (ret) return ret;
1989 image->data = dst_bits.ptr;
1990 /* hack: make sure the bits are readable if we are reading from a DIB section */
1991 /* to be removed once we get rid of DIB access protections */
1992 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
1994 *use_repeat = (width == 1 && height == 1);
1995 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1997 wine_tsx11_lock();
1998 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1999 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2000 src->visrect.left, 0, 0, 0, width, height );
2001 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2002 wine_tsx11_unlock();
2004 /* make coordinates relative to the pixmap */
2005 src->x -= src->visrect.left;
2006 src->y -= src->visrect.top;
2007 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2009 image->data = NULL;
2010 wine_tsx11_lock();
2011 XDestroyImage( image );
2012 wine_tsx11_unlock();
2013 if (dst_bits.free) dst_bits.free( &dst_bits );
2014 return ret;
2017 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2018 Drawable drawable, const struct bitblt_coords *src,
2019 const struct bitblt_coords *dst )
2021 int width = abs( dst->width );
2022 int height = abs( dst->height );
2023 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2024 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2025 int x_dst, y_dst;
2026 Picture src_pict = 0, dst_pict, mask_pict = 0;
2027 BOOL use_repeat;
2028 double xscale, yscale;
2030 use_repeat = use_source_repeat( physdev_src );
2031 if (!use_repeat)
2033 xscale = src->width / (double)dst->width;
2034 yscale = src->height / (double)dst->height;
2036 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2038 if (drawable) /* using an intermediate pixmap */
2040 XRenderPictureAttributes pa;
2042 x_dst = dst->x;
2043 y_dst = dst->y;
2044 pa.repeat = RepeatNone;
2045 wine_tsx11_lock();
2046 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2047 wine_tsx11_unlock();
2049 else
2051 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2052 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2053 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2056 if (src->width < 0) x_src += src->width + 1;
2057 if (src->height < 0) y_src += src->height + 1;
2058 if (dst->width < 0) x_dst += dst->width + 1;
2059 if (dst->height < 0) y_dst += dst->height + 1;
2061 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2063 /* mono -> color */
2064 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2066 XRenderColor fg, bg;
2068 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, &fg );
2069 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, &bg );
2070 fg.alpha = bg.alpha = 0;
2072 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2073 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2075 else /* color -> color (can be at different depths) or mono -> mono */
2077 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2078 mask_pict = get_no_alpha_mask();
2080 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2081 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2084 if (drawable)
2086 wine_tsx11_lock();
2087 pXRenderFreePicture( gdi_display, dst_pict );
2088 wine_tsx11_unlock();
2093 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2094 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2095 Drawable drawable, struct bitblt_coords *src,
2096 struct bitblt_coords *dst, BOOL use_repeat )
2098 int x_src, y_src, x_dst, y_dst;
2099 Picture dst_pict;
2100 XRenderPictureAttributes pa;
2101 double xscale, yscale;
2103 if (drawable) /* using an intermediate pixmap */
2105 RGNDATA *clip_data = NULL;
2107 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2108 x_dst = dst->x;
2109 y_dst = dst->y;
2110 pa.repeat = RepeatNone;
2111 wine_tsx11_lock();
2112 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2113 if (clip_data)
2114 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2115 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2116 wine_tsx11_unlock();
2117 HeapFree( GetProcessHeap(), 0, clip_data );
2119 else
2121 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2122 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2123 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2126 if (!use_repeat)
2128 xscale = src->width / (double)dst->width;
2129 yscale = src->height / (double)dst->height;
2131 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2133 x_src = src->x;
2134 y_src = src->y;
2135 if (src->width < 0) x_src += src->width + 1;
2136 if (src->height < 0) y_src += src->height + 1;
2137 if (dst->width < 0) x_dst += dst->width + 1;
2138 if (dst->height < 0) y_dst += dst->height + 1;
2140 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2141 xscale, yscale, abs( dst->width ), abs( dst->height ));
2143 if (drawable)
2145 wine_tsx11_lock();
2146 pXRenderFreePicture( gdi_display, dst_pict );
2147 wine_tsx11_unlock();
2152 /***********************************************************************
2153 * xrenderdrv_StretchBlt
2155 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2156 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2158 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2159 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2160 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2162 if (src_dev->funcs != dst_dev->funcs)
2164 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2165 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2168 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2170 /* XRender is of no use for color -> mono */
2171 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2172 goto x11drv_fallback;
2174 /* if not stretching, we only need to handle format conversion */
2175 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2177 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2178 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2180 if (rop != SRCCOPY)
2182 GC tmpGC;
2183 Pixmap tmp_pixmap;
2184 struct bitblt_coords tmp;
2186 /* make coordinates relative to tmp pixmap */
2187 tmp = *dst;
2188 tmp.x -= tmp.visrect.left;
2189 tmp.y -= tmp.visrect.top;
2190 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2192 wine_tsx11_lock();
2193 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2194 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2195 XSetGraphicsExposures( gdi_display, tmpGC, False );
2196 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2197 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2198 wine_tsx11_unlock();
2200 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2201 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2203 wine_tsx11_lock();
2204 XFreePixmap( gdi_display, tmp_pixmap );
2205 XFreeGC( gdi_display, tmpGC );
2206 wine_tsx11_unlock();
2208 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2210 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2211 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2212 return TRUE;
2214 x11drv_fallback:
2215 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2219 /***********************************************************************
2220 * xrenderdrv_PutImage
2222 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2223 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2224 struct bitblt_coords *dst, DWORD rop )
2226 struct xrender_physdev *physdev;
2227 X_PHYSBITMAP *bitmap;
2228 DWORD ret;
2229 Pixmap tmp_pixmap;
2230 GC gc;
2231 enum wxr_format src_format, dst_format;
2232 XRenderPictFormat *pict_format;
2233 Pixmap src_pixmap;
2234 Picture src_pict, mask_pict = 0;
2235 BOOL use_repeat;
2237 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2239 if (hbitmap)
2241 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2242 physdev = NULL;
2243 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2245 else
2247 physdev = get_xrender_dev( dev );
2248 bitmap = NULL;
2249 dst_format = physdev->format;
2252 src_format = get_xrender_format_from_bitmapinfo( info );
2253 if (!(pict_format = pict_formats[src_format])) goto update_format;
2255 /* make sure we can create an image with the same bpp */
2256 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2257 goto update_format;
2259 /* mono <-> color conversions not supported */
2260 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2261 goto x11drv_fallback;
2263 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2265 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2267 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2268 if (!ret)
2270 struct bitblt_coords tmp;
2272 if (bitmap)
2274 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2275 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2277 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2279 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2280 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2282 X11DRV_DIB_Unlock( bitmap, TRUE );
2283 DeleteObject( rgn );
2285 else
2287 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2289 if (rop != SRCCOPY)
2291 RGNDATA *clip_data = NULL;
2293 /* make coordinates relative to tmp pixmap */
2294 tmp = *dst;
2295 tmp.x -= tmp.visrect.left;
2296 tmp.y -= tmp.visrect.top;
2297 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2299 if (clip) clip_data = add_extra_clipping_region( physdev->x11dev, clip );
2301 wine_tsx11_lock();
2302 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2303 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2304 XSetGraphicsExposures( gdi_display, gc, False );
2305 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2306 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2307 wine_tsx11_unlock();
2309 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2310 NULL, tmp_pixmap, src, &tmp, use_repeat );
2311 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2313 wine_tsx11_lock();
2314 XFreePixmap( gdi_display, tmp_pixmap );
2315 XFreeGC( gdi_display, gc );
2316 wine_tsx11_unlock();
2318 restore_clipping_region( physdev->x11dev, clip_data );
2320 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2321 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2323 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2326 wine_tsx11_lock();
2327 pXRenderFreePicture( gdi_display, src_pict );
2328 XFreePixmap( gdi_display, src_pixmap );
2329 wine_tsx11_unlock();
2331 return ret;
2333 update_format:
2334 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2335 set_color_info( pict_formats[dst_format], info );
2336 return ERROR_BAD_FORMAT;
2338 x11drv_fallback:
2339 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2340 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2341 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2345 /***********************************************************************
2346 * xrenderdrv_BlendImage
2348 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2349 struct bitblt_coords *src, struct bitblt_coords *dst,
2350 BLENDFUNCTION func )
2352 struct xrender_physdev *physdev = get_xrender_dev( dev );
2353 DWORD ret;
2354 enum wxr_format format;
2355 XRenderPictFormat *pict_format;
2356 Picture dst_pict, src_pict, mask_pict;
2357 Pixmap src_pixmap;
2358 BOOL use_repeat;
2360 if (!X11DRV_XRender_Installed)
2362 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2363 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2366 format = get_xrender_format_from_bitmapinfo( info );
2367 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2368 format = get_format_without_alpha( format );
2369 else if (format != WXR_FORMAT_A8R8G8B8)
2370 return ERROR_INVALID_PARAMETER;
2372 if (!(pict_format = pict_formats[format])) goto update_format;
2374 /* make sure we can create an image with the same bpp */
2375 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2376 goto update_format;
2378 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2379 goto update_format;
2381 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2383 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2384 if (!ret)
2386 double xscale, yscale;
2388 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2390 if (!use_repeat)
2392 xscale = src->width / (double)dst->width;
2393 yscale = src->height / (double)dst->height;
2395 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2397 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2399 EnterCriticalSection( &xrender_cs );
2400 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2402 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2403 physdev->x11dev->dc_rect.left + dst->x,
2404 physdev->x11dev->dc_rect.top + dst->y,
2405 xscale, yscale, dst->width, dst->height );
2407 wine_tsx11_lock();
2408 pXRenderFreePicture( gdi_display, src_pict );
2409 XFreePixmap( gdi_display, src_pixmap );
2410 wine_tsx11_unlock();
2412 LeaveCriticalSection( &xrender_cs );
2414 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2416 return ret;
2418 update_format:
2419 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2420 set_color_info( physdev->pict_format, info );
2421 return ERROR_BAD_FORMAT;
2425 /***********************************************************************
2426 * xrenderdrv_AlphaBlend
2428 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2429 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2431 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2432 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2433 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2434 XRenderPictureAttributes pa;
2435 Pixmap tmp_pixmap = 0;
2436 double xscale, yscale;
2437 BOOL use_repeat;
2439 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2441 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2442 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2445 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2447 SetLastError( ERROR_INVALID_PARAMETER );
2448 return FALSE;
2451 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2452 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2454 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2456 use_repeat = use_source_repeat( physdev_src );
2457 if (!use_repeat)
2459 xscale = src->width / (double)dst->width;
2460 yscale = src->height / (double)dst->height;
2462 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2464 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2466 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2468 /* mono -> color blending needs an intermediate color pixmap */
2469 XRenderColor fg, bg;
2470 int width = src->visrect.right - src->visrect.left;
2471 int height = src->visrect.bottom - src->visrect.top;
2473 /* blending doesn't use the destination DC colors */
2474 fg.red = fg.green = fg.blue = 0;
2475 bg.red = bg.green = bg.blue = 0xffff;
2476 fg.alpha = bg.alpha = 0xffff;
2478 wine_tsx11_lock();
2479 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2480 physdev_dst->pict_format->depth );
2481 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2482 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2483 CPRepeat, &pa );
2484 wine_tsx11_unlock();
2486 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2487 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2489 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2491 /* we need a source picture with no alpha */
2492 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2493 if (format != physdev_src->format)
2495 wine_tsx11_lock();
2496 pa.subwindow_mode = IncludeInferiors;
2497 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2498 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2499 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2500 wine_tsx11_unlock();
2504 if (tmp_pict) src_pict = tmp_pict;
2506 EnterCriticalSection( &xrender_cs );
2507 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2509 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2510 physdev_src->x11dev->dc_rect.left + src->x,
2511 physdev_src->x11dev->dc_rect.top + src->y,
2512 physdev_dst->x11dev->dc_rect.left + dst->x,
2513 physdev_dst->x11dev->dc_rect.top + dst->y,
2514 xscale, yscale, dst->width, dst->height );
2516 wine_tsx11_lock();
2517 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2518 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2519 wine_tsx11_unlock();
2521 LeaveCriticalSection( &xrender_cs );
2522 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2523 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2524 return TRUE;
2527 /***********************************************************************
2528 * xrenderdrv_GradientFill
2530 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2531 void * grad_array, ULONG ngrad, ULONG mode )
2533 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2534 static const XFixed stops[2] = { 0, 1 << 16 };
2535 struct xrender_physdev *physdev = get_xrender_dev( dev );
2536 XLinearGradient gradient;
2537 XRenderColor colors[2];
2538 Picture src_pict, dst_pict;
2539 unsigned int i;
2540 const GRADIENT_RECT *rect = grad_array;
2541 POINT pt[2];
2543 if (!X11DRV_XRender_Installed) goto fallback;
2544 if (!pXRenderCreateLinearGradient) goto fallback;
2546 /* <= 16-bpp uses dithering */
2547 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2549 switch (mode)
2551 case GRADIENT_FILL_RECT_H:
2552 case GRADIENT_FILL_RECT_V:
2553 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2554 for (i = 0; i < ngrad; i++, rect++)
2556 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2557 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2559 colors[0].red = v1->Red * 257 / 256;
2560 colors[0].green = v1->Green * 257 / 256;
2561 colors[0].blue = v1->Blue * 257 / 256;
2562 colors[1].red = v2->Red * 257 / 256;
2563 colors[1].green = v2->Green * 257 / 256;
2564 colors[1].blue = v2->Blue * 257 / 256;
2565 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2566 colors[0].alpha = colors[1].alpha = 65535;
2568 pt[0].x = v1->x;
2569 pt[0].y = v1->y;
2570 pt[1].x = v2->x;
2571 pt[1].y = v2->y;
2572 LPtoDP( dev->hdc, pt, 2 );
2573 if (mode == GRADIENT_FILL_RECT_H)
2575 gradient.p1.y = gradient.p2.y = 0;
2576 if (pt[1].x > pt[0].x)
2578 gradient.p1.x = 0;
2579 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2581 else
2583 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2584 gradient.p2.x = 0;
2587 else
2589 gradient.p1.x = gradient.p2.x = 0;
2590 if (pt[1].y > pt[0].y)
2592 gradient.p1.y = 0;
2593 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2595 else
2597 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2598 gradient.p2.y = 0;
2602 TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2603 mode, pt[0].x, pt[0].y, pt[1].x, pt[1].y,
2604 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2605 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2607 wine_tsx11_lock();
2608 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2609 dst_pict = get_xrender_picture( physdev, 0, NULL );
2610 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0,
2611 physdev->x11dev->dc_rect.left + min( pt[0].x, pt[1].x ),
2612 physdev->x11dev->dc_rect.top + min( pt[0].y, pt[1].y ),
2613 1, 1, abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y) );
2614 pXRenderFreePicture( gdi_display, src_pict );
2615 wine_tsx11_unlock();
2617 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2618 return TRUE;
2621 fallback:
2622 #endif
2623 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2624 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2627 /***********************************************************************
2628 * xrenderdrv_SelectBrush
2630 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, HBITMAP bitmap,
2631 const BITMAPINFO *info, void *bits, UINT usage )
2633 struct xrender_physdev *physdev = get_xrender_dev( dev );
2634 X_PHYSBITMAP *physbitmap;
2635 enum wxr_format format;
2636 BOOL delete_bitmap = FALSE;
2637 BITMAP bm;
2638 Pixmap pixmap;
2639 Picture src_pict, dst_pict;
2640 XRenderPictureAttributes pa;
2642 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2643 if (!bitmap && !info) goto x11drv_fallback;
2644 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2646 if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2648 if (!(bitmap = create_brush_bitmap( physdev->x11dev, info, bits, usage ))) return 0;
2649 physbitmap = X11DRV_get_phys_bitmap( bitmap );
2650 delete_bitmap = TRUE;
2653 format = get_xrender_format_from_color_shifts( physbitmap->depth, &physbitmap->color_shifts );
2654 if (format == WXR_FORMAT_MONO || !pict_formats[format]) goto x11drv_fallback;
2656 GetObjectW( bitmap, sizeof(bm), &bm );
2658 X11DRV_DIB_Lock( physbitmap, DIB_Status_GdiMod );
2660 wine_tsx11_lock();
2661 pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
2662 physdev->pict_format->depth );
2664 pa.repeat = RepeatNone;
2665 src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_formats[format], CPRepeat, &pa);
2666 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
2668 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, bm.bmWidth, bm.bmHeight );
2669 pXRenderFreePicture( gdi_display, src_pict );
2670 pXRenderFreePicture( gdi_display, dst_pict );
2672 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2673 physdev->x11dev->brush.pixmap = pixmap;
2674 physdev->x11dev->brush.fillStyle = FillTiled;
2675 physdev->x11dev->brush.pixel = 0; /* ignored */
2676 wine_tsx11_unlock();
2678 X11DRV_DIB_Unlock( physbitmap, TRUE );
2679 if (delete_bitmap) DeleteObject( bitmap );
2680 return hbrush;
2682 x11drv_fallback:
2683 if (delete_bitmap) DeleteObject( bitmap );
2684 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2685 return dev->funcs->pSelectBrush( dev, hbrush, bitmap, info, bits, usage );
2689 static const struct gdi_dc_funcs xrender_funcs =
2691 NULL, /* pAbortDoc */
2692 NULL, /* pAbortPath */
2693 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2694 NULL, /* pAngleArc */
2695 NULL, /* pArc */
2696 NULL, /* pArcTo */
2697 NULL, /* pBeginPath */
2698 xrenderdrv_BlendImage, /* pBlendImage */
2699 NULL, /* pChoosePixelFormat */
2700 NULL, /* pChord */
2701 NULL, /* pCloseFigure */
2702 xrenderdrv_CopyBitmap, /* pCopyBitmap */
2703 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2704 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2705 xrenderdrv_CreateDC, /* pCreateDC */
2706 NULL, /* pCreateDIBSection */
2707 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
2708 xrenderdrv_DeleteDC, /* pDeleteDC */
2709 NULL, /* pDeleteObject */
2710 NULL, /* pDescribePixelFormat */
2711 NULL, /* pDeviceCapabilities */
2712 NULL, /* pEllipse */
2713 NULL, /* pEndDoc */
2714 NULL, /* pEndPage */
2715 NULL, /* pEndPath */
2716 NULL, /* pEnumFonts */
2717 NULL, /* pEnumICMProfiles */
2718 NULL, /* pExcludeClipRect */
2719 NULL, /* pExtDeviceMode */
2720 xrenderdrv_ExtEscape, /* pExtEscape */
2721 NULL, /* pExtFloodFill */
2722 NULL, /* pExtSelectClipRgn */
2723 xrenderdrv_ExtTextOut, /* pExtTextOut */
2724 NULL, /* pFillPath */
2725 NULL, /* pFillRgn */
2726 NULL, /* pFlattenPath */
2727 NULL, /* pFontIsLinked */
2728 NULL, /* pFrameRgn */
2729 NULL, /* pGdiComment */
2730 NULL, /* pGdiRealizationInfo */
2731 NULL, /* pGetCharABCWidths */
2732 NULL, /* pGetCharABCWidthsI */
2733 NULL, /* pGetCharWidth */
2734 NULL, /* pGetDeviceCaps */
2735 NULL, /* pGetDeviceGammaRamp */
2736 NULL, /* pGetFontData */
2737 NULL, /* pGetFontUnicodeRanges */
2738 NULL, /* pGetGlyphIndices */
2739 NULL, /* pGetGlyphOutline */
2740 NULL, /* pGetICMProfile */
2741 xrenderdrv_GetImage, /* pGetImage */
2742 NULL, /* pGetKerningPairs */
2743 NULL, /* pGetNearestColor */
2744 NULL, /* pGetOutlineTextMetrics */
2745 NULL, /* pGetPixel */
2746 NULL, /* pGetPixelFormat */
2747 NULL, /* pGetSystemPaletteEntries */
2748 NULL, /* pGetTextCharsetInfo */
2749 NULL, /* pGetTextExtentExPoint */
2750 NULL, /* pGetTextExtentExPointI */
2751 NULL, /* pGetTextFace */
2752 NULL, /* pGetTextMetrics */
2753 xrenderdrv_GradientFill, /* pGradientFill */
2754 NULL, /* pIntersectClipRect */
2755 NULL, /* pInvertRgn */
2756 NULL, /* pLineTo */
2757 NULL, /* pModifyWorldTransform */
2758 NULL, /* pMoveTo */
2759 NULL, /* pOffsetClipRgn */
2760 NULL, /* pOffsetViewportOrg */
2761 NULL, /* pOffsetWindowOrg */
2762 NULL, /* pPaintRgn */
2763 NULL, /* pPatBlt */
2764 NULL, /* pPie */
2765 NULL, /* pPolyBezier */
2766 NULL, /* pPolyBezierTo */
2767 NULL, /* pPolyDraw */
2768 NULL, /* pPolyPolygon */
2769 NULL, /* pPolyPolyline */
2770 NULL, /* pPolygon */
2771 NULL, /* pPolyline */
2772 NULL, /* pPolylineTo */
2773 xrenderdrv_PutImage, /* pPutImage */
2774 NULL, /* pRealizeDefaultPalette */
2775 NULL, /* pRealizePalette */
2776 NULL, /* pRectangle */
2777 NULL, /* pResetDC */
2778 NULL, /* pRestoreDC */
2779 NULL, /* pRoundRect */
2780 NULL, /* pSaveDC */
2781 NULL, /* pScaleViewportExt */
2782 NULL, /* pScaleWindowExt */
2783 xrenderdrv_SelectBitmap, /* pSelectBitmap */
2784 xrenderdrv_SelectBrush, /* pSelectBrush */
2785 NULL, /* pSelectClipPath */
2786 xrenderdrv_SelectFont, /* pSelectFont */
2787 NULL, /* pSelectPalette */
2788 NULL, /* pSelectPen */
2789 NULL, /* pSetArcDirection */
2790 NULL, /* pSetBkColor */
2791 NULL, /* pSetBkMode */
2792 NULL, /* pSetDCBrushColor */
2793 NULL, /* pSetDCPenColor */
2794 NULL, /* pSetDIBColorTable */
2795 NULL, /* pSetDIBitsToDevice */
2796 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2797 NULL, /* pSetDeviceGammaRamp */
2798 NULL, /* pSetLayout */
2799 NULL, /* pSetMapMode */
2800 NULL, /* pSetMapperFlags */
2801 NULL, /* pSetPixel */
2802 NULL, /* pSetPixelFormat */
2803 NULL, /* pSetPolyFillMode */
2804 NULL, /* pSetROP2 */
2805 NULL, /* pSetRelAbs */
2806 NULL, /* pSetStretchBltMode */
2807 NULL, /* pSetTextAlign */
2808 NULL, /* pSetTextCharacterExtra */
2809 NULL, /* pSetTextColor */
2810 NULL, /* pSetTextJustification */
2811 NULL, /* pSetViewportExt */
2812 NULL, /* pSetViewportOrg */
2813 NULL, /* pSetWindowExt */
2814 NULL, /* pSetWindowOrg */
2815 NULL, /* pSetWorldTransform */
2816 NULL, /* pStartDoc */
2817 NULL, /* pStartPage */
2818 xrenderdrv_StretchBlt, /* pStretchBlt */
2819 NULL, /* pStretchDIBits */
2820 NULL, /* pStrokeAndFillPath */
2821 NULL, /* pStrokePath */
2822 NULL, /* pSwapBuffers */
2823 NULL, /* pUnrealizePalette */
2824 NULL, /* pWidenPath */
2825 /* OpenGL not supported */
2828 #else /* SONAME_LIBXRENDER */
2830 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2832 TRACE("XRender support not compiled in.\n");
2833 return NULL;
2836 void X11DRV_XRender_Finalize(void)
2840 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2842 return FALSE;
2845 #endif /* SONAME_LIBXRENDER */