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 if (GetGraphicsMode( dev
->hdc
) == GM_COMPATIBLE
&& lfsz
.xform
.eM11
* lfsz
.xform
.eM22
< 0)
1136 lfsz
.lf
.lfOrientation
= -lfsz
.lf
.lfOrientation
;
1138 /* Not used fields, would break hashing */
1139 lfsz
.xform
.eDx
= lfsz
.xform
.eDy
= 0;
1141 lfsz_calc_hash(&lfsz
);
1143 EnterCriticalSection(&xrender_cs
);
1144 if (physdev
->cache_index
!= -1)
1145 dec_ref_cache( physdev
->cache_index
);
1146 physdev
->cache_index
= GetCacheEntry( dev
->hdc
, &lfsz
);
1147 LeaveCriticalSection(&xrender_cs
);
1151 EnterCriticalSection( &xrender_cs
);
1152 if (physdev
->cache_index
!= -1) dec_ref_cache( physdev
->cache_index
);
1153 physdev
->cache_index
= -1;
1154 LeaveCriticalSection( &xrender_cs
);
1159 static BOOL
create_xrender_dc( PHYSDEV
*pdev
, enum wxr_format format
)
1161 X11DRV_PDEVICE
*x11dev
= get_x11drv_dev( *pdev
);
1162 struct xrender_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
1164 if (!physdev
) return FALSE
;
1165 physdev
->x11dev
= x11dev
;
1166 physdev
->cache_index
= -1;
1167 physdev
->format
= format
;
1168 physdev
->pict_format
= pict_formats
[format
];
1169 push_dc_driver( pdev
, &physdev
->dev
, &xrender_funcs
);
1173 /* store the color mask data in the bitmap info structure */
1174 static void set_color_info( XRenderPictFormat
*format
, BITMAPINFO
*info
)
1176 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
1178 info
->bmiHeader
.biPlanes
= 1;
1179 info
->bmiHeader
.biBitCount
= pixmap_formats
[format
->depth
]->bits_per_pixel
;
1180 info
->bmiHeader
.biCompression
= BI_RGB
;
1181 info
->bmiHeader
.biClrUsed
= 0;
1183 switch (info
->bmiHeader
.biBitCount
)
1186 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
1187 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
1188 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
1189 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1192 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
1193 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
1194 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
1195 if (colors
[0] != 0xff0000 || colors
[1] != 0x00ff00 || colors
[2] != 0x0000ff)
1196 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1202 /**********************************************************************
1203 * xrenderdrv_CreateDC
1205 static BOOL
xrenderdrv_CreateDC( PHYSDEV
*pdev
, LPCWSTR driver
, LPCWSTR device
,
1206 LPCWSTR output
, const DEVMODEW
* initData
)
1208 return create_xrender_dc( pdev
, default_format
);
1211 /**********************************************************************
1212 * xrenderdrv_CreateCompatibleDC
1214 static BOOL
xrenderdrv_CreateCompatibleDC( PHYSDEV orig
, PHYSDEV
*pdev
)
1216 if (orig
) /* chain to x11drv first */
1218 orig
= GET_NEXT_PHYSDEV( orig
, pCreateCompatibleDC
);
1219 if (!orig
->funcs
->pCreateCompatibleDC( orig
, pdev
)) return FALSE
;
1221 /* otherwise we have been called by x11drv */
1223 return create_xrender_dc( pdev
, WXR_FORMAT_MONO
);
1226 /**********************************************************************
1227 * xrenderdrv_DeleteDC
1229 static BOOL
xrenderdrv_DeleteDC( PHYSDEV dev
)
1231 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1233 free_xrender_picture( physdev
);
1235 EnterCriticalSection( &xrender_cs
);
1236 if (physdev
->cache_index
!= -1) dec_ref_cache( physdev
->cache_index
);
1237 LeaveCriticalSection( &xrender_cs
);
1239 HeapFree( GetProcessHeap(), 0, physdev
);
1243 /**********************************************************************
1244 * xrenderdrv_ExtEscape
1246 static INT
xrenderdrv_ExtEscape( PHYSDEV dev
, INT escape
, INT in_count
, LPCVOID in_data
,
1247 INT out_count
, LPVOID out_data
)
1249 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1251 dev
= GET_NEXT_PHYSDEV( dev
, pExtEscape
);
1253 if (escape
== X11DRV_ESCAPE
&& in_data
&& in_count
>= sizeof(enum x11drv_escape_codes
))
1255 if (*(const enum x11drv_escape_codes
*)in_data
== X11DRV_SET_DRAWABLE
)
1257 BOOL ret
= dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
1258 if (ret
) free_xrender_picture( physdev
); /* pict format doesn't change, only drawable */
1262 return dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
1265 /****************************************************************************
1266 * xrenderdrv_CopyBitmap
1268 static BOOL
xrenderdrv_CopyBitmap( HBITMAP src
, HBITMAP dst
)
1270 return X11DRV_CopyBitmap( src
, dst
);
1273 /****************************************************************************
1274 * xrenderdrv_CreateBitmap
1276 static BOOL
xrenderdrv_CreateBitmap( PHYSDEV dev
, HBITMAP hbitmap
)
1278 enum wxr_format format
= WXR_INVALID_FORMAT
;
1279 X_PHYSBITMAP
*phys_bitmap
;
1282 if (!GetObjectW( hbitmap
, sizeof(bitmap
), &bitmap
)) return FALSE
;
1284 if (bitmap
.bmBitsPixel
== 1)
1286 if (!(phys_bitmap
= X11DRV_create_phys_bitmap( hbitmap
, &bitmap
, 1 ))) return FALSE
;
1287 phys_bitmap
->format
= WXR_FORMAT_MONO
;
1288 phys_bitmap
->trueColor
= FALSE
;
1292 format
= get_bitmap_format( bitmap
.bmBitsPixel
);
1294 if (pict_formats
[format
])
1296 if (!(phys_bitmap
= X11DRV_create_phys_bitmap( hbitmap
, &bitmap
, pict_formats
[format
]->depth
)))
1298 phys_bitmap
->format
= format
;
1299 phys_bitmap
->trueColor
= TRUE
;
1300 phys_bitmap
->color_shifts
= wxr_color_shifts
[format
];
1304 if (!(phys_bitmap
= X11DRV_create_phys_bitmap( hbitmap
, &bitmap
, screen_depth
)))
1306 phys_bitmap
->format
= WXR_INVALID_FORMAT
;
1307 phys_bitmap
->trueColor
= (visual
->class == TrueColor
|| visual
->class == DirectColor
);
1308 phys_bitmap
->color_shifts
= X11DRV_PALETTE_default_shifts
;
1314 /****************************************************************************
1315 * xrenderdrv_DeleteBitmap
1317 static BOOL
xrenderdrv_DeleteBitmap( HBITMAP hbitmap
)
1319 return X11DRV_DeleteBitmap( hbitmap
);
1322 /***********************************************************************
1323 * xrenderdrv_SelectBitmap
1325 static HBITMAP
xrenderdrv_SelectBitmap( PHYSDEV dev
, HBITMAP hbitmap
)
1328 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1330 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBitmap
);
1331 ret
= dev
->funcs
->pSelectBitmap( dev
, hbitmap
);
1334 free_xrender_picture( physdev
);
1335 if (hbitmap
== BITMAP_stock_phys_bitmap
.hbitmap
) physdev
->format
= WXR_FORMAT_MONO
;
1336 else physdev
->format
= X11DRV_get_phys_bitmap(hbitmap
)->format
;
1337 physdev
->pict_format
= pict_formats
[physdev
->format
];
1342 /***********************************************************************
1343 * xrenderdrv_GetImage
1345 static DWORD
xrenderdrv_GetImage( PHYSDEV dev
, HBITMAP hbitmap
, BITMAPINFO
*info
,
1346 struct gdi_image_bits
*bits
, struct bitblt_coords
*src
)
1348 if (hbitmap
) return X11DRV_GetImage( dev
, hbitmap
, info
, bits
, src
);
1349 dev
= GET_NEXT_PHYSDEV( dev
, pGetImage
);
1350 return dev
->funcs
->pGetImage( dev
, hbitmap
, info
, bits
, src
);
1353 /***********************************************************************
1354 * xrenderdrv_SetDeviceClipping
1356 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev
, HRGN rgn
)
1358 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1360 physdev
->region
= rgn
;
1361 physdev
->update_clip
= TRUE
;
1363 dev
= GET_NEXT_PHYSDEV( dev
, pSetDeviceClipping
);
1364 dev
->funcs
->pSetDeviceClipping( dev
, rgn
);
1368 /************************************************************************
1371 * Helper to ExtTextOut. Must be called inside xrender_cs
1373 static void UploadGlyph(struct xrender_physdev
*physDev
, int glyph
, AA_Type format
)
1375 unsigned int buflen
;
1380 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->cache_index
;
1381 gsCacheEntryFormat
*formatEntry
;
1382 UINT ggo_format
= GGO_GLYPH_INDEX
;
1383 enum wxr_format wxr_format
;
1384 static const char zero
[4];
1385 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
1389 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
1392 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
1395 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
1398 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
1401 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
1405 ERR("aa = %d - not implemented\n", format
);
1407 ggo_format
|= GGO_BITMAP
;
1411 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1412 if(buflen
== GDI_ERROR
) {
1413 if(format
!= AA_None
) {
1415 entry
->aa_default
= AA_None
;
1416 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
1417 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1419 if(buflen
== GDI_ERROR
) {
1420 WARN("GetGlyphOutlineW failed using default glyph\n");
1421 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0, ggo_format
, &gm
, 0, NULL
, &identity
);
1422 if(buflen
== GDI_ERROR
) {
1423 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1424 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0x20, ggo_format
, &gm
, 0, NULL
, &identity
);
1425 if(buflen
== GDI_ERROR
) {
1426 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1431 TRACE("Turning off antialiasing for this monochrome font\n");
1434 /* If there is nothing for the current type, we create the entry. */
1435 if( !entry
->format
[format
] ) {
1436 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
1438 sizeof(gsCacheEntryFormat
));
1440 formatEntry
= entry
->format
[format
];
1442 if(formatEntry
->nrealized
<= glyph
) {
1443 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
1445 if (formatEntry
->realized
)
1446 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
1448 formatEntry
->realized
,
1449 formatEntry
->nrealized
* sizeof(BOOL
));
1451 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
1453 formatEntry
->nrealized
* sizeof(BOOL
));
1455 if (formatEntry
->gis
)
1456 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
1459 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1461 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
1463 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1467 if(formatEntry
->glyphset
== 0) {
1470 wxr_format
= WXR_FORMAT_GRAY
;
1477 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1481 ERR("aa = %d - not implemented\n", format
);
1483 wxr_format
= WXR_FORMAT_MONO
;
1488 formatEntry
->font_format
= pict_formats
[wxr_format
];
1489 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
1490 wine_tsx11_unlock();
1494 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
1495 GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
1496 formatEntry
->realized
[glyph
] = TRUE
;
1498 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1500 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1501 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1503 gi
.width
= gm
.gmBlackBoxX
;
1504 gi
.height
= gm
.gmBlackBoxY
;
1505 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1506 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1507 gi
.xOff
= gm
.gmCellIncX
;
1508 gi
.yOff
= gm
.gmCellIncY
;
1510 if(TRACE_ON(xrender
)) {
1513 unsigned char *line
;
1515 if(format
== AA_None
) {
1516 pitch
= ((gi
.width
+ 31) / 32) * 4;
1517 for(i
= 0; i
< gi
.height
; i
++) {
1518 line
= (unsigned char*) buf
+ i
* pitch
;
1520 for(j
= 0; j
< pitch
* 8; j
++) {
1521 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1523 TRACE("%s\n", output
);
1526 static const char blks
[] = " .:;!o*#";
1530 pitch
= ((gi
.width
+ 3) / 4) * 4;
1531 for(i
= 0; i
< gi
.height
; i
++) {
1532 line
= (unsigned char*) buf
+ i
* pitch
;
1534 for(j
= 0; j
< pitch
; j
++) {
1535 str
[0] = blks
[line
[j
] >> 5];
1536 strcat(output
, str
);
1538 TRACE("%s\n", output
);
1544 if(formatEntry
->glyphset
) {
1545 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1546 unsigned char *byte
= (unsigned char*) buf
, c
;
1552 /* magic to flip bit order */
1553 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1554 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1555 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1560 else if ( format
!= AA_Grey
&&
1561 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1563 unsigned int i
, *data
= (unsigned int *)buf
;
1564 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1569 XRenderCompositeText seems to ignore 0x0 glyphs when
1570 AA_None, which means we lose the advance width of glyphs
1571 like the space. We'll pretend that such glyphs are 1x1
1576 gi
.width
= gi
.height
= 1;
1579 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1580 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1581 wine_tsx11_unlock();
1582 HeapFree(GetProcessHeap(), 0, buf
);
1585 formatEntry
->gis
[glyph
] = gi
;
1588 /*************************************************************
1591 * Returns an appropriate Picture for tiling the text colour.
1592 * Call and use result within the xrender_cs
1594 static Picture
get_tile_pict( enum wxr_format wxr_format
, const XRenderColor
*color
)
1600 XRenderColor current_color
;
1601 } tiles
[WXR_NB_FORMATS
], *tile
;
1603 tile
= &tiles
[wxr_format
];
1607 XRenderPictureAttributes pa
;
1608 XRenderPictFormat
*pict_format
= pict_formats
[wxr_format
];
1611 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_format
->depth
);
1613 pa
.repeat
= RepeatNormal
;
1614 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_format
, CPRepeat
, &pa
);
1615 wine_tsx11_unlock();
1617 /* init current_color to something different from text_pixel */
1618 tile
->current_color
= *color
;
1619 tile
->current_color
.red
^= 0xffff;
1621 if (wxr_format
== WXR_FORMAT_MONO
)
1623 /* for a 1bpp bitmap we always need a 1 in the tile */
1625 col
.red
= col
.green
= col
.blue
= 0;
1628 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1629 wine_tsx11_unlock();
1633 if (memcmp( color
, &tile
->current_color
, sizeof(*color
) ) && wxr_format
!= WXR_FORMAT_MONO
)
1636 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, color
, 0, 0, 1, 1);
1637 wine_tsx11_unlock();
1638 tile
->current_color
= *color
;
1643 /*************************************************************
1646 * Returns an appropriate Picture for masking with the specified alpha.
1647 * Call and use result within the xrender_cs
1649 static Picture
get_mask_pict( int alpha
)
1651 static Pixmap pixmap
;
1652 static Picture pict
;
1653 static int current_alpha
;
1655 if (alpha
== 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1659 XRenderPictureAttributes pa
;
1662 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
1663 pa
.repeat
= RepeatNormal
;
1664 pict
= pXRenderCreatePicture( gdi_display
, pixmap
,
1665 pict_formats
[WXR_FORMAT_A8R8G8B8
], CPRepeat
, &pa
);
1666 wine_tsx11_unlock();
1670 if (alpha
!= current_alpha
)
1673 col
.red
= col
.green
= col
.blue
= 0;
1674 col
.alpha
= current_alpha
= alpha
;
1676 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
1677 wine_tsx11_unlock();
1682 /***********************************************************************
1683 * xrenderdrv_ExtTextOut
1685 static BOOL
xrenderdrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
,
1686 const RECT
*lprect
, LPCWSTR wstr
, UINT count
, const INT
*lpDx
)
1688 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1689 gsCacheEntry
*entry
;
1690 gsCacheEntryFormat
*formatEntry
;
1691 AA_Type aa_type
= AA_None
;
1693 Picture pict
, tile_pict
= 0;
1695 POINT offset
, desired
, current
;
1696 int render_op
= PictOpOver
;
1699 if (!physdev
->x11dev
->has_gdi_font
)
1701 dev
= GET_NEXT_PHYSDEV( dev
, pExtTextOut
);
1702 return dev
->funcs
->pExtTextOut( dev
, x
, y
, flags
, lprect
, wstr
, count
, lpDx
);
1705 get_xrender_color( physdev
, GetTextColor( physdev
->dev
.hdc
), &col
);
1706 pict
= get_xrender_picture( physdev
, 0, (flags
& ETO_CLIPPED
) ? lprect
: NULL
);
1708 if(flags
& ETO_OPAQUE
)
1712 if (physdev
->format
== WXR_FORMAT_MONO
)
1713 /* use the inverse of the text color */
1714 bg
.red
= bg
.green
= bg
.blue
= bg
.alpha
= ~col
.alpha
;
1716 get_xrender_color( physdev
, GetBkColor( physdev
->dev
.hdc
), &bg
);
1719 set_xrender_transformation( pict
, 1, 1, 0, 0 );
1720 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &bg
,
1721 physdev
->x11dev
->dc_rect
.left
+ lprect
->left
,
1722 physdev
->x11dev
->dc_rect
.top
+ lprect
->top
,
1723 lprect
->right
- lprect
->left
,
1724 lprect
->bottom
- lprect
->top
);
1725 wine_tsx11_unlock();
1728 if(count
== 0) return TRUE
;
1730 EnterCriticalSection(&xrender_cs
);
1732 entry
= glyphsetCache
+ physdev
->cache_index
;
1733 aa_type
= entry
->aa_default
;
1734 formatEntry
= entry
->format
[aa_type
];
1736 for(idx
= 0; idx
< count
; idx
++) {
1737 if( !formatEntry
) {
1738 UploadGlyph(physdev
, wstr
[idx
], aa_type
);
1739 /* re-evaluate antialias since aa_default may have changed */
1740 aa_type
= entry
->aa_default
;
1741 formatEntry
= entry
->format
[aa_type
];
1742 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1743 UploadGlyph(physdev
, wstr
[idx
], aa_type
);
1748 WARN("could not upload requested glyphs\n");
1749 LeaveCriticalSection(&xrender_cs
);
1753 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1754 physdev
->x11dev
->dc_rect
.left
+ x
, physdev
->x11dev
->dc_rect
.top
+ y
);
1756 elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1758 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1759 So we pass zeros to the function and move to our starting position using the first
1760 element of the elts array. */
1762 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
;
1763 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
;
1764 offset
.x
= offset
.y
= 0;
1765 current
.x
= current
.y
= 0;
1767 tile_pict
= get_tile_pict(physdev
->format
, &col
);
1769 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1771 if (physdev
->format
== WXR_FORMAT_MONO
&& col
.red
== 0 && col
.green
== 0 && col
.blue
== 0)
1772 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1774 for(idx
= 0; idx
< count
; idx
++)
1776 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1777 elts
[idx
].chars
= wstr
+ idx
;
1778 elts
[idx
].nchars
= 1;
1779 elts
[idx
].xOff
= desired
.x
- current
.x
;
1780 elts
[idx
].yOff
= desired
.y
- current
.y
;
1782 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1783 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1787 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1788 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1794 offset
.x
+= lpDx
[idx
* 2];
1795 offset
.y
+= lpDx
[idx
* 2 + 1];
1798 offset
.x
+= lpDx
[idx
];
1799 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
+ offset
.x
;
1800 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
+ offset
.y
;
1805 /* Make sure we don't have any transforms set from a previous call */
1806 set_xrender_transformation(pict
, 1, 1, 0, 0);
1807 pXRenderCompositeText16(gdi_display
, render_op
,
1810 formatEntry
->font_format
,
1811 0, 0, 0, 0, elts
, count
);
1812 wine_tsx11_unlock();
1813 HeapFree(GetProcessHeap(), 0, elts
);
1815 LeaveCriticalSection(&xrender_cs
);
1819 /* multiply the alpha channel of a picture */
1820 static void multiply_alpha( Picture pict
, XRenderPictFormat
*format
, int alpha
,
1821 int x
, int y
, int width
, int height
)
1823 XRenderPictureAttributes pa
;
1824 Pixmap src_pixmap
, mask_pixmap
;
1825 Picture src_pict
, mask_pict
;
1829 src_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1830 mask_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1831 pa
.repeat
= RepeatNormal
;
1832 src_pict
= pXRenderCreatePicture( gdi_display
, src_pixmap
, format
, CPRepeat
, &pa
);
1833 pa
.component_alpha
= True
;
1834 mask_pict
= pXRenderCreatePicture( gdi_display
, mask_pixmap
, format
, CPRepeat
|CPComponentAlpha
, &pa
);
1835 color
.red
= color
.green
= color
.blue
= color
.alpha
= 0xffff;
1836 pXRenderFillRectangle( gdi_display
, PictOpSrc
, src_pict
, &color
, 0, 0, 1, 1 );
1837 color
.alpha
= alpha
;
1838 pXRenderFillRectangle( gdi_display
, PictOpSrc
, mask_pict
, &color
, 0, 0, 1, 1 );
1839 pXRenderComposite( gdi_display
, PictOpInReverse
, src_pict
, mask_pict
, pict
,
1840 0, 0, 0, 0, x
, y
, width
, height
);
1841 pXRenderFreePicture( gdi_display
, src_pict
);
1842 pXRenderFreePicture( gdi_display
, mask_pict
);
1843 XFreePixmap( gdi_display
, src_pixmap
);
1844 XFreePixmap( gdi_display
, mask_pixmap
);
1845 wine_tsx11_unlock();
1848 /* Helper function for (stretched) blitting using xrender */
1849 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
1850 int x_src
, int y_src
, int width_src
, int height_src
,
1851 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1852 double xscale
, double yscale
)
1854 int x_offset
, y_offset
;
1858 x_src
+= width_src
+ 1;
1859 width_src
= -width_src
;
1863 y_src
+= height_src
+ 1;
1864 height_src
= -height_src
;
1868 x_dst
+= width_dst
+ 1;
1869 width_dst
= -width_dst
;
1873 y_dst
+= height_dst
+ 1;
1874 height_dst
= -height_dst
;
1877 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1878 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1879 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1881 if(xscale
!= 1.0 || yscale
!= 1.0)
1883 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1884 * in the wrong quadrant of the x-y plane.
1886 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1887 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1888 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1894 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1896 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
1897 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width_dst
, height_dst
);
1898 wine_tsx11_unlock();
1901 /* Helper function for (stretched) mono->color blitting using xrender */
1902 static void xrender_mono_blit( Picture src_pict
, Picture dst_pict
,
1903 enum wxr_format dst_format
, XRenderColor
*fg
, XRenderColor
*bg
,
1904 int x_src
, int y_src
, int width_src
, int height_src
,
1905 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1906 double xscale
, double yscale
)
1909 int x_offset
, y_offset
;
1914 x_src
+= width_src
+ 1;
1915 width_src
= -width_src
;
1919 y_src
+= height_src
+ 1;
1920 height_src
= -height_src
;
1924 x_dst
+= width_dst
+ 1;
1925 width_dst
= -width_dst
;
1929 y_dst
+= height_dst
+ 1;
1930 height_dst
= -height_dst
;
1933 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1934 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1937 EnterCriticalSection( &xrender_cs
);
1939 color
.alpha
= 0xffff; /* tile pict needs 100% alpha */
1940 tile_pict
= get_tile_pict( dst_format
, &color
);
1943 pXRenderFillRectangle( gdi_display
, PictOpSrc
, dst_pict
, fg
, x_dst
, y_dst
, width_dst
, height_dst
);
1945 if (xscale
!= 1.0 || yscale
!= 1.0)
1947 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1948 * in the wrong quadrant of the x-y plane.
1950 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1951 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1952 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1958 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1960 pXRenderComposite(gdi_display
, PictOpOver
, tile_pict
, src_pict
, dst_pict
,
1961 0, 0, x_offset
, y_offset
, x_dst
, y_dst
, width_dst
, height_dst
);
1962 wine_tsx11_unlock();
1963 LeaveCriticalSection( &xrender_cs
);
1965 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1966 if (bg
->alpha
!= 0xffff && (dst_format
== WXR_FORMAT_A8R8G8B8
|| dst_format
== WXR_FORMAT_B8G8R8A8
))
1967 multiply_alpha( dst_pict
, pict_formats
[dst_format
], bg
->alpha
,
1968 x_dst
, y_dst
, width_dst
, height_dst
);
1971 /* create a pixmap and render picture for an image */
1972 static DWORD
create_image_pixmap( BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1973 struct bitblt_coords
*src
, enum wxr_format format
,
1974 Pixmap
*pixmap
, Picture
*pict
, BOOL
*use_repeat
)
1977 int width
= src
->visrect
.right
- src
->visrect
.left
;
1978 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1979 int depth
= pict_formats
[format
]->depth
;
1980 struct gdi_image_bits dst_bits
;
1981 XRenderPictureAttributes pa
;
1985 image
= XCreateImage( gdi_display
, visual
, depth
, ZPixmap
, 0, NULL
,
1986 info
->bmiHeader
.biWidth
, height
, 32, 0 );
1987 wine_tsx11_unlock();
1988 if (!image
) return ERROR_OUTOFMEMORY
;
1990 ret
= copy_image_bits( info
, (format
== WXR_FORMAT_R8G8B8
), image
, bits
, &dst_bits
, src
, NULL
, ~0u );
1991 if (ret
) return ret
;
1993 image
->data
= dst_bits
.ptr
;
1995 *use_repeat
= (width
== 1 && height
== 1);
1996 pa
.repeat
= *use_repeat
? RepeatNormal
: RepeatNone
;
1999 *pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, depth
);
2000 XPutImage( gdi_display
, *pixmap
, get_bitmap_gc( depth
), image
,
2001 src
->visrect
.left
, 0, 0, 0, width
, height
);
2002 *pict
= pXRenderCreatePicture( gdi_display
, *pixmap
, pict_formats
[format
], CPRepeat
, &pa
);
2003 wine_tsx11_unlock();
2005 /* make coordinates relative to the pixmap */
2006 src
->x
-= src
->visrect
.left
;
2007 src
->y
-= src
->visrect
.top
;
2008 OffsetRect( &src
->visrect
, -src
->visrect
.left
, -src
->visrect
.top
);
2012 XDestroyImage( image
);
2013 wine_tsx11_unlock();
2014 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
2018 static void xrender_stretch_blit( struct xrender_physdev
*physdev_src
, struct xrender_physdev
*physdev_dst
,
2019 Drawable drawable
, const struct bitblt_coords
*src
,
2020 const struct bitblt_coords
*dst
)
2023 Picture src_pict
= 0, dst_pict
, mask_pict
= 0;
2025 double xscale
, yscale
;
2027 use_repeat
= use_source_repeat( physdev_src
);
2030 xscale
= src
->width
/ (double)dst
->width
;
2031 yscale
= src
->height
/ (double)dst
->height
;
2033 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2035 if (drawable
) /* using an intermediate pixmap */
2037 XRenderPictureAttributes pa
;
2041 pa
.repeat
= RepeatNone
;
2043 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, physdev_dst
->pict_format
, CPRepeat
, &pa
);
2044 wine_tsx11_unlock();
2048 x_dst
= physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
;
2049 y_dst
= physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
;
2050 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
2053 src_pict
= get_xrender_picture_source( physdev_src
, use_repeat
);
2056 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
2058 XRenderColor fg
, bg
;
2060 get_xrender_color( physdev_dst
, GetTextColor( physdev_dst
->dev
.hdc
), &fg
);
2061 get_xrender_color( physdev_dst
, GetBkColor( physdev_dst
->dev
.hdc
), &bg
);
2062 fg
.alpha
= bg
.alpha
= 0;
2064 xrender_mono_blit( src_pict
, dst_pict
, physdev_dst
->format
, &fg
, &bg
,
2065 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
2066 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
2067 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
2069 else /* color -> color (can be at different depths) or mono -> mono */
2071 if (physdev_dst
->pict_format
->depth
== 32 && physdev_src
->pict_format
->depth
< 32)
2072 mask_pict
= get_no_alpha_mask();
2074 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
2075 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
2076 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
2077 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
2083 pXRenderFreePicture( gdi_display
, dst_pict
);
2084 wine_tsx11_unlock();
2089 static void xrender_put_image( Pixmap src_pixmap
, Picture src_pict
, Picture mask_pict
, HRGN clip
,
2090 XRenderPictFormat
*dst_format
, struct xrender_physdev
*physdev
,
2091 Drawable drawable
, struct bitblt_coords
*src
,
2092 struct bitblt_coords
*dst
, BOOL use_repeat
)
2096 XRenderPictureAttributes pa
;
2097 double xscale
, yscale
;
2099 if (drawable
) /* using an intermediate pixmap */
2101 RGNDATA
*clip_data
= NULL
;
2103 if (clip
) clip_data
= X11DRV_GetRegionData( clip
, 0 );
2106 pa
.repeat
= RepeatNone
;
2108 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, dst_format
, CPRepeat
, &pa
);
2110 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
, 0, 0,
2111 (XRectangle
*)clip_data
->Buffer
, clip_data
->rdh
.nCount
);
2112 wine_tsx11_unlock();
2113 HeapFree( GetProcessHeap(), 0, clip_data
);
2117 x_dst
= physdev
->x11dev
->dc_rect
.left
+ dst
->x
;
2118 y_dst
= physdev
->x11dev
->dc_rect
.top
+ dst
->y
;
2119 dst_pict
= get_xrender_picture( physdev
, clip
, &dst
->visrect
);
2124 xscale
= src
->width
/ (double)dst
->width
;
2125 yscale
= src
->height
/ (double)dst
->height
;
2127 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2129 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
, src
->x
, src
->y
, src
->width
, src
->height
,
2130 x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
2135 pXRenderFreePicture( gdi_display
, dst_pict
);
2136 wine_tsx11_unlock();
2141 /***********************************************************************
2142 * xrenderdrv_StretchBlt
2144 static BOOL
xrenderdrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
2145 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
2147 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
2148 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
2149 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
2151 if (src_dev
->funcs
!= dst_dev
->funcs
)
2153 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pStretchBlt
);
2154 return dst_dev
->funcs
->pStretchBlt( dst_dev
, dst
, src_dev
, src
, rop
);
2157 /* XRender is of no use for color -> mono */
2158 if (physdev_dst
->format
== WXR_FORMAT_MONO
&& physdev_src
->format
!= WXR_FORMAT_MONO
)
2159 goto x11drv_fallback
;
2161 /* if not stretching, we only need to handle format conversion */
2162 if (!stretch
&& physdev_dst
->format
== physdev_src
->format
) goto x11drv_fallback
;
2168 struct bitblt_coords tmp
;
2170 /* make coordinates relative to tmp pixmap */
2172 tmp
.x
-= tmp
.visrect
.left
;
2173 tmp
.y
-= tmp
.visrect
.top
;
2174 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
2177 tmpGC
= XCreateGC( gdi_display
, physdev_dst
->x11dev
->drawable
, 0, NULL
);
2178 XSetSubwindowMode( gdi_display
, tmpGC
, IncludeInferiors
);
2179 XSetGraphicsExposures( gdi_display
, tmpGC
, False
);
2180 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, tmp
.visrect
.right
- tmp
.visrect
.left
,
2181 tmp
.visrect
.bottom
- tmp
.visrect
.top
, physdev_dst
->pict_format
->depth
);
2182 wine_tsx11_unlock();
2184 xrender_stretch_blit( physdev_src
, physdev_dst
, tmp_pixmap
, src
, &tmp
);
2185 execute_rop( physdev_dst
->x11dev
, tmp_pixmap
, tmpGC
, &dst
->visrect
, rop
);
2188 XFreePixmap( gdi_display
, tmp_pixmap
);
2189 XFreeGC( gdi_display
, tmpGC
);
2190 wine_tsx11_unlock();
2192 else xrender_stretch_blit( physdev_src
, physdev_dst
, 0, src
, dst
);
2197 return X11DRV_StretchBlt( &physdev_dst
->x11dev
->dev
, dst
, &physdev_src
->x11dev
->dev
, src
, rop
);
2201 /***********************************************************************
2202 * xrenderdrv_PutImage
2204 static DWORD
xrenderdrv_PutImage( PHYSDEV dev
, HBITMAP hbitmap
, HRGN clip
, BITMAPINFO
*info
,
2205 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
2206 struct bitblt_coords
*dst
, DWORD rop
)
2208 struct xrender_physdev
*physdev
;
2209 X_PHYSBITMAP
*bitmap
;
2213 enum wxr_format src_format
, dst_format
;
2214 XRenderPictFormat
*pict_format
;
2216 Picture src_pict
, mask_pict
= 0;
2221 if (!(bitmap
= X11DRV_get_phys_bitmap( hbitmap
))) return ERROR_INVALID_HANDLE
;
2223 dst_format
= bitmap
->format
;
2227 physdev
= get_xrender_dev( dev
);
2229 dst_format
= physdev
->format
;
2232 src_format
= get_xrender_format_from_bitmapinfo( info
);
2233 if (!(pict_format
= pict_formats
[src_format
])) goto update_format
;
2235 /* make sure we can create an image with the same bpp */
2236 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
2239 /* mono <-> color conversions not supported */
2240 if ((src_format
!= dst_format
) && (src_format
== WXR_FORMAT_MONO
|| dst_format
== WXR_FORMAT_MONO
))
2241 goto x11drv_fallback
;
2243 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
2245 if (!has_alpha( src_format
) && has_alpha( dst_format
)) mask_pict
= get_no_alpha_mask();
2247 ret
= create_image_pixmap( info
, bits
, src
, src_format
, &src_pixmap
, &src_pict
, &use_repeat
);
2250 struct bitblt_coords tmp
;
2254 HRGN rgn
= CreateRectRgnIndirect( &dst
->visrect
);
2255 if (clip
) CombineRgn( rgn
, rgn
, clip
, RGN_AND
);
2257 xrender_put_image( src_pixmap
, src_pict
, mask_pict
, rgn
,
2258 pict_formats
[dst_format
], NULL
, bitmap
->pixmap
, src
, dst
, use_repeat
);
2259 DeleteObject( rgn
);
2265 BOOL restore_region
= add_extra_clipping_region( physdev
->x11dev
, clip
);
2267 /* make coordinates relative to tmp pixmap */
2269 tmp
.x
-= tmp
.visrect
.left
;
2270 tmp
.y
-= tmp
.visrect
.top
;
2271 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
2274 gc
= XCreateGC( gdi_display
, physdev
->x11dev
->drawable
, 0, NULL
);
2275 XSetSubwindowMode( gdi_display
, gc
, IncludeInferiors
);
2276 XSetGraphicsExposures( gdi_display
, gc
, False
);
2277 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
,
2278 tmp
.visrect
.right
- tmp
.visrect
.left
,
2279 tmp
.visrect
.bottom
- tmp
.visrect
.top
,
2280 physdev
->pict_format
->depth
);
2281 wine_tsx11_unlock();
2283 xrender_put_image( src_pixmap
, src_pict
, mask_pict
, NULL
, physdev
->pict_format
,
2284 NULL
, tmp_pixmap
, src
, &tmp
, use_repeat
);
2285 execute_rop( physdev
->x11dev
, tmp_pixmap
, gc
, &dst
->visrect
, rop
);
2288 XFreePixmap( gdi_display
, tmp_pixmap
);
2289 XFreeGC( gdi_display
, gc
);
2290 wine_tsx11_unlock();
2292 if (restore_region
) restore_clipping_region( physdev
->x11dev
);
2294 else xrender_put_image( src_pixmap
, src_pict
, mask_pict
, clip
,
2295 physdev
->pict_format
, physdev
, 0, src
, dst
, use_repeat
);
2299 pXRenderFreePicture( gdi_display
, src_pict
);
2300 XFreePixmap( gdi_display
, src_pixmap
);
2301 wine_tsx11_unlock();
2306 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
2307 set_color_info( pict_formats
[dst_format
], info
);
2308 return ERROR_BAD_FORMAT
;
2311 if (hbitmap
) return X11DRV_PutImage( dev
, hbitmap
, clip
, info
, bits
, src
, dst
, rop
);
2312 dev
= GET_NEXT_PHYSDEV( dev
, pPutImage
);
2313 return dev
->funcs
->pPutImage( dev
, hbitmap
, clip
, info
, bits
, src
, dst
, rop
);
2317 /***********************************************************************
2318 * xrenderdrv_BlendImage
2320 static DWORD
xrenderdrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
2321 struct bitblt_coords
*src
, struct bitblt_coords
*dst
,
2322 BLENDFUNCTION func
)
2324 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2326 enum wxr_format format
;
2327 XRenderPictFormat
*pict_format
;
2328 Picture dst_pict
, src_pict
, mask_pict
;
2332 format
= get_xrender_format_from_bitmapinfo( info
);
2333 if (!(func
.AlphaFormat
& AC_SRC_ALPHA
))
2334 format
= get_format_without_alpha( format
);
2335 else if (format
!= WXR_FORMAT_A8R8G8B8
)
2336 return ERROR_INVALID_PARAMETER
;
2338 if (!(pict_format
= pict_formats
[format
])) goto update_format
;
2340 /* make sure we can create an image with the same bpp */
2341 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
2344 if (format
== WXR_FORMAT_MONO
&& physdev
->format
!= WXR_FORMAT_MONO
)
2347 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
2349 ret
= create_image_pixmap( info
, bits
, src
, format
, &src_pixmap
, &src_pict
, &use_repeat
);
2352 double xscale
, yscale
;
2356 xscale
= src
->width
/ (double)dst
->width
;
2357 yscale
= src
->height
/ (double)dst
->height
;
2359 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2361 dst_pict
= get_xrender_picture( physdev
, 0, &dst
->visrect
);
2363 EnterCriticalSection( &xrender_cs
);
2364 mask_pict
= get_mask_pict( func
.SourceConstantAlpha
* 257 );
2366 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2367 src
->x
, src
->y
, src
->width
, src
->height
,
2368 physdev
->x11dev
->dc_rect
.left
+ dst
->x
,
2369 physdev
->x11dev
->dc_rect
.top
+ dst
->y
,
2370 dst
->width
, dst
->height
, xscale
, yscale
);
2373 pXRenderFreePicture( gdi_display
, src_pict
);
2374 XFreePixmap( gdi_display
, src_pixmap
);
2375 wine_tsx11_unlock();
2377 LeaveCriticalSection( &xrender_cs
);
2382 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
2383 set_color_info( physdev
->pict_format
, info
);
2384 return ERROR_BAD_FORMAT
;
2388 /***********************************************************************
2389 * xrenderdrv_AlphaBlend
2391 static BOOL
xrenderdrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
2392 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
2394 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
2395 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
2396 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
2397 XRenderPictureAttributes pa
;
2398 Pixmap tmp_pixmap
= 0;
2399 double xscale
, yscale
;
2402 if (src_dev
->funcs
!= dst_dev
->funcs
)
2404 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pAlphaBlend
);
2405 return dst_dev
->funcs
->pAlphaBlend( dst_dev
, dst
, src_dev
, src
, blendfn
);
2408 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->format
!= WXR_FORMAT_A8R8G8B8
)
2410 SetLastError( ERROR_INVALID_PARAMETER
);
2414 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
2416 use_repeat
= use_source_repeat( physdev_src
);
2419 xscale
= src
->width
/ (double)dst
->width
;
2420 yscale
= src
->height
/ (double)dst
->height
;
2422 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2424 src_pict
= get_xrender_picture_source( physdev_src
, use_repeat
);
2426 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
2428 /* mono -> color blending needs an intermediate color pixmap */
2429 XRenderColor fg
, bg
;
2430 int width
= src
->visrect
.right
- src
->visrect
.left
;
2431 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
2433 /* blending doesn't use the destination DC colors */
2434 fg
.red
= fg
.green
= fg
.blue
= 0;
2435 bg
.red
= bg
.green
= bg
.blue
= 0xffff;
2436 fg
.alpha
= bg
.alpha
= 0xffff;
2439 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
,
2440 physdev_dst
->pict_format
->depth
);
2441 pa
.repeat
= use_repeat
? RepeatNormal
: RepeatNone
;
2442 tmp_pict
= pXRenderCreatePicture( gdi_display
, tmp_pixmap
, physdev_dst
->pict_format
,
2444 wine_tsx11_unlock();
2446 xrender_mono_blit( src_pict
, tmp_pict
, physdev_dst
->format
, &fg
, &bg
,
2447 src
->visrect
.left
, src
->visrect
.top
, width
, height
, 0, 0, width
, height
, 1, 1 );
2449 else if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->pict_format
)
2451 /* we need a source picture with no alpha */
2452 enum wxr_format format
= get_format_without_alpha( physdev_src
->format
);
2453 if (format
!= physdev_src
->format
)
2456 pa
.subwindow_mode
= IncludeInferiors
;
2457 pa
.repeat
= use_repeat
? RepeatNormal
: RepeatNone
;
2458 tmp_pict
= pXRenderCreatePicture( gdi_display
, physdev_src
->x11dev
->drawable
,
2459 pict_formats
[format
], CPSubwindowMode
|CPRepeat
, &pa
);
2460 wine_tsx11_unlock();
2464 if (tmp_pict
) src_pict
= tmp_pict
;
2466 EnterCriticalSection( &xrender_cs
);
2467 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
2469 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2470 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
2471 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
2472 src
->width
, src
->height
,
2473 physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
,
2474 physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
,
2475 dst
->width
, dst
->height
, xscale
, yscale
);
2478 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
2479 if (tmp_pixmap
) XFreePixmap( gdi_display
, tmp_pixmap
);
2480 wine_tsx11_unlock();
2482 LeaveCriticalSection( &xrender_cs
);
2486 /***********************************************************************
2487 * xrenderdrv_GradientFill
2489 static BOOL
xrenderdrv_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
2490 void * grad_array
, ULONG ngrad
, ULONG mode
)
2492 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2493 static const XFixed stops
[2] = { 0, 1 << 16 };
2494 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2495 XLinearGradient gradient
;
2496 XRenderColor colors
[2];
2497 Picture src_pict
, dst_pict
;
2499 const GRADIENT_RECT
*rect
= grad_array
;
2502 if (!pXRenderCreateLinearGradient
) goto fallback
;
2504 /* <= 16-bpp uses dithering */
2505 if (!physdev
->pict_format
|| physdev
->pict_format
->depth
<= 16) goto fallback
;
2509 case GRADIENT_FILL_RECT_H
:
2510 case GRADIENT_FILL_RECT_V
:
2511 for (i
= 0; i
< ngrad
; i
++, rect
++)
2513 const TRIVERTEX
*v1
= vert_array
+ rect
->UpperLeft
;
2514 const TRIVERTEX
*v2
= vert_array
+ rect
->LowerRight
;
2516 colors
[0].red
= v1
->Red
* 257 / 256;
2517 colors
[0].green
= v1
->Green
* 257 / 256;
2518 colors
[0].blue
= v1
->Blue
* 257 / 256;
2519 colors
[1].red
= v2
->Red
* 257 / 256;
2520 colors
[1].green
= v2
->Green
* 257 / 256;
2521 colors
[1].blue
= v2
->Blue
* 257 / 256;
2522 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2523 colors
[0].alpha
= colors
[1].alpha
= 65535;
2529 LPtoDP( dev
->hdc
, pt
, 2 );
2530 if (mode
== GRADIENT_FILL_RECT_H
)
2532 gradient
.p1
.y
= gradient
.p2
.y
= 0;
2533 if (pt
[1].x
> pt
[0].x
)
2536 gradient
.p2
.x
= (pt
[1].x
- pt
[0].x
) << 16;
2540 gradient
.p1
.x
= (pt
[0].x
- pt
[1].x
) << 16;
2546 gradient
.p1
.x
= gradient
.p2
.x
= 0;
2547 if (pt
[1].y
> pt
[0].y
)
2550 gradient
.p2
.y
= (pt
[1].y
- pt
[0].y
) << 16;
2554 gradient
.p1
.y
= (pt
[0].y
- pt
[1].y
) << 16;
2559 TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2560 mode
, pt
[0].x
, pt
[0].y
, pt
[1].x
, pt
[1].y
,
2561 colors
[0].red
, colors
[0].green
, colors
[0].blue
, colors
[0].alpha
,
2562 colors
[1].red
, colors
[1].green
, colors
[1].blue
, colors
[1].alpha
);
2564 dst_pict
= get_xrender_picture( physdev
, 0, NULL
);
2567 src_pict
= pXRenderCreateLinearGradient( gdi_display
, &gradient
, stops
, colors
, 2 );
2568 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
,
2569 0, 0, abs(pt
[1].x
- pt
[0].x
), abs(pt
[1].y
- pt
[0].y
),
2570 physdev
->x11dev
->dc_rect
.left
+ min( pt
[0].x
, pt
[1].x
),
2571 physdev
->x11dev
->dc_rect
.top
+ min( pt
[0].y
, pt
[1].y
),
2572 abs(pt
[1].x
- pt
[0].x
), abs(pt
[1].y
- pt
[0].y
), 1, 1 );
2573 pXRenderFreePicture( gdi_display
, src_pict
);
2574 wine_tsx11_unlock();
2581 dev
= GET_NEXT_PHYSDEV( dev
, pGradientFill
);
2582 return dev
->funcs
->pGradientFill( dev
, vert_array
, nvert
, grad_array
, ngrad
, mode
);
2585 /***********************************************************************
2586 * xrenderdrv_SelectBrush
2588 static HBRUSH
xrenderdrv_SelectBrush( PHYSDEV dev
, HBRUSH hbrush
, const struct brush_pattern
*pattern
)
2590 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2591 X_PHYSBITMAP
*physbitmap
;
2592 BOOL delete_bitmap
= FALSE
;
2596 XRenderPictFormat
*pict_format
;
2597 Picture src_pict
, dst_pict
;
2598 XRenderPictureAttributes pa
;
2600 if (!pattern
) goto x11drv_fallback
;
2601 if (physdev
->format
== WXR_FORMAT_MONO
) goto x11drv_fallback
;
2603 bitmap
= pattern
->bitmap
;
2604 if (!bitmap
|| !(physbitmap
= X11DRV_get_phys_bitmap( bitmap
)))
2606 if (!(bitmap
= create_brush_bitmap( physdev
->x11dev
, pattern
))) return 0;
2607 physbitmap
= X11DRV_get_phys_bitmap( bitmap
);
2608 delete_bitmap
= TRUE
;
2611 if (physbitmap
->format
== WXR_FORMAT_MONO
) goto x11drv_fallback
;
2612 if (!(pict_format
= pict_formats
[physbitmap
->format
])) goto x11drv_fallback
;
2614 GetObjectW( bitmap
, sizeof(bm
), &bm
);
2617 pixmap
= XCreatePixmap( gdi_display
, root_window
, bm
.bmWidth
, bm
.bmHeight
,
2618 physdev
->pict_format
->depth
);
2620 pa
.repeat
= RepeatNone
;
2621 src_pict
= pXRenderCreatePicture(gdi_display
, physbitmap
->pixmap
, pict_format
, CPRepeat
, &pa
);
2622 dst_pict
= pXRenderCreatePicture(gdi_display
, pixmap
, physdev
->pict_format
, CPRepeat
, &pa
);
2624 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
, 0, 0, bm
.bmWidth
, bm
.bmHeight
,
2625 0, 0, bm
.bmWidth
, bm
.bmHeight
, 1.0, 1.0 );
2626 pXRenderFreePicture( gdi_display
, src_pict
);
2627 pXRenderFreePicture( gdi_display
, dst_pict
);
2629 if (physdev
->x11dev
->brush
.pixmap
) XFreePixmap( gdi_display
, physdev
->x11dev
->brush
.pixmap
);
2630 physdev
->x11dev
->brush
.pixmap
= pixmap
;
2631 physdev
->x11dev
->brush
.fillStyle
= FillTiled
;
2632 physdev
->x11dev
->brush
.pixel
= 0; /* ignored */
2633 physdev
->x11dev
->brush
.style
= BS_PATTERN
;
2634 wine_tsx11_unlock();
2636 if (delete_bitmap
) DeleteObject( bitmap
);
2640 if (delete_bitmap
) DeleteObject( bitmap
);
2641 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBrush
);
2642 return dev
->funcs
->pSelectBrush( dev
, hbrush
, pattern
);
2646 static const struct gdi_dc_funcs xrender_funcs
=
2648 NULL
, /* pAbortDoc */
2649 NULL
, /* pAbortPath */
2650 xrenderdrv_AlphaBlend
, /* pAlphaBlend */
2651 NULL
, /* pAngleArc */
2654 NULL
, /* pBeginPath */
2655 xrenderdrv_BlendImage
, /* pBlendImage */
2656 NULL
, /* pChoosePixelFormat */
2658 NULL
, /* pCloseFigure */
2659 xrenderdrv_CopyBitmap
, /* pCopyBitmap */
2660 xrenderdrv_CreateBitmap
, /* pCreateBitmap */
2661 xrenderdrv_CreateCompatibleDC
, /* pCreateCompatibleDC */
2662 xrenderdrv_CreateDC
, /* pCreateDC */
2663 xrenderdrv_DeleteBitmap
, /* pDeleteBitmap */
2664 xrenderdrv_DeleteDC
, /* pDeleteDC */
2665 NULL
, /* pDeleteObject */
2666 NULL
, /* pDescribePixelFormat */
2667 NULL
, /* pDeviceCapabilities */
2668 NULL
, /* pEllipse */
2670 NULL
, /* pEndPage */
2671 NULL
, /* pEndPath */
2672 NULL
, /* pEnumFonts */
2673 NULL
, /* pEnumICMProfiles */
2674 NULL
, /* pExcludeClipRect */
2675 NULL
, /* pExtDeviceMode */
2676 xrenderdrv_ExtEscape
, /* pExtEscape */
2677 NULL
, /* pExtFloodFill */
2678 NULL
, /* pExtSelectClipRgn */
2679 xrenderdrv_ExtTextOut
, /* pExtTextOut */
2680 NULL
, /* pFillPath */
2681 NULL
, /* pFillRgn */
2682 NULL
, /* pFlattenPath */
2683 NULL
, /* pFontIsLinked */
2684 NULL
, /* pFrameRgn */
2685 NULL
, /* pGdiComment */
2686 NULL
, /* pGdiRealizationInfo */
2687 NULL
, /* pGetBoundsRect */
2688 NULL
, /* pGetCharABCWidths */
2689 NULL
, /* pGetCharABCWidthsI */
2690 NULL
, /* pGetCharWidth */
2691 NULL
, /* pGetDeviceCaps */
2692 NULL
, /* pGetDeviceGammaRamp */
2693 NULL
, /* pGetFontData */
2694 NULL
, /* pGetFontUnicodeRanges */
2695 NULL
, /* pGetGlyphIndices */
2696 NULL
, /* pGetGlyphOutline */
2697 NULL
, /* pGetICMProfile */
2698 xrenderdrv_GetImage
, /* pGetImage */
2699 NULL
, /* pGetKerningPairs */
2700 NULL
, /* pGetNearestColor */
2701 NULL
, /* pGetOutlineTextMetrics */
2702 NULL
, /* pGetPixel */
2703 NULL
, /* pGetPixelFormat */
2704 NULL
, /* pGetSystemPaletteEntries */
2705 NULL
, /* pGetTextCharsetInfo */
2706 NULL
, /* pGetTextExtentExPoint */
2707 NULL
, /* pGetTextExtentExPointI */
2708 NULL
, /* pGetTextFace */
2709 NULL
, /* pGetTextMetrics */
2710 xrenderdrv_GradientFill
, /* pGradientFill */
2711 NULL
, /* pIntersectClipRect */
2712 NULL
, /* pInvertRgn */
2714 NULL
, /* pModifyWorldTransform */
2716 NULL
, /* pOffsetClipRgn */
2717 NULL
, /* pOffsetViewportOrg */
2718 NULL
, /* pOffsetWindowOrg */
2719 NULL
, /* pPaintRgn */
2722 NULL
, /* pPolyBezier */
2723 NULL
, /* pPolyBezierTo */
2724 NULL
, /* pPolyDraw */
2725 NULL
, /* pPolyPolygon */
2726 NULL
, /* pPolyPolyline */
2727 NULL
, /* pPolygon */
2728 NULL
, /* pPolyline */
2729 NULL
, /* pPolylineTo */
2730 xrenderdrv_PutImage
, /* pPutImage */
2731 NULL
, /* pRealizeDefaultPalette */
2732 NULL
, /* pRealizePalette */
2733 NULL
, /* pRectangle */
2734 NULL
, /* pResetDC */
2735 NULL
, /* pRestoreDC */
2736 NULL
, /* pRoundRect */
2738 NULL
, /* pScaleViewportExt */
2739 NULL
, /* pScaleWindowExt */
2740 xrenderdrv_SelectBitmap
, /* pSelectBitmap */
2741 xrenderdrv_SelectBrush
, /* pSelectBrush */
2742 NULL
, /* pSelectClipPath */
2743 xrenderdrv_SelectFont
, /* pSelectFont */
2744 NULL
, /* pSelectPalette */
2745 NULL
, /* pSelectPen */
2746 NULL
, /* pSetArcDirection */
2747 NULL
, /* pSetBkColor */
2748 NULL
, /* pSetBkMode */
2749 NULL
, /* pSetDCBrushColor */
2750 NULL
, /* pSetDCPenColor */
2751 NULL
, /* pSetDIBitsToDevice */
2752 xrenderdrv_SetDeviceClipping
, /* pSetDeviceClipping */
2753 NULL
, /* pSetDeviceGammaRamp */
2754 NULL
, /* pSetLayout */
2755 NULL
, /* pSetMapMode */
2756 NULL
, /* pSetMapperFlags */
2757 NULL
, /* pSetPixel */
2758 NULL
, /* pSetPixelFormat */
2759 NULL
, /* pSetPolyFillMode */
2760 NULL
, /* pSetROP2 */
2761 NULL
, /* pSetRelAbs */
2762 NULL
, /* pSetStretchBltMode */
2763 NULL
, /* pSetTextAlign */
2764 NULL
, /* pSetTextCharacterExtra */
2765 NULL
, /* pSetTextColor */
2766 NULL
, /* pSetTextJustification */
2767 NULL
, /* pSetViewportExt */
2768 NULL
, /* pSetViewportOrg */
2769 NULL
, /* pSetWindowExt */
2770 NULL
, /* pSetWindowOrg */
2771 NULL
, /* pSetWorldTransform */
2772 NULL
, /* pStartDoc */
2773 NULL
, /* pStartPage */
2774 xrenderdrv_StretchBlt
, /* pStretchBlt */
2775 NULL
, /* pStretchDIBits */
2776 NULL
, /* pStrokeAndFillPath */
2777 NULL
, /* pStrokePath */
2778 NULL
, /* pSwapBuffers */
2779 NULL
, /* pUnrealizePalette */
2780 NULL
, /* pWidenPath */
2781 /* OpenGL not supported */
2784 #else /* SONAME_LIBXRENDER */
2786 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
2788 TRACE("XRender support not compiled in.\n");
2792 void X11DRV_XRender_Finalize(void)
2796 #endif /* SONAME_LIBXRENDER */