TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blobcefbd22e5ee6693593ffdc1f0bf45ca6b33296a1
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 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
43 #ifdef SONAME_LIBXRENDER
45 WINE_DECLARE_DEBUG_CHANNEL(winediag);
47 #include <X11/Xlib.h>
48 #include <X11/extensions/Xrender.h>
50 #ifndef RepeatNone /* added in 0.10 */
51 #define RepeatNone 0
52 #define RepeatNormal 1
53 #define RepeatPad 2
54 #define RepeatReflect 3
55 #endif
57 enum wxr_format
59 WXR_FORMAT_MONO,
60 WXR_FORMAT_GRAY,
61 WXR_FORMAT_X1R5G5B5,
62 WXR_FORMAT_X1B5G5R5,
63 WXR_FORMAT_R5G6B5,
64 WXR_FORMAT_B5G6R5,
65 WXR_FORMAT_R8G8B8,
66 WXR_FORMAT_B8G8R8,
67 WXR_FORMAT_A8R8G8B8,
68 WXR_FORMAT_B8G8R8A8,
69 WXR_FORMAT_X8R8G8B8,
70 WXR_FORMAT_B8G8R8X8,
71 WXR_NB_FORMATS,
72 WXR_INVALID_FORMAT = WXR_NB_FORMATS
75 typedef struct wine_xrender_format_template
77 unsigned int depth;
78 unsigned int alpha;
79 unsigned int alphaMask;
80 unsigned int red;
81 unsigned int redMask;
82 unsigned int green;
83 unsigned int greenMask;
84 unsigned int blue;
85 unsigned int blueMask;
86 } WineXRenderFormatTemplate;
88 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
90 /* Format depth alpha mask red mask green mask blue mask*/
91 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
92 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
93 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
94 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
95 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
96 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
97 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
98 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
99 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
101 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
105 static enum wxr_format default_format = WXR_INVALID_FORMAT;
106 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
108 typedef struct
110 LOGFONTW lf;
111 XFORM xform;
112 SIZE devsize; /* size in device coords */
113 DWORD hash;
114 } LFANDSIZE;
116 #define INITIAL_REALIZED_BUF_SIZE 128
118 enum glyph_type { GLYPH_INDEX, GLYPH_WCHAR, GLYPH_NBTYPES };
120 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
122 typedef struct
124 GlyphSet glyphset;
125 XRenderPictFormat *font_format;
126 int nrealized;
127 BOOL *realized;
128 XGlyphInfo *gis;
129 } gsCacheEntryFormat;
131 typedef struct
133 LFANDSIZE lfsz;
134 gsCacheEntryFormat *format[GLYPH_NBTYPES][AA_MAXVALUE];
135 INT count;
136 INT next;
137 } gsCacheEntry;
139 struct xrender_physdev
141 struct gdi_physdev dev;
142 X11DRV_PDEVICE *x11dev;
143 HRGN region;
144 enum wxr_format format;
145 UINT aa_flags;
146 int cache_index;
147 BOOL update_clip;
148 Picture pict;
149 Picture pict_src;
150 XRenderPictFormat *pict_format;
153 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
155 return (struct xrender_physdev *)dev;
158 static const struct gdi_dc_funcs xrender_funcs;
160 static gsCacheEntry *glyphsetCache = NULL;
161 static DWORD glyphsetCacheSize = 0;
162 static INT lastfree = -1;
163 static INT mru = -1;
165 #define INIT_CACHE_SIZE 10
167 static void *xrender_handle;
169 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
170 MAKE_FUNCPTR(XRenderAddGlyphs)
171 MAKE_FUNCPTR(XRenderChangePicture)
172 MAKE_FUNCPTR(XRenderComposite)
173 MAKE_FUNCPTR(XRenderCompositeText16)
174 MAKE_FUNCPTR(XRenderCreateGlyphSet)
175 MAKE_FUNCPTR(XRenderCreatePicture)
176 MAKE_FUNCPTR(XRenderFillRectangle)
177 MAKE_FUNCPTR(XRenderFindFormat)
178 MAKE_FUNCPTR(XRenderFindVisualFormat)
179 MAKE_FUNCPTR(XRenderFreeGlyphSet)
180 MAKE_FUNCPTR(XRenderFreePicture)
181 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
182 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
183 MAKE_FUNCPTR(XRenderCreateLinearGradient)
184 #endif
185 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
186 MAKE_FUNCPTR(XRenderSetPictureTransform)
187 #endif
188 MAKE_FUNCPTR(XRenderQueryExtension)
190 #undef MAKE_FUNCPTR
192 static CRITICAL_SECTION xrender_cs;
193 static CRITICAL_SECTION_DEBUG critsect_debug =
195 0, 0, &xrender_cs,
196 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
197 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
199 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
201 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
202 ( ( (ULONG)_x4 << 24 ) | \
203 ( (ULONG)_x3 << 16 ) | \
204 ( (ULONG)_x2 << 8 ) | \
205 (ULONG)_x1 )
207 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
209 #define GASP_GRIDFIT 0x01
210 #define GASP_DOGRAY 0x02
212 #ifdef WORDS_BIGENDIAN
213 #define get_be_word(x) (x)
214 #define NATIVE_BYTE_ORDER MSBFirst
215 #else
216 #define get_be_word(x) RtlUshortByteSwap(x)
217 #define NATIVE_BYTE_ORDER LSBFirst
218 #endif
220 static BOOL has_alpha( enum wxr_format format )
222 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
225 static enum wxr_format get_format_without_alpha( enum wxr_format format )
227 switch (format)
229 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
230 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
231 default: return format;
235 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
237 templ->id = 0;
238 templ->type = PictTypeDirect;
239 templ->depth = fmt->depth;
240 templ->direct.alpha = fmt->alpha;
241 templ->direct.alphaMask = fmt->alphaMask;
242 templ->direct.red = fmt->red;
243 templ->direct.redMask = fmt->redMask;
244 templ->direct.green = fmt->green;
245 templ->direct.greenMask = fmt->greenMask;
246 templ->direct.blue = fmt->blue;
247 templ->direct.blueMask = fmt->blueMask;
248 templ->colormap = 0;
250 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
252 return TRUE;
255 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
257 if(fmt->depth != default_visual.depth) return FALSE;
258 if( (fmt->redMask << fmt->red) != default_visual.red_mask) return FALSE;
259 if( (fmt->greenMask << fmt->green) != default_visual.green_mask) return FALSE;
260 if( (fmt->blueMask << fmt->blue) != default_visual.blue_mask) return FALSE;
262 /* We never select a default ARGB visual */
263 if(fmt->alphaMask) return FALSE;
264 return TRUE;
267 static int load_xrender_formats(void)
269 int count = 0;
270 unsigned int i;
272 for (i = 0; i < WXR_NB_FORMATS; i++)
274 XRenderPictFormat templ;
276 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
278 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, default_visual.visual);
279 if (!pict_formats[i])
281 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
282 if (default_visual.class == DirectColor)
284 XVisualInfo info;
285 if (XMatchVisualInfo( gdi_display, default_visual.screen,
286 default_visual.depth, TrueColor, &info ))
288 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
289 if (pict_formats[i]) default_visual = info;
293 if (pict_formats[i]) default_format = i;
295 else
297 unsigned long mask = 0;
298 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
299 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
301 if (pict_formats[i])
303 count++;
304 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
307 return count;
310 /***********************************************************************
311 * X11DRV_XRender_Init
313 * Let's see if our XServer has the extension available
316 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
318 int event_base, i;
320 if (!client_side_with_render) return NULL;
321 if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
323 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
324 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
325 LOAD_FUNCPTR(XRenderAddGlyphs);
326 LOAD_FUNCPTR(XRenderChangePicture);
327 LOAD_FUNCPTR(XRenderComposite);
328 LOAD_FUNCPTR(XRenderCompositeText16);
329 LOAD_FUNCPTR(XRenderCreateGlyphSet);
330 LOAD_FUNCPTR(XRenderCreatePicture);
331 LOAD_FUNCPTR(XRenderFillRectangle);
332 LOAD_FUNCPTR(XRenderFindFormat);
333 LOAD_FUNCPTR(XRenderFindVisualFormat);
334 LOAD_FUNCPTR(XRenderFreeGlyphSet);
335 LOAD_FUNCPTR(XRenderFreePicture);
336 LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
337 LOAD_FUNCPTR(XRenderQueryExtension);
338 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
339 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
340 #endif
341 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
342 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
343 #endif
344 #undef LOAD_OPTIONAL_FUNCPTR
345 #undef LOAD_FUNCPTR
347 if (!pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) return NULL;
349 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
350 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
352 ERR_(winediag)("Wine has detected that you probably have a buggy version "
353 "of libXrender. Because of this client side font rendering "
354 "will be disabled. Please upgrade this library.\n");
355 return NULL;
358 if (!default_visual.red_mask || !default_visual.green_mask || !default_visual.blue_mask)
360 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
361 return NULL;
364 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
365 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
367 glyphsetCacheSize = INIT_CACHE_SIZE;
368 lastfree = 0;
369 for(i = 0; i < INIT_CACHE_SIZE; i++) {
370 glyphsetCache[i].next = i + 1;
371 glyphsetCache[i].count = -1;
373 glyphsetCache[i-1].next = -1;
375 return &xrender_funcs;
378 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
379 static void get_xrender_color( struct xrender_physdev *physdev, COLORREF src_color, XRenderColor *dst_color )
381 if (src_color & (1 << 24)) /* PALETTEINDEX */
383 HPALETTE pal = GetCurrentObject( physdev->dev.hdc, OBJ_PAL );
384 PALETTEENTRY pal_ent;
386 if (!GetPaletteEntries( pal, LOWORD(src_color), 1, &pal_ent ))
387 GetPaletteEntries( pal, 0, 1, &pal_ent );
388 dst_color->red = pal_ent.peRed * 257;
389 dst_color->green = pal_ent.peGreen * 257;
390 dst_color->blue = pal_ent.peBlue * 257;
392 else
394 if (src_color >> 16 == 0x10ff) src_color = 0; /* DIBINDEX */
396 dst_color->red = GetRValue( src_color ) * 257;
397 dst_color->green = GetGValue( src_color ) * 257;
398 dst_color->blue = GetBValue( src_color ) * 257;
401 if (physdev->format == WXR_FORMAT_MONO && !dst_color->red && !dst_color->green && !dst_color->blue)
402 dst_color->alpha = 0;
403 else
404 dst_color->alpha = 0xffff;
407 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
409 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
411 switch (info->bmiHeader.biBitCount)
413 case 1:
414 return WXR_FORMAT_MONO;
415 case 4:
416 case 8:
417 break;
418 case 24:
419 if (info->bmiHeader.biCompression != BI_RGB) break;
420 return WXR_FORMAT_R8G8B8;
421 case 16:
422 case 32:
423 if (info->bmiHeader.biCompression == BI_BITFIELDS)
425 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
426 unsigned int i;
428 for (i = 0; i < WXR_NB_FORMATS; i++)
430 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
431 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
432 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
433 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
434 return i;
436 break;
438 if (info->bmiHeader.biCompression != BI_RGB) break;
439 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
441 return WXR_INVALID_FORMAT;
444 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
445 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
447 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
448 XTransform xform = {{
449 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
450 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
451 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
454 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
455 #endif
458 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
460 XRenderPictureAttributes pa;
461 RGNDATA *data;
463 if (!rgn)
465 pa.clip_mask = None;
466 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
468 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
470 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
471 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
472 (XRectangle *)data->Buffer, data->rdh.nCount );
473 HeapFree( GetProcessHeap(), 0, data );
478 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
480 if (!dev->pict && dev->pict_format)
482 XRenderPictureAttributes pa;
484 pa.subwindow_mode = IncludeInferiors;
485 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
486 dev->pict_format, CPSubwindowMode, &pa );
487 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
488 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
489 dev->update_clip = (dev->region != 0);
492 if (clip_rect)
494 HRGN rgn = CreateRectRgnIndirect( clip_rect );
495 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
496 if (dev->region) CombineRgn( rgn, rgn, dev->region, RGN_AND );
497 update_xrender_clipping( dev, rgn );
498 DeleteObject( rgn );
500 else if (clip_rgn)
502 if (dev->region)
504 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
505 CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
506 update_xrender_clipping( dev, rgn );
507 DeleteObject( rgn );
509 else update_xrender_clipping( dev, clip_rgn );
511 else if (dev->update_clip) update_xrender_clipping( dev, dev->region );
513 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
514 return dev->pict;
517 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
519 if (!dev->pict_src && dev->pict_format)
521 XRenderPictureAttributes pa;
523 pa.subwindow_mode = IncludeInferiors;
524 pa.repeat = repeat ? RepeatNormal : RepeatNone;
525 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
526 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
528 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
529 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
532 return dev->pict_src;
535 static void free_xrender_picture( struct xrender_physdev *dev )
537 if (dev->pict || dev->pict_src)
539 XFlush( gdi_display );
540 if (dev->pict)
542 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
543 pXRenderFreePicture(gdi_display, dev->pict);
544 dev->pict = 0;
546 if(dev->pict_src)
548 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
549 pXRenderFreePicture(gdi_display, dev->pict_src);
550 dev->pict_src = 0;
555 /* return a mask picture used to force alpha to 0 */
556 static Picture get_no_alpha_mask(void)
558 static Pixmap pixmap;
559 static Picture pict;
561 EnterCriticalSection( &xrender_cs );
562 if (!pict)
564 XRenderPictureAttributes pa;
565 XRenderColor col;
567 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
568 pa.repeat = RepeatNormal;
569 pa.component_alpha = True;
570 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
571 CPRepeat|CPComponentAlpha, &pa );
572 col.red = col.green = col.blue = 0xffff;
573 col.alpha = 0;
574 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
576 LeaveCriticalSection( &xrender_cs );
577 return pict;
580 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
582 if(p1->hash != p2->hash) return TRUE;
583 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
584 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
585 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
586 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
589 static int LookupEntry(LFANDSIZE *plfsz)
591 int i, prev_i = -1;
593 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
594 TRACE("%d\n", i);
595 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
597 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
598 glyphsetCache[i].count++;
599 if(prev_i >= 0) {
600 glyphsetCache[prev_i].next = glyphsetCache[i].next;
601 glyphsetCache[i].next = mru;
602 mru = i;
604 TRACE("found font in cache %d\n", i);
605 return i;
607 prev_i = i;
609 TRACE("font not in cache\n");
610 return -1;
613 static void FreeEntry(int entry)
615 int type, format;
617 for (type = 0; type < GLYPH_NBTYPES; type++)
619 for(format = 0; format < AA_MAXVALUE; format++) {
620 gsCacheEntryFormat * formatEntry;
622 if( !glyphsetCache[entry].format[type][format] )
623 continue;
625 formatEntry = glyphsetCache[entry].format[type][format];
627 if(formatEntry->glyphset) {
628 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
629 formatEntry->glyphset = 0;
631 if(formatEntry->nrealized) {
632 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
633 formatEntry->realized = NULL;
634 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
635 formatEntry->gis = NULL;
636 formatEntry->nrealized = 0;
639 HeapFree(GetProcessHeap(), 0, formatEntry);
640 glyphsetCache[entry].format[type][format] = NULL;
645 static int AllocEntry(void)
647 int best = -1, prev_best = -1, i, prev_i = -1;
649 if(lastfree >= 0) {
650 assert(glyphsetCache[lastfree].count == -1);
651 glyphsetCache[lastfree].count = 1;
652 best = lastfree;
653 lastfree = glyphsetCache[lastfree].next;
654 assert(best != mru);
655 glyphsetCache[best].next = mru;
656 mru = best;
658 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
659 return mru;
662 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
663 if(glyphsetCache[i].count == 0) {
664 best = i;
665 prev_best = prev_i;
667 prev_i = i;
670 if(best >= 0) {
671 TRACE("freeing unused glyphset at cache %d\n", best);
672 FreeEntry(best);
673 glyphsetCache[best].count = 1;
674 if(prev_best >= 0) {
675 glyphsetCache[prev_best].next = glyphsetCache[best].next;
676 glyphsetCache[best].next = mru;
677 mru = best;
678 } else {
679 assert(mru == best);
681 return mru;
684 TRACE("Growing cache\n");
686 if (glyphsetCache)
687 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
688 glyphsetCache,
689 (glyphsetCacheSize + INIT_CACHE_SIZE)
690 * sizeof(*glyphsetCache));
691 else
692 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
693 (glyphsetCacheSize + INIT_CACHE_SIZE)
694 * sizeof(*glyphsetCache));
696 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
697 i++) {
698 glyphsetCache[i].next = i + 1;
699 glyphsetCache[i].count = -1;
701 glyphsetCache[i-1].next = -1;
702 glyphsetCacheSize += INIT_CACHE_SIZE;
704 lastfree = glyphsetCache[best].next;
705 glyphsetCache[best].count = 1;
706 glyphsetCache[best].next = mru;
707 mru = best;
708 TRACE("new free cache slot at %d\n", mru);
709 return mru;
712 static int GetCacheEntry( LFANDSIZE *plfsz )
714 int ret;
715 gsCacheEntry *entry;
717 if((ret = LookupEntry(plfsz)) != -1) return ret;
719 ret = AllocEntry();
720 entry = glyphsetCache + ret;
721 entry->lfsz = *plfsz;
722 return ret;
725 static void dec_ref_cache(int index)
727 assert(index >= 0);
728 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
729 assert(glyphsetCache[index].count > 0);
730 glyphsetCache[index].count--;
733 static void lfsz_calc_hash(LFANDSIZE *plfsz)
735 DWORD hash = 0, *ptr, two_chars;
736 WORD *pwc;
737 unsigned int i;
739 hash ^= plfsz->devsize.cx;
740 hash ^= plfsz->devsize.cy;
741 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
742 hash ^= *ptr;
743 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
744 hash ^= *ptr;
745 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
746 two_chars = *ptr;
747 pwc = (WCHAR *)&two_chars;
748 if(!*pwc) break;
749 *pwc = toupperW(*pwc);
750 pwc++;
751 *pwc = toupperW(*pwc);
752 hash ^= two_chars;
753 if(!*pwc) break;
755 plfsz->hash = hash;
756 return;
759 static AA_Type aa_type_from_flags( UINT aa_flags )
761 switch (aa_flags & 0x7f)
763 case GGO_BITMAP:
764 return AA_None;
765 case WINE_GGO_GRAY16_BITMAP:
766 return AA_Grey;
767 case WINE_GGO_HRGB_BITMAP:
768 return AA_RGB;
769 case WINE_GGO_HBGR_BITMAP:
770 return AA_BGR;
771 case WINE_GGO_VRGB_BITMAP:
772 return AA_VRGB;
773 case WINE_GGO_VBGR_BITMAP:
774 return AA_VBGR;
775 default:
776 FIXME( "unknown flags %x\n", aa_flags );
777 return AA_None;
781 static UINT get_xft_aa_flags( const LOGFONTW *lf )
783 char *value;
784 UINT ret = 0;
786 switch (lf->lfQuality)
788 case NONANTIALIASED_QUALITY:
789 case ANTIALIASED_QUALITY:
790 break;
791 default:
792 if (!(value = XGetDefault( gdi_display, "Xft", "antialias" ))) break;
793 TRACE( "got antialias '%s'\n", value );
794 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
795 value[0] == '0' || !strcasecmp( value, "off" ))
797 ret = GGO_BITMAP;
798 break;
800 ret = GGO_GRAY4_BITMAP;
801 /* fall through */
802 case CLEARTYPE_QUALITY:
803 case CLEARTYPE_NATURAL_QUALITY:
804 if (!(value = XGetDefault( gdi_display, "Xft", "rgba" ))) break;
805 TRACE( "got rgba '%s'\n", value );
806 if (!strcmp( value, "rgb" )) ret = WINE_GGO_HRGB_BITMAP;
807 else if (!strcmp( value, "bgr" )) ret = WINE_GGO_HBGR_BITMAP;
808 else if (!strcmp( value, "vrgb" )) ret = WINE_GGO_VRGB_BITMAP;
809 else if (!strcmp( value, "vbgr" )) ret = WINE_GGO_VBGR_BITMAP;
810 else if (!strcmp( value, "none" )) ret = GGO_GRAY4_BITMAP;
811 break;
813 return ret;
816 /**********************************************************************
817 * xrenderdrv_SelectFont
819 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
821 LFANDSIZE lfsz;
822 struct xrender_physdev *physdev = get_xrender_dev( dev );
823 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
824 HFONT ret;
826 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
827 if (!*aa_flags) *aa_flags = get_xft_aa_flags( &lfsz.lf );
829 ret = next->funcs->pSelectFont( next, hfont, aa_flags );
830 if (!ret) return 0;
832 switch (*aa_flags)
834 case GGO_GRAY2_BITMAP:
835 case GGO_GRAY4_BITMAP:
836 case GGO_GRAY8_BITMAP:
837 physdev->aa_flags = WINE_GGO_GRAY16_BITMAP;
838 break;
839 case 0:
840 physdev->aa_flags = GGO_BITMAP;
841 break;
842 default:
843 physdev->aa_flags = *aa_flags;
844 break;
847 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
848 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
849 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
850 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
851 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
852 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
854 GetTransform( dev->hdc, 0x204, &lfsz.xform );
855 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
856 lfsz.xform.eM21, lfsz.xform.eM22);
858 if (GetGraphicsMode( dev->hdc ) == GM_COMPATIBLE)
860 lfsz.lf.lfOrientation = lfsz.lf.lfEscapement;
861 if (lfsz.xform.eM11 * lfsz.xform.eM22 < 0)
862 lfsz.lf.lfOrientation = -lfsz.lf.lfOrientation;
865 /* Not used fields, would break hashing */
866 lfsz.xform.eDx = lfsz.xform.eDy = 0;
868 lfsz_calc_hash(&lfsz);
870 EnterCriticalSection(&xrender_cs);
871 if (physdev->cache_index != -1)
872 dec_ref_cache( physdev->cache_index );
873 physdev->cache_index = GetCacheEntry( &lfsz );
874 LeaveCriticalSection(&xrender_cs);
875 return ret;
878 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
880 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
881 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
883 if (!physdev) return FALSE;
884 physdev->x11dev = x11dev;
885 physdev->cache_index = -1;
886 physdev->format = format;
887 physdev->pict_format = pict_formats[format];
888 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
889 return TRUE;
892 /* store the color mask data in the bitmap info structure */
893 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
895 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
897 info->bmiHeader.biPlanes = 1;
898 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
899 info->bmiHeader.biCompression = BI_RGB;
900 info->bmiHeader.biClrUsed = 0;
902 switch (info->bmiHeader.biBitCount)
904 case 16:
905 colors[0] = format->direct.redMask << format->direct.red;
906 colors[1] = format->direct.greenMask << format->direct.green;
907 colors[2] = format->direct.blueMask << format->direct.blue;
908 info->bmiHeader.biCompression = BI_BITFIELDS;
909 break;
910 case 32:
911 colors[0] = format->direct.redMask << format->direct.red;
912 colors[1] = format->direct.greenMask << format->direct.green;
913 colors[2] = format->direct.blueMask << format->direct.blue;
914 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
915 info->bmiHeader.biCompression = BI_BITFIELDS;
916 break;
921 /**********************************************************************
922 * xrenderdrv_CreateDC
924 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
925 LPCWSTR output, const DEVMODEW* initData )
927 return create_xrender_dc( pdev, default_format );
930 /**********************************************************************
931 * xrenderdrv_CreateCompatibleDC
933 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
935 if (orig) /* chain to x11drv first */
937 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
938 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
940 /* otherwise we have been called by x11drv */
942 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
945 /**********************************************************************
946 * xrenderdrv_DeleteDC
948 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
950 struct xrender_physdev *physdev = get_xrender_dev( dev );
952 free_xrender_picture( physdev );
954 EnterCriticalSection( &xrender_cs );
955 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
956 LeaveCriticalSection( &xrender_cs );
958 HeapFree( GetProcessHeap(), 0, physdev );
959 return TRUE;
962 /**********************************************************************
963 * xrenderdrv_ExtEscape
965 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
966 INT out_count, LPVOID out_data )
968 struct xrender_physdev *physdev = get_xrender_dev( dev );
970 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
972 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
974 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
976 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
977 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
978 return ret;
981 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
984 /***********************************************************************
985 * xrenderdrv_SetDeviceClipping
987 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
989 struct xrender_physdev *physdev = get_xrender_dev( dev );
991 physdev->region = rgn;
992 physdev->update_clip = TRUE;
994 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
995 dev->funcs->pSetDeviceClipping( dev, rgn );
999 /************************************************************************
1000 * UploadGlyph
1002 * Helper to ExtTextOut. Must be called inside xrender_cs
1004 static void UploadGlyph(struct xrender_physdev *physDev, UINT glyph, enum glyph_type type)
1006 unsigned int buflen;
1007 char *buf;
1008 Glyph gid;
1009 GLYPHMETRICS gm;
1010 XGlyphInfo gi;
1011 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1012 gsCacheEntryFormat *formatEntry;
1013 UINT ggo_format = physDev->aa_flags;
1014 AA_Type format = aa_type_from_flags( physDev->aa_flags );
1015 enum wxr_format wxr_format;
1016 static const char zero[4];
1017 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1019 if (type == GLYPH_INDEX) ggo_format |= GGO_GLYPH_INDEX;
1020 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1021 if(buflen == GDI_ERROR) {
1022 if(format != AA_None) {
1023 format = AA_None;
1024 physDev->aa_flags = GGO_BITMAP;
1025 ggo_format = (ggo_format & GGO_GLYPH_INDEX) | GGO_BITMAP;
1026 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1028 if(buflen == GDI_ERROR) {
1029 WARN("GetGlyphOutlineW failed using default glyph\n");
1030 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1031 if(buflen == GDI_ERROR) {
1032 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1033 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1034 if(buflen == GDI_ERROR) {
1035 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1036 return;
1040 TRACE("Turning off antialiasing for this monochrome font\n");
1043 /* If there is nothing for the current type, we create the entry. */
1044 if( !entry->format[type][format] ) {
1045 entry->format[type][format] = HeapAlloc(GetProcessHeap(),
1046 HEAP_ZERO_MEMORY,
1047 sizeof(gsCacheEntryFormat));
1049 formatEntry = entry->format[type][format];
1051 if(formatEntry->nrealized <= glyph) {
1052 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1054 if (formatEntry->realized)
1055 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1056 HEAP_ZERO_MEMORY,
1057 formatEntry->realized,
1058 formatEntry->nrealized * sizeof(BOOL));
1059 else
1060 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1061 HEAP_ZERO_MEMORY,
1062 formatEntry->nrealized * sizeof(BOOL));
1064 if (formatEntry->gis)
1065 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1066 HEAP_ZERO_MEMORY,
1067 formatEntry->gis,
1068 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1069 else
1070 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1071 HEAP_ZERO_MEMORY,
1072 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1076 if(formatEntry->glyphset == 0) {
1077 switch(format) {
1078 case AA_Grey:
1079 wxr_format = WXR_FORMAT_GRAY;
1080 break;
1082 case AA_RGB:
1083 case AA_BGR:
1084 case AA_VRGB:
1085 case AA_VBGR:
1086 wxr_format = WXR_FORMAT_A8R8G8B8;
1087 break;
1089 default:
1090 ERR("aa = %d - not implemented\n", format);
1091 /* fall through */
1092 case AA_None:
1093 wxr_format = WXR_FORMAT_MONO;
1094 break;
1097 formatEntry->font_format = pict_formats[wxr_format];
1098 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1102 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1103 if (buflen)
1104 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1105 else
1106 gm.gmBlackBoxX = gm.gmBlackBoxY = 0; /* empty glyph */
1107 formatEntry->realized[glyph] = TRUE;
1109 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1110 buflen,
1111 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1112 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1114 gi.width = gm.gmBlackBoxX;
1115 gi.height = gm.gmBlackBoxY;
1116 gi.x = -gm.gmptGlyphOrigin.x;
1117 gi.y = gm.gmptGlyphOrigin.y;
1118 gi.xOff = gm.gmCellIncX;
1119 gi.yOff = gm.gmCellIncY;
1121 if(TRACE_ON(xrender)) {
1122 int pitch, i, j;
1123 char output[300];
1124 unsigned char *line;
1126 if(format == AA_None) {
1127 pitch = ((gi.width + 31) / 32) * 4;
1128 for(i = 0; i < gi.height; i++) {
1129 line = (unsigned char*) buf + i * pitch;
1130 output[0] = '\0';
1131 for(j = 0; j < pitch * 8; j++) {
1132 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1134 TRACE("%s\n", output);
1136 } else {
1137 static const char blks[] = " .:;!o*#";
1138 char str[2];
1140 str[1] = '\0';
1141 pitch = ((gi.width + 3) / 4) * 4;
1142 for(i = 0; i < gi.height; i++) {
1143 line = (unsigned char*) buf + i * pitch;
1144 output[0] = '\0';
1145 for(j = 0; j < pitch; j++) {
1146 str[0] = blks[line[j] >> 5];
1147 strcat(output, str);
1149 TRACE("%s\n", output);
1155 if(formatEntry->glyphset) {
1156 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1157 unsigned char *byte = (unsigned char*) buf, c;
1158 int i = buflen;
1160 while(i--) {
1161 c = *byte;
1163 /* magic to flip bit order */
1164 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1165 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1166 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1168 *byte++ = c;
1171 else if ( format != AA_Grey &&
1172 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1174 unsigned int i, *data = (unsigned int *)buf;
1175 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1177 gid = glyph;
1180 XRenderCompositeText seems to ignore 0x0 glyphs when
1181 AA_None, which means we lose the advance width of glyphs
1182 like the space. We'll pretend that such glyphs are 1x1
1183 bitmaps.
1186 if(buflen == 0)
1187 gi.width = gi.height = 1;
1189 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1190 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1193 HeapFree(GetProcessHeap(), 0, buf);
1194 formatEntry->gis[glyph] = gi;
1197 /*************************************************************
1198 * get_tile_pict
1200 * Returns an appropriate Picture for tiling the text colour.
1201 * Call and use result within the xrender_cs
1203 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1205 static struct
1207 Pixmap xpm;
1208 Picture pict;
1209 XRenderColor current_color;
1210 } tiles[WXR_NB_FORMATS], *tile;
1212 tile = &tiles[wxr_format];
1214 if(!tile->xpm)
1216 XRenderPictureAttributes pa;
1217 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1219 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1221 pa.repeat = RepeatNormal;
1222 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1224 /* init current_color to something different from text_pixel */
1225 tile->current_color = *color;
1226 tile->current_color.red ^= 0xffff;
1228 if (wxr_format == WXR_FORMAT_MONO)
1230 /* for a 1bpp bitmap we always need a 1 in the tile */
1231 XRenderColor col;
1232 col.red = col.green = col.blue = 0;
1233 col.alpha = 0xffff;
1234 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1238 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1240 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1241 tile->current_color = *color;
1243 return tile->pict;
1246 /*************************************************************
1247 * get_mask_pict
1249 * Returns an appropriate Picture for masking with the specified alpha.
1250 * Call and use result within the xrender_cs
1252 static Picture get_mask_pict( int alpha )
1254 static Pixmap pixmap;
1255 static Picture pict;
1256 static int current_alpha;
1258 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1260 if (!pixmap)
1262 XRenderPictureAttributes pa;
1264 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1265 pa.repeat = RepeatNormal;
1266 pict = pXRenderCreatePicture( gdi_display, pixmap,
1267 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1268 current_alpha = -1;
1271 if (alpha != current_alpha)
1273 XRenderColor col;
1274 col.red = col.green = col.blue = 0;
1275 col.alpha = current_alpha = alpha;
1276 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1278 return pict;
1281 /***********************************************************************
1282 * xrenderdrv_ExtTextOut
1284 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1285 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1287 struct xrender_physdev *physdev = get_xrender_dev( dev );
1288 gsCacheEntry *entry;
1289 gsCacheEntryFormat *formatEntry;
1290 unsigned int idx;
1291 Picture pict, tile_pict = 0;
1292 XGlyphElt16 *elts;
1293 POINT offset, desired, current;
1294 int render_op = PictOpOver;
1295 XRenderColor col;
1296 RECT rect, bounds;
1297 enum glyph_type type = (flags & ETO_GLYPH_INDEX) ? GLYPH_INDEX : GLYPH_WCHAR;
1299 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1300 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1302 if(flags & ETO_OPAQUE)
1304 XRenderColor bg;
1306 if (physdev->format == WXR_FORMAT_MONO)
1307 /* use the inverse of the text color */
1308 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1309 else
1310 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1312 set_xrender_transformation( pict, 1, 1, 0, 0 );
1313 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1314 physdev->x11dev->dc_rect.left + lprect->left,
1315 physdev->x11dev->dc_rect.top + lprect->top,
1316 lprect->right - lprect->left,
1317 lprect->bottom - lprect->top );
1318 add_device_bounds( physdev->x11dev, lprect );
1321 if(count == 0) return TRUE;
1323 EnterCriticalSection(&xrender_cs);
1325 entry = glyphsetCache + physdev->cache_index;
1326 formatEntry = entry->format[type][aa_type_from_flags( physdev->aa_flags )];
1328 for(idx = 0; idx < count; idx++) {
1329 if( !formatEntry ) {
1330 UploadGlyph(physdev, wstr[idx], type);
1331 /* re-evaluate format entry since aa_flags may have changed */
1332 formatEntry = entry->format[type][aa_type_from_flags( physdev->aa_flags )];
1333 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1334 UploadGlyph(physdev, wstr[idx], type);
1337 if (!formatEntry)
1339 WARN("could not upload requested glyphs\n");
1340 LeaveCriticalSection(&xrender_cs);
1341 return FALSE;
1344 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1345 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1347 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1349 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1350 So we pass zeros to the function and move to our starting position using the first
1351 element of the elts array. */
1353 desired.x = physdev->x11dev->dc_rect.left + x;
1354 desired.y = physdev->x11dev->dc_rect.top + y;
1355 offset.x = offset.y = 0;
1356 current.x = current.y = 0;
1358 tile_pict = get_tile_pict(physdev->format, &col);
1360 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1362 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1363 render_op = PictOpOutReverse; /* This gives us 'black' text */
1365 reset_bounds( &bounds );
1366 for(idx = 0; idx < count; idx++)
1368 elts[idx].glyphset = formatEntry->glyphset;
1369 elts[idx].chars = wstr + idx;
1370 elts[idx].nchars = 1;
1371 elts[idx].xOff = desired.x - current.x;
1372 elts[idx].yOff = desired.y - current.y;
1374 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1375 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1377 rect.left = desired.x - physdev->x11dev->dc_rect.left - formatEntry->gis[wstr[idx]].x;
1378 rect.top = desired.y - physdev->x11dev->dc_rect.top - formatEntry->gis[wstr[idx]].y;
1379 rect.right = rect.left + formatEntry->gis[wstr[idx]].width;
1380 rect.bottom = rect.top + formatEntry->gis[wstr[idx]].height;
1381 add_bounds_rect( &bounds, &rect );
1383 if(!lpDx)
1385 desired.x += formatEntry->gis[wstr[idx]].xOff;
1386 desired.y += formatEntry->gis[wstr[idx]].yOff;
1388 else
1390 if(flags & ETO_PDY)
1392 offset.x += lpDx[idx * 2];
1393 offset.y += lpDx[idx * 2 + 1];
1395 else
1396 offset.x += lpDx[idx];
1397 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1398 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1402 /* Make sure we don't have any transforms set from a previous call */
1403 set_xrender_transformation(pict, 1, 1, 0, 0);
1404 pXRenderCompositeText16(gdi_display, render_op,
1405 tile_pict,
1406 pict,
1407 formatEntry->font_format,
1408 0, 0, 0, 0, elts, count);
1409 HeapFree(GetProcessHeap(), 0, elts);
1411 LeaveCriticalSection(&xrender_cs);
1412 add_device_bounds( physdev->x11dev, &bounds );
1413 return TRUE;
1416 /* multiply the alpha channel of a picture */
1417 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1418 int x, int y, int width, int height )
1420 XRenderPictureAttributes pa;
1421 Pixmap src_pixmap, mask_pixmap;
1422 Picture src_pict, mask_pict;
1423 XRenderColor color;
1425 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1426 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1427 pa.repeat = RepeatNormal;
1428 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1429 pa.component_alpha = True;
1430 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1431 color.red = color.green = color.blue = color.alpha = 0xffff;
1432 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1433 color.alpha = alpha;
1434 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1435 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1436 0, 0, 0, 0, x, y, width, height );
1437 pXRenderFreePicture( gdi_display, src_pict );
1438 pXRenderFreePicture( gdi_display, mask_pict );
1439 XFreePixmap( gdi_display, src_pixmap );
1440 XFreePixmap( gdi_display, mask_pixmap );
1443 /* Helper function for (stretched) blitting using xrender */
1444 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1445 int x_src, int y_src, int width_src, int height_src,
1446 int x_dst, int y_dst, int width_dst, int height_dst,
1447 double xscale, double yscale )
1449 int x_offset, y_offset;
1451 if (width_src < 0)
1453 x_src += width_src + 1;
1454 width_src = -width_src;
1456 if (height_src < 0)
1458 y_src += height_src + 1;
1459 height_src = -height_src;
1461 if (width_dst < 0)
1463 x_dst += width_dst + 1;
1464 width_dst = -width_dst;
1466 if (height_dst < 0)
1468 y_dst += height_dst + 1;
1469 height_dst = -height_dst;
1472 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1473 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1474 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1475 if(xscale != 1.0 || yscale != 1.0)
1477 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1478 * in the wrong quadrant of the x-y plane.
1480 x_offset = (xscale < 0) ? -width_dst : 0;
1481 y_offset = (yscale < 0) ? -height_dst : 0;
1482 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1484 else
1486 x_offset = x_src;
1487 y_offset = y_src;
1488 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1490 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1491 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1494 /* Helper function for (stretched) mono->color blitting using xrender */
1495 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1496 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1497 int x_src, int y_src, int width_src, int height_src,
1498 int x_dst, int y_dst, int width_dst, int height_dst,
1499 double xscale, double yscale )
1501 Picture tile_pict;
1502 int x_offset, y_offset;
1503 XRenderColor color;
1505 if (width_src < 0)
1507 x_src += width_src + 1;
1508 width_src = -width_src;
1510 if (height_src < 0)
1512 y_src += height_src + 1;
1513 height_src = -height_src;
1515 if (width_dst < 0)
1517 x_dst += width_dst + 1;
1518 width_dst = -width_dst;
1520 if (height_dst < 0)
1522 y_dst += height_dst + 1;
1523 height_dst = -height_dst;
1526 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1527 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1528 * the tile data.
1530 EnterCriticalSection( &xrender_cs );
1531 color = *bg;
1532 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1533 tile_pict = get_tile_pict( dst_format, &color );
1535 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1537 if (xscale != 1.0 || yscale != 1.0)
1539 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1540 * in the wrong quadrant of the x-y plane.
1542 x_offset = (xscale < 0) ? -width_dst : 0;
1543 y_offset = (yscale < 0) ? -height_dst : 0;
1544 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1546 else
1548 x_offset = x_src;
1549 y_offset = y_src;
1550 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1552 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1553 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1554 LeaveCriticalSection( &xrender_cs );
1556 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1557 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1558 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1559 x_dst, y_dst, width_dst, height_dst );
1562 /* create a pixmap and render picture for an image */
1563 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1564 struct bitblt_coords *src, enum wxr_format format,
1565 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1567 DWORD ret;
1568 int width = src->visrect.right - src->visrect.left;
1569 int height = src->visrect.bottom - src->visrect.top;
1570 int depth = pict_formats[format]->depth;
1571 struct gdi_image_bits dst_bits;
1572 XRenderPictureAttributes pa;
1573 GC gc;
1574 XImage *image;
1576 image = XCreateImage( gdi_display, default_visual.visual, depth, ZPixmap, 0, NULL,
1577 info->bmiHeader.biWidth, height, 32, 0 );
1578 if (!image) return ERROR_OUTOFMEMORY;
1580 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1581 if (ret) return ret;
1583 image->data = dst_bits.ptr;
1585 *use_repeat = (width == 1 && height == 1);
1586 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1588 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1589 gc = XCreateGC( gdi_display, *pixmap, 0, NULL );
1590 XPutImage( gdi_display, *pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1591 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1592 XFreeGC( gdi_display, gc );
1594 /* make coordinates relative to the pixmap */
1595 src->x -= src->visrect.left;
1596 src->y -= src->visrect.top;
1597 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1599 image->data = NULL;
1600 XDestroyImage( image );
1601 if (dst_bits.free) dst_bits.free( &dst_bits );
1602 return ret;
1605 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
1606 Drawable drawable, const struct bitblt_coords *src,
1607 const struct bitblt_coords *dst )
1609 int x_dst, y_dst;
1610 Picture src_pict = 0, dst_pict, mask_pict = 0;
1611 double xscale = src->width / (double)dst->width;
1612 double yscale = src->height / (double)dst->height;
1614 if (drawable) /* using an intermediate pixmap */
1616 x_dst = dst->x;
1617 y_dst = dst->y;
1618 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, 0, NULL );
1620 else
1622 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
1623 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
1624 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1627 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1629 /* mono -> color */
1630 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1632 XRenderColor fg, bg;
1634 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
1635 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
1636 fg.alpha = bg.alpha = 0;
1638 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
1639 physdev_src->x11dev->dc_rect.left + src->x,
1640 physdev_src->x11dev->dc_rect.top + src->y,
1641 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1643 else /* color -> color (can be at different depths) or mono -> mono */
1645 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
1646 mask_pict = get_no_alpha_mask();
1648 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
1649 physdev_src->x11dev->dc_rect.left + src->x,
1650 physdev_src->x11dev->dc_rect.top + src->y,
1651 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1654 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1658 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
1659 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
1660 Drawable drawable, struct bitblt_coords *src,
1661 struct bitblt_coords *dst, BOOL use_repeat )
1663 int x_dst, y_dst;
1664 Picture dst_pict;
1665 double xscale, yscale;
1667 if (drawable) /* using an intermediate pixmap */
1669 RGNDATA *clip_data = NULL;
1671 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1672 x_dst = dst->x;
1673 y_dst = dst->y;
1674 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, 0, NULL );
1675 if (clip_data)
1676 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
1677 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
1678 HeapFree( GetProcessHeap(), 0, clip_data );
1680 else
1682 x_dst = physdev->x11dev->dc_rect.left + dst->x;
1683 y_dst = physdev->x11dev->dc_rect.top + dst->y;
1684 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
1687 if (!use_repeat)
1689 xscale = src->width / (double)dst->width;
1690 yscale = src->height / (double)dst->height;
1692 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1694 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
1695 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1697 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1701 /***********************************************************************
1702 * xrenderdrv_StretchBlt
1704 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1705 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1707 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1708 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1709 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
1711 if (src_dev->funcs != dst_dev->funcs)
1713 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
1714 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
1717 /* XRender is of no use for color -> mono */
1718 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
1719 goto x11drv_fallback;
1721 /* if not stretching, we only need to handle format conversion */
1722 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
1724 if (rop != SRCCOPY)
1726 GC tmpGC;
1727 Pixmap tmp_pixmap;
1728 struct bitblt_coords tmp;
1730 /* make coordinates relative to tmp pixmap */
1731 tmp = *dst;
1732 tmp.x -= tmp.visrect.left;
1733 tmp.y -= tmp.visrect.top;
1734 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1736 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
1737 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1738 XSetGraphicsExposures( gdi_display, tmpGC, False );
1739 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
1740 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
1742 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
1743 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
1745 XFreePixmap( gdi_display, tmp_pixmap );
1746 XFreeGC( gdi_display, tmpGC );
1748 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
1750 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
1751 return TRUE;
1753 x11drv_fallback:
1754 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
1758 /***********************************************************************
1759 * xrenderdrv_PutImage
1761 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1762 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1763 struct bitblt_coords *dst, DWORD rop )
1765 struct xrender_physdev *physdev = get_xrender_dev( dev );
1766 DWORD ret;
1767 Pixmap tmp_pixmap;
1768 GC gc;
1769 enum wxr_format src_format, dst_format;
1770 XRenderPictFormat *pict_format;
1771 Pixmap src_pixmap;
1772 Picture src_pict, mask_pict = 0;
1773 BOOL use_repeat;
1775 dst_format = physdev->format;
1776 src_format = get_xrender_format_from_bitmapinfo( info );
1777 if (!(pict_format = pict_formats[src_format])) goto update_format;
1779 /* make sure we can create an image with the same bpp */
1780 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
1781 goto update_format;
1783 /* mono <-> color conversions not supported */
1784 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
1785 goto x11drv_fallback;
1787 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1789 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
1791 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
1792 if (!ret)
1794 struct bitblt_coords tmp;
1796 if (rop != SRCCOPY)
1798 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
1800 /* make coordinates relative to tmp pixmap */
1801 tmp = *dst;
1802 tmp.x -= tmp.visrect.left;
1803 tmp.y -= tmp.visrect.top;
1804 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1806 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
1807 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1808 XSetGraphicsExposures( gdi_display, gc, False );
1809 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
1810 tmp.visrect.right - tmp.visrect.left,
1811 tmp.visrect.bottom - tmp.visrect.top,
1812 physdev->pict_format->depth );
1814 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
1815 NULL, tmp_pixmap, src, &tmp, use_repeat );
1816 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
1818 XFreePixmap( gdi_display, tmp_pixmap );
1819 XFreeGC( gdi_display, gc );
1820 if (restore_region) restore_clipping_region( physdev->x11dev );
1822 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
1823 physdev->pict_format, physdev, 0, src, dst, use_repeat );
1825 add_device_bounds( physdev->x11dev, &dst->visrect );
1827 pXRenderFreePicture( gdi_display, src_pict );
1828 XFreePixmap( gdi_display, src_pixmap );
1830 return ret;
1832 update_format:
1833 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1834 set_color_info( pict_formats[dst_format], info );
1835 return ERROR_BAD_FORMAT;
1837 x11drv_fallback:
1838 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
1839 return dev->funcs->pPutImage( dev, clip, info, bits, src, dst, rop );
1843 /***********************************************************************
1844 * xrenderdrv_BlendImage
1846 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
1847 struct bitblt_coords *src, struct bitblt_coords *dst,
1848 BLENDFUNCTION func )
1850 struct xrender_physdev *physdev = get_xrender_dev( dev );
1851 DWORD ret;
1852 enum wxr_format format;
1853 XRenderPictFormat *pict_format;
1854 Picture dst_pict, src_pict, mask_pict;
1855 Pixmap src_pixmap;
1856 BOOL use_repeat;
1858 format = get_xrender_format_from_bitmapinfo( info );
1859 if (!(func.AlphaFormat & AC_SRC_ALPHA))
1860 format = get_format_without_alpha( format );
1861 else if (format != WXR_FORMAT_A8R8G8B8 || info->bmiHeader.biCompression != BI_RGB)
1862 return ERROR_INVALID_PARAMETER;
1864 if (!(pict_format = pict_formats[format])) goto update_format;
1866 /* make sure we can create an image with the same bpp */
1867 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
1868 goto update_format;
1870 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
1871 goto update_format;
1873 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1875 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
1876 if (!ret)
1878 double xscale, yscale;
1880 if (!use_repeat)
1882 xscale = src->width / (double)dst->width;
1883 yscale = src->height / (double)dst->height;
1885 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1887 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
1889 EnterCriticalSection( &xrender_cs );
1890 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
1892 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
1893 src->x, src->y, src->width, src->height,
1894 physdev->x11dev->dc_rect.left + dst->x,
1895 physdev->x11dev->dc_rect.top + dst->y,
1896 dst->width, dst->height, xscale, yscale );
1898 pXRenderFreePicture( gdi_display, src_pict );
1899 XFreePixmap( gdi_display, src_pixmap );
1901 LeaveCriticalSection( &xrender_cs );
1902 add_device_bounds( physdev->x11dev, &dst->visrect );
1904 return ret;
1906 update_format:
1907 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1908 set_color_info( physdev->pict_format, info );
1909 return ERROR_BAD_FORMAT;
1913 /***********************************************************************
1914 * xrenderdrv_AlphaBlend
1916 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
1917 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
1919 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1920 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1921 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
1922 XRenderPictureAttributes pa;
1923 Pixmap tmp_pixmap = 0;
1924 double xscale, yscale;
1926 if (src_dev->funcs != dst_dev->funcs)
1928 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
1929 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
1932 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
1934 SetLastError( ERROR_INVALID_PARAMETER );
1935 return FALSE;
1938 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1940 xscale = src->width / (double)dst->width;
1941 yscale = src->height / (double)dst->height;
1943 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1945 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1947 /* mono -> color blending needs an intermediate color pixmap */
1948 XRenderColor fg, bg;
1949 int width = src->visrect.right - src->visrect.left;
1950 int height = src->visrect.bottom - src->visrect.top;
1952 /* blending doesn't use the destination DC colors */
1953 fg.red = fg.green = fg.blue = 0;
1954 bg.red = bg.green = bg.blue = 0xffff;
1955 fg.alpha = bg.alpha = 0xffff;
1957 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
1958 physdev_dst->pict_format->depth );
1959 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format, 0, NULL );
1961 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
1962 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
1964 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
1966 /* we need a source picture with no alpha */
1967 enum wxr_format format = get_format_without_alpha( physdev_src->format );
1968 if (format != physdev_src->format)
1970 pa.subwindow_mode = IncludeInferiors;
1971 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
1972 pict_formats[format], CPSubwindowMode, &pa );
1976 if (tmp_pict) src_pict = tmp_pict;
1978 EnterCriticalSection( &xrender_cs );
1979 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
1981 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
1982 physdev_src->x11dev->dc_rect.left + src->x,
1983 physdev_src->x11dev->dc_rect.top + src->y,
1984 src->width, src->height,
1985 physdev_dst->x11dev->dc_rect.left + dst->x,
1986 physdev_dst->x11dev->dc_rect.top + dst->y,
1987 dst->width, dst->height, xscale, yscale );
1989 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
1990 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
1992 LeaveCriticalSection( &xrender_cs );
1993 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
1994 return TRUE;
1997 /***********************************************************************
1998 * xrenderdrv_GradientFill
2000 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2001 void * grad_array, ULONG ngrad, ULONG mode )
2003 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2004 static const XFixed stops[2] = { 0, 1 << 16 };
2005 struct xrender_physdev *physdev = get_xrender_dev( dev );
2006 XLinearGradient gradient;
2007 XRenderColor colors[2];
2008 Picture src_pict, dst_pict;
2009 unsigned int i;
2010 const GRADIENT_RECT *rect = grad_array;
2011 RECT rc;
2012 POINT pt[2];
2014 if (!pXRenderCreateLinearGradient) goto fallback;
2016 /* <= 16-bpp uses dithering */
2017 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2019 switch (mode)
2021 case GRADIENT_FILL_RECT_H:
2022 case GRADIENT_FILL_RECT_V:
2023 for (i = 0; i < ngrad; i++, rect++)
2025 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2026 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2028 colors[0].red = v1->Red * 257 / 256;
2029 colors[0].green = v1->Green * 257 / 256;
2030 colors[0].blue = v1->Blue * 257 / 256;
2031 colors[1].red = v2->Red * 257 / 256;
2032 colors[1].green = v2->Green * 257 / 256;
2033 colors[1].blue = v2->Blue * 257 / 256;
2034 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2035 colors[0].alpha = colors[1].alpha = 65535;
2037 pt[0].x = v1->x;
2038 pt[0].y = v1->y;
2039 pt[1].x = v2->x;
2040 pt[1].y = v2->y;
2041 LPtoDP( dev->hdc, pt, 2 );
2042 if (mode == GRADIENT_FILL_RECT_H)
2044 gradient.p1.y = gradient.p2.y = 0;
2045 if (pt[1].x > pt[0].x)
2047 gradient.p1.x = 0;
2048 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2050 else
2052 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2053 gradient.p2.x = 0;
2056 else
2058 gradient.p1.x = gradient.p2.x = 0;
2059 if (pt[1].y > pt[0].y)
2061 gradient.p1.y = 0;
2062 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2064 else
2066 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2067 gradient.p2.y = 0;
2071 rc.left = min( pt[0].x, pt[1].x );
2072 rc.top = min( pt[0].y, pt[1].y );
2073 rc.right = max( pt[0].x, pt[1].x );
2074 rc.bottom = max( pt[0].y, pt[1].y );
2076 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2077 mode, wine_dbgstr_rect( &rc ),
2078 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2079 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2081 dst_pict = get_xrender_picture( physdev, 0, NULL );
2083 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2084 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2085 0, 0, rc.right - rc.left, rc.bottom - rc.top,
2086 physdev->x11dev->dc_rect.left + rc.left,
2087 physdev->x11dev->dc_rect.top + rc.top,
2088 rc.right - rc.left, rc.bottom - rc.top, 1, 1 );
2089 pXRenderFreePicture( gdi_display, src_pict );
2090 add_device_bounds( physdev->x11dev, &rc );
2092 return TRUE;
2095 fallback:
2096 #endif
2097 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2098 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2101 /***********************************************************************
2102 * xrenderdrv_SelectBrush
2104 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2106 struct xrender_physdev *physdev = get_xrender_dev( dev );
2107 Pixmap pixmap;
2108 XVisualInfo vis = default_visual;
2109 XRenderPictFormat *format = physdev->pict_format;
2111 if (!pattern) goto x11drv_fallback;
2112 if (pattern->info->bmiHeader.biBitCount == 1) goto x11drv_fallback;
2113 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2115 vis.depth = format->depth;
2116 vis.red_mask = format->direct.redMask << format->direct.red;
2117 vis.green_mask = format->direct.greenMask << format->direct.green;
2118 vis.blue_mask = format->direct.blueMask << format->direct.blue;
2120 pixmap = create_pixmap_from_image( physdev->dev.hdc, &vis, pattern->info,
2121 &pattern->bits, pattern->usage );
2122 if (!pixmap) return 0;
2124 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2125 physdev->x11dev->brush.pixmap = pixmap;
2126 physdev->x11dev->brush.fillStyle = FillTiled;
2127 physdev->x11dev->brush.pixel = 0; /* ignored */
2128 physdev->x11dev->brush.style = BS_PATTERN;
2129 return hbrush;
2131 x11drv_fallback:
2132 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2133 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2137 static const struct gdi_dc_funcs xrender_funcs =
2139 NULL, /* pAbortDoc */
2140 NULL, /* pAbortPath */
2141 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2142 NULL, /* pAngleArc */
2143 NULL, /* pArc */
2144 NULL, /* pArcTo */
2145 NULL, /* pBeginPath */
2146 xrenderdrv_BlendImage, /* pBlendImage */
2147 NULL, /* pChord */
2148 NULL, /* pCloseFigure */
2149 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2150 xrenderdrv_CreateDC, /* pCreateDC */
2151 xrenderdrv_DeleteDC, /* pDeleteDC */
2152 NULL, /* pDeleteObject */
2153 NULL, /* pDeviceCapabilities */
2154 NULL, /* pEllipse */
2155 NULL, /* pEndDoc */
2156 NULL, /* pEndPage */
2157 NULL, /* pEndPath */
2158 NULL, /* pEnumFonts */
2159 NULL, /* pEnumICMProfiles */
2160 NULL, /* pExcludeClipRect */
2161 NULL, /* pExtDeviceMode */
2162 xrenderdrv_ExtEscape, /* pExtEscape */
2163 NULL, /* pExtFloodFill */
2164 NULL, /* pExtSelectClipRgn */
2165 xrenderdrv_ExtTextOut, /* pExtTextOut */
2166 NULL, /* pFillPath */
2167 NULL, /* pFillRgn */
2168 NULL, /* pFlattenPath */
2169 NULL, /* pFontIsLinked */
2170 NULL, /* pFrameRgn */
2171 NULL, /* pGdiComment */
2172 NULL, /* pGetBoundsRect */
2173 NULL, /* pGetCharABCWidths */
2174 NULL, /* pGetCharABCWidthsI */
2175 NULL, /* pGetCharWidth */
2176 NULL, /* pGetDeviceCaps */
2177 NULL, /* pGetDeviceGammaRamp */
2178 NULL, /* pGetFontData */
2179 NULL, /* pGetFontRealizationInfo */
2180 NULL, /* pGetFontUnicodeRanges */
2181 NULL, /* pGetGlyphIndices */
2182 NULL, /* pGetGlyphOutline */
2183 NULL, /* pGetICMProfile */
2184 NULL, /* pGetImage */
2185 NULL, /* pGetKerningPairs */
2186 NULL, /* pGetNearestColor */
2187 NULL, /* pGetOutlineTextMetrics */
2188 NULL, /* pGetPixel */
2189 NULL, /* pGetSystemPaletteEntries */
2190 NULL, /* pGetTextCharsetInfo */
2191 NULL, /* pGetTextExtentExPoint */
2192 NULL, /* pGetTextExtentExPointI */
2193 NULL, /* pGetTextFace */
2194 NULL, /* pGetTextMetrics */
2195 xrenderdrv_GradientFill, /* pGradientFill */
2196 NULL, /* pIntersectClipRect */
2197 NULL, /* pInvertRgn */
2198 NULL, /* pLineTo */
2199 NULL, /* pModifyWorldTransform */
2200 NULL, /* pMoveTo */
2201 NULL, /* pOffsetClipRgn */
2202 NULL, /* pOffsetViewportOrg */
2203 NULL, /* pOffsetWindowOrg */
2204 NULL, /* pPaintRgn */
2205 NULL, /* pPatBlt */
2206 NULL, /* pPie */
2207 NULL, /* pPolyBezier */
2208 NULL, /* pPolyBezierTo */
2209 NULL, /* pPolyDraw */
2210 NULL, /* pPolyPolygon */
2211 NULL, /* pPolyPolyline */
2212 NULL, /* pPolygon */
2213 NULL, /* pPolyline */
2214 NULL, /* pPolylineTo */
2215 xrenderdrv_PutImage, /* pPutImage */
2216 NULL, /* pRealizeDefaultPalette */
2217 NULL, /* pRealizePalette */
2218 NULL, /* pRectangle */
2219 NULL, /* pResetDC */
2220 NULL, /* pRestoreDC */
2221 NULL, /* pRoundRect */
2222 NULL, /* pSaveDC */
2223 NULL, /* pScaleViewportExt */
2224 NULL, /* pScaleWindowExt */
2225 NULL, /* pSelectBitmap */
2226 xrenderdrv_SelectBrush, /* pSelectBrush */
2227 NULL, /* pSelectClipPath */
2228 xrenderdrv_SelectFont, /* pSelectFont */
2229 NULL, /* pSelectPalette */
2230 NULL, /* pSelectPen */
2231 NULL, /* pSetArcDirection */
2232 NULL, /* pSetBkColor */
2233 NULL, /* pSetBkMode */
2234 NULL, /* pSetBoundsRect */
2235 NULL, /* pSetDCBrushColor */
2236 NULL, /* pSetDCPenColor */
2237 NULL, /* pSetDIBitsToDevice */
2238 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2239 NULL, /* pSetDeviceGammaRamp */
2240 NULL, /* pSetLayout */
2241 NULL, /* pSetMapMode */
2242 NULL, /* pSetMapperFlags */
2243 NULL, /* pSetPixel */
2244 NULL, /* pSetPolyFillMode */
2245 NULL, /* pSetROP2 */
2246 NULL, /* pSetRelAbs */
2247 NULL, /* pSetStretchBltMode */
2248 NULL, /* pSetTextAlign */
2249 NULL, /* pSetTextCharacterExtra */
2250 NULL, /* pSetTextColor */
2251 NULL, /* pSetTextJustification */
2252 NULL, /* pSetViewportExt */
2253 NULL, /* pSetViewportOrg */
2254 NULL, /* pSetWindowExt */
2255 NULL, /* pSetWindowOrg */
2256 NULL, /* pSetWorldTransform */
2257 NULL, /* pStartDoc */
2258 NULL, /* pStartPage */
2259 xrenderdrv_StretchBlt, /* pStretchBlt */
2260 NULL, /* pStretchDIBits */
2261 NULL, /* pStrokeAndFillPath */
2262 NULL, /* pStrokePath */
2263 NULL, /* pUnrealizePalette */
2264 NULL, /* pWidenPath */
2265 NULL, /* wine_get_wgl_driver */
2266 GDI_PRIORITY_GRAPHICS_DRV + 10 /* priority */
2269 #else /* SONAME_LIBXRENDER */
2271 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2273 TRACE("XRender support not compiled in.\n");
2274 return NULL;
2277 #endif /* SONAME_LIBXRENDER */