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
);
50 #include <X11/extensions/Xrender.h>
52 #ifndef RepeatNone /* added in 0.10 */
54 #define RepeatNormal 1
56 #define RepeatReflect 3
74 WXR_INVALID_FORMAT
= WXR_NB_FORMATS
77 typedef struct wine_xrender_format_template
81 unsigned int alphaMask
;
85 unsigned int greenMask
;
87 unsigned int blueMask
;
88 } WineXRenderFormatTemplate
;
90 static const WineXRenderFormatTemplate wxr_formats_template
[WXR_NB_FORMATS
] =
92 /* Format depth alpha mask red mask green mask blue mask*/
93 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
94 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
95 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
96 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
97 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
98 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
99 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
101 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
103 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
107 static const ColorShifts wxr_color_shifts
[WXR_NB_FORMATS
] =
109 /* format phys red phys green phys blue log red log green log blue */
110 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
111 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
112 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
113 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
114 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
115 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
116 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
117 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
118 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
120 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
121 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
124 static enum wxr_format default_format
= WXR_INVALID_FORMAT
;
125 static XRenderPictFormat
*pict_formats
[WXR_NB_FORMATS
+ 1 /* invalid format */];
131 SIZE devsize
; /* size in device coords */
135 #define INITIAL_REALIZED_BUF_SIZE 128
137 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
142 XRenderPictFormat
*font_format
;
146 } gsCacheEntryFormat
;
152 gsCacheEntryFormat
* format
[AA_MAXVALUE
];
157 struct xrender_physdev
159 struct gdi_physdev dev
;
160 X11DRV_PDEVICE
*x11dev
;
162 enum wxr_format format
;
167 XRenderPictFormat
*pict_format
;
170 static inline struct xrender_physdev
*get_xrender_dev( PHYSDEV dev
)
172 return (struct xrender_physdev
*)dev
;
175 static const struct gdi_dc_funcs xrender_funcs
;
177 static gsCacheEntry
*glyphsetCache
= NULL
;
178 static DWORD glyphsetCacheSize
= 0;
179 static INT lastfree
= -1;
182 #define INIT_CACHE_SIZE 10
184 static int antialias
= 1;
186 static void *xrender_handle
;
188 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
189 MAKE_FUNCPTR(XRenderAddGlyphs
)
190 MAKE_FUNCPTR(XRenderChangePicture
)
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)
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 ok
= pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
);
400 if (!ok
) 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");
411 if (!visual
->red_mask
|| !visual
->green_mask
|| !visual
->blue_mask
)
413 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
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( struct xrender_physdev
*physdev
, COLORREF src_color
, XRenderColor
*dst_color
)
459 if (src_color
& (1 << 24)) /* PALETTEINDEX */
461 HPALETTE pal
= GetCurrentObject( physdev
->dev
.hdc
, OBJ_PAL
);
462 PALETTEENTRY pal_ent
;
464 if (!GetPaletteEntries( pal
, LOWORD(src_color
), 1, &pal_ent
))
465 GetPaletteEntries( pal
, 0, 1, &pal_ent
);
466 dst_color
->red
= pal_ent
.peRed
* 257;
467 dst_color
->green
= pal_ent
.peGreen
* 257;
468 dst_color
->blue
= pal_ent
.peBlue
* 257;
472 if (src_color
>> 16 == 0x10ff) src_color
= 0; /* DIBINDEX */
474 dst_color
->red
= GetRValue( src_color
) * 257;
475 dst_color
->green
= GetGValue( src_color
) * 257;
476 dst_color
->blue
= GetBValue( src_color
) * 257;
479 if (physdev
->format
== WXR_FORMAT_MONO
&& !dst_color
->red
&& !dst_color
->green
&& !dst_color
->blue
)
480 dst_color
->alpha
= 0;
482 dst_color
->alpha
= 0xffff;
485 static enum wxr_format
get_xrender_format_from_bitmapinfo( const BITMAPINFO
*info
)
487 if (info
->bmiHeader
.biPlanes
!= 1) return WXR_INVALID_FORMAT
;
489 switch (info
->bmiHeader
.biBitCount
)
492 return WXR_FORMAT_MONO
;
497 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
498 return WXR_FORMAT_R8G8B8
;
501 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
503 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
506 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
508 if (info
->bmiHeader
.biBitCount
== wxr_formats_template
[i
].depth
&&
509 colors
[0] == (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
510 colors
[1] == (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
511 colors
[2] == (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
))
516 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
517 return (info
->bmiHeader
.biBitCount
== 16) ? WXR_FORMAT_X1R5G5B5
: WXR_FORMAT_A8R8G8B8
;
519 return WXR_INVALID_FORMAT
;
522 static enum wxr_format
get_bitmap_format( int bpp
)
524 enum wxr_format format
= WXR_INVALID_FORMAT
;
526 if (bpp
== screen_bpp
)
530 case 16: format
= WXR_FORMAT_R5G6B5
; break;
531 case 24: format
= WXR_FORMAT_R8G8B8
; break;
532 case 32: format
= WXR_FORMAT_A8R8G8B8
; break;
538 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
539 static void set_xrender_transformation(Picture src_pict
, double xscale
, double yscale
, int xoffset
, int yoffset
)
541 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
542 XTransform xform
= {{
543 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(xoffset
) },
544 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(yoffset
) },
545 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
548 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
552 /* check if we can use repeating instead of scaling for the specified source DC */
553 static BOOL
use_source_repeat( struct xrender_physdev
*dev
)
555 return (dev
->x11dev
->bitmap
&&
556 dev
->x11dev
->drawable_rect
.right
- dev
->x11dev
->drawable_rect
.left
== 1 &&
557 dev
->x11dev
->drawable_rect
.bottom
- dev
->x11dev
->drawable_rect
.top
== 1);
560 static void update_xrender_clipping( struct xrender_physdev
*dev
, HRGN rgn
)
562 XRenderPictureAttributes pa
;
569 pXRenderChangePicture( gdi_display
, dev
->pict
, CPClipMask
, &pa
);
572 else if ((data
= X11DRV_GetRegionData( rgn
, 0 )))
575 pXRenderSetPictureClipRectangles( gdi_display
, dev
->pict
,
576 dev
->x11dev
->dc_rect
.left
, dev
->x11dev
->dc_rect
.top
,
577 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
579 HeapFree( GetProcessHeap(), 0, data
);
584 static Picture
get_xrender_picture( struct xrender_physdev
*dev
, HRGN clip_rgn
, const RECT
*clip_rect
)
586 if (!dev
->pict
&& dev
->pict_format
)
588 XRenderPictureAttributes pa
;
591 pa
.subwindow_mode
= IncludeInferiors
;
592 dev
->pict
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
593 dev
->pict_format
, CPSubwindowMode
, &pa
);
595 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
596 dev
->pict
, dev
->dev
.hdc
, dev
->x11dev
->drawable
);
597 dev
->update_clip
= (dev
->region
!= 0);
602 HRGN rgn
= CreateRectRgnIndirect( clip_rect
);
603 if (clip_rgn
) CombineRgn( rgn
, rgn
, clip_rgn
, RGN_AND
);
604 if (dev
->region
) CombineRgn( rgn
, rgn
, dev
->region
, RGN_AND
);
605 update_xrender_clipping( dev
, rgn
);
612 HRGN rgn
= CreateRectRgn( 0, 0, 0, 0 );
613 CombineRgn( rgn
, clip_rgn
, dev
->region
, RGN_AND
);
614 update_xrender_clipping( dev
, rgn
);
617 else update_xrender_clipping( dev
, clip_rgn
);
619 else if (dev
->update_clip
) update_xrender_clipping( dev
, dev
->region
);
621 dev
->update_clip
= (clip_rect
|| clip_rgn
); /* have to update again if we are using a custom region */
625 static Picture
get_xrender_picture_source( struct xrender_physdev
*dev
, BOOL repeat
)
627 if (!dev
->pict_src
&& dev
->pict_format
)
629 XRenderPictureAttributes pa
;
632 pa
.subwindow_mode
= IncludeInferiors
;
633 pa
.repeat
= repeat
? RepeatNormal
: RepeatNone
;
634 dev
->pict_src
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
635 dev
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
638 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
639 dev
->pict_src
, dev
->dev
.hdc
, dev
->x11dev
->drawable
, pa
.repeat
);
642 return dev
->pict_src
;
645 static void free_xrender_picture( struct xrender_physdev
*dev
)
647 if (dev
->pict
|| dev
->pict_src
)
650 XFlush( gdi_display
);
653 TRACE("freeing pict = %lx dc = %p\n", dev
->pict
, dev
->dev
.hdc
);
654 pXRenderFreePicture(gdi_display
, dev
->pict
);
659 TRACE("freeing pict = %lx dc = %p\n", dev
->pict_src
, dev
->dev
.hdc
);
660 pXRenderFreePicture(gdi_display
, dev
->pict_src
);
667 /* return a mask picture used to force alpha to 0 */
668 static Picture
get_no_alpha_mask(void)
670 static Pixmap pixmap
;
676 XRenderPictureAttributes pa
;
679 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
680 pa
.repeat
= RepeatNormal
;
681 pa
.component_alpha
= True
;
682 pict
= pXRenderCreatePicture( gdi_display
, pixmap
, pict_formats
[WXR_FORMAT_A8R8G8B8
],
683 CPRepeat
|CPComponentAlpha
, &pa
);
684 col
.red
= col
.green
= col
.blue
= 0xffff;
686 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
692 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
694 if(p1
->hash
!= p2
->hash
) return TRUE
;
695 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
696 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
697 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
698 return strcmpiW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
702 static void walk_cache(void)
706 EnterCriticalSection(&xrender_cs
);
707 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
708 TRACE("item %d\n", i
);
709 LeaveCriticalSection(&xrender_cs
);
713 static int LookupEntry(LFANDSIZE
*plfsz
)
717 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
719 if(glyphsetCache
[i
].count
== -1) break; /* reached free list so stop */
721 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
722 glyphsetCache
[i
].count
++;
724 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
725 glyphsetCache
[i
].next
= mru
;
728 TRACE("found font in cache %d\n", i
);
733 TRACE("font not in cache\n");
737 static void FreeEntry(int entry
)
741 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
742 gsCacheEntryFormat
* formatEntry
;
744 if( !glyphsetCache
[entry
].format
[format
] )
747 formatEntry
= glyphsetCache
[entry
].format
[format
];
749 if(formatEntry
->glyphset
) {
751 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
753 formatEntry
->glyphset
= 0;
755 if(formatEntry
->nrealized
) {
756 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
757 formatEntry
->realized
= NULL
;
758 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
759 formatEntry
->gis
= NULL
;
760 formatEntry
->nrealized
= 0;
763 HeapFree(GetProcessHeap(), 0, formatEntry
);
764 glyphsetCache
[entry
].format
[format
] = NULL
;
768 static int AllocEntry(void)
770 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
773 assert(glyphsetCache
[lastfree
].count
== -1);
774 glyphsetCache
[lastfree
].count
= 1;
776 lastfree
= glyphsetCache
[lastfree
].next
;
778 glyphsetCache
[best
].next
= mru
;
781 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
785 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
786 if(glyphsetCache
[i
].count
== 0) {
794 TRACE("freeing unused glyphset at cache %d\n", best
);
796 glyphsetCache
[best
].count
= 1;
798 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
799 glyphsetCache
[best
].next
= mru
;
807 TRACE("Growing cache\n");
810 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
812 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
813 * sizeof(*glyphsetCache
));
815 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
816 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
817 * sizeof(*glyphsetCache
));
819 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
821 glyphsetCache
[i
].next
= i
+ 1;
822 glyphsetCache
[i
].count
= -1;
824 glyphsetCache
[i
-1].next
= -1;
825 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
827 lastfree
= glyphsetCache
[best
].next
;
828 glyphsetCache
[best
].count
= 1;
829 glyphsetCache
[best
].next
= mru
;
831 TRACE("new free cache slot at %d\n", mru
);
835 static BOOL
get_gasp_flags(HDC hdc
, WORD
*flags
)
845 size
= GetFontData(hdc
, MS_GASP_TAG
, 0, NULL
, 0);
846 if(size
== GDI_ERROR
)
849 gasp
= buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
850 GetFontData(hdc
, MS_GASP_TAG
, 0, gasp
, size
);
852 GetTextMetricsW(hdc
, &tm
);
853 ppem
= abs(X11DRV_YWStoDS(hdc
, tm
.tmAscent
+ tm
.tmDescent
- tm
.tmInternalLeading
));
856 num_recs
= get_be_word(*gasp
);
860 *flags
= get_be_word(*(gasp
+ 1));
861 if(ppem
<= get_be_word(*gasp
))
865 TRACE("got flags %04x for ppem %d\n", *flags
, ppem
);
867 HeapFree(GetProcessHeap(), 0, buffer
);
871 static AA_Type
get_antialias_type( HDC hdc
, BOOL subpixel
, BOOL hinter
)
875 UINT font_smoothing_type
, font_smoothing_orientation
;
878 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE
, 0, &font_smoothing_type
, 0) &&
879 font_smoothing_type
== FE_FONTSMOOTHINGCLEARTYPE
)
881 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION
, 0,
882 &font_smoothing_orientation
, 0) &&
883 font_smoothing_orientation
== FE_FONTSMOOTHINGORIENTATIONBGR
)
890 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
891 But, Wine's subpixel rendering can support the portrait mode.
894 else if (!hinter
|| !get_gasp_flags(hdc
, &flags
) || flags
& GASP_DOGRAY
)
902 static int GetCacheEntry( HDC hdc
, LFANDSIZE
*plfsz
)
907 static int hinter
= -1;
908 static int subpixel
= -1;
911 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
914 entry
= glyphsetCache
+ ret
;
915 entry
->lfsz
= *plfsz
;
916 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
917 assert( !entry
->format
[format
] );
920 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
922 if(hinter
== -1 || subpixel
== -1)
924 RASTERIZER_STATUS status
;
925 GetRasterizerCaps(&status
, sizeof(status
));
926 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
927 subpixel
= status
.wFlags
& WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
930 switch (plfsz
->lf
.lfQuality
)
932 case ANTIALIASED_QUALITY
:
933 entry
->aa_default
= get_antialias_type( hdc
, FALSE
, hinter
);
934 return ret
; /* ignore further configuration */
935 case CLEARTYPE_QUALITY
:
936 case CLEARTYPE_NATURAL_QUALITY
:
937 entry
->aa_default
= get_antialias_type( hdc
, subpixel
, hinter
);
939 case DEFAULT_QUALITY
:
943 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING
, 0, &font_smoothing
, 0) &&
946 entry
->aa_default
= get_antialias_type( hdc
, subpixel
, hinter
);
949 entry
->aa_default
= AA_None
;
953 font_smoothing
= TRUE
; /* default to enabled */
954 #ifdef SONAME_LIBFONTCONFIG
955 if (fontconfig_installed
)
957 FcPattern
*match
, *pattern
;
959 char family
[LF_FACESIZE
* 4];
961 #if defined(__i386__) && defined(__GNUC__)
962 /* fontconfig generates floating point exceptions, mask them */
963 WORD cw
, default_cw
= 0x37f;
964 __asm__
__volatile__("fnstcw %0; fldcw %1" : "=m" (cw
) : "m" (default_cw
));
967 WideCharToMultiByte( CP_UTF8
, 0, plfsz
->lf
.lfFaceName
, -1, family
, sizeof(family
), NULL
, NULL
);
968 pattern
= pFcPatternCreate();
969 pFcPatternAddString( pattern
, FC_FAMILY
, (FcChar8
*)family
);
970 if (plfsz
->lf
.lfWeight
!= FW_DONTCARE
)
973 switch (plfsz
->lf
.lfWeight
)
975 case FW_THIN
: weight
= FC_WEIGHT_THIN
; break;
976 case FW_EXTRALIGHT
: weight
= FC_WEIGHT_EXTRALIGHT
; break;
977 case FW_LIGHT
: weight
= FC_WEIGHT_LIGHT
; break;
978 case FW_NORMAL
: weight
= FC_WEIGHT_NORMAL
; break;
979 case FW_MEDIUM
: weight
= FC_WEIGHT_MEDIUM
; break;
980 case FW_SEMIBOLD
: weight
= FC_WEIGHT_SEMIBOLD
; break;
981 case FW_BOLD
: weight
= FC_WEIGHT_BOLD
; break;
982 case FW_EXTRABOLD
: weight
= FC_WEIGHT_EXTRABOLD
; break;
983 case FW_HEAVY
: weight
= FC_WEIGHT_HEAVY
; break;
984 default: weight
= (plfsz
->lf
.lfWeight
- 80) / 4; break;
986 pFcPatternAddInteger( pattern
, FC_WEIGHT
, weight
);
988 pFcPatternAddInteger( pattern
, FC_SLANT
, plfsz
->lf
.lfItalic
? FC_SLANT_ITALIC
: FC_SLANT_ROMAN
);
989 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
990 pFcDefaultSubstitute( pattern
);
991 if ((match
= pFcFontMatch( NULL
, pattern
, &result
)))
996 if (pFcPatternGetBool( match
, FC_ANTIALIAS
, 0, &antialias
) != FcResultMatch
)
998 if (pFcPatternGetInteger( match
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
1001 if (pFcPatternGetString( match
, FC_FILE
, 0, &file
) != FcResultMatch
) file
= NULL
;
1003 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
1004 rgba
, antialias
, debugstr_w(plfsz
->lf
.lfFaceName
), debugstr_a((char *)file
) );
1008 case FC_RGBA_RGB
: entry
->aa_default
= AA_RGB
; break;
1009 case FC_RGBA_BGR
: entry
->aa_default
= AA_BGR
; break;
1010 case FC_RGBA_VRGB
: entry
->aa_default
= AA_VRGB
; break;
1011 case FC_RGBA_VBGR
: entry
->aa_default
= AA_VBGR
; break;
1012 case FC_RGBA_NONE
: entry
->aa_default
= AA_Grey
; break;
1015 if (!antialias
) font_smoothing
= FALSE
;
1016 pFcPatternDestroy( match
);
1018 pFcPatternDestroy( pattern
);
1020 #if defined(__i386__) && defined(__GNUC__)
1021 __asm__
__volatile__("fnclex; fldcw %0" : : "m" (cw
));
1024 #endif /* SONAME_LIBFONTCONFIG */
1026 /* now check Xft resources */
1029 BOOL antialias
= TRUE
;
1032 if ((value
= XGetDefault( gdi_display
, "Xft", "antialias" )))
1034 if (tolower(value
[0]) == 'f' || tolower(value
[0]) == 'n' ||
1035 value
[0] == '0' || !strcasecmp( value
, "off" ))
1038 if ((value
= XGetDefault( gdi_display
, "Xft", "rgba" )))
1040 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value
, antialias
);
1041 if (!strcmp( value
, "rgb" )) entry
->aa_default
= AA_RGB
;
1042 else if (!strcmp( value
, "bgr" )) entry
->aa_default
= AA_BGR
;
1043 else if (!strcmp( value
, "vrgb" )) entry
->aa_default
= AA_VRGB
;
1044 else if (!strcmp( value
, "vbgr" )) entry
->aa_default
= AA_VBGR
;
1045 else if (!strcmp( value
, "none" )) entry
->aa_default
= AA_Grey
;
1047 wine_tsx11_unlock();
1048 if (!antialias
) font_smoothing
= FALSE
;
1051 if (!font_smoothing
) entry
->aa_default
= AA_None
;
1054 entry
->aa_default
= AA_None
;
1059 static void dec_ref_cache(int index
)
1062 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
1063 assert(glyphsetCache
[index
].count
> 0);
1064 glyphsetCache
[index
].count
--;
1067 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
1069 DWORD hash
= 0, *ptr
, two_chars
;
1073 hash
^= plfsz
->devsize
.cx
;
1074 hash
^= plfsz
->devsize
.cy
;
1075 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
1077 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
1079 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
1081 pwc
= (WCHAR
*)&two_chars
;
1083 *pwc
= toupperW(*pwc
);
1085 *pwc
= toupperW(*pwc
);
1093 /***********************************************************************
1094 * X11DRV_XRender_Finalize
1096 void X11DRV_XRender_Finalize(void)
1100 EnterCriticalSection(&xrender_cs
);
1101 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
1103 LeaveCriticalSection(&xrender_cs
);
1104 DeleteCriticalSection(&xrender_cs
);
1107 /**********************************************************************
1108 * xrenderdrv_SelectFont
1110 static HFONT
xrenderdrv_SelectFont( PHYSDEV dev
, HFONT hfont
)
1112 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1113 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
1114 HFONT ret
= next
->funcs
->pSelectFont( next
, hfont
);
1118 if (physdev
->x11dev
->has_gdi_font
)
1122 GetObjectW( hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
1124 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1125 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
1126 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
1127 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
1128 lfsz
.devsize
.cx
= X11DRV_XWStoDS( dev
->hdc
, lfsz
.lf
.lfWidth
);
1129 lfsz
.devsize
.cy
= X11DRV_YWStoDS( dev
->hdc
, lfsz
.lf
.lfHeight
);
1131 GetTransform( dev
->hdc
, 0x204, &lfsz
.xform
);
1132 TRACE("font transform %f %f %f %f\n", lfsz
.xform
.eM11
, lfsz
.xform
.eM12
,
1133 lfsz
.xform
.eM21
, lfsz
.xform
.eM22
);
1135 /* Not used fields, would break hashing */
1136 lfsz
.xform
.eDx
= lfsz
.xform
.eDy
= 0;
1138 lfsz_calc_hash(&lfsz
);
1140 EnterCriticalSection(&xrender_cs
);
1141 if (physdev
->cache_index
!= -1)
1142 dec_ref_cache( physdev
->cache_index
);
1143 physdev
->cache_index
= GetCacheEntry( dev
->hdc
, &lfsz
);
1144 LeaveCriticalSection(&xrender_cs
);
1148 EnterCriticalSection( &xrender_cs
);
1149 if (physdev
->cache_index
!= -1) dec_ref_cache( physdev
->cache_index
);
1150 physdev
->cache_index
= -1;
1151 LeaveCriticalSection( &xrender_cs
);
1156 static BOOL
create_xrender_dc( PHYSDEV
*pdev
, enum wxr_format format
)
1158 X11DRV_PDEVICE
*x11dev
= get_x11drv_dev( *pdev
);
1159 struct xrender_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
1161 if (!physdev
) return FALSE
;
1162 physdev
->x11dev
= x11dev
;
1163 physdev
->cache_index
= -1;
1164 physdev
->format
= format
;
1165 physdev
->pict_format
= pict_formats
[format
];
1166 push_dc_driver( pdev
, &physdev
->dev
, &xrender_funcs
);
1170 /* store the color mask data in the bitmap info structure */
1171 static void set_color_info( XRenderPictFormat
*format
, BITMAPINFO
*info
)
1173 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
1175 info
->bmiHeader
.biPlanes
= 1;
1176 info
->bmiHeader
.biBitCount
= pixmap_formats
[format
->depth
]->bits_per_pixel
;
1177 info
->bmiHeader
.biCompression
= BI_RGB
;
1178 info
->bmiHeader
.biClrUsed
= 0;
1180 switch (info
->bmiHeader
.biBitCount
)
1183 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
1184 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
1185 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
1186 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1189 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
1190 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
1191 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
1192 if (colors
[0] != 0xff0000 || colors
[1] != 0x00ff00 || colors
[2] != 0x0000ff)
1193 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1199 /**********************************************************************
1200 * xrenderdrv_CreateDC
1202 static BOOL
xrenderdrv_CreateDC( PHYSDEV
*pdev
, LPCWSTR driver
, LPCWSTR device
,
1203 LPCWSTR output
, const DEVMODEW
* initData
)
1205 return create_xrender_dc( pdev
, default_format
);
1208 /**********************************************************************
1209 * xrenderdrv_CreateCompatibleDC
1211 static BOOL
xrenderdrv_CreateCompatibleDC( PHYSDEV orig
, PHYSDEV
*pdev
)
1213 if (orig
) /* chain to x11drv first */
1215 orig
= GET_NEXT_PHYSDEV( orig
, pCreateCompatibleDC
);
1216 if (!orig
->funcs
->pCreateCompatibleDC( orig
, pdev
)) return FALSE
;
1218 /* otherwise we have been called by x11drv */
1220 return create_xrender_dc( pdev
, WXR_FORMAT_MONO
);
1223 /**********************************************************************
1224 * xrenderdrv_DeleteDC
1226 static BOOL
xrenderdrv_DeleteDC( PHYSDEV dev
)
1228 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1230 free_xrender_picture( physdev
);
1232 EnterCriticalSection( &xrender_cs
);
1233 if (physdev
->cache_index
!= -1) dec_ref_cache( physdev
->cache_index
);
1234 LeaveCriticalSection( &xrender_cs
);
1236 HeapFree( GetProcessHeap(), 0, physdev
);
1240 /**********************************************************************
1241 * xrenderdrv_ExtEscape
1243 static INT
xrenderdrv_ExtEscape( PHYSDEV dev
, INT escape
, INT in_count
, LPCVOID in_data
,
1244 INT out_count
, LPVOID out_data
)
1246 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1248 dev
= GET_NEXT_PHYSDEV( dev
, pExtEscape
);
1250 if (escape
== X11DRV_ESCAPE
&& in_data
&& in_count
>= sizeof(enum x11drv_escape_codes
))
1252 if (*(const enum x11drv_escape_codes
*)in_data
== X11DRV_SET_DRAWABLE
)
1254 BOOL ret
= dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
1255 if (ret
) free_xrender_picture( physdev
); /* pict format doesn't change, only drawable */
1259 return dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
1262 /****************************************************************************
1263 * xrenderdrv_CopyBitmap
1265 static BOOL
xrenderdrv_CopyBitmap( HBITMAP src
, HBITMAP dst
)
1267 return X11DRV_CopyBitmap( src
, dst
);
1270 /****************************************************************************
1271 * xrenderdrv_CreateBitmap
1273 static BOOL
xrenderdrv_CreateBitmap( PHYSDEV dev
, HBITMAP hbitmap
)
1275 enum wxr_format format
= WXR_INVALID_FORMAT
;
1276 X_PHYSBITMAP
*phys_bitmap
;
1279 if (!GetObjectW( hbitmap
, sizeof(bitmap
), &bitmap
)) return FALSE
;
1281 if (bitmap
.bmBitsPixel
== 1)
1283 if (!(phys_bitmap
= X11DRV_create_phys_bitmap( hbitmap
, &bitmap
, 1 ))) return FALSE
;
1284 phys_bitmap
->format
= WXR_FORMAT_MONO
;
1285 phys_bitmap
->trueColor
= FALSE
;
1289 format
= get_bitmap_format( bitmap
.bmBitsPixel
);
1291 if (pict_formats
[format
])
1293 if (!(phys_bitmap
= X11DRV_create_phys_bitmap( hbitmap
, &bitmap
, pict_formats
[format
]->depth
)))
1295 phys_bitmap
->format
= format
;
1296 phys_bitmap
->trueColor
= TRUE
;
1297 phys_bitmap
->color_shifts
= wxr_color_shifts
[format
];
1301 if (!(phys_bitmap
= X11DRV_create_phys_bitmap( hbitmap
, &bitmap
, screen_depth
)))
1303 phys_bitmap
->format
= WXR_INVALID_FORMAT
;
1304 phys_bitmap
->trueColor
= (visual
->class == TrueColor
|| visual
->class == DirectColor
);
1305 phys_bitmap
->color_shifts
= X11DRV_PALETTE_default_shifts
;
1311 /****************************************************************************
1312 * xrenderdrv_DeleteBitmap
1314 static BOOL
xrenderdrv_DeleteBitmap( HBITMAP hbitmap
)
1316 return X11DRV_DeleteBitmap( hbitmap
);
1319 /***********************************************************************
1320 * xrenderdrv_SelectBitmap
1322 static HBITMAP
xrenderdrv_SelectBitmap( PHYSDEV dev
, HBITMAP hbitmap
)
1325 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1327 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBitmap
);
1328 ret
= dev
->funcs
->pSelectBitmap( dev
, hbitmap
);
1331 free_xrender_picture( physdev
);
1332 if (hbitmap
== BITMAP_stock_phys_bitmap
.hbitmap
) physdev
->format
= WXR_FORMAT_MONO
;
1333 else physdev
->format
= X11DRV_get_phys_bitmap(hbitmap
)->format
;
1334 physdev
->pict_format
= pict_formats
[physdev
->format
];
1339 /***********************************************************************
1340 * xrenderdrv_GetImage
1342 static DWORD
xrenderdrv_GetImage( PHYSDEV dev
, HBITMAP hbitmap
, BITMAPINFO
*info
,
1343 struct gdi_image_bits
*bits
, struct bitblt_coords
*src
)
1345 if (hbitmap
) return X11DRV_GetImage( dev
, hbitmap
, info
, bits
, src
);
1346 dev
= GET_NEXT_PHYSDEV( dev
, pGetImage
);
1347 return dev
->funcs
->pGetImage( dev
, hbitmap
, info
, bits
, src
);
1350 /***********************************************************************
1351 * xrenderdrv_SetDeviceClipping
1353 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev
, HRGN rgn
)
1355 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1357 physdev
->region
= rgn
;
1358 physdev
->update_clip
= TRUE
;
1360 dev
= GET_NEXT_PHYSDEV( dev
, pSetDeviceClipping
);
1361 dev
->funcs
->pSetDeviceClipping( dev
, rgn
);
1365 /************************************************************************
1368 * Helper to ExtTextOut. Must be called inside xrender_cs
1370 static void UploadGlyph(struct xrender_physdev
*physDev
, int glyph
, AA_Type format
)
1372 unsigned int buflen
;
1377 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->cache_index
;
1378 gsCacheEntryFormat
*formatEntry
;
1379 UINT ggo_format
= GGO_GLYPH_INDEX
;
1380 enum wxr_format wxr_format
;
1381 static const char zero
[4];
1382 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
1386 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
1389 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
1392 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
1395 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
1398 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
1402 ERR("aa = %d - not implemented\n", format
);
1404 ggo_format
|= GGO_BITMAP
;
1408 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1409 if(buflen
== GDI_ERROR
) {
1410 if(format
!= AA_None
) {
1412 entry
->aa_default
= AA_None
;
1413 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
1414 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1416 if(buflen
== GDI_ERROR
) {
1417 WARN("GetGlyphOutlineW failed using default glyph\n");
1418 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0, ggo_format
, &gm
, 0, NULL
, &identity
);
1419 if(buflen
== GDI_ERROR
) {
1420 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1421 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0x20, ggo_format
, &gm
, 0, NULL
, &identity
);
1422 if(buflen
== GDI_ERROR
) {
1423 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1428 TRACE("Turning off antialiasing for this monochrome font\n");
1431 /* If there is nothing for the current type, we create the entry. */
1432 if( !entry
->format
[format
] ) {
1433 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
1435 sizeof(gsCacheEntryFormat
));
1437 formatEntry
= entry
->format
[format
];
1439 if(formatEntry
->nrealized
<= glyph
) {
1440 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
1442 if (formatEntry
->realized
)
1443 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
1445 formatEntry
->realized
,
1446 formatEntry
->nrealized
* sizeof(BOOL
));
1448 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
1450 formatEntry
->nrealized
* sizeof(BOOL
));
1452 if (formatEntry
->gis
)
1453 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
1456 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1458 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
1460 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1464 if(formatEntry
->glyphset
== 0) {
1467 wxr_format
= WXR_FORMAT_GRAY
;
1474 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1478 ERR("aa = %d - not implemented\n", format
);
1480 wxr_format
= WXR_FORMAT_MONO
;
1485 formatEntry
->font_format
= pict_formats
[wxr_format
];
1486 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
1487 wine_tsx11_unlock();
1491 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
1492 GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
1493 formatEntry
->realized
[glyph
] = TRUE
;
1495 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1497 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1498 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1500 gi
.width
= gm
.gmBlackBoxX
;
1501 gi
.height
= gm
.gmBlackBoxY
;
1502 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1503 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1504 gi
.xOff
= gm
.gmCellIncX
;
1505 gi
.yOff
= gm
.gmCellIncY
;
1507 if(TRACE_ON(xrender
)) {
1510 unsigned char *line
;
1512 if(format
== AA_None
) {
1513 pitch
= ((gi
.width
+ 31) / 32) * 4;
1514 for(i
= 0; i
< gi
.height
; i
++) {
1515 line
= (unsigned char*) buf
+ i
* pitch
;
1517 for(j
= 0; j
< pitch
* 8; j
++) {
1518 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1520 TRACE("%s\n", output
);
1523 static const char blks
[] = " .:;!o*#";
1527 pitch
= ((gi
.width
+ 3) / 4) * 4;
1528 for(i
= 0; i
< gi
.height
; i
++) {
1529 line
= (unsigned char*) buf
+ i
* pitch
;
1531 for(j
= 0; j
< pitch
; j
++) {
1532 str
[0] = blks
[line
[j
] >> 5];
1533 strcat(output
, str
);
1535 TRACE("%s\n", output
);
1541 if(formatEntry
->glyphset
) {
1542 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1543 unsigned char *byte
= (unsigned char*) buf
, c
;
1549 /* magic to flip bit order */
1550 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1551 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1552 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1557 else if ( format
!= AA_Grey
&&
1558 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1560 unsigned int i
, *data
= (unsigned int *)buf
;
1561 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1566 XRenderCompositeText seems to ignore 0x0 glyphs when
1567 AA_None, which means we lose the advance width of glyphs
1568 like the space. We'll pretend that such glyphs are 1x1
1573 gi
.width
= gi
.height
= 1;
1576 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1577 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1578 wine_tsx11_unlock();
1579 HeapFree(GetProcessHeap(), 0, buf
);
1582 formatEntry
->gis
[glyph
] = gi
;
1585 /*************************************************************
1588 * Returns an appropriate Picture for tiling the text colour.
1589 * Call and use result within the xrender_cs
1591 static Picture
get_tile_pict( enum wxr_format wxr_format
, const XRenderColor
*color
)
1597 XRenderColor current_color
;
1598 } tiles
[WXR_NB_FORMATS
], *tile
;
1600 tile
= &tiles
[wxr_format
];
1604 XRenderPictureAttributes pa
;
1605 XRenderPictFormat
*pict_format
= pict_formats
[wxr_format
];
1608 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_format
->depth
);
1610 pa
.repeat
= RepeatNormal
;
1611 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_format
, CPRepeat
, &pa
);
1612 wine_tsx11_unlock();
1614 /* init current_color to something different from text_pixel */
1615 tile
->current_color
= *color
;
1616 tile
->current_color
.red
^= 0xffff;
1618 if (wxr_format
== WXR_FORMAT_MONO
)
1620 /* for a 1bpp bitmap we always need a 1 in the tile */
1622 col
.red
= col
.green
= col
.blue
= 0;
1625 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1626 wine_tsx11_unlock();
1630 if (memcmp( color
, &tile
->current_color
, sizeof(*color
) ) && wxr_format
!= WXR_FORMAT_MONO
)
1633 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, color
, 0, 0, 1, 1);
1634 wine_tsx11_unlock();
1635 tile
->current_color
= *color
;
1640 /*************************************************************
1643 * Returns an appropriate Picture for masking with the specified alpha.
1644 * Call and use result within the xrender_cs
1646 static Picture
get_mask_pict( int alpha
)
1648 static Pixmap pixmap
;
1649 static Picture pict
;
1650 static int current_alpha
;
1652 if (alpha
== 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1656 XRenderPictureAttributes pa
;
1659 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
1660 pa
.repeat
= RepeatNormal
;
1661 pict
= pXRenderCreatePicture( gdi_display
, pixmap
,
1662 pict_formats
[WXR_FORMAT_A8R8G8B8
], CPRepeat
, &pa
);
1663 wine_tsx11_unlock();
1667 if (alpha
!= current_alpha
)
1670 col
.red
= col
.green
= col
.blue
= 0;
1671 col
.alpha
= current_alpha
= alpha
;
1673 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
1674 wine_tsx11_unlock();
1679 /***********************************************************************
1680 * xrenderdrv_ExtTextOut
1682 static BOOL
xrenderdrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
,
1683 const RECT
*lprect
, LPCWSTR wstr
, UINT count
, const INT
*lpDx
)
1685 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1686 gsCacheEntry
*entry
;
1687 gsCacheEntryFormat
*formatEntry
;
1688 AA_Type aa_type
= AA_None
;
1690 Picture pict
, tile_pict
= 0;
1692 POINT offset
, desired
, current
;
1693 int render_op
= PictOpOver
;
1696 if (!physdev
->x11dev
->has_gdi_font
)
1698 dev
= GET_NEXT_PHYSDEV( dev
, pExtTextOut
);
1699 return dev
->funcs
->pExtTextOut( dev
, x
, y
, flags
, lprect
, wstr
, count
, lpDx
);
1702 get_xrender_color( physdev
, GetTextColor( physdev
->dev
.hdc
), &col
);
1703 pict
= get_xrender_picture( physdev
, 0, (flags
& ETO_CLIPPED
) ? lprect
: NULL
);
1705 if(flags
& ETO_OPAQUE
)
1709 if (physdev
->format
== WXR_FORMAT_MONO
)
1710 /* use the inverse of the text color */
1711 bg
.red
= bg
.green
= bg
.blue
= bg
.alpha
= ~col
.alpha
;
1713 get_xrender_color( physdev
, GetBkColor( physdev
->dev
.hdc
), &bg
);
1716 set_xrender_transformation( pict
, 1, 1, 0, 0 );
1717 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &bg
,
1718 physdev
->x11dev
->dc_rect
.left
+ lprect
->left
,
1719 physdev
->x11dev
->dc_rect
.top
+ lprect
->top
,
1720 lprect
->right
- lprect
->left
,
1721 lprect
->bottom
- lprect
->top
);
1722 wine_tsx11_unlock();
1725 if(count
== 0) return TRUE
;
1727 EnterCriticalSection(&xrender_cs
);
1729 entry
= glyphsetCache
+ physdev
->cache_index
;
1730 aa_type
= entry
->aa_default
;
1731 formatEntry
= entry
->format
[aa_type
];
1733 for(idx
= 0; idx
< count
; idx
++) {
1734 if( !formatEntry
) {
1735 UploadGlyph(physdev
, wstr
[idx
], aa_type
);
1736 /* re-evaluate antialias since aa_default may have changed */
1737 aa_type
= entry
->aa_default
;
1738 formatEntry
= entry
->format
[aa_type
];
1739 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1740 UploadGlyph(physdev
, wstr
[idx
], aa_type
);
1745 WARN("could not upload requested glyphs\n");
1746 LeaveCriticalSection(&xrender_cs
);
1750 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1751 physdev
->x11dev
->dc_rect
.left
+ x
, physdev
->x11dev
->dc_rect
.top
+ y
);
1753 elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1755 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1756 So we pass zeros to the function and move to our starting position using the first
1757 element of the elts array. */
1759 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
;
1760 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
;
1761 offset
.x
= offset
.y
= 0;
1762 current
.x
= current
.y
= 0;
1764 tile_pict
= get_tile_pict(physdev
->format
, &col
);
1766 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1768 if (physdev
->format
== WXR_FORMAT_MONO
&& col
.red
== 0 && col
.green
== 0 && col
.blue
== 0)
1769 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1771 for(idx
= 0; idx
< count
; idx
++)
1773 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1774 elts
[idx
].chars
= wstr
+ idx
;
1775 elts
[idx
].nchars
= 1;
1776 elts
[idx
].xOff
= desired
.x
- current
.x
;
1777 elts
[idx
].yOff
= desired
.y
- current
.y
;
1779 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1780 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1784 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1785 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1791 offset
.x
+= lpDx
[idx
* 2];
1792 offset
.y
+= lpDx
[idx
* 2 + 1];
1795 offset
.x
+= lpDx
[idx
];
1796 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
+ offset
.x
;
1797 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
+ offset
.y
;
1802 /* Make sure we don't have any transforms set from a previous call */
1803 set_xrender_transformation(pict
, 1, 1, 0, 0);
1804 pXRenderCompositeText16(gdi_display
, render_op
,
1807 formatEntry
->font_format
,
1808 0, 0, 0, 0, elts
, count
);
1809 wine_tsx11_unlock();
1810 HeapFree(GetProcessHeap(), 0, elts
);
1812 LeaveCriticalSection(&xrender_cs
);
1816 /* multiply the alpha channel of a picture */
1817 static void multiply_alpha( Picture pict
, XRenderPictFormat
*format
, int alpha
,
1818 int x
, int y
, int width
, int height
)
1820 XRenderPictureAttributes pa
;
1821 Pixmap src_pixmap
, mask_pixmap
;
1822 Picture src_pict
, mask_pict
;
1826 src_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1827 mask_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1828 pa
.repeat
= RepeatNormal
;
1829 src_pict
= pXRenderCreatePicture( gdi_display
, src_pixmap
, format
, CPRepeat
, &pa
);
1830 pa
.component_alpha
= True
;
1831 mask_pict
= pXRenderCreatePicture( gdi_display
, mask_pixmap
, format
, CPRepeat
|CPComponentAlpha
, &pa
);
1832 color
.red
= color
.green
= color
.blue
= color
.alpha
= 0xffff;
1833 pXRenderFillRectangle( gdi_display
, PictOpSrc
, src_pict
, &color
, 0, 0, 1, 1 );
1834 color
.alpha
= alpha
;
1835 pXRenderFillRectangle( gdi_display
, PictOpSrc
, mask_pict
, &color
, 0, 0, 1, 1 );
1836 pXRenderComposite( gdi_display
, PictOpInReverse
, src_pict
, mask_pict
, pict
,
1837 0, 0, 0, 0, x
, y
, width
, height
);
1838 pXRenderFreePicture( gdi_display
, src_pict
);
1839 pXRenderFreePicture( gdi_display
, mask_pict
);
1840 XFreePixmap( gdi_display
, src_pixmap
);
1841 XFreePixmap( gdi_display
, mask_pixmap
);
1842 wine_tsx11_unlock();
1845 /* Helper function for (stretched) blitting using xrender */
1846 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
1847 int x_src
, int y_src
, int width_src
, int height_src
,
1848 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1849 double xscale
, double yscale
)
1851 int x_offset
, y_offset
;
1855 x_src
+= width_src
+ 1;
1856 width_src
= -width_src
;
1860 y_src
+= height_src
+ 1;
1861 height_src
= -height_src
;
1865 x_dst
+= width_dst
+ 1;
1866 width_dst
= -width_dst
;
1870 y_dst
+= height_dst
+ 1;
1871 height_dst
= -height_dst
;
1874 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1875 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1876 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1878 if(xscale
!= 1.0 || yscale
!= 1.0)
1880 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1881 * in the wrong quadrant of the x-y plane.
1883 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1884 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1885 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1891 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1893 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
1894 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width_dst
, height_dst
);
1895 wine_tsx11_unlock();
1898 /* Helper function for (stretched) mono->color blitting using xrender */
1899 static void xrender_mono_blit( Picture src_pict
, Picture dst_pict
,
1900 enum wxr_format dst_format
, XRenderColor
*fg
, XRenderColor
*bg
,
1901 int x_src
, int y_src
, int width_src
, int height_src
,
1902 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1903 double xscale
, double yscale
)
1906 int x_offset
, y_offset
;
1911 x_src
+= width_src
+ 1;
1912 width_src
= -width_src
;
1916 y_src
+= height_src
+ 1;
1917 height_src
= -height_src
;
1921 x_dst
+= width_dst
+ 1;
1922 width_dst
= -width_dst
;
1926 y_dst
+= height_dst
+ 1;
1927 height_dst
= -height_dst
;
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_dst
, height_dst
);
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_dst
: 0;
1948 y_offset
= (yscale
< 0) ? -height_dst
: 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_dst
, height_dst
);
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
,
1965 x_dst
, y_dst
, width_dst
, height_dst
);
1968 /* create a pixmap and render picture for an image */
1969 static DWORD
create_image_pixmap( BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1970 struct bitblt_coords
*src
, enum wxr_format format
,
1971 Pixmap
*pixmap
, Picture
*pict
, BOOL
*use_repeat
)
1974 int width
= src
->visrect
.right
- src
->visrect
.left
;
1975 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1976 int depth
= pict_formats
[format
]->depth
;
1977 struct gdi_image_bits dst_bits
;
1978 XRenderPictureAttributes pa
;
1982 image
= XCreateImage( gdi_display
, visual
, depth
, ZPixmap
, 0, NULL
,
1983 info
->bmiHeader
.biWidth
, height
, 32, 0 );
1984 wine_tsx11_unlock();
1985 if (!image
) return ERROR_OUTOFMEMORY
;
1987 ret
= copy_image_bits( info
, (format
== WXR_FORMAT_R8G8B8
), image
, bits
, &dst_bits
, src
, NULL
, ~0u );
1988 if (ret
) return ret
;
1990 image
->data
= dst_bits
.ptr
;
1992 *use_repeat
= (width
== 1 && height
== 1);
1993 pa
.repeat
= *use_repeat
? RepeatNormal
: RepeatNone
;
1996 *pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, depth
);
1997 XPutImage( gdi_display
, *pixmap
, get_bitmap_gc( depth
), image
,
1998 src
->visrect
.left
, 0, 0, 0, width
, height
);
1999 *pict
= pXRenderCreatePicture( gdi_display
, *pixmap
, pict_formats
[format
], CPRepeat
, &pa
);
2000 wine_tsx11_unlock();
2002 /* make coordinates relative to the pixmap */
2003 src
->x
-= src
->visrect
.left
;
2004 src
->y
-= src
->visrect
.top
;
2005 OffsetRect( &src
->visrect
, -src
->visrect
.left
, -src
->visrect
.top
);
2009 XDestroyImage( image
);
2010 wine_tsx11_unlock();
2011 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
2015 static void xrender_stretch_blit( struct xrender_physdev
*physdev_src
, struct xrender_physdev
*physdev_dst
,
2016 Drawable drawable
, const struct bitblt_coords
*src
,
2017 const struct bitblt_coords
*dst
)
2020 Picture src_pict
= 0, dst_pict
, mask_pict
= 0;
2022 double xscale
, yscale
;
2024 use_repeat
= use_source_repeat( physdev_src
);
2027 xscale
= src
->width
/ (double)dst
->width
;
2028 yscale
= src
->height
/ (double)dst
->height
;
2030 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2032 if (drawable
) /* using an intermediate pixmap */
2034 XRenderPictureAttributes pa
;
2038 pa
.repeat
= RepeatNone
;
2040 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, physdev_dst
->pict_format
, CPRepeat
, &pa
);
2041 wine_tsx11_unlock();
2045 x_dst
= physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
;
2046 y_dst
= physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
;
2047 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
2050 src_pict
= get_xrender_picture_source( physdev_src
, use_repeat
);
2053 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
2055 XRenderColor fg
, bg
;
2057 get_xrender_color( physdev_dst
, GetTextColor( physdev_dst
->dev
.hdc
), &fg
);
2058 get_xrender_color( physdev_dst
, GetBkColor( physdev_dst
->dev
.hdc
), &bg
);
2059 fg
.alpha
= bg
.alpha
= 0;
2061 xrender_mono_blit( src_pict
, dst_pict
, physdev_dst
->format
, &fg
, &bg
,
2062 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
2063 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
2064 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
2066 else /* color -> color (can be at different depths) or mono -> mono */
2068 if (physdev_dst
->pict_format
->depth
== 32 && physdev_src
->pict_format
->depth
< 32)
2069 mask_pict
= get_no_alpha_mask();
2071 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
2072 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
2073 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
2074 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
2080 pXRenderFreePicture( gdi_display
, dst_pict
);
2081 wine_tsx11_unlock();
2086 static void xrender_put_image( Pixmap src_pixmap
, Picture src_pict
, Picture mask_pict
, HRGN clip
,
2087 XRenderPictFormat
*dst_format
, struct xrender_physdev
*physdev
,
2088 Drawable drawable
, struct bitblt_coords
*src
,
2089 struct bitblt_coords
*dst
, BOOL use_repeat
)
2093 XRenderPictureAttributes pa
;
2094 double xscale
, yscale
;
2096 if (drawable
) /* using an intermediate pixmap */
2098 RGNDATA
*clip_data
= NULL
;
2100 if (clip
) clip_data
= X11DRV_GetRegionData( clip
, 0 );
2103 pa
.repeat
= RepeatNone
;
2105 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, dst_format
, CPRepeat
, &pa
);
2107 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
, 0, 0,
2108 (XRectangle
*)clip_data
->Buffer
, clip_data
->rdh
.nCount
);
2109 wine_tsx11_unlock();
2110 HeapFree( GetProcessHeap(), 0, clip_data
);
2114 x_dst
= physdev
->x11dev
->dc_rect
.left
+ dst
->x
;
2115 y_dst
= physdev
->x11dev
->dc_rect
.top
+ dst
->y
;
2116 dst_pict
= get_xrender_picture( physdev
, clip
, &dst
->visrect
);
2121 xscale
= src
->width
/ (double)dst
->width
;
2122 yscale
= src
->height
/ (double)dst
->height
;
2124 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2126 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
, src
->x
, src
->y
, src
->width
, src
->height
,
2127 x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
2132 pXRenderFreePicture( gdi_display
, dst_pict
);
2133 wine_tsx11_unlock();
2138 /***********************************************************************
2139 * xrenderdrv_StretchBlt
2141 static BOOL
xrenderdrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
2142 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
2144 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
2145 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
2146 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
2148 if (src_dev
->funcs
!= dst_dev
->funcs
)
2150 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pStretchBlt
);
2151 return dst_dev
->funcs
->pStretchBlt( dst_dev
, dst
, src_dev
, src
, rop
);
2154 /* XRender is of no use for color -> mono */
2155 if (physdev_dst
->format
== WXR_FORMAT_MONO
&& physdev_src
->format
!= WXR_FORMAT_MONO
)
2156 goto x11drv_fallback
;
2158 /* if not stretching, we only need to handle format conversion */
2159 if (!stretch
&& physdev_dst
->format
== physdev_src
->format
) goto x11drv_fallback
;
2165 struct bitblt_coords tmp
;
2167 /* make coordinates relative to tmp pixmap */
2169 tmp
.x
-= tmp
.visrect
.left
;
2170 tmp
.y
-= tmp
.visrect
.top
;
2171 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
2174 tmpGC
= XCreateGC( gdi_display
, physdev_dst
->x11dev
->drawable
, 0, NULL
);
2175 XSetSubwindowMode( gdi_display
, tmpGC
, IncludeInferiors
);
2176 XSetGraphicsExposures( gdi_display
, tmpGC
, False
);
2177 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, tmp
.visrect
.right
- tmp
.visrect
.left
,
2178 tmp
.visrect
.bottom
- tmp
.visrect
.top
, physdev_dst
->pict_format
->depth
);
2179 wine_tsx11_unlock();
2181 xrender_stretch_blit( physdev_src
, physdev_dst
, tmp_pixmap
, src
, &tmp
);
2182 execute_rop( physdev_dst
->x11dev
, tmp_pixmap
, tmpGC
, &dst
->visrect
, rop
);
2185 XFreePixmap( gdi_display
, tmp_pixmap
);
2186 XFreeGC( gdi_display
, tmpGC
);
2187 wine_tsx11_unlock();
2189 else xrender_stretch_blit( physdev_src
, physdev_dst
, 0, src
, dst
);
2194 return X11DRV_StretchBlt( &physdev_dst
->x11dev
->dev
, dst
, &physdev_src
->x11dev
->dev
, src
, rop
);
2198 /***********************************************************************
2199 * xrenderdrv_PutImage
2201 static DWORD
xrenderdrv_PutImage( PHYSDEV dev
, HBITMAP hbitmap
, HRGN clip
, BITMAPINFO
*info
,
2202 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
2203 struct bitblt_coords
*dst
, DWORD rop
)
2205 struct xrender_physdev
*physdev
;
2206 X_PHYSBITMAP
*bitmap
;
2210 enum wxr_format src_format
, dst_format
;
2211 XRenderPictFormat
*pict_format
;
2213 Picture src_pict
, mask_pict
= 0;
2218 if (!(bitmap
= X11DRV_get_phys_bitmap( hbitmap
))) return ERROR_INVALID_HANDLE
;
2220 dst_format
= bitmap
->format
;
2224 physdev
= get_xrender_dev( dev
);
2226 dst_format
= physdev
->format
;
2229 src_format
= get_xrender_format_from_bitmapinfo( info
);
2230 if (!(pict_format
= pict_formats
[src_format
])) goto update_format
;
2232 /* make sure we can create an image with the same bpp */
2233 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
2236 /* mono <-> color conversions not supported */
2237 if ((src_format
!= dst_format
) && (src_format
== WXR_FORMAT_MONO
|| dst_format
== WXR_FORMAT_MONO
))
2238 goto x11drv_fallback
;
2240 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
2242 if (!has_alpha( src_format
) && has_alpha( dst_format
)) mask_pict
= get_no_alpha_mask();
2244 ret
= create_image_pixmap( info
, bits
, src
, src_format
, &src_pixmap
, &src_pict
, &use_repeat
);
2247 struct bitblt_coords tmp
;
2251 HRGN rgn
= CreateRectRgnIndirect( &dst
->visrect
);
2252 if (clip
) CombineRgn( rgn
, rgn
, clip
, RGN_AND
);
2254 xrender_put_image( src_pixmap
, src_pict
, mask_pict
, rgn
,
2255 pict_formats
[dst_format
], NULL
, bitmap
->pixmap
, src
, dst
, use_repeat
);
2256 DeleteObject( rgn
);
2262 BOOL restore_region
= add_extra_clipping_region( physdev
->x11dev
, clip
);
2264 /* make coordinates relative to tmp pixmap */
2266 tmp
.x
-= tmp
.visrect
.left
;
2267 tmp
.y
-= tmp
.visrect
.top
;
2268 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
2271 gc
= XCreateGC( gdi_display
, physdev
->x11dev
->drawable
, 0, NULL
);
2272 XSetSubwindowMode( gdi_display
, gc
, IncludeInferiors
);
2273 XSetGraphicsExposures( gdi_display
, gc
, False
);
2274 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
,
2275 tmp
.visrect
.right
- tmp
.visrect
.left
,
2276 tmp
.visrect
.bottom
- tmp
.visrect
.top
,
2277 physdev
->pict_format
->depth
);
2278 wine_tsx11_unlock();
2280 xrender_put_image( src_pixmap
, src_pict
, mask_pict
, NULL
, physdev
->pict_format
,
2281 NULL
, tmp_pixmap
, src
, &tmp
, use_repeat
);
2282 execute_rop( physdev
->x11dev
, tmp_pixmap
, gc
, &dst
->visrect
, rop
);
2285 XFreePixmap( gdi_display
, tmp_pixmap
);
2286 XFreeGC( gdi_display
, gc
);
2287 wine_tsx11_unlock();
2289 if (restore_region
) restore_clipping_region( physdev
->x11dev
);
2291 else xrender_put_image( src_pixmap
, src_pict
, mask_pict
, clip
,
2292 physdev
->pict_format
, physdev
, 0, src
, dst
, use_repeat
);
2296 pXRenderFreePicture( gdi_display
, src_pict
);
2297 XFreePixmap( gdi_display
, src_pixmap
);
2298 wine_tsx11_unlock();
2303 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
2304 set_color_info( pict_formats
[dst_format
], info
);
2305 return ERROR_BAD_FORMAT
;
2308 if (hbitmap
) return X11DRV_PutImage( dev
, hbitmap
, clip
, info
, bits
, src
, dst
, rop
);
2309 dev
= GET_NEXT_PHYSDEV( dev
, pPutImage
);
2310 return dev
->funcs
->pPutImage( dev
, hbitmap
, clip
, info
, bits
, src
, dst
, rop
);
2314 /***********************************************************************
2315 * xrenderdrv_BlendImage
2317 static DWORD
xrenderdrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
2318 struct bitblt_coords
*src
, struct bitblt_coords
*dst
,
2319 BLENDFUNCTION func
)
2321 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2323 enum wxr_format format
;
2324 XRenderPictFormat
*pict_format
;
2325 Picture dst_pict
, src_pict
, mask_pict
;
2329 format
= get_xrender_format_from_bitmapinfo( info
);
2330 if (!(func
.AlphaFormat
& AC_SRC_ALPHA
))
2331 format
= get_format_without_alpha( format
);
2332 else if (format
!= WXR_FORMAT_A8R8G8B8
)
2333 return ERROR_INVALID_PARAMETER
;
2335 if (!(pict_format
= pict_formats
[format
])) goto update_format
;
2337 /* make sure we can create an image with the same bpp */
2338 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
2341 if (format
== WXR_FORMAT_MONO
&& physdev
->format
!= WXR_FORMAT_MONO
)
2344 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
2346 ret
= create_image_pixmap( info
, bits
, src
, format
, &src_pixmap
, &src_pict
, &use_repeat
);
2349 double xscale
, yscale
;
2353 xscale
= src
->width
/ (double)dst
->width
;
2354 yscale
= src
->height
/ (double)dst
->height
;
2356 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2358 dst_pict
= get_xrender_picture( physdev
, 0, &dst
->visrect
);
2360 EnterCriticalSection( &xrender_cs
);
2361 mask_pict
= get_mask_pict( func
.SourceConstantAlpha
* 257 );
2363 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2364 src
->x
, src
->y
, src
->width
, src
->height
,
2365 physdev
->x11dev
->dc_rect
.left
+ dst
->x
,
2366 physdev
->x11dev
->dc_rect
.top
+ dst
->y
,
2367 dst
->width
, dst
->height
, xscale
, yscale
);
2370 pXRenderFreePicture( gdi_display
, src_pict
);
2371 XFreePixmap( gdi_display
, src_pixmap
);
2372 wine_tsx11_unlock();
2374 LeaveCriticalSection( &xrender_cs
);
2379 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
2380 set_color_info( physdev
->pict_format
, info
);
2381 return ERROR_BAD_FORMAT
;
2385 /***********************************************************************
2386 * xrenderdrv_AlphaBlend
2388 static BOOL
xrenderdrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
2389 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
2391 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
2392 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
2393 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
2394 XRenderPictureAttributes pa
;
2395 Pixmap tmp_pixmap
= 0;
2396 double xscale
, yscale
;
2399 if (src_dev
->funcs
!= dst_dev
->funcs
)
2401 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pAlphaBlend
);
2402 return dst_dev
->funcs
->pAlphaBlend( dst_dev
, dst
, src_dev
, src
, blendfn
);
2405 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->format
!= WXR_FORMAT_A8R8G8B8
)
2407 SetLastError( ERROR_INVALID_PARAMETER
);
2411 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
2413 use_repeat
= use_source_repeat( physdev_src
);
2416 xscale
= src
->width
/ (double)dst
->width
;
2417 yscale
= src
->height
/ (double)dst
->height
;
2419 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2421 src_pict
= get_xrender_picture_source( physdev_src
, use_repeat
);
2423 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
2425 /* mono -> color blending needs an intermediate color pixmap */
2426 XRenderColor fg
, bg
;
2427 int width
= src
->visrect
.right
- src
->visrect
.left
;
2428 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
2430 /* blending doesn't use the destination DC colors */
2431 fg
.red
= fg
.green
= fg
.blue
= 0;
2432 bg
.red
= bg
.green
= bg
.blue
= 0xffff;
2433 fg
.alpha
= bg
.alpha
= 0xffff;
2436 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
,
2437 physdev_dst
->pict_format
->depth
);
2438 pa
.repeat
= use_repeat
? RepeatNormal
: RepeatNone
;
2439 tmp_pict
= pXRenderCreatePicture( gdi_display
, tmp_pixmap
, physdev_dst
->pict_format
,
2441 wine_tsx11_unlock();
2443 xrender_mono_blit( src_pict
, tmp_pict
, physdev_dst
->format
, &fg
, &bg
,
2444 src
->visrect
.left
, src
->visrect
.top
, width
, height
, 0, 0, width
, height
, 1, 1 );
2446 else if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->pict_format
)
2448 /* we need a source picture with no alpha */
2449 enum wxr_format format
= get_format_without_alpha( physdev_src
->format
);
2450 if (format
!= physdev_src
->format
)
2453 pa
.subwindow_mode
= IncludeInferiors
;
2454 pa
.repeat
= use_repeat
? RepeatNormal
: RepeatNone
;
2455 tmp_pict
= pXRenderCreatePicture( gdi_display
, physdev_src
->x11dev
->drawable
,
2456 pict_formats
[format
], CPSubwindowMode
|CPRepeat
, &pa
);
2457 wine_tsx11_unlock();
2461 if (tmp_pict
) src_pict
= tmp_pict
;
2463 EnterCriticalSection( &xrender_cs
);
2464 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
2466 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2467 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
2468 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
2469 src
->width
, src
->height
,
2470 physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
,
2471 physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
,
2472 dst
->width
, dst
->height
, xscale
, yscale
);
2475 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
2476 if (tmp_pixmap
) XFreePixmap( gdi_display
, tmp_pixmap
);
2477 wine_tsx11_unlock();
2479 LeaveCriticalSection( &xrender_cs
);
2483 /***********************************************************************
2484 * xrenderdrv_GradientFill
2486 static BOOL
xrenderdrv_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
2487 void * grad_array
, ULONG ngrad
, ULONG mode
)
2489 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2490 static const XFixed stops
[2] = { 0, 1 << 16 };
2491 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2492 XLinearGradient gradient
;
2493 XRenderColor colors
[2];
2494 Picture src_pict
, dst_pict
;
2496 const GRADIENT_RECT
*rect
= grad_array
;
2499 if (!pXRenderCreateLinearGradient
) goto fallback
;
2501 /* <= 16-bpp uses dithering */
2502 if (!physdev
->pict_format
|| physdev
->pict_format
->depth
<= 16) goto fallback
;
2506 case GRADIENT_FILL_RECT_H
:
2507 case GRADIENT_FILL_RECT_V
:
2508 for (i
= 0; i
< ngrad
; i
++, rect
++)
2510 const TRIVERTEX
*v1
= vert_array
+ rect
->UpperLeft
;
2511 const TRIVERTEX
*v2
= vert_array
+ rect
->LowerRight
;
2513 colors
[0].red
= v1
->Red
* 257 / 256;
2514 colors
[0].green
= v1
->Green
* 257 / 256;
2515 colors
[0].blue
= v1
->Blue
* 257 / 256;
2516 colors
[1].red
= v2
->Red
* 257 / 256;
2517 colors
[1].green
= v2
->Green
* 257 / 256;
2518 colors
[1].blue
= v2
->Blue
* 257 / 256;
2519 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2520 colors
[0].alpha
= colors
[1].alpha
= 65535;
2526 LPtoDP( dev
->hdc
, pt
, 2 );
2527 if (mode
== GRADIENT_FILL_RECT_H
)
2529 gradient
.p1
.y
= gradient
.p2
.y
= 0;
2530 if (pt
[1].x
> pt
[0].x
)
2533 gradient
.p2
.x
= (pt
[1].x
- pt
[0].x
) << 16;
2537 gradient
.p1
.x
= (pt
[0].x
- pt
[1].x
) << 16;
2543 gradient
.p1
.x
= gradient
.p2
.x
= 0;
2544 if (pt
[1].y
> pt
[0].y
)
2547 gradient
.p2
.y
= (pt
[1].y
- pt
[0].y
) << 16;
2551 gradient
.p1
.y
= (pt
[0].y
- pt
[1].y
) << 16;
2556 TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2557 mode
, pt
[0].x
, pt
[0].y
, pt
[1].x
, pt
[1].y
,
2558 colors
[0].red
, colors
[0].green
, colors
[0].blue
, colors
[0].alpha
,
2559 colors
[1].red
, colors
[1].green
, colors
[1].blue
, colors
[1].alpha
);
2561 dst_pict
= get_xrender_picture( physdev
, 0, NULL
);
2564 src_pict
= pXRenderCreateLinearGradient( gdi_display
, &gradient
, stops
, colors
, 2 );
2565 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
,
2566 0, 0, abs(pt
[1].x
- pt
[0].x
), abs(pt
[1].y
- pt
[0].y
),
2567 physdev
->x11dev
->dc_rect
.left
+ min( pt
[0].x
, pt
[1].x
),
2568 physdev
->x11dev
->dc_rect
.top
+ min( pt
[0].y
, pt
[1].y
),
2569 abs(pt
[1].x
- pt
[0].x
), abs(pt
[1].y
- pt
[0].y
), 1, 1 );
2570 pXRenderFreePicture( gdi_display
, src_pict
);
2571 wine_tsx11_unlock();
2578 dev
= GET_NEXT_PHYSDEV( dev
, pGradientFill
);
2579 return dev
->funcs
->pGradientFill( dev
, vert_array
, nvert
, grad_array
, ngrad
, mode
);
2582 /***********************************************************************
2583 * xrenderdrv_SelectBrush
2585 static HBRUSH
xrenderdrv_SelectBrush( PHYSDEV dev
, HBRUSH hbrush
, const struct brush_pattern
*pattern
)
2587 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2588 X_PHYSBITMAP
*physbitmap
;
2589 BOOL delete_bitmap
= FALSE
;
2593 XRenderPictFormat
*pict_format
;
2594 Picture src_pict
, dst_pict
;
2595 XRenderPictureAttributes pa
;
2597 if (!pattern
) goto x11drv_fallback
;
2598 if (physdev
->format
== WXR_FORMAT_MONO
) goto x11drv_fallback
;
2600 bitmap
= pattern
->bitmap
;
2601 if (!bitmap
|| !(physbitmap
= X11DRV_get_phys_bitmap( bitmap
)))
2603 if (!(bitmap
= create_brush_bitmap( physdev
->x11dev
, pattern
))) return 0;
2604 physbitmap
= X11DRV_get_phys_bitmap( bitmap
);
2605 delete_bitmap
= TRUE
;
2608 if (physbitmap
->format
== WXR_FORMAT_MONO
) goto x11drv_fallback
;
2609 if (!(pict_format
= pict_formats
[physbitmap
->format
])) goto x11drv_fallback
;
2611 GetObjectW( bitmap
, sizeof(bm
), &bm
);
2614 pixmap
= XCreatePixmap( gdi_display
, root_window
, bm
.bmWidth
, bm
.bmHeight
,
2615 physdev
->pict_format
->depth
);
2617 pa
.repeat
= RepeatNone
;
2618 src_pict
= pXRenderCreatePicture(gdi_display
, physbitmap
->pixmap
, pict_format
, CPRepeat
, &pa
);
2619 dst_pict
= pXRenderCreatePicture(gdi_display
, pixmap
, physdev
->pict_format
, CPRepeat
, &pa
);
2621 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
, 0, 0, bm
.bmWidth
, bm
.bmHeight
,
2622 0, 0, bm
.bmWidth
, bm
.bmHeight
, 1.0, 1.0 );
2623 pXRenderFreePicture( gdi_display
, src_pict
);
2624 pXRenderFreePicture( gdi_display
, dst_pict
);
2626 if (physdev
->x11dev
->brush
.pixmap
) XFreePixmap( gdi_display
, physdev
->x11dev
->brush
.pixmap
);
2627 physdev
->x11dev
->brush
.pixmap
= pixmap
;
2628 physdev
->x11dev
->brush
.fillStyle
= FillTiled
;
2629 physdev
->x11dev
->brush
.pixel
= 0; /* ignored */
2630 physdev
->x11dev
->brush
.style
= BS_PATTERN
;
2631 wine_tsx11_unlock();
2633 if (delete_bitmap
) DeleteObject( bitmap
);
2637 if (delete_bitmap
) DeleteObject( bitmap
);
2638 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBrush
);
2639 return dev
->funcs
->pSelectBrush( dev
, hbrush
, pattern
);
2643 static const struct gdi_dc_funcs xrender_funcs
=
2645 NULL
, /* pAbortDoc */
2646 NULL
, /* pAbortPath */
2647 xrenderdrv_AlphaBlend
, /* pAlphaBlend */
2648 NULL
, /* pAngleArc */
2651 NULL
, /* pBeginPath */
2652 xrenderdrv_BlendImage
, /* pBlendImage */
2653 NULL
, /* pChoosePixelFormat */
2655 NULL
, /* pCloseFigure */
2656 xrenderdrv_CopyBitmap
, /* pCopyBitmap */
2657 xrenderdrv_CreateBitmap
, /* pCreateBitmap */
2658 xrenderdrv_CreateCompatibleDC
, /* pCreateCompatibleDC */
2659 xrenderdrv_CreateDC
, /* pCreateDC */
2660 xrenderdrv_DeleteBitmap
, /* pDeleteBitmap */
2661 xrenderdrv_DeleteDC
, /* pDeleteDC */
2662 NULL
, /* pDeleteObject */
2663 NULL
, /* pDescribePixelFormat */
2664 NULL
, /* pDeviceCapabilities */
2665 NULL
, /* pEllipse */
2667 NULL
, /* pEndPage */
2668 NULL
, /* pEndPath */
2669 NULL
, /* pEnumFonts */
2670 NULL
, /* pEnumICMProfiles */
2671 NULL
, /* pExcludeClipRect */
2672 NULL
, /* pExtDeviceMode */
2673 xrenderdrv_ExtEscape
, /* pExtEscape */
2674 NULL
, /* pExtFloodFill */
2675 NULL
, /* pExtSelectClipRgn */
2676 xrenderdrv_ExtTextOut
, /* pExtTextOut */
2677 NULL
, /* pFillPath */
2678 NULL
, /* pFillRgn */
2679 NULL
, /* pFlattenPath */
2680 NULL
, /* pFontIsLinked */
2681 NULL
, /* pFrameRgn */
2682 NULL
, /* pGdiComment */
2683 NULL
, /* pGdiRealizationInfo */
2684 NULL
, /* pGetCharABCWidths */
2685 NULL
, /* pGetCharABCWidthsI */
2686 NULL
, /* pGetCharWidth */
2687 NULL
, /* pGetDeviceCaps */
2688 NULL
, /* pGetDeviceGammaRamp */
2689 NULL
, /* pGetFontData */
2690 NULL
, /* pGetFontUnicodeRanges */
2691 NULL
, /* pGetGlyphIndices */
2692 NULL
, /* pGetGlyphOutline */
2693 NULL
, /* pGetICMProfile */
2694 xrenderdrv_GetImage
, /* pGetImage */
2695 NULL
, /* pGetKerningPairs */
2696 NULL
, /* pGetNearestColor */
2697 NULL
, /* pGetOutlineTextMetrics */
2698 NULL
, /* pGetPixel */
2699 NULL
, /* pGetPixelFormat */
2700 NULL
, /* pGetSystemPaletteEntries */
2701 NULL
, /* pGetTextCharsetInfo */
2702 NULL
, /* pGetTextExtentExPoint */
2703 NULL
, /* pGetTextExtentExPointI */
2704 NULL
, /* pGetTextFace */
2705 NULL
, /* pGetTextMetrics */
2706 xrenderdrv_GradientFill
, /* pGradientFill */
2707 NULL
, /* pIntersectClipRect */
2708 NULL
, /* pInvertRgn */
2710 NULL
, /* pModifyWorldTransform */
2712 NULL
, /* pOffsetClipRgn */
2713 NULL
, /* pOffsetViewportOrg */
2714 NULL
, /* pOffsetWindowOrg */
2715 NULL
, /* pPaintRgn */
2718 NULL
, /* pPolyBezier */
2719 NULL
, /* pPolyBezierTo */
2720 NULL
, /* pPolyDraw */
2721 NULL
, /* pPolyPolygon */
2722 NULL
, /* pPolyPolyline */
2723 NULL
, /* pPolygon */
2724 NULL
, /* pPolyline */
2725 NULL
, /* pPolylineTo */
2726 xrenderdrv_PutImage
, /* pPutImage */
2727 NULL
, /* pRealizeDefaultPalette */
2728 NULL
, /* pRealizePalette */
2729 NULL
, /* pRectangle */
2730 NULL
, /* pResetDC */
2731 NULL
, /* pRestoreDC */
2732 NULL
, /* pRoundRect */
2734 NULL
, /* pScaleViewportExt */
2735 NULL
, /* pScaleWindowExt */
2736 xrenderdrv_SelectBitmap
, /* pSelectBitmap */
2737 xrenderdrv_SelectBrush
, /* pSelectBrush */
2738 NULL
, /* pSelectClipPath */
2739 xrenderdrv_SelectFont
, /* pSelectFont */
2740 NULL
, /* pSelectPalette */
2741 NULL
, /* pSelectPen */
2742 NULL
, /* pSetArcDirection */
2743 NULL
, /* pSetBkColor */
2744 NULL
, /* pSetBkMode */
2745 NULL
, /* pSetDCBrushColor */
2746 NULL
, /* pSetDCPenColor */
2747 NULL
, /* pSetDIBitsToDevice */
2748 xrenderdrv_SetDeviceClipping
, /* pSetDeviceClipping */
2749 NULL
, /* pSetDeviceGammaRamp */
2750 NULL
, /* pSetLayout */
2751 NULL
, /* pSetMapMode */
2752 NULL
, /* pSetMapperFlags */
2753 NULL
, /* pSetPixel */
2754 NULL
, /* pSetPixelFormat */
2755 NULL
, /* pSetPolyFillMode */
2756 NULL
, /* pSetROP2 */
2757 NULL
, /* pSetRelAbs */
2758 NULL
, /* pSetStretchBltMode */
2759 NULL
, /* pSetTextAlign */
2760 NULL
, /* pSetTextCharacterExtra */
2761 NULL
, /* pSetTextColor */
2762 NULL
, /* pSetTextJustification */
2763 NULL
, /* pSetViewportExt */
2764 NULL
, /* pSetViewportOrg */
2765 NULL
, /* pSetWindowExt */
2766 NULL
, /* pSetWindowOrg */
2767 NULL
, /* pSetWorldTransform */
2768 NULL
, /* pStartDoc */
2769 NULL
, /* pStartPage */
2770 xrenderdrv_StretchBlt
, /* pStretchBlt */
2771 NULL
, /* pStretchDIBits */
2772 NULL
, /* pStrokeAndFillPath */
2773 NULL
, /* pStrokePath */
2774 NULL
, /* pSwapBuffers */
2775 NULL
, /* pUnrealizePalette */
2776 NULL
, /* pWidenPath */
2777 /* OpenGL not supported */
2780 #else /* SONAME_LIBXRENDER */
2782 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
2784 TRACE("XRender support not compiled in.\n");
2788 void X11DRV_XRender_Finalize(void)
2792 #endif /* SONAME_LIBXRENDER */