2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
6 * Copyright 2011 Alexandre Julliard
9 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
37 #include "wine/library.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(xrender
);
43 #ifdef SONAME_LIBXRENDER
45 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
48 #include <X11/extensions/Xrender.h>
50 #ifndef RepeatNone /* added in 0.10 */
52 #define RepeatNormal 1
54 #define RepeatReflect 3
72 WXR_INVALID_FORMAT
= WXR_NB_FORMATS
75 typedef struct wine_xrender_format_template
79 unsigned int alphaMask
;
83 unsigned int greenMask
;
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 const ColorShifts wxr_color_shifts
[WXR_NB_FORMATS
] =
107 /* format phys red phys green phys blue log red log green log blue */
108 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
109 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
110 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
111 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
112 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
113 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
114 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
115 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
116 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
117 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
118 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
122 static enum wxr_format default_format
= WXR_INVALID_FORMAT
;
123 static XRenderPictFormat
*pict_formats
[WXR_NB_FORMATS
+ 1 /* invalid format */];
129 SIZE devsize
; /* size in device coords */
133 #define INITIAL_REALIZED_BUF_SIZE 128
135 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
140 XRenderPictFormat
*font_format
;
144 } gsCacheEntryFormat
;
150 gsCacheEntryFormat
* format
[AA_MAXVALUE
];
155 struct xrender_physdev
157 struct gdi_physdev dev
;
158 X11DRV_PDEVICE
*x11dev
;
160 enum wxr_format format
;
165 XRenderPictFormat
*pict_format
;
168 static inline struct xrender_physdev
*get_xrender_dev( PHYSDEV dev
)
170 return (struct xrender_physdev
*)dev
;
173 static const struct gdi_dc_funcs xrender_funcs
;
175 static gsCacheEntry
*glyphsetCache
= NULL
;
176 static DWORD glyphsetCacheSize
= 0;
177 static INT lastfree
= -1;
180 #define INIT_CACHE_SIZE 10
182 static void *xrender_handle
;
184 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
185 MAKE_FUNCPTR(XRenderAddGlyphs
)
186 MAKE_FUNCPTR(XRenderChangePicture
)
187 MAKE_FUNCPTR(XRenderComposite
)
188 MAKE_FUNCPTR(XRenderCompositeText16
)
189 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
190 MAKE_FUNCPTR(XRenderCreatePicture
)
191 MAKE_FUNCPTR(XRenderFillRectangle
)
192 MAKE_FUNCPTR(XRenderFindFormat
)
193 MAKE_FUNCPTR(XRenderFindVisualFormat
)
194 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
195 MAKE_FUNCPTR(XRenderFreePicture
)
196 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
197 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
198 MAKE_FUNCPTR(XRenderCreateLinearGradient
)
200 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
201 MAKE_FUNCPTR(XRenderSetPictureTransform
)
203 MAKE_FUNCPTR(XRenderQueryExtension
)
207 static CRITICAL_SECTION xrender_cs
;
208 static CRITICAL_SECTION_DEBUG critsect_debug
=
211 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
212 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
214 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
216 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
217 ( ( (ULONG)_x4 << 24 ) | \
218 ( (ULONG)_x3 << 16 ) | \
219 ( (ULONG)_x2 << 8 ) | \
222 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
224 #define GASP_GRIDFIT 0x01
225 #define GASP_DOGRAY 0x02
227 #ifdef WORDS_BIGENDIAN
228 #define get_be_word(x) (x)
229 #define NATIVE_BYTE_ORDER MSBFirst
231 #define get_be_word(x) RtlUshortByteSwap(x)
232 #define NATIVE_BYTE_ORDER LSBFirst
235 static BOOL
has_alpha( enum wxr_format format
)
237 return (format
== WXR_FORMAT_A8R8G8B8
|| format
== WXR_FORMAT_B8G8R8A8
);
240 static enum wxr_format
get_format_without_alpha( enum wxr_format format
)
244 case WXR_FORMAT_A8R8G8B8
: return WXR_FORMAT_X8R8G8B8
;
245 case WXR_FORMAT_B8G8R8A8
: return WXR_FORMAT_B8G8R8X8
;
246 default: return format
;
250 static BOOL
get_xrender_template(const WineXRenderFormatTemplate
*fmt
, XRenderPictFormat
*templ
, unsigned long *mask
)
253 templ
->type
= PictTypeDirect
;
254 templ
->depth
= fmt
->depth
;
255 templ
->direct
.alpha
= fmt
->alpha
;
256 templ
->direct
.alphaMask
= fmt
->alphaMask
;
257 templ
->direct
.red
= fmt
->red
;
258 templ
->direct
.redMask
= fmt
->redMask
;
259 templ
->direct
.green
= fmt
->green
;
260 templ
->direct
.greenMask
= fmt
->greenMask
;
261 templ
->direct
.blue
= fmt
->blue
;
262 templ
->direct
.blueMask
= fmt
->blueMask
;
265 *mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
| PictFormatRed
| PictFormatRedMask
| PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
| PictFormatBlueMask
;
270 static BOOL
is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate
*fmt
)
272 if(fmt
->depth
!= default_visual
.depth
) return FALSE
;
273 if( (fmt
->redMask
<< fmt
->red
) != default_visual
.red_mask
) return FALSE
;
274 if( (fmt
->greenMask
<< fmt
->green
) != default_visual
.green_mask
) return FALSE
;
275 if( (fmt
->blueMask
<< fmt
->blue
) != default_visual
.blue_mask
) return FALSE
;
277 /* We never select a default ARGB visual */
278 if(fmt
->alphaMask
) return FALSE
;
282 static int load_xrender_formats(void)
287 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
289 XRenderPictFormat templ
;
291 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template
[i
]))
293 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, default_visual
.visual
);
294 if (!pict_formats
[i
])
296 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
297 if (default_visual
.class == DirectColor
)
300 if (XMatchVisualInfo( gdi_display
, default_visual
.screen
,
301 default_visual
.depth
, TrueColor
, &info
))
303 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, info
.visual
);
304 if (pict_formats
[i
]) default_visual
= info
;
308 if (pict_formats
[i
]) default_format
= i
;
312 unsigned long mask
= 0;
313 get_xrender_template(&wxr_formats_template
[i
], &templ
, &mask
);
314 pict_formats
[i
] = pXRenderFindFormat(gdi_display
, mask
, &templ
, 0);
319 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats
[i
]->id
, i
);
325 /***********************************************************************
326 * X11DRV_XRender_Init
328 * Let's see if our XServer has the extension available
331 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
335 if (!client_side_with_render
) return NULL
;
336 if (!(xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0))) return NULL
;
338 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
339 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
340 LOAD_FUNCPTR(XRenderAddGlyphs
);
341 LOAD_FUNCPTR(XRenderChangePicture
);
342 LOAD_FUNCPTR(XRenderComposite
);
343 LOAD_FUNCPTR(XRenderCompositeText16
);
344 LOAD_FUNCPTR(XRenderCreateGlyphSet
);
345 LOAD_FUNCPTR(XRenderCreatePicture
);
346 LOAD_FUNCPTR(XRenderFillRectangle
);
347 LOAD_FUNCPTR(XRenderFindFormat
);
348 LOAD_FUNCPTR(XRenderFindVisualFormat
);
349 LOAD_FUNCPTR(XRenderFreeGlyphSet
);
350 LOAD_FUNCPTR(XRenderFreePicture
);
351 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
);
352 LOAD_FUNCPTR(XRenderQueryExtension
);
353 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
354 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient
);
356 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
357 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
);
359 #undef LOAD_OPTIONAL_FUNCPTR
362 if (!pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
)) return NULL
;
364 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
365 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
367 ERR_(winediag
)("Wine has detected that you probably have a buggy version "
368 "of libXrender. Because of this client side font rendering "
369 "will be disabled. Please upgrade this library.\n");
373 if (!default_visual
.red_mask
|| !default_visual
.green_mask
|| !default_visual
.blue_mask
)
375 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
379 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
380 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
382 glyphsetCacheSize
= INIT_CACHE_SIZE
;
384 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
385 glyphsetCache
[i
].next
= i
+ 1;
386 glyphsetCache
[i
].count
= -1;
388 glyphsetCache
[i
-1].next
= -1;
390 return &xrender_funcs
;
393 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
394 static void get_xrender_color( struct xrender_physdev
*physdev
, COLORREF src_color
, XRenderColor
*dst_color
)
396 if (src_color
& (1 << 24)) /* PALETTEINDEX */
398 HPALETTE pal
= GetCurrentObject( physdev
->dev
.hdc
, OBJ_PAL
);
399 PALETTEENTRY pal_ent
;
401 if (!GetPaletteEntries( pal
, LOWORD(src_color
), 1, &pal_ent
))
402 GetPaletteEntries( pal
, 0, 1, &pal_ent
);
403 dst_color
->red
= pal_ent
.peRed
* 257;
404 dst_color
->green
= pal_ent
.peGreen
* 257;
405 dst_color
->blue
= pal_ent
.peBlue
* 257;
409 if (src_color
>> 16 == 0x10ff) src_color
= 0; /* DIBINDEX */
411 dst_color
->red
= GetRValue( src_color
) * 257;
412 dst_color
->green
= GetGValue( src_color
) * 257;
413 dst_color
->blue
= GetBValue( src_color
) * 257;
416 if (physdev
->format
== WXR_FORMAT_MONO
&& !dst_color
->red
&& !dst_color
->green
&& !dst_color
->blue
)
417 dst_color
->alpha
= 0;
419 dst_color
->alpha
= 0xffff;
422 static enum wxr_format
get_xrender_format_from_bitmapinfo( const BITMAPINFO
*info
)
424 if (info
->bmiHeader
.biPlanes
!= 1) return WXR_INVALID_FORMAT
;
426 switch (info
->bmiHeader
.biBitCount
)
429 return WXR_FORMAT_MONO
;
434 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
435 return WXR_FORMAT_R8G8B8
;
438 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
440 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
443 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
445 if (info
->bmiHeader
.biBitCount
== wxr_formats_template
[i
].depth
&&
446 colors
[0] == (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
447 colors
[1] == (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
448 colors
[2] == (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
))
453 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
454 return (info
->bmiHeader
.biBitCount
== 16) ? WXR_FORMAT_X1R5G5B5
: WXR_FORMAT_A8R8G8B8
;
456 return WXR_INVALID_FORMAT
;
459 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
460 static void set_xrender_transformation(Picture src_pict
, double xscale
, double yscale
, int xoffset
, int yoffset
)
462 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
463 XTransform xform
= {{
464 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(xoffset
) },
465 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(yoffset
) },
466 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
469 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
473 static void update_xrender_clipping( struct xrender_physdev
*dev
, HRGN rgn
)
475 XRenderPictureAttributes pa
;
481 pXRenderChangePicture( gdi_display
, dev
->pict
, CPClipMask
, &pa
);
483 else if ((data
= X11DRV_GetRegionData( rgn
, 0 )))
485 pXRenderSetPictureClipRectangles( gdi_display
, dev
->pict
,
486 dev
->x11dev
->dc_rect
.left
, dev
->x11dev
->dc_rect
.top
,
487 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
488 HeapFree( GetProcessHeap(), 0, data
);
493 static Picture
get_xrender_picture( struct xrender_physdev
*dev
, HRGN clip_rgn
, const RECT
*clip_rect
)
495 if (!dev
->pict
&& dev
->pict_format
)
497 XRenderPictureAttributes pa
;
499 pa
.subwindow_mode
= IncludeInferiors
;
500 dev
->pict
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
501 dev
->pict_format
, CPSubwindowMode
, &pa
);
502 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
503 dev
->pict
, dev
->dev
.hdc
, dev
->x11dev
->drawable
);
504 dev
->update_clip
= (dev
->region
!= 0);
509 HRGN rgn
= CreateRectRgnIndirect( clip_rect
);
510 if (clip_rgn
) CombineRgn( rgn
, rgn
, clip_rgn
, RGN_AND
);
511 if (dev
->region
) CombineRgn( rgn
, rgn
, dev
->region
, RGN_AND
);
512 update_xrender_clipping( dev
, rgn
);
519 HRGN rgn
= CreateRectRgn( 0, 0, 0, 0 );
520 CombineRgn( rgn
, clip_rgn
, dev
->region
, RGN_AND
);
521 update_xrender_clipping( dev
, rgn
);
524 else update_xrender_clipping( dev
, clip_rgn
);
526 else if (dev
->update_clip
) update_xrender_clipping( dev
, dev
->region
);
528 dev
->update_clip
= (clip_rect
|| clip_rgn
); /* have to update again if we are using a custom region */
532 static Picture
get_xrender_picture_source( struct xrender_physdev
*dev
, BOOL repeat
)
534 if (!dev
->pict_src
&& dev
->pict_format
)
536 XRenderPictureAttributes pa
;
538 pa
.subwindow_mode
= IncludeInferiors
;
539 pa
.repeat
= repeat
? RepeatNormal
: RepeatNone
;
540 dev
->pict_src
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
541 dev
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
543 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
544 dev
->pict_src
, dev
->dev
.hdc
, dev
->x11dev
->drawable
, pa
.repeat
);
547 return dev
->pict_src
;
550 static void free_xrender_picture( struct xrender_physdev
*dev
)
552 if (dev
->pict
|| dev
->pict_src
)
554 XFlush( gdi_display
);
557 TRACE("freeing pict = %lx dc = %p\n", dev
->pict
, dev
->dev
.hdc
);
558 pXRenderFreePicture(gdi_display
, dev
->pict
);
563 TRACE("freeing pict = %lx dc = %p\n", dev
->pict_src
, dev
->dev
.hdc
);
564 pXRenderFreePicture(gdi_display
, dev
->pict_src
);
570 /* return a mask picture used to force alpha to 0 */
571 static Picture
get_no_alpha_mask(void)
573 static Pixmap pixmap
;
576 EnterCriticalSection( &xrender_cs
);
579 XRenderPictureAttributes pa
;
582 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
583 pa
.repeat
= RepeatNormal
;
584 pa
.component_alpha
= True
;
585 pict
= pXRenderCreatePicture( gdi_display
, pixmap
, pict_formats
[WXR_FORMAT_A8R8G8B8
],
586 CPRepeat
|CPComponentAlpha
, &pa
);
587 col
.red
= col
.green
= col
.blue
= 0xffff;
589 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
591 LeaveCriticalSection( &xrender_cs
);
595 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
597 if(p1
->hash
!= p2
->hash
) return TRUE
;
598 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
599 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
600 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
601 return strcmpiW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
605 static void walk_cache(void)
609 EnterCriticalSection(&xrender_cs
);
610 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
611 TRACE("item %d\n", i
);
612 LeaveCriticalSection(&xrender_cs
);
616 static int LookupEntry(LFANDSIZE
*plfsz
)
620 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
622 if(glyphsetCache
[i
].count
== -1) break; /* reached free list so stop */
624 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
625 glyphsetCache
[i
].count
++;
627 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
628 glyphsetCache
[i
].next
= mru
;
631 TRACE("found font in cache %d\n", i
);
636 TRACE("font not in cache\n");
640 static void FreeEntry(int entry
)
644 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
645 gsCacheEntryFormat
* formatEntry
;
647 if( !glyphsetCache
[entry
].format
[format
] )
650 formatEntry
= glyphsetCache
[entry
].format
[format
];
652 if(formatEntry
->glyphset
) {
653 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
654 formatEntry
->glyphset
= 0;
656 if(formatEntry
->nrealized
) {
657 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
658 formatEntry
->realized
= NULL
;
659 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
660 formatEntry
->gis
= NULL
;
661 formatEntry
->nrealized
= 0;
664 HeapFree(GetProcessHeap(), 0, formatEntry
);
665 glyphsetCache
[entry
].format
[format
] = NULL
;
669 static int AllocEntry(void)
671 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
674 assert(glyphsetCache
[lastfree
].count
== -1);
675 glyphsetCache
[lastfree
].count
= 1;
677 lastfree
= glyphsetCache
[lastfree
].next
;
679 glyphsetCache
[best
].next
= mru
;
682 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
686 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
687 if(glyphsetCache
[i
].count
== 0) {
695 TRACE("freeing unused glyphset at cache %d\n", best
);
697 glyphsetCache
[best
].count
= 1;
699 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
700 glyphsetCache
[best
].next
= mru
;
708 TRACE("Growing cache\n");
711 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
713 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
714 * sizeof(*glyphsetCache
));
716 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
717 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
718 * sizeof(*glyphsetCache
));
720 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
722 glyphsetCache
[i
].next
= i
+ 1;
723 glyphsetCache
[i
].count
= -1;
725 glyphsetCache
[i
-1].next
= -1;
726 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
728 lastfree
= glyphsetCache
[best
].next
;
729 glyphsetCache
[best
].count
= 1;
730 glyphsetCache
[best
].next
= mru
;
732 TRACE("new free cache slot at %d\n", mru
);
736 static int GetCacheEntry( LFANDSIZE
*plfsz
)
742 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
745 entry
= glyphsetCache
+ ret
;
746 entry
->lfsz
= *plfsz
;
747 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
748 assert( !entry
->format
[format
] );
754 static void dec_ref_cache(int index
)
757 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
758 assert(glyphsetCache
[index
].count
> 0);
759 glyphsetCache
[index
].count
--;
762 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
764 DWORD hash
= 0, *ptr
, two_chars
;
768 hash
^= plfsz
->devsize
.cx
;
769 hash
^= plfsz
->devsize
.cy
;
770 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
772 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
774 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
776 pwc
= (WCHAR
*)&two_chars
;
778 *pwc
= toupperW(*pwc
);
780 *pwc
= toupperW(*pwc
);
788 static AA_Type
aa_type_from_flags( UINT aa_flags
)
790 switch (aa_flags
& 0x7f)
795 case GGO_GRAY4_BITMAP
:
796 case WINE_GGO_GRAY16_BITMAP
:
798 case WINE_GGO_HRGB_BITMAP
:
800 case WINE_GGO_HBGR_BITMAP
:
802 case WINE_GGO_VRGB_BITMAP
:
804 case WINE_GGO_VBGR_BITMAP
:
807 FIXME( "unknown flags %x\n", aa_flags
);
812 static UINT
get_xft_aa_flags( const LOGFONTW
*lf
)
817 switch (lf
->lfQuality
)
819 case NONANTIALIASED_QUALITY
:
820 case ANTIALIASED_QUALITY
:
823 if (!(value
= XGetDefault( gdi_display
, "Xft", "antialias" ))) break;
824 TRACE( "got antialias '%s'\n", value
);
825 if (tolower(value
[0]) == 'f' || tolower(value
[0]) == 'n' ||
826 value
[0] == '0' || !strcasecmp( value
, "off" ))
831 ret
= GGO_GRAY4_BITMAP
;
833 case CLEARTYPE_QUALITY
:
834 case CLEARTYPE_NATURAL_QUALITY
:
835 if (!(value
= XGetDefault( gdi_display
, "Xft", "rgba" ))) break;
836 TRACE( "got rgba '%s'\n", value
);
837 if (!strcmp( value
, "rgb" )) ret
= WINE_GGO_HRGB_BITMAP
;
838 else if (!strcmp( value
, "bgr" )) ret
= WINE_GGO_HBGR_BITMAP
;
839 else if (!strcmp( value
, "vrgb" )) ret
= WINE_GGO_VRGB_BITMAP
;
840 else if (!strcmp( value
, "vbgr" )) ret
= WINE_GGO_VBGR_BITMAP
;
841 else if (!strcmp( value
, "none" )) ret
= GGO_GRAY4_BITMAP
;
847 /**********************************************************************
848 * xrenderdrv_SelectFont
850 static HFONT
xrenderdrv_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
853 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
854 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
857 GetObjectW( hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
858 if (!*aa_flags
) *aa_flags
= get_xft_aa_flags( &lfsz
.lf
);
860 ret
= next
->funcs
->pSelectFont( next
, hfont
, aa_flags
);
863 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
864 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
865 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
866 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
867 lfsz
.devsize
.cx
= X11DRV_XWStoDS( dev
->hdc
, lfsz
.lf
.lfWidth
);
868 lfsz
.devsize
.cy
= X11DRV_YWStoDS( dev
->hdc
, lfsz
.lf
.lfHeight
);
870 GetTransform( dev
->hdc
, 0x204, &lfsz
.xform
);
871 TRACE("font transform %f %f %f %f\n", lfsz
.xform
.eM11
, lfsz
.xform
.eM12
,
872 lfsz
.xform
.eM21
, lfsz
.xform
.eM22
);
874 if (GetGraphicsMode( dev
->hdc
) == GM_COMPATIBLE
&& lfsz
.xform
.eM11
* lfsz
.xform
.eM22
< 0)
875 lfsz
.lf
.lfOrientation
= -lfsz
.lf
.lfOrientation
;
877 /* Not used fields, would break hashing */
878 lfsz
.xform
.eDx
= lfsz
.xform
.eDy
= 0;
880 lfsz_calc_hash(&lfsz
);
882 EnterCriticalSection(&xrender_cs
);
883 if (physdev
->cache_index
!= -1)
884 dec_ref_cache( physdev
->cache_index
);
885 physdev
->cache_index
= GetCacheEntry( &lfsz
);
886 glyphsetCache
[physdev
->cache_index
].aa_default
= aa_type_from_flags( *aa_flags
);
887 LeaveCriticalSection(&xrender_cs
);
891 static BOOL
create_xrender_dc( PHYSDEV
*pdev
, enum wxr_format format
)
893 X11DRV_PDEVICE
*x11dev
= get_x11drv_dev( *pdev
);
894 struct xrender_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
896 if (!physdev
) return FALSE
;
897 physdev
->x11dev
= x11dev
;
898 physdev
->cache_index
= -1;
899 physdev
->format
= format
;
900 physdev
->pict_format
= pict_formats
[format
];
901 push_dc_driver( pdev
, &physdev
->dev
, &xrender_funcs
);
905 /* store the color mask data in the bitmap info structure */
906 static void set_color_info( XRenderPictFormat
*format
, BITMAPINFO
*info
)
908 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
910 info
->bmiHeader
.biPlanes
= 1;
911 info
->bmiHeader
.biBitCount
= pixmap_formats
[format
->depth
]->bits_per_pixel
;
912 info
->bmiHeader
.biCompression
= BI_RGB
;
913 info
->bmiHeader
.biClrUsed
= 0;
915 switch (info
->bmiHeader
.biBitCount
)
918 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
919 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
920 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
921 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
924 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
925 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
926 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
927 if (colors
[0] != 0xff0000 || colors
[1] != 0x00ff00 || colors
[2] != 0x0000ff)
928 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
934 /**********************************************************************
935 * xrenderdrv_CreateDC
937 static BOOL
xrenderdrv_CreateDC( PHYSDEV
*pdev
, LPCWSTR driver
, LPCWSTR device
,
938 LPCWSTR output
, const DEVMODEW
* initData
)
940 return create_xrender_dc( pdev
, default_format
);
943 /**********************************************************************
944 * xrenderdrv_CreateCompatibleDC
946 static BOOL
xrenderdrv_CreateCompatibleDC( PHYSDEV orig
, PHYSDEV
*pdev
)
948 if (orig
) /* chain to x11drv first */
950 orig
= GET_NEXT_PHYSDEV( orig
, pCreateCompatibleDC
);
951 if (!orig
->funcs
->pCreateCompatibleDC( orig
, pdev
)) return FALSE
;
953 /* otherwise we have been called by x11drv */
955 return create_xrender_dc( pdev
, WXR_FORMAT_MONO
);
958 /**********************************************************************
959 * xrenderdrv_DeleteDC
961 static BOOL
xrenderdrv_DeleteDC( PHYSDEV dev
)
963 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
965 free_xrender_picture( physdev
);
967 EnterCriticalSection( &xrender_cs
);
968 if (physdev
->cache_index
!= -1) dec_ref_cache( physdev
->cache_index
);
969 LeaveCriticalSection( &xrender_cs
);
971 HeapFree( GetProcessHeap(), 0, physdev
);
975 /**********************************************************************
976 * xrenderdrv_ExtEscape
978 static INT
xrenderdrv_ExtEscape( PHYSDEV dev
, INT escape
, INT in_count
, LPCVOID in_data
,
979 INT out_count
, LPVOID out_data
)
981 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
983 dev
= GET_NEXT_PHYSDEV( dev
, pExtEscape
);
985 if (escape
== X11DRV_ESCAPE
&& in_data
&& in_count
>= sizeof(enum x11drv_escape_codes
))
987 if (*(const enum x11drv_escape_codes
*)in_data
== X11DRV_SET_DRAWABLE
)
989 BOOL ret
= dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
990 if (ret
) free_xrender_picture( physdev
); /* pict format doesn't change, only drawable */
994 return dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
997 /***********************************************************************
998 * xrenderdrv_SetDeviceClipping
1000 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev
, HRGN rgn
)
1002 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1004 physdev
->region
= rgn
;
1005 physdev
->update_clip
= TRUE
;
1007 dev
= GET_NEXT_PHYSDEV( dev
, pSetDeviceClipping
);
1008 dev
->funcs
->pSetDeviceClipping( dev
, rgn
);
1012 /************************************************************************
1015 * Helper to ExtTextOut. Must be called inside xrender_cs
1017 static void UploadGlyph(struct xrender_physdev
*physDev
, int glyph
, AA_Type format
)
1019 unsigned int buflen
;
1024 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->cache_index
;
1025 gsCacheEntryFormat
*formatEntry
;
1026 UINT ggo_format
= GGO_GLYPH_INDEX
;
1027 enum wxr_format wxr_format
;
1028 static const char zero
[4];
1029 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
1033 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
1036 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
1039 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
1042 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
1045 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
1049 ERR("aa = %d - not implemented\n", format
);
1051 ggo_format
|= GGO_BITMAP
;
1055 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1056 if(buflen
== GDI_ERROR
) {
1057 if(format
!= AA_None
) {
1059 entry
->aa_default
= AA_None
;
1060 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
1061 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1063 if(buflen
== GDI_ERROR
) {
1064 WARN("GetGlyphOutlineW failed using default glyph\n");
1065 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0, ggo_format
, &gm
, 0, NULL
, &identity
);
1066 if(buflen
== GDI_ERROR
) {
1067 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1068 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0x20, ggo_format
, &gm
, 0, NULL
, &identity
);
1069 if(buflen
== GDI_ERROR
) {
1070 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1075 TRACE("Turning off antialiasing for this monochrome font\n");
1078 /* If there is nothing for the current type, we create the entry. */
1079 if( !entry
->format
[format
] ) {
1080 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
1082 sizeof(gsCacheEntryFormat
));
1084 formatEntry
= entry
->format
[format
];
1086 if(formatEntry
->nrealized
<= glyph
) {
1087 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
1089 if (formatEntry
->realized
)
1090 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
1092 formatEntry
->realized
,
1093 formatEntry
->nrealized
* sizeof(BOOL
));
1095 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
1097 formatEntry
->nrealized
* sizeof(BOOL
));
1099 if (formatEntry
->gis
)
1100 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
1103 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1105 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
1107 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1111 if(formatEntry
->glyphset
== 0) {
1114 wxr_format
= WXR_FORMAT_GRAY
;
1121 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1125 ERR("aa = %d - not implemented\n", format
);
1127 wxr_format
= WXR_FORMAT_MONO
;
1131 formatEntry
->font_format
= pict_formats
[wxr_format
];
1132 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
1136 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
1137 GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
1138 formatEntry
->realized
[glyph
] = TRUE
;
1140 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1142 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1143 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1145 gi
.width
= gm
.gmBlackBoxX
;
1146 gi
.height
= gm
.gmBlackBoxY
;
1147 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1148 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1149 gi
.xOff
= gm
.gmCellIncX
;
1150 gi
.yOff
= gm
.gmCellIncY
;
1152 if(TRACE_ON(xrender
)) {
1155 unsigned char *line
;
1157 if(format
== AA_None
) {
1158 pitch
= ((gi
.width
+ 31) / 32) * 4;
1159 for(i
= 0; i
< gi
.height
; i
++) {
1160 line
= (unsigned char*) buf
+ i
* pitch
;
1162 for(j
= 0; j
< pitch
* 8; j
++) {
1163 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1165 TRACE("%s\n", output
);
1168 static const char blks
[] = " .:;!o*#";
1172 pitch
= ((gi
.width
+ 3) / 4) * 4;
1173 for(i
= 0; i
< gi
.height
; i
++) {
1174 line
= (unsigned char*) buf
+ i
* pitch
;
1176 for(j
= 0; j
< pitch
; j
++) {
1177 str
[0] = blks
[line
[j
] >> 5];
1178 strcat(output
, str
);
1180 TRACE("%s\n", output
);
1186 if(formatEntry
->glyphset
) {
1187 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1188 unsigned char *byte
= (unsigned char*) buf
, c
;
1194 /* magic to flip bit order */
1195 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1196 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1197 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1202 else if ( format
!= AA_Grey
&&
1203 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1205 unsigned int i
, *data
= (unsigned int *)buf
;
1206 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1211 XRenderCompositeText seems to ignore 0x0 glyphs when
1212 AA_None, which means we lose the advance width of glyphs
1213 like the space. We'll pretend that such glyphs are 1x1
1218 gi
.width
= gi
.height
= 1;
1220 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1221 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1224 HeapFree(GetProcessHeap(), 0, buf
);
1225 formatEntry
->gis
[glyph
] = gi
;
1228 /*************************************************************
1231 * Returns an appropriate Picture for tiling the text colour.
1232 * Call and use result within the xrender_cs
1234 static Picture
get_tile_pict( enum wxr_format wxr_format
, const XRenderColor
*color
)
1240 XRenderColor current_color
;
1241 } tiles
[WXR_NB_FORMATS
], *tile
;
1243 tile
= &tiles
[wxr_format
];
1247 XRenderPictureAttributes pa
;
1248 XRenderPictFormat
*pict_format
= pict_formats
[wxr_format
];
1250 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_format
->depth
);
1252 pa
.repeat
= RepeatNormal
;
1253 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_format
, CPRepeat
, &pa
);
1255 /* init current_color to something different from text_pixel */
1256 tile
->current_color
= *color
;
1257 tile
->current_color
.red
^= 0xffff;
1259 if (wxr_format
== WXR_FORMAT_MONO
)
1261 /* for a 1bpp bitmap we always need a 1 in the tile */
1263 col
.red
= col
.green
= col
.blue
= 0;
1265 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1269 if (memcmp( color
, &tile
->current_color
, sizeof(*color
) ) && wxr_format
!= WXR_FORMAT_MONO
)
1271 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, color
, 0, 0, 1, 1);
1272 tile
->current_color
= *color
;
1277 /*************************************************************
1280 * Returns an appropriate Picture for masking with the specified alpha.
1281 * Call and use result within the xrender_cs
1283 static Picture
get_mask_pict( int alpha
)
1285 static Pixmap pixmap
;
1286 static Picture pict
;
1287 static int current_alpha
;
1289 if (alpha
== 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1293 XRenderPictureAttributes pa
;
1295 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
1296 pa
.repeat
= RepeatNormal
;
1297 pict
= pXRenderCreatePicture( gdi_display
, pixmap
,
1298 pict_formats
[WXR_FORMAT_A8R8G8B8
], CPRepeat
, &pa
);
1302 if (alpha
!= current_alpha
)
1305 col
.red
= col
.green
= col
.blue
= 0;
1306 col
.alpha
= current_alpha
= alpha
;
1307 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
1312 /***********************************************************************
1313 * xrenderdrv_ExtTextOut
1315 static BOOL
xrenderdrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
,
1316 const RECT
*lprect
, LPCWSTR wstr
, UINT count
, const INT
*lpDx
)
1318 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1319 gsCacheEntry
*entry
;
1320 gsCacheEntryFormat
*formatEntry
;
1321 AA_Type aa_type
= AA_None
;
1323 Picture pict
, tile_pict
= 0;
1325 POINT offset
, desired
, current
;
1326 int render_op
= PictOpOver
;
1330 get_xrender_color( physdev
, GetTextColor( physdev
->dev
.hdc
), &col
);
1331 pict
= get_xrender_picture( physdev
, 0, (flags
& ETO_CLIPPED
) ? lprect
: NULL
);
1333 if(flags
& ETO_OPAQUE
)
1337 if (physdev
->format
== WXR_FORMAT_MONO
)
1338 /* use the inverse of the text color */
1339 bg
.red
= bg
.green
= bg
.blue
= bg
.alpha
= ~col
.alpha
;
1341 get_xrender_color( physdev
, GetBkColor( physdev
->dev
.hdc
), &bg
);
1343 set_xrender_transformation( pict
, 1, 1, 0, 0 );
1344 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &bg
,
1345 physdev
->x11dev
->dc_rect
.left
+ lprect
->left
,
1346 physdev
->x11dev
->dc_rect
.top
+ lprect
->top
,
1347 lprect
->right
- lprect
->left
,
1348 lprect
->bottom
- lprect
->top
);
1349 add_device_bounds( physdev
->x11dev
, lprect
);
1352 if(count
== 0) return TRUE
;
1354 EnterCriticalSection(&xrender_cs
);
1356 entry
= glyphsetCache
+ physdev
->cache_index
;
1357 aa_type
= entry
->aa_default
;
1358 formatEntry
= entry
->format
[aa_type
];
1360 for(idx
= 0; idx
< count
; idx
++) {
1361 if( !formatEntry
) {
1362 UploadGlyph(physdev
, wstr
[idx
], aa_type
);
1363 /* re-evaluate antialias since aa_default may have changed */
1364 aa_type
= entry
->aa_default
;
1365 formatEntry
= entry
->format
[aa_type
];
1366 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1367 UploadGlyph(physdev
, wstr
[idx
], aa_type
);
1372 WARN("could not upload requested glyphs\n");
1373 LeaveCriticalSection(&xrender_cs
);
1377 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1378 physdev
->x11dev
->dc_rect
.left
+ x
, physdev
->x11dev
->dc_rect
.top
+ y
);
1380 elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1382 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1383 So we pass zeros to the function and move to our starting position using the first
1384 element of the elts array. */
1386 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
;
1387 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
;
1388 offset
.x
= offset
.y
= 0;
1389 current
.x
= current
.y
= 0;
1391 tile_pict
= get_tile_pict(physdev
->format
, &col
);
1393 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1395 if (physdev
->format
== WXR_FORMAT_MONO
&& col
.red
== 0 && col
.green
== 0 && col
.blue
== 0)
1396 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1398 reset_bounds( &bounds
);
1399 for(idx
= 0; idx
< count
; idx
++)
1401 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1402 elts
[idx
].chars
= wstr
+ idx
;
1403 elts
[idx
].nchars
= 1;
1404 elts
[idx
].xOff
= desired
.x
- current
.x
;
1405 elts
[idx
].yOff
= desired
.y
- current
.y
;
1407 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1408 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1410 rect
.left
= desired
.x
- physdev
->x11dev
->dc_rect
.left
- formatEntry
->gis
[wstr
[idx
]].x
;
1411 rect
.top
= desired
.y
- physdev
->x11dev
->dc_rect
.top
- formatEntry
->gis
[wstr
[idx
]].y
;
1412 rect
.right
= rect
.left
+ formatEntry
->gis
[wstr
[idx
]].width
;
1413 rect
.bottom
= rect
.top
+ formatEntry
->gis
[wstr
[idx
]].height
;
1414 add_bounds_rect( &bounds
, &rect
);
1418 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1419 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1425 offset
.x
+= lpDx
[idx
* 2];
1426 offset
.y
+= lpDx
[idx
* 2 + 1];
1429 offset
.x
+= lpDx
[idx
];
1430 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
+ offset
.x
;
1431 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
+ offset
.y
;
1435 /* Make sure we don't have any transforms set from a previous call */
1436 set_xrender_transformation(pict
, 1, 1, 0, 0);
1437 pXRenderCompositeText16(gdi_display
, render_op
,
1440 formatEntry
->font_format
,
1441 0, 0, 0, 0, elts
, count
);
1442 HeapFree(GetProcessHeap(), 0, elts
);
1444 LeaveCriticalSection(&xrender_cs
);
1445 add_device_bounds( physdev
->x11dev
, &bounds
);
1449 /* multiply the alpha channel of a picture */
1450 static void multiply_alpha( Picture pict
, XRenderPictFormat
*format
, int alpha
,
1451 int x
, int y
, int width
, int height
)
1453 XRenderPictureAttributes pa
;
1454 Pixmap src_pixmap
, mask_pixmap
;
1455 Picture src_pict
, mask_pict
;
1458 src_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1459 mask_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1460 pa
.repeat
= RepeatNormal
;
1461 src_pict
= pXRenderCreatePicture( gdi_display
, src_pixmap
, format
, CPRepeat
, &pa
);
1462 pa
.component_alpha
= True
;
1463 mask_pict
= pXRenderCreatePicture( gdi_display
, mask_pixmap
, format
, CPRepeat
|CPComponentAlpha
, &pa
);
1464 color
.red
= color
.green
= color
.blue
= color
.alpha
= 0xffff;
1465 pXRenderFillRectangle( gdi_display
, PictOpSrc
, src_pict
, &color
, 0, 0, 1, 1 );
1466 color
.alpha
= alpha
;
1467 pXRenderFillRectangle( gdi_display
, PictOpSrc
, mask_pict
, &color
, 0, 0, 1, 1 );
1468 pXRenderComposite( gdi_display
, PictOpInReverse
, src_pict
, mask_pict
, pict
,
1469 0, 0, 0, 0, x
, y
, width
, height
);
1470 pXRenderFreePicture( gdi_display
, src_pict
);
1471 pXRenderFreePicture( gdi_display
, mask_pict
);
1472 XFreePixmap( gdi_display
, src_pixmap
);
1473 XFreePixmap( gdi_display
, mask_pixmap
);
1476 /* Helper function for (stretched) blitting using xrender */
1477 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
1478 int x_src
, int y_src
, int width_src
, int height_src
,
1479 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1480 double xscale
, double yscale
)
1482 int x_offset
, y_offset
;
1486 x_src
+= width_src
+ 1;
1487 width_src
= -width_src
;
1491 y_src
+= height_src
+ 1;
1492 height_src
= -height_src
;
1496 x_dst
+= width_dst
+ 1;
1497 width_dst
= -width_dst
;
1501 y_dst
+= height_dst
+ 1;
1502 height_dst
= -height_dst
;
1505 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1506 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1507 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1508 if(xscale
!= 1.0 || yscale
!= 1.0)
1510 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1511 * in the wrong quadrant of the x-y plane.
1513 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1514 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1515 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1521 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1523 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
1524 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width_dst
, height_dst
);
1527 /* Helper function for (stretched) mono->color blitting using xrender */
1528 static void xrender_mono_blit( Picture src_pict
, Picture dst_pict
,
1529 enum wxr_format dst_format
, XRenderColor
*fg
, XRenderColor
*bg
,
1530 int x_src
, int y_src
, int width_src
, int height_src
,
1531 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1532 double xscale
, double yscale
)
1535 int x_offset
, y_offset
;
1540 x_src
+= width_src
+ 1;
1541 width_src
= -width_src
;
1545 y_src
+= height_src
+ 1;
1546 height_src
= -height_src
;
1550 x_dst
+= width_dst
+ 1;
1551 width_dst
= -width_dst
;
1555 y_dst
+= height_dst
+ 1;
1556 height_dst
= -height_dst
;
1559 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1560 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1563 EnterCriticalSection( &xrender_cs
);
1565 color
.alpha
= 0xffff; /* tile pict needs 100% alpha */
1566 tile_pict
= get_tile_pict( dst_format
, &color
);
1568 pXRenderFillRectangle( gdi_display
, PictOpSrc
, dst_pict
, fg
, x_dst
, y_dst
, width_dst
, height_dst
);
1570 if (xscale
!= 1.0 || yscale
!= 1.0)
1572 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1573 * in the wrong quadrant of the x-y plane.
1575 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1576 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1577 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1583 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1585 pXRenderComposite(gdi_display
, PictOpOver
, tile_pict
, src_pict
, dst_pict
,
1586 0, 0, x_offset
, y_offset
, x_dst
, y_dst
, width_dst
, height_dst
);
1587 LeaveCriticalSection( &xrender_cs
);
1589 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1590 if (bg
->alpha
!= 0xffff && (dst_format
== WXR_FORMAT_A8R8G8B8
|| dst_format
== WXR_FORMAT_B8G8R8A8
))
1591 multiply_alpha( dst_pict
, pict_formats
[dst_format
], bg
->alpha
,
1592 x_dst
, y_dst
, width_dst
, height_dst
);
1595 /* create a pixmap and render picture for an image */
1596 static DWORD
create_image_pixmap( BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1597 struct bitblt_coords
*src
, enum wxr_format format
,
1598 Pixmap
*pixmap
, Picture
*pict
, BOOL
*use_repeat
)
1601 int width
= src
->visrect
.right
- src
->visrect
.left
;
1602 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1603 int depth
= pict_formats
[format
]->depth
;
1604 struct gdi_image_bits dst_bits
;
1605 XRenderPictureAttributes pa
;
1609 image
= XCreateImage( gdi_display
, default_visual
.visual
, depth
, ZPixmap
, 0, NULL
,
1610 info
->bmiHeader
.biWidth
, height
, 32, 0 );
1611 if (!image
) return ERROR_OUTOFMEMORY
;
1613 ret
= copy_image_bits( info
, (format
== WXR_FORMAT_R8G8B8
), image
, bits
, &dst_bits
, src
, NULL
, ~0u );
1614 if (ret
) return ret
;
1616 image
->data
= dst_bits
.ptr
;
1618 *use_repeat
= (width
== 1 && height
== 1);
1619 pa
.repeat
= *use_repeat
? RepeatNormal
: RepeatNone
;
1621 *pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, depth
);
1622 gc
= XCreateGC( gdi_display
, *pixmap
, 0, NULL
);
1623 XPutImage( gdi_display
, *pixmap
, gc
, image
, src
->visrect
.left
, 0, 0, 0, width
, height
);
1624 *pict
= pXRenderCreatePicture( gdi_display
, *pixmap
, pict_formats
[format
], CPRepeat
, &pa
);
1625 XFreeGC( gdi_display
, gc
);
1627 /* make coordinates relative to the pixmap */
1628 src
->x
-= src
->visrect
.left
;
1629 src
->y
-= src
->visrect
.top
;
1630 OffsetRect( &src
->visrect
, -src
->visrect
.left
, -src
->visrect
.top
);
1633 XDestroyImage( image
);
1634 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
1638 static void xrender_stretch_blit( struct xrender_physdev
*physdev_src
, struct xrender_physdev
*physdev_dst
,
1639 Drawable drawable
, const struct bitblt_coords
*src
,
1640 const struct bitblt_coords
*dst
)
1643 Picture src_pict
= 0, dst_pict
, mask_pict
= 0;
1644 double xscale
= src
->width
/ (double)dst
->width
;
1645 double yscale
= src
->height
/ (double)dst
->height
;
1647 if (drawable
) /* using an intermediate pixmap */
1651 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, physdev_dst
->pict_format
, 0, NULL
);
1655 x_dst
= physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
;
1656 y_dst
= physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
;
1657 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
1660 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
1663 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
1665 XRenderColor fg
, bg
;
1667 get_xrender_color( physdev_dst
, GetTextColor( physdev_dst
->dev
.hdc
), &fg
);
1668 get_xrender_color( physdev_dst
, GetBkColor( physdev_dst
->dev
.hdc
), &bg
);
1669 fg
.alpha
= bg
.alpha
= 0;
1671 xrender_mono_blit( src_pict
, dst_pict
, physdev_dst
->format
, &fg
, &bg
,
1672 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1673 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1674 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1676 else /* color -> color (can be at different depths) or mono -> mono */
1678 if (physdev_dst
->pict_format
->depth
== 32 && physdev_src
->pict_format
->depth
< 32)
1679 mask_pict
= get_no_alpha_mask();
1681 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
1682 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1683 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1684 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1687 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1691 static void xrender_put_image( Pixmap src_pixmap
, Picture src_pict
, Picture mask_pict
, HRGN clip
,
1692 XRenderPictFormat
*dst_format
, struct xrender_physdev
*physdev
,
1693 Drawable drawable
, struct bitblt_coords
*src
,
1694 struct bitblt_coords
*dst
, BOOL use_repeat
)
1698 double xscale
, yscale
;
1700 if (drawable
) /* using an intermediate pixmap */
1702 RGNDATA
*clip_data
= NULL
;
1704 if (clip
) clip_data
= X11DRV_GetRegionData( clip
, 0 );
1707 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, dst_format
, 0, NULL
);
1709 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
, 0, 0,
1710 (XRectangle
*)clip_data
->Buffer
, clip_data
->rdh
.nCount
);
1711 HeapFree( GetProcessHeap(), 0, clip_data
);
1715 x_dst
= physdev
->x11dev
->dc_rect
.left
+ dst
->x
;
1716 y_dst
= physdev
->x11dev
->dc_rect
.top
+ dst
->y
;
1717 dst_pict
= get_xrender_picture( physdev
, clip
, &dst
->visrect
);
1722 xscale
= src
->width
/ (double)dst
->width
;
1723 yscale
= src
->height
/ (double)dst
->height
;
1725 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
1727 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
, src
->x
, src
->y
, src
->width
, src
->height
,
1728 x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1730 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1734 /***********************************************************************
1735 * xrenderdrv_StretchBlt
1737 static BOOL
xrenderdrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
1738 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
1740 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
1741 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
1742 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
1744 if (src_dev
->funcs
!= dst_dev
->funcs
)
1746 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pStretchBlt
);
1747 return dst_dev
->funcs
->pStretchBlt( dst_dev
, dst
, src_dev
, src
, rop
);
1750 /* XRender is of no use for color -> mono */
1751 if (physdev_dst
->format
== WXR_FORMAT_MONO
&& physdev_src
->format
!= WXR_FORMAT_MONO
)
1752 goto x11drv_fallback
;
1754 /* if not stretching, we only need to handle format conversion */
1755 if (!stretch
&& physdev_dst
->format
== physdev_src
->format
) goto x11drv_fallback
;
1761 struct bitblt_coords tmp
;
1763 /* make coordinates relative to tmp pixmap */
1765 tmp
.x
-= tmp
.visrect
.left
;
1766 tmp
.y
-= tmp
.visrect
.top
;
1767 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
1769 tmpGC
= XCreateGC( gdi_display
, physdev_dst
->x11dev
->drawable
, 0, NULL
);
1770 XSetSubwindowMode( gdi_display
, tmpGC
, IncludeInferiors
);
1771 XSetGraphicsExposures( gdi_display
, tmpGC
, False
);
1772 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, tmp
.visrect
.right
- tmp
.visrect
.left
,
1773 tmp
.visrect
.bottom
- tmp
.visrect
.top
, physdev_dst
->pict_format
->depth
);
1775 xrender_stretch_blit( physdev_src
, physdev_dst
, tmp_pixmap
, src
, &tmp
);
1776 execute_rop( physdev_dst
->x11dev
, tmp_pixmap
, tmpGC
, &dst
->visrect
, rop
);
1778 XFreePixmap( gdi_display
, tmp_pixmap
);
1779 XFreeGC( gdi_display
, tmpGC
);
1781 else xrender_stretch_blit( physdev_src
, physdev_dst
, 0, src
, dst
);
1783 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
1787 return X11DRV_StretchBlt( &physdev_dst
->x11dev
->dev
, dst
, &physdev_src
->x11dev
->dev
, src
, rop
);
1791 /***********************************************************************
1792 * xrenderdrv_PutImage
1794 static DWORD
xrenderdrv_PutImage( PHYSDEV dev
, HRGN clip
, BITMAPINFO
*info
,
1795 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
1796 struct bitblt_coords
*dst
, DWORD rop
)
1798 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1802 enum wxr_format src_format
, dst_format
;
1803 XRenderPictFormat
*pict_format
;
1805 Picture src_pict
, mask_pict
= 0;
1808 dst_format
= physdev
->format
;
1809 src_format
= get_xrender_format_from_bitmapinfo( info
);
1810 if (!(pict_format
= pict_formats
[src_format
])) goto update_format
;
1812 /* make sure we can create an image with the same bpp */
1813 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
1816 /* mono <-> color conversions not supported */
1817 if ((src_format
!= dst_format
) && (src_format
== WXR_FORMAT_MONO
|| dst_format
== WXR_FORMAT_MONO
))
1818 goto x11drv_fallback
;
1820 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
1822 if (!has_alpha( src_format
) && has_alpha( dst_format
)) mask_pict
= get_no_alpha_mask();
1824 ret
= create_image_pixmap( info
, bits
, src
, src_format
, &src_pixmap
, &src_pict
, &use_repeat
);
1827 struct bitblt_coords tmp
;
1831 BOOL restore_region
= add_extra_clipping_region( physdev
->x11dev
, clip
);
1833 /* make coordinates relative to tmp pixmap */
1835 tmp
.x
-= tmp
.visrect
.left
;
1836 tmp
.y
-= tmp
.visrect
.top
;
1837 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
1839 gc
= XCreateGC( gdi_display
, physdev
->x11dev
->drawable
, 0, NULL
);
1840 XSetSubwindowMode( gdi_display
, gc
, IncludeInferiors
);
1841 XSetGraphicsExposures( gdi_display
, gc
, False
);
1842 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
,
1843 tmp
.visrect
.right
- tmp
.visrect
.left
,
1844 tmp
.visrect
.bottom
- tmp
.visrect
.top
,
1845 physdev
->pict_format
->depth
);
1847 xrender_put_image( src_pixmap
, src_pict
, mask_pict
, NULL
, physdev
->pict_format
,
1848 NULL
, tmp_pixmap
, src
, &tmp
, use_repeat
);
1849 execute_rop( physdev
->x11dev
, tmp_pixmap
, gc
, &dst
->visrect
, rop
);
1851 XFreePixmap( gdi_display
, tmp_pixmap
);
1852 XFreeGC( gdi_display
, gc
);
1853 if (restore_region
) restore_clipping_region( physdev
->x11dev
);
1855 else xrender_put_image( src_pixmap
, src_pict
, mask_pict
, clip
,
1856 physdev
->pict_format
, physdev
, 0, src
, dst
, use_repeat
);
1858 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
1860 pXRenderFreePicture( gdi_display
, src_pict
);
1861 XFreePixmap( gdi_display
, src_pixmap
);
1866 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
1867 set_color_info( pict_formats
[dst_format
], info
);
1868 return ERROR_BAD_FORMAT
;
1871 dev
= GET_NEXT_PHYSDEV( dev
, pPutImage
);
1872 return dev
->funcs
->pPutImage( dev
, clip
, info
, bits
, src
, dst
, rop
);
1876 /***********************************************************************
1877 * xrenderdrv_BlendImage
1879 static DWORD
xrenderdrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1880 struct bitblt_coords
*src
, struct bitblt_coords
*dst
,
1881 BLENDFUNCTION func
)
1883 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1885 enum wxr_format format
;
1886 XRenderPictFormat
*pict_format
;
1887 Picture dst_pict
, src_pict
, mask_pict
;
1891 format
= get_xrender_format_from_bitmapinfo( info
);
1892 if (!(func
.AlphaFormat
& AC_SRC_ALPHA
))
1893 format
= get_format_without_alpha( format
);
1894 else if (format
!= WXR_FORMAT_A8R8G8B8
|| info
->bmiHeader
.biCompression
!= BI_RGB
)
1895 return ERROR_INVALID_PARAMETER
;
1897 if (!(pict_format
= pict_formats
[format
])) goto update_format
;
1899 /* make sure we can create an image with the same bpp */
1900 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
1903 if (format
== WXR_FORMAT_MONO
&& physdev
->format
!= WXR_FORMAT_MONO
)
1906 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
1908 ret
= create_image_pixmap( info
, bits
, src
, format
, &src_pixmap
, &src_pict
, &use_repeat
);
1911 double xscale
, yscale
;
1915 xscale
= src
->width
/ (double)dst
->width
;
1916 yscale
= src
->height
/ (double)dst
->height
;
1918 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
1920 dst_pict
= get_xrender_picture( physdev
, 0, &dst
->visrect
);
1922 EnterCriticalSection( &xrender_cs
);
1923 mask_pict
= get_mask_pict( func
.SourceConstantAlpha
* 257 );
1925 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
1926 src
->x
, src
->y
, src
->width
, src
->height
,
1927 physdev
->x11dev
->dc_rect
.left
+ dst
->x
,
1928 physdev
->x11dev
->dc_rect
.top
+ dst
->y
,
1929 dst
->width
, dst
->height
, xscale
, yscale
);
1931 pXRenderFreePicture( gdi_display
, src_pict
);
1932 XFreePixmap( gdi_display
, src_pixmap
);
1934 LeaveCriticalSection( &xrender_cs
);
1935 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
1940 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
1941 set_color_info( physdev
->pict_format
, info
);
1942 return ERROR_BAD_FORMAT
;
1946 /***********************************************************************
1947 * xrenderdrv_AlphaBlend
1949 static BOOL
xrenderdrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
1950 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
1952 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
1953 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
1954 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
1955 XRenderPictureAttributes pa
;
1956 Pixmap tmp_pixmap
= 0;
1957 double xscale
, yscale
;
1959 if (src_dev
->funcs
!= dst_dev
->funcs
)
1961 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pAlphaBlend
);
1962 return dst_dev
->funcs
->pAlphaBlend( dst_dev
, dst
, src_dev
, src
, blendfn
);
1965 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->format
!= WXR_FORMAT_A8R8G8B8
)
1967 SetLastError( ERROR_INVALID_PARAMETER
);
1971 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
1973 xscale
= src
->width
/ (double)dst
->width
;
1974 yscale
= src
->height
/ (double)dst
->height
;
1976 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
1978 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
1980 /* mono -> color blending needs an intermediate color pixmap */
1981 XRenderColor fg
, bg
;
1982 int width
= src
->visrect
.right
- src
->visrect
.left
;
1983 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1985 /* blending doesn't use the destination DC colors */
1986 fg
.red
= fg
.green
= fg
.blue
= 0;
1987 bg
.red
= bg
.green
= bg
.blue
= 0xffff;
1988 fg
.alpha
= bg
.alpha
= 0xffff;
1990 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
,
1991 physdev_dst
->pict_format
->depth
);
1992 tmp_pict
= pXRenderCreatePicture( gdi_display
, tmp_pixmap
, physdev_dst
->pict_format
, 0, NULL
);
1994 xrender_mono_blit( src_pict
, tmp_pict
, physdev_dst
->format
, &fg
, &bg
,
1995 src
->visrect
.left
, src
->visrect
.top
, width
, height
, 0, 0, width
, height
, 1, 1 );
1997 else if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->pict_format
)
1999 /* we need a source picture with no alpha */
2000 enum wxr_format format
= get_format_without_alpha( physdev_src
->format
);
2001 if (format
!= physdev_src
->format
)
2003 pa
.subwindow_mode
= IncludeInferiors
;
2004 tmp_pict
= pXRenderCreatePicture( gdi_display
, physdev_src
->x11dev
->drawable
,
2005 pict_formats
[format
], CPSubwindowMode
, &pa
);
2009 if (tmp_pict
) src_pict
= tmp_pict
;
2011 EnterCriticalSection( &xrender_cs
);
2012 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
2014 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2015 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
2016 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
2017 src
->width
, src
->height
,
2018 physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
,
2019 physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
,
2020 dst
->width
, dst
->height
, xscale
, yscale
);
2022 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
2023 if (tmp_pixmap
) XFreePixmap( gdi_display
, tmp_pixmap
);
2025 LeaveCriticalSection( &xrender_cs
);
2026 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
2030 /***********************************************************************
2031 * xrenderdrv_GradientFill
2033 static BOOL
xrenderdrv_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
2034 void * grad_array
, ULONG ngrad
, ULONG mode
)
2036 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2037 static const XFixed stops
[2] = { 0, 1 << 16 };
2038 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2039 XLinearGradient gradient
;
2040 XRenderColor colors
[2];
2041 Picture src_pict
, dst_pict
;
2043 const GRADIENT_RECT
*rect
= grad_array
;
2047 if (!pXRenderCreateLinearGradient
) goto fallback
;
2049 /* <= 16-bpp uses dithering */
2050 if (!physdev
->pict_format
|| physdev
->pict_format
->depth
<= 16) goto fallback
;
2054 case GRADIENT_FILL_RECT_H
:
2055 case GRADIENT_FILL_RECT_V
:
2056 for (i
= 0; i
< ngrad
; i
++, rect
++)
2058 const TRIVERTEX
*v1
= vert_array
+ rect
->UpperLeft
;
2059 const TRIVERTEX
*v2
= vert_array
+ rect
->LowerRight
;
2061 colors
[0].red
= v1
->Red
* 257 / 256;
2062 colors
[0].green
= v1
->Green
* 257 / 256;
2063 colors
[0].blue
= v1
->Blue
* 257 / 256;
2064 colors
[1].red
= v2
->Red
* 257 / 256;
2065 colors
[1].green
= v2
->Green
* 257 / 256;
2066 colors
[1].blue
= v2
->Blue
* 257 / 256;
2067 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2068 colors
[0].alpha
= colors
[1].alpha
= 65535;
2074 LPtoDP( dev
->hdc
, pt
, 2 );
2075 if (mode
== GRADIENT_FILL_RECT_H
)
2077 gradient
.p1
.y
= gradient
.p2
.y
= 0;
2078 if (pt
[1].x
> pt
[0].x
)
2081 gradient
.p2
.x
= (pt
[1].x
- pt
[0].x
) << 16;
2085 gradient
.p1
.x
= (pt
[0].x
- pt
[1].x
) << 16;
2091 gradient
.p1
.x
= gradient
.p2
.x
= 0;
2092 if (pt
[1].y
> pt
[0].y
)
2095 gradient
.p2
.y
= (pt
[1].y
- pt
[0].y
) << 16;
2099 gradient
.p1
.y
= (pt
[0].y
- pt
[1].y
) << 16;
2104 rc
.left
= min( pt
[0].x
, pt
[1].x
);
2105 rc
.top
= min( pt
[0].y
, pt
[1].y
);
2106 rc
.right
= max( pt
[0].x
, pt
[1].x
);
2107 rc
.bottom
= max( pt
[0].y
, pt
[1].y
);
2109 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2110 mode
, wine_dbgstr_rect( &rc
),
2111 colors
[0].red
, colors
[0].green
, colors
[0].blue
, colors
[0].alpha
,
2112 colors
[1].red
, colors
[1].green
, colors
[1].blue
, colors
[1].alpha
);
2114 dst_pict
= get_xrender_picture( physdev
, 0, NULL
);
2116 src_pict
= pXRenderCreateLinearGradient( gdi_display
, &gradient
, stops
, colors
, 2 );
2117 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
,
2118 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
2119 physdev
->x11dev
->dc_rect
.left
+ rc
.left
,
2120 physdev
->x11dev
->dc_rect
.top
+ rc
.top
,
2121 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, 1, 1 );
2122 pXRenderFreePicture( gdi_display
, src_pict
);
2123 add_device_bounds( physdev
->x11dev
, &rc
);
2130 dev
= GET_NEXT_PHYSDEV( dev
, pGradientFill
);
2131 return dev
->funcs
->pGradientFill( dev
, vert_array
, nvert
, grad_array
, ngrad
, mode
);
2134 /***********************************************************************
2135 * xrenderdrv_SelectBrush
2137 static HBRUSH
xrenderdrv_SelectBrush( PHYSDEV dev
, HBRUSH hbrush
, const struct brush_pattern
*pattern
)
2139 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2141 XVisualInfo vis
= default_visual
;
2142 XRenderPictFormat
*format
= physdev
->pict_format
;
2144 if (!pattern
) goto x11drv_fallback
;
2145 if (pattern
->info
->bmiHeader
.biBitCount
== 1) goto x11drv_fallback
;
2146 if (physdev
->format
== WXR_FORMAT_MONO
) goto x11drv_fallback
;
2148 vis
.depth
= format
->depth
;
2149 vis
.red_mask
= format
->direct
.redMask
<< format
->direct
.red
;
2150 vis
.green_mask
= format
->direct
.greenMask
<< format
->direct
.green
;
2151 vis
.blue_mask
= format
->direct
.blueMask
<< format
->direct
.blue
;
2153 pixmap
= create_pixmap_from_image( physdev
->dev
.hdc
, &vis
, pattern
->info
,
2154 &pattern
->bits
, pattern
->usage
);
2155 if (!pixmap
) return 0;
2157 if (physdev
->x11dev
->brush
.pixmap
) XFreePixmap( gdi_display
, physdev
->x11dev
->brush
.pixmap
);
2158 physdev
->x11dev
->brush
.pixmap
= pixmap
;
2159 physdev
->x11dev
->brush
.fillStyle
= FillTiled
;
2160 physdev
->x11dev
->brush
.pixel
= 0; /* ignored */
2161 physdev
->x11dev
->brush
.style
= BS_PATTERN
;
2165 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBrush
);
2166 return dev
->funcs
->pSelectBrush( dev
, hbrush
, pattern
);
2170 static const struct gdi_dc_funcs xrender_funcs
=
2172 NULL
, /* pAbortDoc */
2173 NULL
, /* pAbortPath */
2174 xrenderdrv_AlphaBlend
, /* pAlphaBlend */
2175 NULL
, /* pAngleArc */
2178 NULL
, /* pBeginPath */
2179 xrenderdrv_BlendImage
, /* pBlendImage */
2181 NULL
, /* pCloseFigure */
2182 xrenderdrv_CreateCompatibleDC
, /* pCreateCompatibleDC */
2183 xrenderdrv_CreateDC
, /* pCreateDC */
2184 xrenderdrv_DeleteDC
, /* pDeleteDC */
2185 NULL
, /* pDeleteObject */
2186 NULL
, /* pDeviceCapabilities */
2187 NULL
, /* pEllipse */
2189 NULL
, /* pEndPage */
2190 NULL
, /* pEndPath */
2191 NULL
, /* pEnumFonts */
2192 NULL
, /* pEnumICMProfiles */
2193 NULL
, /* pExcludeClipRect */
2194 NULL
, /* pExtDeviceMode */
2195 xrenderdrv_ExtEscape
, /* pExtEscape */
2196 NULL
, /* pExtFloodFill */
2197 NULL
, /* pExtSelectClipRgn */
2198 xrenderdrv_ExtTextOut
, /* pExtTextOut */
2199 NULL
, /* pFillPath */
2200 NULL
, /* pFillRgn */
2201 NULL
, /* pFlattenPath */
2202 NULL
, /* pFontIsLinked */
2203 NULL
, /* pFrameRgn */
2204 NULL
, /* pGdiComment */
2205 NULL
, /* pGdiRealizationInfo */
2206 NULL
, /* pGetBoundsRect */
2207 NULL
, /* pGetCharABCWidths */
2208 NULL
, /* pGetCharABCWidthsI */
2209 NULL
, /* pGetCharWidth */
2210 NULL
, /* pGetDeviceCaps */
2211 NULL
, /* pGetDeviceGammaRamp */
2212 NULL
, /* pGetFontData */
2213 NULL
, /* pGetFontUnicodeRanges */
2214 NULL
, /* pGetGlyphIndices */
2215 NULL
, /* pGetGlyphOutline */
2216 NULL
, /* pGetICMProfile */
2217 NULL
, /* pGetImage */
2218 NULL
, /* pGetKerningPairs */
2219 NULL
, /* pGetNearestColor */
2220 NULL
, /* pGetOutlineTextMetrics */
2221 NULL
, /* pGetPixel */
2222 NULL
, /* pGetSystemPaletteEntries */
2223 NULL
, /* pGetTextCharsetInfo */
2224 NULL
, /* pGetTextExtentExPoint */
2225 NULL
, /* pGetTextExtentExPointI */
2226 NULL
, /* pGetTextFace */
2227 NULL
, /* pGetTextMetrics */
2228 xrenderdrv_GradientFill
, /* pGradientFill */
2229 NULL
, /* pIntersectClipRect */
2230 NULL
, /* pInvertRgn */
2232 NULL
, /* pModifyWorldTransform */
2234 NULL
, /* pOffsetClipRgn */
2235 NULL
, /* pOffsetViewportOrg */
2236 NULL
, /* pOffsetWindowOrg */
2237 NULL
, /* pPaintRgn */
2240 NULL
, /* pPolyBezier */
2241 NULL
, /* pPolyBezierTo */
2242 NULL
, /* pPolyDraw */
2243 NULL
, /* pPolyPolygon */
2244 NULL
, /* pPolyPolyline */
2245 NULL
, /* pPolygon */
2246 NULL
, /* pPolyline */
2247 NULL
, /* pPolylineTo */
2248 xrenderdrv_PutImage
, /* pPutImage */
2249 NULL
, /* pRealizeDefaultPalette */
2250 NULL
, /* pRealizePalette */
2251 NULL
, /* pRectangle */
2252 NULL
, /* pResetDC */
2253 NULL
, /* pRestoreDC */
2254 NULL
, /* pRoundRect */
2256 NULL
, /* pScaleViewportExt */
2257 NULL
, /* pScaleWindowExt */
2258 NULL
, /* pSelectBitmap */
2259 xrenderdrv_SelectBrush
, /* pSelectBrush */
2260 NULL
, /* pSelectClipPath */
2261 xrenderdrv_SelectFont
, /* pSelectFont */
2262 NULL
, /* pSelectPalette */
2263 NULL
, /* pSelectPen */
2264 NULL
, /* pSetArcDirection */
2265 NULL
, /* pSetBkColor */
2266 NULL
, /* pSetBkMode */
2267 NULL
, /* pSetBoundsRect */
2268 NULL
, /* pSetDCBrushColor */
2269 NULL
, /* pSetDCPenColor */
2270 NULL
, /* pSetDIBitsToDevice */
2271 xrenderdrv_SetDeviceClipping
, /* pSetDeviceClipping */
2272 NULL
, /* pSetDeviceGammaRamp */
2273 NULL
, /* pSetLayout */
2274 NULL
, /* pSetMapMode */
2275 NULL
, /* pSetMapperFlags */
2276 NULL
, /* pSetPixel */
2277 NULL
, /* pSetPolyFillMode */
2278 NULL
, /* pSetROP2 */
2279 NULL
, /* pSetRelAbs */
2280 NULL
, /* pSetStretchBltMode */
2281 NULL
, /* pSetTextAlign */
2282 NULL
, /* pSetTextCharacterExtra */
2283 NULL
, /* pSetTextColor */
2284 NULL
, /* pSetTextJustification */
2285 NULL
, /* pSetViewportExt */
2286 NULL
, /* pSetViewportOrg */
2287 NULL
, /* pSetWindowExt */
2288 NULL
, /* pSetWindowOrg */
2289 NULL
, /* pSetWorldTransform */
2290 NULL
, /* pStartDoc */
2291 NULL
, /* pStartPage */
2292 xrenderdrv_StretchBlt
, /* pStretchBlt */
2293 NULL
, /* pStretchDIBits */
2294 NULL
, /* pStrokeAndFillPath */
2295 NULL
, /* pStrokePath */
2296 NULL
, /* pUnrealizePalette */
2297 NULL
, /* pWidenPath */
2298 NULL
, /* wine_get_wgl_driver */
2299 GDI_PRIORITY_GRAPHICS_DRV
+ 10 /* priority */
2302 #else /* SONAME_LIBXRENDER */
2304 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
2306 TRACE("XRender support not compiled in.\n");
2310 #endif /* SONAME_LIBXRENDER */