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 int using_client_side_fonts
= FALSE
;
43 WINE_DEFAULT_DEBUG_CHANNEL(xrender
);
45 #ifdef SONAME_LIBXRENDER
47 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
49 static BOOL X11DRV_XRender_Installed
= FALSE
;
52 #include <X11/extensions/Xrender.h>
54 #ifndef RepeatNone /* added in 0.10 */
56 #define RepeatNormal 1
58 #define RepeatReflect 3
76 WXR_INVALID_FORMAT
= WXR_NB_FORMATS
79 typedef struct wine_xrender_format_template
83 unsigned int alphaMask
;
87 unsigned int greenMask
;
89 unsigned int blueMask
;
90 } WineXRenderFormatTemplate
;
92 static const WineXRenderFormatTemplate wxr_formats_template
[WXR_NB_FORMATS
] =
94 /* Format depth alpha mask red mask green mask blue mask*/
95 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
96 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
97 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
98 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
99 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
100 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
101 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
103 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
105 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
106 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
109 static const ColorShifts wxr_color_shifts
[WXR_NB_FORMATS
] =
111 /* format phys red phys green phys blue log red log green log blue */
112 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
113 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
114 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
115 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
116 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
117 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
118 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
120 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
121 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
122 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
123 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
126 static enum wxr_format default_format
= WXR_INVALID_FORMAT
;
127 static XRenderPictFormat
*pict_formats
[WXR_NB_FORMATS
+ 1 /* invalid format */];
133 SIZE devsize
; /* size in device coords */
137 #define INITIAL_REALIZED_BUF_SIZE 128
139 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
144 XRenderPictFormat
*font_format
;
148 } gsCacheEntryFormat
;
154 gsCacheEntryFormat
* format
[AA_MAXVALUE
];
159 struct xrender_physdev
161 struct gdi_physdev dev
;
162 X11DRV_PDEVICE
*x11dev
;
163 enum wxr_format format
;
168 XRenderPictFormat
*pict_format
;
171 static inline struct xrender_physdev
*get_xrender_dev( PHYSDEV dev
)
173 return (struct xrender_physdev
*)dev
;
176 static const struct gdi_dc_funcs xrender_funcs
;
178 static gsCacheEntry
*glyphsetCache
= NULL
;
179 static DWORD glyphsetCacheSize
= 0;
180 static INT lastfree
= -1;
183 #define INIT_CACHE_SIZE 10
185 static int antialias
= 1;
187 static void *xrender_handle
;
189 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
190 MAKE_FUNCPTR(XRenderAddGlyphs
)
191 MAKE_FUNCPTR(XRenderChangePicture
)
192 MAKE_FUNCPTR(XRenderComposite
)
193 MAKE_FUNCPTR(XRenderCompositeText16
)
194 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
195 MAKE_FUNCPTR(XRenderCreatePicture
)
196 MAKE_FUNCPTR(XRenderFillRectangle
)
197 MAKE_FUNCPTR(XRenderFindFormat
)
198 MAKE_FUNCPTR(XRenderFindVisualFormat
)
199 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
200 MAKE_FUNCPTR(XRenderFreePicture
)
201 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
202 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
203 MAKE_FUNCPTR(XRenderCreateLinearGradient
)
205 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
206 MAKE_FUNCPTR(XRenderSetPictureTransform
)
208 MAKE_FUNCPTR(XRenderQueryExtension
)
210 #ifdef SONAME_LIBFONTCONFIG
211 #include <fontconfig/fontconfig.h>
212 MAKE_FUNCPTR(FcConfigSubstitute
)
213 MAKE_FUNCPTR(FcDefaultSubstitute
)
214 MAKE_FUNCPTR(FcFontMatch
)
216 MAKE_FUNCPTR(FcPatternCreate
)
217 MAKE_FUNCPTR(FcPatternDestroy
)
218 MAKE_FUNCPTR(FcPatternAddInteger
)
219 MAKE_FUNCPTR(FcPatternAddString
)
220 MAKE_FUNCPTR(FcPatternGetBool
)
221 MAKE_FUNCPTR(FcPatternGetInteger
)
222 MAKE_FUNCPTR(FcPatternGetString
)
223 static void *fontconfig_handle
;
224 static BOOL fontconfig_installed
;
229 static CRITICAL_SECTION xrender_cs
;
230 static CRITICAL_SECTION_DEBUG critsect_debug
=
233 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
234 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
236 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
238 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
239 ( ( (ULONG)_x4 << 24 ) | \
240 ( (ULONG)_x3 << 16 ) | \
241 ( (ULONG)_x2 << 8 ) | \
244 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
246 #define GASP_GRIDFIT 0x01
247 #define GASP_DOGRAY 0x02
249 #ifdef WORDS_BIGENDIAN
250 #define get_be_word(x) (x)
251 #define NATIVE_BYTE_ORDER MSBFirst
253 #define get_be_word(x) RtlUshortByteSwap(x)
254 #define NATIVE_BYTE_ORDER LSBFirst
257 static BOOL
has_alpha( enum wxr_format format
)
259 return (format
== WXR_FORMAT_A8R8G8B8
|| format
== WXR_FORMAT_B8G8R8A8
);
262 static enum wxr_format
get_format_without_alpha( enum wxr_format format
)
266 case WXR_FORMAT_A8R8G8B8
: return WXR_FORMAT_X8R8G8B8
;
267 case WXR_FORMAT_B8G8R8A8
: return WXR_FORMAT_B8G8R8X8
;
268 default: return format
;
272 static BOOL
get_xrender_template(const WineXRenderFormatTemplate
*fmt
, XRenderPictFormat
*templ
, unsigned long *mask
)
275 templ
->type
= PictTypeDirect
;
276 templ
->depth
= fmt
->depth
;
277 templ
->direct
.alpha
= fmt
->alpha
;
278 templ
->direct
.alphaMask
= fmt
->alphaMask
;
279 templ
->direct
.red
= fmt
->red
;
280 templ
->direct
.redMask
= fmt
->redMask
;
281 templ
->direct
.green
= fmt
->green
;
282 templ
->direct
.greenMask
= fmt
->greenMask
;
283 templ
->direct
.blue
= fmt
->blue
;
284 templ
->direct
.blueMask
= fmt
->blueMask
;
287 *mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
| PictFormatRed
| PictFormatRedMask
| PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
| PictFormatBlueMask
;
292 static BOOL
is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate
*fmt
)
294 if(fmt
->depth
!= screen_depth
)
296 if( (fmt
->redMask
<< fmt
->red
) != visual
->red_mask
)
298 if( (fmt
->greenMask
<< fmt
->green
) != visual
->green_mask
)
300 if( (fmt
->blueMask
<< fmt
->blue
) != visual
->blue_mask
)
303 /* We never select a default ARGB visual */
310 static int load_xrender_formats(void)
315 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
317 XRenderPictFormat templ
;
319 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template
[i
]))
322 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, visual
);
323 if (!pict_formats
[i
])
325 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
326 if (visual
->class == DirectColor
)
329 if (XMatchVisualInfo( gdi_display
, DefaultScreen(gdi_display
),
330 screen_depth
, TrueColor
, &info
))
332 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, info
.visual
);
333 if (pict_formats
[i
]) visual
= info
.visual
;
338 if (pict_formats
[i
]) default_format
= i
;
342 unsigned long mask
= 0;
343 get_xrender_template(&wxr_formats_template
[i
], &templ
, &mask
);
346 pict_formats
[i
] = pXRenderFindFormat(gdi_display
, mask
, &templ
, 0);
352 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats
[i
]->id
, i
);
358 /***********************************************************************
359 * X11DRV_XRender_Init
361 * Let's see if our XServer has the extension available
364 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
368 using_client_side_fonts
= client_side_with_render
|| client_side_with_core
;
370 if (!client_side_with_render
) return NULL
;
371 if (!(xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0))) return NULL
;
373 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
374 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
375 LOAD_FUNCPTR(XRenderAddGlyphs
);
376 LOAD_FUNCPTR(XRenderChangePicture
);
377 LOAD_FUNCPTR(XRenderComposite
);
378 LOAD_FUNCPTR(XRenderCompositeText16
);
379 LOAD_FUNCPTR(XRenderCreateGlyphSet
);
380 LOAD_FUNCPTR(XRenderCreatePicture
);
381 LOAD_FUNCPTR(XRenderFillRectangle
);
382 LOAD_FUNCPTR(XRenderFindFormat
);
383 LOAD_FUNCPTR(XRenderFindVisualFormat
);
384 LOAD_FUNCPTR(XRenderFreeGlyphSet
);
385 LOAD_FUNCPTR(XRenderFreePicture
);
386 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
);
387 LOAD_FUNCPTR(XRenderQueryExtension
);
388 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
389 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient
);
391 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
392 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
);
394 #undef LOAD_OPTIONAL_FUNCPTR
398 X11DRV_XRender_Installed
= pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
);
400 if (!X11DRV_XRender_Installed
) return NULL
;
402 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
403 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
405 ERR_(winediag
)("Wine has detected that you probably have a buggy version "
406 "of libXrender. Because of this client side font rendering "
407 "will be disabled. Please upgrade this library.\n");
408 X11DRV_XRender_Installed
= FALSE
;
412 if (!visual
->red_mask
|| !visual
->green_mask
|| !visual
->blue_mask
)
414 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
415 X11DRV_XRender_Installed
= FALSE
;
419 #ifdef SONAME_LIBFONTCONFIG
420 if ((fontconfig_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0)))
422 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fontconfig_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
423 LOAD_FUNCPTR(FcConfigSubstitute
);
424 LOAD_FUNCPTR(FcDefaultSubstitute
);
425 LOAD_FUNCPTR(FcFontMatch
);
426 LOAD_FUNCPTR(FcInit
);
427 LOAD_FUNCPTR(FcPatternCreate
);
428 LOAD_FUNCPTR(FcPatternDestroy
);
429 LOAD_FUNCPTR(FcPatternAddInteger
);
430 LOAD_FUNCPTR(FcPatternAddString
);
431 LOAD_FUNCPTR(FcPatternGetBool
);
432 LOAD_FUNCPTR(FcPatternGetInteger
);
433 LOAD_FUNCPTR(FcPatternGetString
);
435 fontconfig_installed
= pFcInit();
437 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG
"\n" );
442 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
443 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
445 glyphsetCacheSize
= INIT_CACHE_SIZE
;
447 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
448 glyphsetCache
[i
].next
= i
+ 1;
449 glyphsetCache
[i
].count
= -1;
451 glyphsetCache
[i
-1].next
= -1;
453 if(screen_depth
<= 8 || !client_side_antialias_with_render
) antialias
= 0;
455 return &xrender_funcs
;
458 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
459 static void get_xrender_color( XRenderPictFormat
*pf
, int src_color
, XRenderColor
*dst_color
)
461 if(pf
->direct
.redMask
)
462 dst_color
->red
= ((src_color
>> pf
->direct
.red
) & pf
->direct
.redMask
) * 65535/pf
->direct
.redMask
;
466 if(pf
->direct
.greenMask
)
467 dst_color
->green
= ((src_color
>> pf
->direct
.green
) & pf
->direct
.greenMask
) * 65535/pf
->direct
.greenMask
;
469 dst_color
->green
= 0;
471 if(pf
->direct
.blueMask
)
472 dst_color
->blue
= ((src_color
>> pf
->direct
.blue
) & pf
->direct
.blueMask
) * 65535/pf
->direct
.blueMask
;
476 dst_color
->alpha
= 0xffff;
479 static enum wxr_format
get_xrender_format_from_color_shifts(int depth
, ColorShifts
*shifts
)
481 int redMask
, greenMask
, blueMask
;
484 if (depth
== 1) return WXR_FORMAT_MONO
;
486 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
487 if (!shifts
) return default_format
;
489 redMask
= shifts
->physicalRed
.max
<< shifts
->physicalRed
.shift
;
490 greenMask
= shifts
->physicalGreen
.max
<< shifts
->physicalGreen
.shift
;
491 blueMask
= shifts
->physicalBlue
.max
<< shifts
->physicalBlue
.shift
;
493 /* Try to locate a format which matches the specification of the dibsection. */
494 for(i
= 0; i
< WXR_NB_FORMATS
; i
++)
496 if( depth
== wxr_formats_template
[i
].depth
&&
497 redMask
== (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
498 greenMask
== (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
499 blueMask
== (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
) )
503 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
504 ERR("No XRender format found for %u %08x/%08x/%08x\n", depth
, redMask
, greenMask
, blueMask
);
505 return WXR_INVALID_FORMAT
;
508 static enum wxr_format
get_xrender_format_from_bitmapinfo( const BITMAPINFO
*info
)
510 if (info
->bmiHeader
.biPlanes
!= 1) return WXR_INVALID_FORMAT
;
512 switch (info
->bmiHeader
.biBitCount
)
515 return WXR_FORMAT_MONO
;
520 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
521 return WXR_FORMAT_R8G8B8
;
524 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
526 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
529 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
531 if (info
->bmiHeader
.biBitCount
== wxr_formats_template
[i
].depth
&&
532 colors
[0] == (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
533 colors
[1] == (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
534 colors
[2] == (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
))
539 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
540 return (info
->bmiHeader
.biBitCount
== 16) ? WXR_FORMAT_X1R5G5B5
: WXR_FORMAT_A8R8G8B8
;
542 return WXR_INVALID_FORMAT
;
545 static enum wxr_format
get_bitmap_format( int bpp
)
547 enum wxr_format format
= WXR_INVALID_FORMAT
;
549 if (bpp
== screen_bpp
)
553 case 16: format
= WXR_FORMAT_R5G6B5
; break;
554 case 24: format
= WXR_FORMAT_R8G8B8
; break;
555 case 32: format
= WXR_FORMAT_A8R8G8B8
; break;
561 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
562 static void set_xrender_transformation(Picture src_pict
, double xscale
, double yscale
, int xoffset
, int yoffset
)
564 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
565 XTransform xform
= {{
566 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(xoffset
) },
567 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(yoffset
) },
568 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
571 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
575 /* check if we can use repeating instead of scaling for the specified source DC */
576 static BOOL
use_source_repeat( struct xrender_physdev
*dev
)
578 return (dev
->x11dev
->bitmap
&&
579 dev
->x11dev
->drawable_rect
.right
- dev
->x11dev
->drawable_rect
.left
== 1 &&
580 dev
->x11dev
->drawable_rect
.bottom
- dev
->x11dev
->drawable_rect
.top
== 1);
583 static void update_xrender_clipping( struct xrender_physdev
*dev
, HRGN rgn
)
585 XRenderPictureAttributes pa
;
592 pXRenderChangePicture( gdi_display
, dev
->pict
, CPClipMask
, &pa
);
595 else if ((data
= X11DRV_GetRegionData( rgn
, 0 )))
598 pXRenderSetPictureClipRectangles( gdi_display
, dev
->pict
,
599 dev
->x11dev
->dc_rect
.left
, dev
->x11dev
->dc_rect
.top
,
600 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
602 HeapFree( GetProcessHeap(), 0, data
);
607 static Picture
get_xrender_picture( struct xrender_physdev
*dev
, HRGN clip_rgn
, const RECT
*clip_rect
)
609 if (!dev
->pict
&& dev
->pict_format
)
611 XRenderPictureAttributes pa
;
614 pa
.subwindow_mode
= IncludeInferiors
;
615 dev
->pict
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
616 dev
->pict_format
, CPSubwindowMode
, &pa
);
618 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
619 dev
->pict
, dev
->dev
.hdc
, dev
->x11dev
->drawable
);
620 dev
->update_clip
= (dev
->x11dev
->region
!= 0);
625 HRGN rgn
= CreateRectRgnIndirect( clip_rect
);
626 if (clip_rgn
) CombineRgn( rgn
, rgn
, clip_rgn
, RGN_AND
);
627 if (dev
->x11dev
->region
) CombineRgn( rgn
, rgn
, dev
->x11dev
->region
, RGN_AND
);
628 update_xrender_clipping( dev
, rgn
);
633 if (dev
->x11dev
->region
)
635 HRGN rgn
= CreateRectRgn( 0, 0, 0, 0 );
636 CombineRgn( rgn
, clip_rgn
, dev
->x11dev
->region
, RGN_AND
);
637 update_xrender_clipping( dev
, rgn
);
640 else update_xrender_clipping( dev
, clip_rgn
);
642 else if (dev
->update_clip
) update_xrender_clipping( dev
, dev
->x11dev
->region
);
644 dev
->update_clip
= (clip_rect
|| clip_rgn
); /* have to update again if we are using a custom region */
648 static Picture
get_xrender_picture_source( struct xrender_physdev
*dev
, BOOL repeat
)
650 if (!dev
->pict_src
&& dev
->pict_format
)
652 XRenderPictureAttributes pa
;
655 pa
.subwindow_mode
= IncludeInferiors
;
656 pa
.repeat
= repeat
? RepeatNormal
: RepeatNone
;
657 dev
->pict_src
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
658 dev
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
661 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
662 dev
->pict_src
, dev
->dev
.hdc
, dev
->x11dev
->drawable
, pa
.repeat
);
665 return dev
->pict_src
;
668 static void free_xrender_picture( struct xrender_physdev
*dev
)
670 if (dev
->pict
|| dev
->pict_src
)
673 XFlush( gdi_display
);
676 TRACE("freeing pict = %lx dc = %p\n", dev
->pict
, dev
->dev
.hdc
);
677 pXRenderFreePicture(gdi_display
, dev
->pict
);
682 TRACE("freeing pict = %lx dc = %p\n", dev
->pict_src
, dev
->dev
.hdc
);
683 pXRenderFreePicture(gdi_display
, dev
->pict_src
);
690 /* return a mask picture used to force alpha to 0 */
691 static Picture
get_no_alpha_mask(void)
693 static Pixmap pixmap
;
699 XRenderPictureAttributes pa
;
702 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
703 pa
.repeat
= RepeatNormal
;
704 pa
.component_alpha
= True
;
705 pict
= pXRenderCreatePicture( gdi_display
, pixmap
, pict_formats
[WXR_FORMAT_A8R8G8B8
],
706 CPRepeat
|CPComponentAlpha
, &pa
);
707 col
.red
= col
.green
= col
.blue
= 0xffff;
709 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
715 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
717 if(p1
->hash
!= p2
->hash
) return TRUE
;
718 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
719 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
720 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
721 return strcmpiW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
725 static void walk_cache(void)
729 EnterCriticalSection(&xrender_cs
);
730 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
731 TRACE("item %d\n", i
);
732 LeaveCriticalSection(&xrender_cs
);
736 static int LookupEntry(LFANDSIZE
*plfsz
)
740 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
742 if(glyphsetCache
[i
].count
== -1) break; /* reached free list so stop */
744 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
745 glyphsetCache
[i
].count
++;
747 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
748 glyphsetCache
[i
].next
= mru
;
751 TRACE("found font in cache %d\n", i
);
756 TRACE("font not in cache\n");
760 static void FreeEntry(int entry
)
764 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
765 gsCacheEntryFormat
* formatEntry
;
767 if( !glyphsetCache
[entry
].format
[format
] )
770 formatEntry
= glyphsetCache
[entry
].format
[format
];
772 if(formatEntry
->glyphset
) {
774 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
776 formatEntry
->glyphset
= 0;
778 if(formatEntry
->nrealized
) {
779 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
780 formatEntry
->realized
= NULL
;
781 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
782 formatEntry
->gis
= NULL
;
783 formatEntry
->nrealized
= 0;
786 HeapFree(GetProcessHeap(), 0, formatEntry
);
787 glyphsetCache
[entry
].format
[format
] = NULL
;
791 static int AllocEntry(void)
793 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
796 assert(glyphsetCache
[lastfree
].count
== -1);
797 glyphsetCache
[lastfree
].count
= 1;
799 lastfree
= glyphsetCache
[lastfree
].next
;
801 glyphsetCache
[best
].next
= mru
;
804 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
808 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
809 if(glyphsetCache
[i
].count
== 0) {
817 TRACE("freeing unused glyphset at cache %d\n", best
);
819 glyphsetCache
[best
].count
= 1;
821 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
822 glyphsetCache
[best
].next
= mru
;
830 TRACE("Growing cache\n");
833 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
835 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
836 * sizeof(*glyphsetCache
));
838 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
839 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
840 * sizeof(*glyphsetCache
));
842 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
844 glyphsetCache
[i
].next
= i
+ 1;
845 glyphsetCache
[i
].count
= -1;
847 glyphsetCache
[i
-1].next
= -1;
848 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
850 lastfree
= glyphsetCache
[best
].next
;
851 glyphsetCache
[best
].count
= 1;
852 glyphsetCache
[best
].next
= mru
;
854 TRACE("new free cache slot at %d\n", mru
);
858 static BOOL
get_gasp_flags(HDC hdc
, WORD
*flags
)
868 size
= GetFontData(hdc
, MS_GASP_TAG
, 0, NULL
, 0);
869 if(size
== GDI_ERROR
)
872 gasp
= buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
873 GetFontData(hdc
, MS_GASP_TAG
, 0, gasp
, size
);
875 GetTextMetricsW(hdc
, &tm
);
876 ppem
= abs(X11DRV_YWStoDS(hdc
, tm
.tmAscent
+ tm
.tmDescent
- tm
.tmInternalLeading
));
879 num_recs
= get_be_word(*gasp
);
883 *flags
= get_be_word(*(gasp
+ 1));
884 if(ppem
<= get_be_word(*gasp
))
888 TRACE("got flags %04x for ppem %d\n", *flags
, ppem
);
890 HeapFree(GetProcessHeap(), 0, buffer
);
894 static AA_Type
get_antialias_type( HDC hdc
, BOOL subpixel
, BOOL hinter
)
898 UINT font_smoothing_type
, font_smoothing_orientation
;
900 if (X11DRV_XRender_Installed
&& subpixel
&&
901 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE
, 0, &font_smoothing_type
, 0) &&
902 font_smoothing_type
== FE_FONTSMOOTHINGCLEARTYPE
)
904 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION
, 0,
905 &font_smoothing_orientation
, 0) &&
906 font_smoothing_orientation
== FE_FONTSMOOTHINGORIENTATIONBGR
)
913 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
914 But, Wine's subpixel rendering can support the portrait mode.
917 else if (!hinter
|| !get_gasp_flags(hdc
, &flags
) || flags
& GASP_DOGRAY
)
925 static int GetCacheEntry( HDC hdc
, LFANDSIZE
*plfsz
)
930 static int hinter
= -1;
931 static int subpixel
= -1;
934 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
937 entry
= glyphsetCache
+ ret
;
938 entry
->lfsz
= *plfsz
;
939 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
940 assert( !entry
->format
[format
] );
943 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
945 if(hinter
== -1 || subpixel
== -1)
947 RASTERIZER_STATUS status
;
948 GetRasterizerCaps(&status
, sizeof(status
));
949 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
950 subpixel
= status
.wFlags
& WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
953 switch (plfsz
->lf
.lfQuality
)
955 case ANTIALIASED_QUALITY
:
956 entry
->aa_default
= get_antialias_type( hdc
, FALSE
, hinter
);
957 return ret
; /* ignore further configuration */
958 case CLEARTYPE_QUALITY
:
959 case CLEARTYPE_NATURAL_QUALITY
:
960 entry
->aa_default
= get_antialias_type( hdc
, subpixel
, hinter
);
962 case DEFAULT_QUALITY
:
966 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING
, 0, &font_smoothing
, 0) &&
969 entry
->aa_default
= get_antialias_type( hdc
, subpixel
, hinter
);
972 entry
->aa_default
= AA_None
;
976 font_smoothing
= TRUE
; /* default to enabled */
977 #ifdef SONAME_LIBFONTCONFIG
978 if (fontconfig_installed
)
980 FcPattern
*match
, *pattern
;
982 char family
[LF_FACESIZE
* 4];
984 #if defined(__i386__) && defined(__GNUC__)
985 /* fontconfig generates floating point exceptions, mask them */
986 WORD cw
, default_cw
= 0x37f;
987 __asm__
__volatile__("fnstcw %0; fldcw %1" : "=m" (cw
) : "m" (default_cw
));
990 WideCharToMultiByte( CP_UTF8
, 0, plfsz
->lf
.lfFaceName
, -1, family
, sizeof(family
), NULL
, NULL
);
991 pattern
= pFcPatternCreate();
992 pFcPatternAddString( pattern
, FC_FAMILY
, (FcChar8
*)family
);
993 if (plfsz
->lf
.lfWeight
!= FW_DONTCARE
)
996 switch (plfsz
->lf
.lfWeight
)
998 case FW_THIN
: weight
= FC_WEIGHT_THIN
; break;
999 case FW_EXTRALIGHT
: weight
= FC_WEIGHT_EXTRALIGHT
; break;
1000 case FW_LIGHT
: weight
= FC_WEIGHT_LIGHT
; break;
1001 case FW_NORMAL
: weight
= FC_WEIGHT_NORMAL
; break;
1002 case FW_MEDIUM
: weight
= FC_WEIGHT_MEDIUM
; break;
1003 case FW_SEMIBOLD
: weight
= FC_WEIGHT_SEMIBOLD
; break;
1004 case FW_BOLD
: weight
= FC_WEIGHT_BOLD
; break;
1005 case FW_EXTRABOLD
: weight
= FC_WEIGHT_EXTRABOLD
; break;
1006 case FW_HEAVY
: weight
= FC_WEIGHT_HEAVY
; break;
1007 default: weight
= (plfsz
->lf
.lfWeight
- 80) / 4; break;
1009 pFcPatternAddInteger( pattern
, FC_WEIGHT
, weight
);
1011 pFcPatternAddInteger( pattern
, FC_SLANT
, plfsz
->lf
.lfItalic
? FC_SLANT_ITALIC
: FC_SLANT_ROMAN
);
1012 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1013 pFcDefaultSubstitute( pattern
);
1014 if ((match
= pFcFontMatch( NULL
, pattern
, &result
)))
1019 if (pFcPatternGetBool( match
, FC_ANTIALIAS
, 0, &antialias
) != FcResultMatch
)
1021 if (pFcPatternGetInteger( match
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
1024 if (pFcPatternGetString( match
, FC_FILE
, 0, &file
) != FcResultMatch
) file
= NULL
;
1026 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
1027 rgba
, antialias
, debugstr_w(plfsz
->lf
.lfFaceName
), debugstr_a((char *)file
) );
1031 case FC_RGBA_RGB
: entry
->aa_default
= AA_RGB
; break;
1032 case FC_RGBA_BGR
: entry
->aa_default
= AA_BGR
; break;
1033 case FC_RGBA_VRGB
: entry
->aa_default
= AA_VRGB
; break;
1034 case FC_RGBA_VBGR
: entry
->aa_default
= AA_VBGR
; break;
1035 case FC_RGBA_NONE
: entry
->aa_default
= AA_Grey
; break;
1038 if (!antialias
) font_smoothing
= FALSE
;
1039 pFcPatternDestroy( match
);
1041 pFcPatternDestroy( pattern
);
1043 #if defined(__i386__) && defined(__GNUC__)
1044 __asm__
__volatile__("fnclex; fldcw %0" : : "m" (cw
));
1047 #endif /* SONAME_LIBFONTCONFIG */
1049 /* now check Xft resources */
1052 BOOL antialias
= TRUE
;
1055 if ((value
= XGetDefault( gdi_display
, "Xft", "antialias" )))
1057 if (tolower(value
[0]) == 'f' || tolower(value
[0]) == 'n' ||
1058 value
[0] == '0' || !strcasecmp( value
, "off" ))
1061 if ((value
= XGetDefault( gdi_display
, "Xft", "rgba" )))
1063 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value
, antialias
);
1064 if (!strcmp( value
, "rgb" )) entry
->aa_default
= AA_RGB
;
1065 else if (!strcmp( value
, "bgr" )) entry
->aa_default
= AA_BGR
;
1066 else if (!strcmp( value
, "vrgb" )) entry
->aa_default
= AA_VRGB
;
1067 else if (!strcmp( value
, "vbgr" )) entry
->aa_default
= AA_VBGR
;
1068 else if (!strcmp( value
, "none" )) entry
->aa_default
= AA_Grey
;
1070 wine_tsx11_unlock();
1071 if (!antialias
) font_smoothing
= FALSE
;
1074 if (!font_smoothing
) entry
->aa_default
= AA_None
;
1076 /* we can't support subpixel without xrender */
1077 if (!X11DRV_XRender_Installed
&& entry
->aa_default
> AA_Grey
) entry
->aa_default
= AA_Grey
;
1080 entry
->aa_default
= AA_None
;
1085 static void dec_ref_cache(int index
)
1088 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
1089 assert(glyphsetCache
[index
].count
> 0);
1090 glyphsetCache
[index
].count
--;
1093 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
1095 DWORD hash
= 0, *ptr
, two_chars
;
1099 hash
^= plfsz
->devsize
.cx
;
1100 hash
^= plfsz
->devsize
.cy
;
1101 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
1103 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
1105 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
1107 pwc
= (WCHAR
*)&two_chars
;
1109 *pwc
= toupperW(*pwc
);
1111 *pwc
= toupperW(*pwc
);
1119 /***********************************************************************
1120 * X11DRV_XRender_Finalize
1122 void X11DRV_XRender_Finalize(void)
1126 EnterCriticalSection(&xrender_cs
);
1127 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
1129 LeaveCriticalSection(&xrender_cs
);
1130 DeleteCriticalSection(&xrender_cs
);
1133 /**********************************************************************
1134 * xrenderdrv_SelectFont
1136 static HFONT
xrenderdrv_SelectFont( PHYSDEV dev
, HFONT hfont
)
1138 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1139 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
1140 HFONT ret
= next
->funcs
->pSelectFont( next
, hfont
);
1144 if (physdev
->x11dev
->has_gdi_font
)
1148 GetObjectW( hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
1150 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1151 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
1152 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
1153 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
1154 lfsz
.devsize
.cx
= X11DRV_XWStoDS( dev
->hdc
, lfsz
.lf
.lfWidth
);
1155 lfsz
.devsize
.cy
= X11DRV_YWStoDS( dev
->hdc
, lfsz
.lf
.lfHeight
);
1157 GetTransform( dev
->hdc
, 0x204, &lfsz
.xform
);
1158 TRACE("font transform %f %f %f %f\n", lfsz
.xform
.eM11
, lfsz
.xform
.eM12
,
1159 lfsz
.xform
.eM21
, lfsz
.xform
.eM22
);
1161 /* Not used fields, would break hashing */
1162 lfsz
.xform
.eDx
= lfsz
.xform
.eDy
= 0;
1164 lfsz_calc_hash(&lfsz
);
1166 EnterCriticalSection(&xrender_cs
);
1167 if (physdev
->cache_index
!= -1)
1168 dec_ref_cache( physdev
->cache_index
);
1169 physdev
->cache_index
= GetCacheEntry( dev
->hdc
, &lfsz
);
1170 LeaveCriticalSection(&xrender_cs
);
1174 EnterCriticalSection( &xrender_cs
);
1175 if (physdev
->cache_index
!= -1) dec_ref_cache( physdev
->cache_index
);
1176 physdev
->cache_index
= -1;
1177 LeaveCriticalSection( &xrender_cs
);
1182 static BOOL
create_xrender_dc( PHYSDEV
*pdev
, enum wxr_format format
)
1184 X11DRV_PDEVICE
*x11dev
= get_x11drv_dev( *pdev
);
1185 struct xrender_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
1187 if (!physdev
) return FALSE
;
1188 physdev
->x11dev
= x11dev
;
1189 physdev
->cache_index
= -1;
1190 physdev
->format
= format
;
1191 physdev
->pict_format
= pict_formats
[format
];
1192 push_dc_driver( pdev
, &physdev
->dev
, &xrender_funcs
);
1196 /* store the color mask data in the bitmap info structure */
1197 static void set_color_info( XRenderPictFormat
*format
, BITMAPINFO
*info
)
1199 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
1201 info
->bmiHeader
.biPlanes
= 1;
1202 info
->bmiHeader
.biBitCount
= pixmap_formats
[format
->depth
]->bits_per_pixel
;
1203 info
->bmiHeader
.biCompression
= BI_RGB
;
1204 info
->bmiHeader
.biClrUsed
= 0;
1206 switch (info
->bmiHeader
.biBitCount
)
1209 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
1210 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
1211 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
1212 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1215 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
1216 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
1217 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
1218 if (colors
[0] != 0xff0000 || colors
[1] != 0x00ff00 || colors
[2] != 0x0000ff)
1219 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1225 /**********************************************************************
1226 * xrenderdrv_CreateDC
1228 static BOOL
xrenderdrv_CreateDC( PHYSDEV
*pdev
, LPCWSTR driver
, LPCWSTR device
,
1229 LPCWSTR output
, const DEVMODEW
* initData
)
1231 return create_xrender_dc( pdev
, default_format
);
1234 /**********************************************************************
1235 * xrenderdrv_CreateCompatibleDC
1237 static BOOL
xrenderdrv_CreateCompatibleDC( PHYSDEV orig
, PHYSDEV
*pdev
)
1239 if (orig
) /* chain to x11drv first */
1241 orig
= GET_NEXT_PHYSDEV( orig
, pCreateCompatibleDC
);
1242 if (!orig
->funcs
->pCreateCompatibleDC( orig
, pdev
)) return FALSE
;
1244 /* otherwise we have been called by x11drv */
1246 return create_xrender_dc( pdev
, WXR_FORMAT_MONO
);
1249 /**********************************************************************
1250 * xrenderdrv_DeleteDC
1252 static BOOL
xrenderdrv_DeleteDC( PHYSDEV dev
)
1254 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1256 free_xrender_picture( physdev
);
1258 EnterCriticalSection( &xrender_cs
);
1259 if (physdev
->cache_index
!= -1) dec_ref_cache( physdev
->cache_index
);
1260 LeaveCriticalSection( &xrender_cs
);
1262 HeapFree( GetProcessHeap(), 0, physdev
);
1266 /**********************************************************************
1267 * xrenderdrv_ExtEscape
1269 static INT
xrenderdrv_ExtEscape( PHYSDEV dev
, INT escape
, INT in_count
, LPCVOID in_data
,
1270 INT out_count
, LPVOID out_data
)
1272 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1274 dev
= GET_NEXT_PHYSDEV( dev
, pExtEscape
);
1276 if (escape
== X11DRV_ESCAPE
&& in_data
&& in_count
>= sizeof(enum x11drv_escape_codes
))
1278 if (*(const enum x11drv_escape_codes
*)in_data
== X11DRV_SET_DRAWABLE
)
1280 BOOL ret
= dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
1281 if (ret
) free_xrender_picture( physdev
); /* pict format doesn't change, only drawable */
1285 return dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
1288 /****************************************************************************
1289 * xrenderdrv_CopyBitmap
1291 static BOOL
xrenderdrv_CopyBitmap( HBITMAP src
, HBITMAP dst
)
1293 return X11DRV_CopyBitmap( src
, dst
);
1296 /****************************************************************************
1297 * xrenderdrv_CreateBitmap
1299 static BOOL
xrenderdrv_CreateBitmap( PHYSDEV dev
, HBITMAP hbitmap
)
1301 enum wxr_format format
;
1304 if (!GetObjectW( hbitmap
, sizeof(bitmap
), &bitmap
)) return FALSE
;
1306 format
= get_bitmap_format( bitmap
.bmBitsPixel
);
1308 if (pict_formats
[format
])
1309 return X11DRV_create_phys_bitmap( hbitmap
, &bitmap
, pict_formats
[format
]->depth
,
1310 TRUE
, &wxr_color_shifts
[format
] );
1312 dev
= GET_NEXT_PHYSDEV( dev
, pCreateBitmap
);
1313 return dev
->funcs
->pCreateBitmap( dev
, hbitmap
);
1316 /****************************************************************************
1317 * xrenderdrv_DeleteBitmap
1319 static BOOL
xrenderdrv_DeleteBitmap( HBITMAP hbitmap
)
1321 return X11DRV_DeleteBitmap( hbitmap
);
1324 /***********************************************************************
1325 * xrenderdrv_SelectBitmap
1327 static HBITMAP
xrenderdrv_SelectBitmap( PHYSDEV dev
, HBITMAP hbitmap
)
1330 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1332 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBitmap
);
1333 ret
= dev
->funcs
->pSelectBitmap( dev
, hbitmap
);
1336 free_xrender_picture( physdev
);
1337 physdev
->format
= get_xrender_format_from_color_shifts( physdev
->x11dev
->depth
,
1338 physdev
->x11dev
->color_shifts
);
1339 physdev
->pict_format
= pict_formats
[physdev
->format
];
1344 /***********************************************************************
1345 * xrenderdrv_GetImage
1347 static DWORD
xrenderdrv_GetImage( PHYSDEV dev
, HBITMAP hbitmap
, BITMAPINFO
*info
,
1348 struct gdi_image_bits
*bits
, struct bitblt_coords
*src
)
1350 if (hbitmap
) return X11DRV_GetImage( dev
, hbitmap
, info
, bits
, src
);
1351 dev
= GET_NEXT_PHYSDEV( dev
, pGetImage
);
1352 return dev
->funcs
->pGetImage( dev
, hbitmap
, info
, bits
, src
);
1355 /***********************************************************************
1356 * xrenderdrv_SetDeviceClipping
1358 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev
, HRGN rgn
)
1360 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1362 physdev
->update_clip
= TRUE
;
1364 dev
= GET_NEXT_PHYSDEV( dev
, pSetDeviceClipping
);
1365 dev
->funcs
->pSetDeviceClipping( dev
, rgn
);
1369 BOOL
X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP
*physBitmap
, int bits_pixel
, const DIBSECTION
*dib
)
1371 XRenderPictFormat
*pict_format
;
1373 const DWORD
*bitfields
;
1374 static const DWORD bitfields_32
[3] = {0xff0000, 0x00ff00, 0x0000ff};
1375 static const DWORD bitfields_16
[3] = {0x7c00, 0x03e0, 0x001f};
1378 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1379 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1380 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1381 if (!X11DRV_XRender_Installed
|| bits_pixel
<= 8)
1384 if(dib
->dsBmih
.biCompression
== BI_BITFIELDS
)
1385 bitfields
= dib
->dsBitfields
;
1386 else if(bits_pixel
== 24 || bits_pixel
== 32)
1387 bitfields
= bitfields_32
;
1389 bitfields
= bitfields_16
;
1391 X11DRV_PALETTE_ComputeColorShifts(&shifts
, bitfields
[0], bitfields
[1], bitfields
[2]);
1392 pict_format
= pict_formats
[get_xrender_format_from_color_shifts(dib
->dsBm
.bmBitsPixel
, &shifts
)];
1394 /* Common formats should be in our picture format table. */
1397 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1398 dib
->dsBm
.bmBitsPixel
, bitfields
[0], bitfields
[1], bitfields
[2]);
1402 physBitmap
->depth
= pict_format
->depth
;
1403 physBitmap
->trueColor
= TRUE
;
1404 physBitmap
->color_shifts
= shifts
;
1408 /************************************************************************
1411 * Helper to ExtTextOut. Must be called inside xrender_cs
1413 static void UploadGlyph(struct xrender_physdev
*physDev
, int glyph
, AA_Type format
)
1415 unsigned int buflen
;
1420 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->cache_index
;
1421 gsCacheEntryFormat
*formatEntry
;
1422 UINT ggo_format
= GGO_GLYPH_INDEX
;
1423 enum wxr_format wxr_format
;
1424 static const char zero
[4];
1425 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
1429 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
1432 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
1435 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
1438 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
1441 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
1445 ERR("aa = %d - not implemented\n", format
);
1447 ggo_format
|= GGO_BITMAP
;
1451 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1452 if(buflen
== GDI_ERROR
) {
1453 if(format
!= AA_None
) {
1455 entry
->aa_default
= AA_None
;
1456 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
1457 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1459 if(buflen
== GDI_ERROR
) {
1460 WARN("GetGlyphOutlineW failed using default glyph\n");
1461 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0, ggo_format
, &gm
, 0, NULL
, &identity
);
1462 if(buflen
== GDI_ERROR
) {
1463 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1464 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0x20, ggo_format
, &gm
, 0, NULL
, &identity
);
1465 if(buflen
== GDI_ERROR
) {
1466 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1471 TRACE("Turning off antialiasing for this monochrome font\n");
1474 /* If there is nothing for the current type, we create the entry. */
1475 if( !entry
->format
[format
] ) {
1476 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
1478 sizeof(gsCacheEntryFormat
));
1480 formatEntry
= entry
->format
[format
];
1482 if(formatEntry
->nrealized
<= glyph
) {
1483 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
1485 if (formatEntry
->realized
)
1486 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
1488 formatEntry
->realized
,
1489 formatEntry
->nrealized
* sizeof(BOOL
));
1491 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
1493 formatEntry
->nrealized
* sizeof(BOOL
));
1495 if (formatEntry
->gis
)
1496 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
1499 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1501 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
1503 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1507 if(formatEntry
->glyphset
== 0) {
1510 wxr_format
= WXR_FORMAT_GRAY
;
1517 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1521 ERR("aa = %d - not implemented\n", format
);
1523 wxr_format
= WXR_FORMAT_MONO
;
1528 formatEntry
->font_format
= pict_formats
[wxr_format
];
1529 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
1530 wine_tsx11_unlock();
1534 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
1535 GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
1536 formatEntry
->realized
[glyph
] = TRUE
;
1538 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1540 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1541 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1543 gi
.width
= gm
.gmBlackBoxX
;
1544 gi
.height
= gm
.gmBlackBoxY
;
1545 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1546 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1547 gi
.xOff
= gm
.gmCellIncX
;
1548 gi
.yOff
= gm
.gmCellIncY
;
1550 if(TRACE_ON(xrender
)) {
1553 unsigned char *line
;
1555 if(format
== AA_None
) {
1556 pitch
= ((gi
.width
+ 31) / 32) * 4;
1557 for(i
= 0; i
< gi
.height
; i
++) {
1558 line
= (unsigned char*) buf
+ i
* pitch
;
1560 for(j
= 0; j
< pitch
* 8; j
++) {
1561 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1563 TRACE("%s\n", output
);
1566 static const char blks
[] = " .:;!o*#";
1570 pitch
= ((gi
.width
+ 3) / 4) * 4;
1571 for(i
= 0; i
< gi
.height
; i
++) {
1572 line
= (unsigned char*) buf
+ i
* pitch
;
1574 for(j
= 0; j
< pitch
; j
++) {
1575 str
[0] = blks
[line
[j
] >> 5];
1576 strcat(output
, str
);
1578 TRACE("%s\n", output
);
1584 if(formatEntry
->glyphset
) {
1585 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1586 unsigned char *byte
= (unsigned char*) buf
, c
;
1592 /* magic to flip bit order */
1593 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1594 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1595 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1600 else if ( format
!= AA_Grey
&&
1601 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1603 unsigned int i
, *data
= (unsigned int *)buf
;
1604 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1609 XRenderCompositeText seems to ignore 0x0 glyphs when
1610 AA_None, which means we lose the advance width of glyphs
1611 like the space. We'll pretend that such glyphs are 1x1
1616 gi
.width
= gi
.height
= 1;
1619 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1620 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1621 wine_tsx11_unlock();
1622 HeapFree(GetProcessHeap(), 0, buf
);
1625 formatEntry
->gis
[glyph
] = gi
;
1628 /*************************************************************
1631 * Returns an appropriate Picture for tiling the text colour.
1632 * Call and use result within the xrender_cs
1634 static Picture
get_tile_pict( enum wxr_format wxr_format
, const XRenderColor
*color
)
1640 XRenderColor current_color
;
1641 } tiles
[WXR_NB_FORMATS
], *tile
;
1643 tile
= &tiles
[wxr_format
];
1647 XRenderPictureAttributes pa
;
1648 XRenderPictFormat
*pict_format
= pict_formats
[wxr_format
];
1651 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_format
->depth
);
1653 pa
.repeat
= RepeatNormal
;
1654 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_format
, CPRepeat
, &pa
);
1655 wine_tsx11_unlock();
1657 /* init current_color to something different from text_pixel */
1658 tile
->current_color
= *color
;
1659 tile
->current_color
.red
^= 0xffff;
1661 if (wxr_format
== WXR_FORMAT_MONO
)
1663 /* for a 1bpp bitmap we always need a 1 in the tile */
1665 col
.red
= col
.green
= col
.blue
= 0;
1668 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1669 wine_tsx11_unlock();
1673 if (memcmp( color
, &tile
->current_color
, sizeof(*color
) ) && wxr_format
!= WXR_FORMAT_MONO
)
1676 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, color
, 0, 0, 1, 1);
1677 wine_tsx11_unlock();
1678 tile
->current_color
= *color
;
1683 /*************************************************************
1686 * Returns an appropriate Picture for masking with the specified alpha.
1687 * Call and use result within the xrender_cs
1689 static Picture
get_mask_pict( int alpha
)
1691 static Pixmap pixmap
;
1692 static Picture pict
;
1693 static int current_alpha
;
1695 if (alpha
== 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1699 XRenderPictureAttributes pa
;
1702 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
1703 pa
.repeat
= RepeatNormal
;
1704 pict
= pXRenderCreatePicture( gdi_display
, pixmap
,
1705 pict_formats
[WXR_FORMAT_A8R8G8B8
], CPRepeat
, &pa
);
1706 wine_tsx11_unlock();
1710 if (alpha
!= current_alpha
)
1713 col
.red
= col
.green
= col
.blue
= 0;
1714 col
.alpha
= current_alpha
= alpha
;
1716 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
1717 wine_tsx11_unlock();
1722 /***********************************************************************
1723 * xrenderdrv_ExtTextOut
1725 static BOOL
xrenderdrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
,
1726 const RECT
*lprect
, LPCWSTR wstr
, UINT count
, const INT
*lpDx
)
1728 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1730 gsCacheEntry
*entry
;
1731 gsCacheEntryFormat
*formatEntry
;
1732 int textPixel
, backgroundPixel
;
1733 AA_Type aa_type
= AA_None
;
1735 Picture pict
, tile_pict
= 0;
1737 POINT offset
, desired
, current
;
1738 int render_op
= PictOpOver
;
1741 if (!X11DRV_XRender_Installed
|| !physdev
->x11dev
->has_gdi_font
)
1743 dev
= GET_NEXT_PHYSDEV( dev
, pExtTextOut
);
1744 return dev
->funcs
->pExtTextOut( dev
, x
, y
, flags
, lprect
, wstr
, count
, lpDx
);
1747 xgcval
.function
= GXcopy
;
1748 xgcval
.background
= physdev
->x11dev
->backgroundPixel
;
1749 xgcval
.fill_style
= FillSolid
;
1751 XChangeGC( gdi_display
, physdev
->x11dev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1752 wine_tsx11_unlock();
1754 X11DRV_LockDIBSection( physdev
->x11dev
, DIB_Status_GdiMod
);
1756 if(physdev
->x11dev
->depth
== 1) {
1757 if((physdev
->x11dev
->textPixel
& 0xffffff) == 0) {
1759 backgroundPixel
= 1;
1762 backgroundPixel
= 0;
1765 textPixel
= physdev
->x11dev
->textPixel
;
1766 backgroundPixel
= physdev
->x11dev
->backgroundPixel
;
1769 if(flags
& ETO_OPAQUE
)
1772 XSetForeground( gdi_display
, physdev
->x11dev
->gc
, backgroundPixel
);
1773 XFillRectangle( gdi_display
, physdev
->x11dev
->drawable
, physdev
->x11dev
->gc
,
1774 physdev
->x11dev
->dc_rect
.left
+ lprect
->left
, physdev
->x11dev
->dc_rect
.top
+ lprect
->top
,
1775 lprect
->right
- lprect
->left
, lprect
->bottom
- lprect
->top
);
1776 wine_tsx11_unlock();
1781 X11DRV_UnlockDIBSection( physdev
->x11dev
, TRUE
);
1785 EnterCriticalSection(&xrender_cs
);
1787 entry
= glyphsetCache
+ physdev
->cache_index
;
1788 aa_type
= entry
->aa_default
;
1789 formatEntry
= entry
->format
[aa_type
];
1791 for(idx
= 0; idx
< count
; idx
++) {
1792 if( !formatEntry
) {
1793 UploadGlyph(physdev
, wstr
[idx
], aa_type
);
1794 /* re-evaluate antialias since aa_default may have changed */
1795 aa_type
= entry
->aa_default
;
1796 formatEntry
= entry
->format
[aa_type
];
1797 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1798 UploadGlyph(physdev
, wstr
[idx
], aa_type
);
1803 WARN("could not upload requested glyphs\n");
1804 LeaveCriticalSection(&xrender_cs
);
1805 X11DRV_UnlockDIBSection( physdev
->x11dev
, TRUE
);
1809 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1810 physdev
->x11dev
->dc_rect
.left
+ x
, physdev
->x11dev
->dc_rect
.top
+ y
);
1812 elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1813 pict
= get_xrender_picture( physdev
, 0, (flags
& ETO_CLIPPED
) ? lprect
: NULL
);
1815 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1816 So we pass zeros to the function and move to our starting position using the first
1817 element of the elts array. */
1819 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
;
1820 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
;
1821 offset
.x
= offset
.y
= 0;
1822 current
.x
= current
.y
= 0;
1824 get_xrender_color(physdev
->pict_format
, physdev
->x11dev
->textPixel
, &col
);
1825 tile_pict
= get_tile_pict(physdev
->format
, &col
);
1827 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1829 if((physdev
->format
== WXR_FORMAT_MONO
) && (textPixel
== 0))
1830 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1832 for(idx
= 0; idx
< count
; idx
++)
1834 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1835 elts
[idx
].chars
= wstr
+ idx
;
1836 elts
[idx
].nchars
= 1;
1837 elts
[idx
].xOff
= desired
.x
- current
.x
;
1838 elts
[idx
].yOff
= desired
.y
- current
.y
;
1840 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1841 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1845 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1846 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1852 offset
.x
+= lpDx
[idx
* 2];
1853 offset
.y
+= lpDx
[idx
* 2 + 1];
1856 offset
.x
+= lpDx
[idx
];
1857 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
+ offset
.x
;
1858 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
+ offset
.y
;
1863 /* Make sure we don't have any transforms set from a previous call */
1864 set_xrender_transformation(pict
, 1, 1, 0, 0);
1865 pXRenderCompositeText16(gdi_display
, render_op
,
1868 formatEntry
->font_format
,
1869 0, 0, 0, 0, elts
, count
);
1870 wine_tsx11_unlock();
1871 HeapFree(GetProcessHeap(), 0, elts
);
1873 LeaveCriticalSection(&xrender_cs
);
1874 X11DRV_UnlockDIBSection( physdev
->x11dev
, TRUE
);
1878 /* multiply the alpha channel of a picture */
1879 static void multiply_alpha( Picture pict
, XRenderPictFormat
*format
, int alpha
,
1880 int x
, int y
, int width
, int height
)
1882 XRenderPictureAttributes pa
;
1883 Pixmap src_pixmap
, mask_pixmap
;
1884 Picture src_pict
, mask_pict
;
1888 src_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1889 mask_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1890 pa
.repeat
= RepeatNormal
;
1891 src_pict
= pXRenderCreatePicture( gdi_display
, src_pixmap
, format
, CPRepeat
, &pa
);
1892 pa
.component_alpha
= True
;
1893 mask_pict
= pXRenderCreatePicture( gdi_display
, mask_pixmap
, format
, CPRepeat
|CPComponentAlpha
, &pa
);
1894 color
.red
= color
.green
= color
.blue
= color
.alpha
= 0xffff;
1895 pXRenderFillRectangle( gdi_display
, PictOpSrc
, src_pict
, &color
, 0, 0, 1, 1 );
1896 color
.alpha
= alpha
;
1897 pXRenderFillRectangle( gdi_display
, PictOpSrc
, mask_pict
, &color
, 0, 0, 1, 1 );
1898 pXRenderComposite( gdi_display
, PictOpInReverse
, src_pict
, mask_pict
, pict
,
1899 0, 0, 0, 0, x
, y
, width
, height
);
1900 pXRenderFreePicture( gdi_display
, src_pict
);
1901 pXRenderFreePicture( gdi_display
, mask_pict
);
1902 XFreePixmap( gdi_display
, src_pixmap
);
1903 XFreePixmap( gdi_display
, mask_pixmap
);
1904 wine_tsx11_unlock();
1907 /* Helper function for (stretched) blitting using xrender */
1908 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
1909 int x_src
, int y_src
, int x_dst
, int y_dst
,
1910 double xscale
, double yscale
, int width
, int height
)
1912 int x_offset
, y_offset
;
1914 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1915 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1916 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1918 if(xscale
!= 1.0 || yscale
!= 1.0)
1920 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1921 * in the wrong quadrant of the x-y plane.
1923 x_offset
= (xscale
< 0) ? -width
: 0;
1924 y_offset
= (yscale
< 0) ? -height
: 0;
1925 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1931 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1933 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
1934 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width
, height
);
1935 wine_tsx11_unlock();
1938 /* Helper function for (stretched) mono->color blitting using xrender */
1939 static void xrender_mono_blit( Picture src_pict
, Picture dst_pict
,
1940 enum wxr_format dst_format
, XRenderColor
*fg
, XRenderColor
*bg
,
1941 int x_src
, int y_src
, int x_dst
, int y_dst
,
1942 double xscale
, double yscale
, int width
, int height
)
1945 int x_offset
, y_offset
;
1948 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1949 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1952 EnterCriticalSection( &xrender_cs
);
1954 color
.alpha
= 0xffff; /* tile pict needs 100% alpha */
1955 tile_pict
= get_tile_pict( dst_format
, &color
);
1958 pXRenderFillRectangle( gdi_display
, PictOpSrc
, dst_pict
, fg
, x_dst
, y_dst
, width
, height
);
1960 if (xscale
!= 1.0 || yscale
!= 1.0)
1962 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1963 * in the wrong quadrant of the x-y plane.
1965 x_offset
= (xscale
< 0) ? -width
: 0;
1966 y_offset
= (yscale
< 0) ? -height
: 0;
1967 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1973 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1975 pXRenderComposite(gdi_display
, PictOpOver
, tile_pict
, src_pict
, dst_pict
,
1976 0, 0, x_offset
, y_offset
, x_dst
, y_dst
, width
, height
);
1977 wine_tsx11_unlock();
1978 LeaveCriticalSection( &xrender_cs
);
1980 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1981 if (bg
->alpha
!= 0xffff && (dst_format
== WXR_FORMAT_A8R8G8B8
|| dst_format
== WXR_FORMAT_B8G8R8A8
))
1982 multiply_alpha( dst_pict
, pict_formats
[dst_format
], bg
->alpha
, x_dst
, y_dst
, width
, height
);
1985 /* create a pixmap and render picture for an image */
1986 static DWORD
create_image_pixmap( BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1987 struct bitblt_coords
*src
, enum wxr_format format
,
1988 Pixmap
*pixmap
, Picture
*pict
, BOOL
*use_repeat
)
1991 int width
= src
->visrect
.right
- src
->visrect
.left
;
1992 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1993 int depth
= pict_formats
[format
]->depth
;
1994 struct gdi_image_bits dst_bits
;
1995 XRenderPictureAttributes pa
;
1999 image
= XCreateImage( gdi_display
, visual
, depth
, ZPixmap
, 0, NULL
,
2000 info
->bmiHeader
.biWidth
, height
, 32, 0 );
2001 wine_tsx11_unlock();
2002 if (!image
) return ERROR_OUTOFMEMORY
;
2004 ret
= copy_image_bits( info
, (format
== WXR_FORMAT_R8G8B8
), image
, bits
, &dst_bits
, src
, NULL
, ~0u );
2005 if (ret
) return ret
;
2007 image
->data
= dst_bits
.ptr
;
2008 /* hack: make sure the bits are readable if we are reading from a DIB section */
2009 /* to be removed once we get rid of DIB access protections */
2010 if (!dst_bits
.is_copy
) IsBadReadPtr( dst_bits
.ptr
, image
->height
* image
->bytes_per_line
);
2012 *use_repeat
= (width
== 1 && height
== 1);
2013 pa
.repeat
= *use_repeat
? RepeatNormal
: RepeatNone
;
2016 *pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, depth
);
2017 XPutImage( gdi_display
, *pixmap
, get_bitmap_gc( depth
), image
,
2018 src
->visrect
.left
, 0, 0, 0, width
, height
);
2019 *pict
= pXRenderCreatePicture( gdi_display
, *pixmap
, pict_formats
[format
], CPRepeat
, &pa
);
2020 wine_tsx11_unlock();
2022 /* make coordinates relative to the pixmap */
2023 src
->x
-= src
->visrect
.left
;
2024 src
->y
-= src
->visrect
.top
;
2025 OffsetRect( &src
->visrect
, -src
->visrect
.left
, -src
->visrect
.top
);
2029 XDestroyImage( image
);
2030 wine_tsx11_unlock();
2031 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
2035 static void xrender_stretch_blit( struct xrender_physdev
*physdev_src
, struct xrender_physdev
*physdev_dst
,
2036 Drawable drawable
, const struct bitblt_coords
*src
,
2037 const struct bitblt_coords
*dst
)
2039 int width
= abs( dst
->width
);
2040 int height
= abs( dst
->height
);
2041 int x_src
= physdev_src
->x11dev
->dc_rect
.left
+ src
->x
;
2042 int y_src
= physdev_src
->x11dev
->dc_rect
.top
+ src
->y
;
2044 Picture src_pict
= 0, dst_pict
, mask_pict
= 0;
2046 double xscale
, yscale
;
2048 use_repeat
= use_source_repeat( physdev_src
);
2051 xscale
= src
->width
/ (double)dst
->width
;
2052 yscale
= src
->height
/ (double)dst
->height
;
2054 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2056 if (drawable
) /* using an intermediate pixmap */
2058 XRenderPictureAttributes pa
;
2062 pa
.repeat
= RepeatNone
;
2064 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, physdev_dst
->pict_format
, CPRepeat
, &pa
);
2065 wine_tsx11_unlock();
2069 x_dst
= physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
;
2070 y_dst
= physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
;
2071 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
2074 if (src
->width
< 0) x_src
+= src
->width
+ 1;
2075 if (src
->height
< 0) y_src
+= src
->height
+ 1;
2076 if (dst
->width
< 0) x_dst
+= dst
->width
+ 1;
2077 if (dst
->height
< 0) y_dst
+= dst
->height
+ 1;
2079 src_pict
= get_xrender_picture_source( physdev_src
, use_repeat
);
2082 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
2084 XRenderColor fg
, bg
;
2086 get_xrender_color( physdev_dst
->pict_format
, physdev_dst
->x11dev
->textPixel
, &fg
);
2087 get_xrender_color( physdev_dst
->pict_format
, physdev_dst
->x11dev
->backgroundPixel
, &bg
);
2088 fg
.alpha
= bg
.alpha
= 0;
2090 xrender_mono_blit( src_pict
, dst_pict
, physdev_dst
->format
, &fg
, &bg
,
2091 x_src
, y_src
, x_dst
, y_dst
, xscale
, yscale
, width
, height
);
2093 else /* color -> color (can be at different depths) or mono -> mono */
2095 if (physdev_dst
->x11dev
->depth
== 32 && physdev_src
->x11dev
->depth
< 32)
2096 mask_pict
= get_no_alpha_mask();
2098 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
2099 x_src
, y_src
, x_dst
, y_dst
, xscale
, yscale
, width
, height
);
2105 pXRenderFreePicture( gdi_display
, dst_pict
);
2106 wine_tsx11_unlock();
2111 static void xrender_put_image( Pixmap src_pixmap
, Picture src_pict
, Picture mask_pict
, HRGN clip
,
2112 XRenderPictFormat
*dst_format
, struct xrender_physdev
*physdev
,
2113 Drawable drawable
, struct bitblt_coords
*src
,
2114 struct bitblt_coords
*dst
, BOOL use_repeat
)
2116 int x_src
, y_src
, x_dst
, y_dst
;
2118 XRenderPictureAttributes pa
;
2119 double xscale
, yscale
;
2121 if (drawable
) /* using an intermediate pixmap */
2123 RGNDATA
*clip_data
= NULL
;
2125 if (clip
) clip_data
= X11DRV_GetRegionData( clip
, 0 );
2128 pa
.repeat
= RepeatNone
;
2130 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, dst_format
, CPRepeat
, &pa
);
2132 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
, 0, 0,
2133 (XRectangle
*)clip_data
->Buffer
, clip_data
->rdh
.nCount
);
2134 wine_tsx11_unlock();
2135 HeapFree( GetProcessHeap(), 0, clip_data
);
2139 x_dst
= physdev
->x11dev
->dc_rect
.left
+ dst
->x
;
2140 y_dst
= physdev
->x11dev
->dc_rect
.top
+ dst
->y
;
2141 dst_pict
= get_xrender_picture( physdev
, clip
, &dst
->visrect
);
2146 xscale
= src
->width
/ (double)dst
->width
;
2147 yscale
= src
->height
/ (double)dst
->height
;
2149 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2153 if (src
->width
< 0) x_src
+= src
->width
+ 1;
2154 if (src
->height
< 0) y_src
+= src
->height
+ 1;
2155 if (dst
->width
< 0) x_dst
+= dst
->width
+ 1;
2156 if (dst
->height
< 0) y_dst
+= dst
->height
+ 1;
2158 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
, x_src
, y_src
, x_dst
, y_dst
,
2159 xscale
, yscale
, abs( dst
->width
), abs( dst
->height
));
2164 pXRenderFreePicture( gdi_display
, dst_pict
);
2165 wine_tsx11_unlock();
2170 /***********************************************************************
2171 * xrenderdrv_StretchBlt
2173 static BOOL
xrenderdrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
2174 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
2176 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
2177 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
2178 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
2180 if (src_dev
->funcs
!= dst_dev
->funcs
)
2182 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pStretchBlt
);
2183 return dst_dev
->funcs
->pStretchBlt( dst_dev
, dst
, src_dev
, src
, rop
);
2186 if (!X11DRV_XRender_Installed
) goto x11drv_fallback
;
2188 /* XRender is of no use for color -> mono */
2189 if (physdev_dst
->format
== WXR_FORMAT_MONO
&& physdev_src
->format
!= WXR_FORMAT_MONO
)
2190 goto x11drv_fallback
;
2192 /* if not stretching, we only need to handle format conversion */
2193 if (!stretch
&& physdev_dst
->format
== physdev_src
->format
) goto x11drv_fallback
;
2199 struct bitblt_coords tmp
;
2201 /* make coordinates relative to tmp pixmap */
2203 tmp
.x
-= tmp
.visrect
.left
;
2204 tmp
.y
-= tmp
.visrect
.top
;
2205 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
2208 tmpGC
= XCreateGC( gdi_display
, physdev_dst
->x11dev
->drawable
, 0, NULL
);
2209 XSetSubwindowMode( gdi_display
, tmpGC
, IncludeInferiors
);
2210 XSetGraphicsExposures( gdi_display
, tmpGC
, False
);
2211 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, tmp
.visrect
.right
- tmp
.visrect
.left
,
2212 tmp
.visrect
.bottom
- tmp
.visrect
.top
, physdev_dst
->x11dev
->depth
);
2213 wine_tsx11_unlock();
2215 xrender_stretch_blit( physdev_src
, physdev_dst
, tmp_pixmap
, src
, &tmp
);
2216 execute_rop( physdev_dst
->x11dev
, tmp_pixmap
, tmpGC
, &dst
->visrect
, rop
);
2219 XFreePixmap( gdi_display
, tmp_pixmap
);
2220 XFreeGC( gdi_display
, tmpGC
);
2221 wine_tsx11_unlock();
2223 else xrender_stretch_blit( physdev_src
, physdev_dst
, 0, src
, dst
);
2228 return X11DRV_StretchBlt( &physdev_dst
->x11dev
->dev
, dst
, &physdev_src
->x11dev
->dev
, src
, rop
);
2232 /***********************************************************************
2233 * xrenderdrv_PutImage
2235 static DWORD
xrenderdrv_PutImage( PHYSDEV dev
, HBITMAP hbitmap
, HRGN clip
, BITMAPINFO
*info
,
2236 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
2237 struct bitblt_coords
*dst
, DWORD rop
)
2239 struct xrender_physdev
*physdev
;
2240 X_PHYSBITMAP
*bitmap
;
2244 enum wxr_format src_format
, dst_format
;
2245 XRenderPictFormat
*pict_format
;
2247 Picture src_pict
, mask_pict
= 0;
2250 if (!X11DRV_XRender_Installed
) goto x11drv_fallback
;
2254 if (!(bitmap
= X11DRV_get_phys_bitmap( hbitmap
))) return ERROR_INVALID_HANDLE
;
2256 dst_format
= get_xrender_format_from_color_shifts( bitmap
->depth
, &bitmap
->color_shifts
);
2260 physdev
= get_xrender_dev( dev
);
2262 dst_format
= physdev
->format
;
2265 src_format
= get_xrender_format_from_bitmapinfo( info
);
2266 if (!(pict_format
= pict_formats
[src_format
])) goto update_format
;
2268 /* make sure we can create an image with the same bpp */
2269 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
2272 /* mono <-> color conversions not supported */
2273 if ((src_format
!= dst_format
) && (src_format
== WXR_FORMAT_MONO
|| dst_format
== WXR_FORMAT_MONO
))
2274 goto x11drv_fallback
;
2276 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
2278 if (!has_alpha( src_format
) && has_alpha( dst_format
)) mask_pict
= get_no_alpha_mask();
2280 ret
= create_image_pixmap( info
, bits
, src
, src_format
, &src_pixmap
, &src_pict
, &use_repeat
);
2283 struct bitblt_coords tmp
;
2287 HRGN rgn
= CreateRectRgnIndirect( &dst
->visrect
);
2288 if (clip
) CombineRgn( rgn
, rgn
, clip
, RGN_AND
);
2290 xrender_put_image( src_pixmap
, src_pict
, mask_pict
, rgn
,
2291 pict_formats
[dst_format
], NULL
, bitmap
->pixmap
, src
, dst
, use_repeat
);
2292 DeleteObject( rgn
);
2298 BOOL restore_region
= add_extra_clipping_region( physdev
->x11dev
, clip
);
2300 /* make coordinates relative to tmp pixmap */
2302 tmp
.x
-= tmp
.visrect
.left
;
2303 tmp
.y
-= tmp
.visrect
.top
;
2304 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
2307 gc
= XCreateGC( gdi_display
, physdev
->x11dev
->drawable
, 0, NULL
);
2308 XSetSubwindowMode( gdi_display
, gc
, IncludeInferiors
);
2309 XSetGraphicsExposures( gdi_display
, gc
, False
);
2310 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, tmp
.visrect
.right
- tmp
.visrect
.left
,
2311 tmp
.visrect
.bottom
- tmp
.visrect
.top
, physdev
->x11dev
->depth
);
2312 wine_tsx11_unlock();
2314 xrender_put_image( src_pixmap
, src_pict
, mask_pict
, NULL
, physdev
->pict_format
,
2315 NULL
, tmp_pixmap
, src
, &tmp
, use_repeat
);
2316 execute_rop( physdev
->x11dev
, tmp_pixmap
, gc
, &dst
->visrect
, rop
);
2319 XFreePixmap( gdi_display
, tmp_pixmap
);
2320 XFreeGC( gdi_display
, gc
);
2321 wine_tsx11_unlock();
2323 if (restore_region
) restore_clipping_region( physdev
->x11dev
);
2325 else xrender_put_image( src_pixmap
, src_pict
, mask_pict
, clip
,
2326 physdev
->pict_format
, physdev
, 0, src
, dst
, use_repeat
);
2330 pXRenderFreePicture( gdi_display
, src_pict
);
2331 XFreePixmap( gdi_display
, src_pixmap
);
2332 wine_tsx11_unlock();
2337 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
2338 set_color_info( pict_formats
[dst_format
], info
);
2339 return ERROR_BAD_FORMAT
;
2342 if (hbitmap
) return X11DRV_PutImage( dev
, hbitmap
, clip
, info
, bits
, src
, dst
, rop
);
2343 dev
= GET_NEXT_PHYSDEV( dev
, pPutImage
);
2344 return dev
->funcs
->pPutImage( dev
, hbitmap
, clip
, info
, bits
, src
, dst
, rop
);
2348 /***********************************************************************
2349 * xrenderdrv_BlendImage
2351 static DWORD
xrenderdrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
2352 struct bitblt_coords
*src
, struct bitblt_coords
*dst
,
2353 BLENDFUNCTION func
)
2355 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2357 enum wxr_format format
;
2358 XRenderPictFormat
*pict_format
;
2359 Picture dst_pict
, src_pict
, mask_pict
;
2363 if (!X11DRV_XRender_Installed
)
2365 dev
= GET_NEXT_PHYSDEV( dev
, pBlendImage
);
2366 return dev
->funcs
->pBlendImage( dev
, info
, bits
, src
, dst
, func
);
2369 format
= get_xrender_format_from_bitmapinfo( info
);
2370 if (!(func
.AlphaFormat
& AC_SRC_ALPHA
))
2371 format
= get_format_without_alpha( format
);
2372 else if (format
!= WXR_FORMAT_A8R8G8B8
)
2373 return ERROR_INVALID_PARAMETER
;
2375 if (!(pict_format
= pict_formats
[format
])) goto update_format
;
2377 /* make sure we can create an image with the same bpp */
2378 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
2381 if (format
== WXR_FORMAT_MONO
&& physdev
->format
!= WXR_FORMAT_MONO
)
2384 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
2386 ret
= create_image_pixmap( info
, bits
, src
, format
, &src_pixmap
, &src_pict
, &use_repeat
);
2389 double xscale
, yscale
;
2393 xscale
= src
->width
/ (double)dst
->width
;
2394 yscale
= src
->height
/ (double)dst
->height
;
2396 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2398 dst_pict
= get_xrender_picture( physdev
, 0, &dst
->visrect
);
2400 EnterCriticalSection( &xrender_cs
);
2401 mask_pict
= get_mask_pict( func
.SourceConstantAlpha
* 257 );
2403 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
, src
->x
, src
->y
,
2404 physdev
->x11dev
->dc_rect
.left
+ dst
->x
,
2405 physdev
->x11dev
->dc_rect
.top
+ dst
->y
,
2406 xscale
, yscale
, dst
->width
, dst
->height
);
2409 pXRenderFreePicture( gdi_display
, src_pict
);
2410 XFreePixmap( gdi_display
, src_pixmap
);
2411 wine_tsx11_unlock();
2413 LeaveCriticalSection( &xrender_cs
);
2418 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
2419 set_color_info( physdev
->pict_format
, info
);
2420 return ERROR_BAD_FORMAT
;
2424 /***********************************************************************
2425 * xrenderdrv_AlphaBlend
2427 static BOOL
xrenderdrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
2428 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
2430 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
2431 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
2432 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
2433 XRenderPictureAttributes pa
;
2434 Pixmap tmp_pixmap
= 0;
2435 double xscale
, yscale
;
2438 if (!X11DRV_XRender_Installed
|| src_dev
->funcs
!= dst_dev
->funcs
)
2440 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pAlphaBlend
);
2441 return dst_dev
->funcs
->pAlphaBlend( dst_dev
, dst
, src_dev
, src
, blendfn
);
2444 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->format
!= WXR_FORMAT_A8R8G8B8
)
2446 SetLastError( ERROR_INVALID_PARAMETER
);
2450 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
2452 use_repeat
= use_source_repeat( physdev_src
);
2455 xscale
= src
->width
/ (double)dst
->width
;
2456 yscale
= src
->height
/ (double)dst
->height
;
2458 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2460 src_pict
= get_xrender_picture_source( physdev_src
, use_repeat
);
2462 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
2464 /* mono -> color blending needs an intermediate color pixmap */
2465 XRenderColor fg
, bg
;
2466 int width
= src
->visrect
.right
- src
->visrect
.left
;
2467 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
2469 /* blending doesn't use the destination DC colors */
2470 fg
.red
= fg
.green
= fg
.blue
= 0;
2471 bg
.red
= bg
.green
= bg
.blue
= 0xffff;
2472 fg
.alpha
= bg
.alpha
= 0xffff;
2475 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
,
2476 physdev_dst
->pict_format
->depth
);
2477 pa
.repeat
= use_repeat
? RepeatNormal
: RepeatNone
;
2478 tmp_pict
= pXRenderCreatePicture( gdi_display
, tmp_pixmap
, physdev_dst
->pict_format
,
2480 wine_tsx11_unlock();
2482 xrender_mono_blit( src_pict
, tmp_pict
, physdev_dst
->format
, &fg
, &bg
,
2483 src
->visrect
.left
, src
->visrect
.top
, 0, 0, 1, 1, width
, height
);
2485 else if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->pict_format
)
2487 /* we need a source picture with no alpha */
2488 enum wxr_format format
= get_format_without_alpha( physdev_src
->format
);
2489 if (format
!= physdev_src
->format
)
2492 pa
.subwindow_mode
= IncludeInferiors
;
2493 pa
.repeat
= use_repeat
? RepeatNormal
: RepeatNone
;
2494 tmp_pict
= pXRenderCreatePicture( gdi_display
, physdev_src
->x11dev
->drawable
,
2495 pict_formats
[format
], CPSubwindowMode
|CPRepeat
, &pa
);
2496 wine_tsx11_unlock();
2500 if (tmp_pict
) src_pict
= tmp_pict
;
2502 EnterCriticalSection( &xrender_cs
);
2503 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
2505 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2506 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
2507 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
2508 physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
,
2509 physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
,
2510 xscale
, yscale
, dst
->width
, dst
->height
);
2513 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
2514 if (tmp_pixmap
) XFreePixmap( gdi_display
, tmp_pixmap
);
2515 wine_tsx11_unlock();
2517 LeaveCriticalSection( &xrender_cs
);
2521 /***********************************************************************
2522 * xrenderdrv_GradientFill
2524 static BOOL
xrenderdrv_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
2525 void * grad_array
, ULONG ngrad
, ULONG mode
)
2527 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2528 static const XFixed stops
[2] = { 0, 1 << 16 };
2529 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2530 XLinearGradient gradient
;
2531 XRenderColor colors
[2];
2532 Picture src_pict
, dst_pict
;
2534 const GRADIENT_RECT
*rect
= grad_array
;
2537 if (!X11DRV_XRender_Installed
) goto fallback
;
2538 if (!pXRenderCreateLinearGradient
) goto fallback
;
2540 /* <= 16-bpp uses dithering */
2541 if (!physdev
->pict_format
|| physdev
->pict_format
->depth
<= 16) goto fallback
;
2545 case GRADIENT_FILL_RECT_H
:
2546 case GRADIENT_FILL_RECT_V
:
2547 for (i
= 0; i
< ngrad
; i
++, rect
++)
2549 const TRIVERTEX
*v1
= vert_array
+ rect
->UpperLeft
;
2550 const TRIVERTEX
*v2
= vert_array
+ rect
->LowerRight
;
2552 colors
[0].red
= v1
->Red
* 257 / 256;
2553 colors
[0].green
= v1
->Green
* 257 / 256;
2554 colors
[0].blue
= v1
->Blue
* 257 / 256;
2555 colors
[1].red
= v2
->Red
* 257 / 256;
2556 colors
[1].green
= v2
->Green
* 257 / 256;
2557 colors
[1].blue
= v2
->Blue
* 257 / 256;
2558 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2559 colors
[0].alpha
= colors
[1].alpha
= 65535;
2565 LPtoDP( dev
->hdc
, pt
, 2 );
2566 if (mode
== GRADIENT_FILL_RECT_H
)
2568 gradient
.p1
.y
= gradient
.p2
.y
= 0;
2569 if (pt
[1].x
> pt
[0].x
)
2572 gradient
.p2
.x
= (pt
[1].x
- pt
[0].x
) << 16;
2576 gradient
.p1
.x
= (pt
[0].x
- pt
[1].x
) << 16;
2582 gradient
.p1
.x
= gradient
.p2
.x
= 0;
2583 if (pt
[1].y
> pt
[0].y
)
2586 gradient
.p2
.y
= (pt
[1].y
- pt
[0].y
) << 16;
2590 gradient
.p1
.y
= (pt
[0].y
- pt
[1].y
) << 16;
2595 TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2596 mode
, pt
[0].x
, pt
[0].y
, pt
[1].x
, pt
[1].y
,
2597 colors
[0].red
, colors
[0].green
, colors
[0].blue
, colors
[0].alpha
,
2598 colors
[1].red
, colors
[1].green
, colors
[1].blue
, colors
[1].alpha
);
2600 dst_pict
= get_xrender_picture( physdev
, 0, NULL
);
2603 src_pict
= pXRenderCreateLinearGradient( gdi_display
, &gradient
, stops
, colors
, 2 );
2604 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
, 0, 0,
2605 physdev
->x11dev
->dc_rect
.left
+ min( pt
[0].x
, pt
[1].x
),
2606 physdev
->x11dev
->dc_rect
.top
+ min( pt
[0].y
, pt
[1].y
),
2607 1, 1, abs(pt
[1].x
- pt
[0].x
), abs(pt
[1].y
- pt
[0].y
) );
2608 pXRenderFreePicture( gdi_display
, src_pict
);
2609 wine_tsx11_unlock();
2616 dev
= GET_NEXT_PHYSDEV( dev
, pGradientFill
);
2617 return dev
->funcs
->pGradientFill( dev
, vert_array
, nvert
, grad_array
, ngrad
, mode
);
2620 /***********************************************************************
2621 * xrenderdrv_SelectBrush
2623 static HBRUSH
xrenderdrv_SelectBrush( PHYSDEV dev
, HBRUSH hbrush
, HBITMAP bitmap
,
2624 const BITMAPINFO
*info
, void *bits
, UINT usage
)
2626 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2627 X_PHYSBITMAP
*physbitmap
;
2628 enum wxr_format format
;
2629 BOOL delete_bitmap
= FALSE
;
2632 Picture src_pict
, dst_pict
;
2633 XRenderPictureAttributes pa
;
2635 if (!X11DRV_XRender_Installed
) goto x11drv_fallback
;
2636 if (!bitmap
&& !info
) goto x11drv_fallback
;
2637 if (physdev
->format
== WXR_FORMAT_MONO
) goto x11drv_fallback
;
2639 if (!bitmap
|| !(physbitmap
= X11DRV_get_phys_bitmap( bitmap
)))
2641 if (!(bitmap
= create_brush_bitmap( physdev
->x11dev
, info
, bits
, usage
))) return 0;
2642 physbitmap
= X11DRV_get_phys_bitmap( bitmap
);
2643 delete_bitmap
= TRUE
;
2646 format
= get_xrender_format_from_color_shifts( physbitmap
->depth
, &physbitmap
->color_shifts
);
2647 if (format
== WXR_FORMAT_MONO
|| !pict_formats
[format
]) goto x11drv_fallback
;
2649 GetObjectW( bitmap
, sizeof(bm
), &bm
);
2651 X11DRV_DIB_Lock( physbitmap
, DIB_Status_GdiMod
);
2654 pixmap
= XCreatePixmap( gdi_display
, root_window
, bm
.bmWidth
, bm
.bmHeight
,
2655 physdev
->pict_format
->depth
);
2657 pa
.repeat
= RepeatNone
;
2658 src_pict
= pXRenderCreatePicture(gdi_display
, physbitmap
->pixmap
, pict_formats
[format
], CPRepeat
, &pa
);
2659 dst_pict
= pXRenderCreatePicture(gdi_display
, pixmap
, physdev
->pict_format
, CPRepeat
, &pa
);
2661 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
, 0, 0, 0, 0, 1.0, 1.0, bm
.bmWidth
, bm
.bmHeight
);
2662 pXRenderFreePicture( gdi_display
, src_pict
);
2663 pXRenderFreePicture( gdi_display
, dst_pict
);
2665 if (physdev
->x11dev
->brush
.pixmap
) XFreePixmap( gdi_display
, physdev
->x11dev
->brush
.pixmap
);
2666 physdev
->x11dev
->brush
.pixmap
= pixmap
;
2667 physdev
->x11dev
->brush
.fillStyle
= FillTiled
;
2668 physdev
->x11dev
->brush
.pixel
= 0; /* ignored */
2669 physdev
->x11dev
->brush
.style
= BS_PATTERN
;
2670 wine_tsx11_unlock();
2672 X11DRV_DIB_Unlock( physbitmap
, TRUE
);
2673 if (delete_bitmap
) DeleteObject( bitmap
);
2677 if (delete_bitmap
) DeleteObject( bitmap
);
2678 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBrush
);
2679 return dev
->funcs
->pSelectBrush( dev
, hbrush
, bitmap
, info
, bits
, usage
);
2683 static const struct gdi_dc_funcs xrender_funcs
=
2685 NULL
, /* pAbortDoc */
2686 NULL
, /* pAbortPath */
2687 xrenderdrv_AlphaBlend
, /* pAlphaBlend */
2688 NULL
, /* pAngleArc */
2691 NULL
, /* pBeginPath */
2692 xrenderdrv_BlendImage
, /* pBlendImage */
2693 NULL
, /* pChoosePixelFormat */
2695 NULL
, /* pCloseFigure */
2696 xrenderdrv_CopyBitmap
, /* pCopyBitmap */
2697 xrenderdrv_CreateBitmap
, /* pCreateBitmap */
2698 xrenderdrv_CreateCompatibleDC
, /* pCreateCompatibleDC */
2699 xrenderdrv_CreateDC
, /* pCreateDC */
2700 NULL
, /* pCreateDIBSection */
2701 xrenderdrv_DeleteBitmap
, /* pDeleteBitmap */
2702 xrenderdrv_DeleteDC
, /* pDeleteDC */
2703 NULL
, /* pDeleteObject */
2704 NULL
, /* pDescribePixelFormat */
2705 NULL
, /* pDeviceCapabilities */
2706 NULL
, /* pEllipse */
2708 NULL
, /* pEndPage */
2709 NULL
, /* pEndPath */
2710 NULL
, /* pEnumFonts */
2711 NULL
, /* pEnumICMProfiles */
2712 NULL
, /* pExcludeClipRect */
2713 NULL
, /* pExtDeviceMode */
2714 xrenderdrv_ExtEscape
, /* pExtEscape */
2715 NULL
, /* pExtFloodFill */
2716 NULL
, /* pExtSelectClipRgn */
2717 xrenderdrv_ExtTextOut
, /* pExtTextOut */
2718 NULL
, /* pFillPath */
2719 NULL
, /* pFillRgn */
2720 NULL
, /* pFlattenPath */
2721 NULL
, /* pFontIsLinked */
2722 NULL
, /* pFrameRgn */
2723 NULL
, /* pGdiComment */
2724 NULL
, /* pGdiRealizationInfo */
2725 NULL
, /* pGetCharABCWidths */
2726 NULL
, /* pGetCharABCWidthsI */
2727 NULL
, /* pGetCharWidth */
2728 NULL
, /* pGetDeviceCaps */
2729 NULL
, /* pGetDeviceGammaRamp */
2730 NULL
, /* pGetFontData */
2731 NULL
, /* pGetFontUnicodeRanges */
2732 NULL
, /* pGetGlyphIndices */
2733 NULL
, /* pGetGlyphOutline */
2734 NULL
, /* pGetICMProfile */
2735 xrenderdrv_GetImage
, /* pGetImage */
2736 NULL
, /* pGetKerningPairs */
2737 NULL
, /* pGetNearestColor */
2738 NULL
, /* pGetOutlineTextMetrics */
2739 NULL
, /* pGetPixel */
2740 NULL
, /* pGetPixelFormat */
2741 NULL
, /* pGetSystemPaletteEntries */
2742 NULL
, /* pGetTextCharsetInfo */
2743 NULL
, /* pGetTextExtentExPoint */
2744 NULL
, /* pGetTextExtentExPointI */
2745 NULL
, /* pGetTextFace */
2746 NULL
, /* pGetTextMetrics */
2747 xrenderdrv_GradientFill
, /* pGradientFill */
2748 NULL
, /* pIntersectClipRect */
2749 NULL
, /* pInvertRgn */
2751 NULL
, /* pModifyWorldTransform */
2753 NULL
, /* pOffsetClipRgn */
2754 NULL
, /* pOffsetViewportOrg */
2755 NULL
, /* pOffsetWindowOrg */
2756 NULL
, /* pPaintRgn */
2759 NULL
, /* pPolyBezier */
2760 NULL
, /* pPolyBezierTo */
2761 NULL
, /* pPolyDraw */
2762 NULL
, /* pPolyPolygon */
2763 NULL
, /* pPolyPolyline */
2764 NULL
, /* pPolygon */
2765 NULL
, /* pPolyline */
2766 NULL
, /* pPolylineTo */
2767 xrenderdrv_PutImage
, /* pPutImage */
2768 NULL
, /* pRealizeDefaultPalette */
2769 NULL
, /* pRealizePalette */
2770 NULL
, /* pRectangle */
2771 NULL
, /* pResetDC */
2772 NULL
, /* pRestoreDC */
2773 NULL
, /* pRoundRect */
2775 NULL
, /* pScaleViewportExt */
2776 NULL
, /* pScaleWindowExt */
2777 xrenderdrv_SelectBitmap
, /* pSelectBitmap */
2778 xrenderdrv_SelectBrush
, /* pSelectBrush */
2779 NULL
, /* pSelectClipPath */
2780 xrenderdrv_SelectFont
, /* pSelectFont */
2781 NULL
, /* pSelectPalette */
2782 NULL
, /* pSelectPen */
2783 NULL
, /* pSetArcDirection */
2784 NULL
, /* pSetBkColor */
2785 NULL
, /* pSetBkMode */
2786 NULL
, /* pSetDCBrushColor */
2787 NULL
, /* pSetDCPenColor */
2788 NULL
, /* pSetDIBColorTable */
2789 NULL
, /* pSetDIBitsToDevice */
2790 xrenderdrv_SetDeviceClipping
, /* pSetDeviceClipping */
2791 NULL
, /* pSetDeviceGammaRamp */
2792 NULL
, /* pSetLayout */
2793 NULL
, /* pSetMapMode */
2794 NULL
, /* pSetMapperFlags */
2795 NULL
, /* pSetPixel */
2796 NULL
, /* pSetPixelFormat */
2797 NULL
, /* pSetPolyFillMode */
2798 NULL
, /* pSetROP2 */
2799 NULL
, /* pSetRelAbs */
2800 NULL
, /* pSetStretchBltMode */
2801 NULL
, /* pSetTextAlign */
2802 NULL
, /* pSetTextCharacterExtra */
2803 NULL
, /* pSetTextColor */
2804 NULL
, /* pSetTextJustification */
2805 NULL
, /* pSetViewportExt */
2806 NULL
, /* pSetViewportOrg */
2807 NULL
, /* pSetWindowExt */
2808 NULL
, /* pSetWindowOrg */
2809 NULL
, /* pSetWorldTransform */
2810 NULL
, /* pStartDoc */
2811 NULL
, /* pStartPage */
2812 xrenderdrv_StretchBlt
, /* pStretchBlt */
2813 NULL
, /* pStretchDIBits */
2814 NULL
, /* pStrokeAndFillPath */
2815 NULL
, /* pStrokePath */
2816 NULL
, /* pSwapBuffers */
2817 NULL
, /* pUnrealizePalette */
2818 NULL
, /* pWidenPath */
2819 /* OpenGL not supported */
2822 #else /* SONAME_LIBXRENDER */
2824 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
2826 TRACE("XRender support not compiled in.\n");
2830 void X11DRV_XRender_Finalize(void)
2834 BOOL
X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP
*physBitmap
, int bits_pixel
, const DIBSECTION
*dib
)
2839 #endif /* SONAME_LIBXRENDER */