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