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
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(xrender
);
46 #ifdef SONAME_LIBXRENDER
48 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
51 #include <X11/extensions/Xrender.h>
53 #ifndef RepeatNone /* added in 0.10 */
55 #define RepeatNormal 1
57 #define RepeatReflect 3
74 WXR_FORMAT_ROOT
, /* placeholder for the format to use on the root window */
76 WXR_INVALID_FORMAT
= WXR_NB_FORMATS
79 typedef struct wine_xrender_format_template
83 unsigned int alphaMask
;
87 unsigned int greenMask
;
89 unsigned int blueMask
;
90 } WineXRenderFormatTemplate
;
92 static const WineXRenderFormatTemplate wxr_formats_template
[WXR_NB_FORMATS
] =
94 /* Format depth alpha mask red mask green mask blue mask*/
95 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
96 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
97 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
98 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
99 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
100 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
101 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
103 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
105 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
106 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
109 static enum wxr_format default_format
= WXR_INVALID_FORMAT
;
110 static XRenderPictFormat
*pict_formats
[WXR_NB_FORMATS
+ 1 /* invalid format */];
116 SIZE devsize
; /* size in device coords */
120 #define INITIAL_REALIZED_BUF_SIZE 128
122 enum glyph_type
{ GLYPH_INDEX
, GLYPH_WCHAR
, GLYPH_NBTYPES
};
124 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
129 XRenderPictFormat
*font_format
;
133 } gsCacheEntryFormat
;
138 gsCacheEntryFormat
*format
[GLYPH_NBTYPES
][AA_MAXVALUE
];
143 struct xrender_physdev
145 struct gdi_physdev dev
;
146 X11DRV_PDEVICE
*x11dev
;
148 enum wxr_format format
;
154 XRenderPictFormat
*pict_format
;
157 static inline struct xrender_physdev
*get_xrender_dev( PHYSDEV dev
)
159 return (struct xrender_physdev
*)dev
;
162 static const struct gdi_dc_funcs xrender_funcs
;
164 static gsCacheEntry
*glyphsetCache
= NULL
;
165 static DWORD glyphsetCacheSize
= 0;
166 static INT lastfree
= -1;
169 #define INIT_CACHE_SIZE 10
171 static void *xrender_handle
;
173 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
174 MAKE_FUNCPTR(XRenderAddGlyphs
)
175 MAKE_FUNCPTR(XRenderChangePicture
)
176 MAKE_FUNCPTR(XRenderComposite
)
177 MAKE_FUNCPTR(XRenderCompositeText16
)
178 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
179 MAKE_FUNCPTR(XRenderCreatePicture
)
180 MAKE_FUNCPTR(XRenderFillRectangle
)
181 MAKE_FUNCPTR(XRenderFindFormat
)
182 MAKE_FUNCPTR(XRenderFindVisualFormat
)
183 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
184 MAKE_FUNCPTR(XRenderFreePicture
)
185 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
186 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
187 MAKE_FUNCPTR(XRenderCreateLinearGradient
)
189 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
190 MAKE_FUNCPTR(XRenderSetPictureTransform
)
192 MAKE_FUNCPTR(XRenderQueryExtension
)
196 static pthread_mutex_t xrender_mutex
= PTHREAD_MUTEX_INITIALIZER
;
198 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
199 ( ( (ULONG)_x4 << 24 ) | \
200 ( (ULONG)_x3 << 16 ) | \
201 ( (ULONG)_x2 << 8 ) | \
204 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
206 #define GASP_GRIDFIT 0x01
207 #define GASP_DOGRAY 0x02
209 #ifdef WORDS_BIGENDIAN
210 #define get_be_word(x) (x)
211 #define NATIVE_BYTE_ORDER MSBFirst
213 #define get_be_word(x) RtlUshortByteSwap(x)
214 #define NATIVE_BYTE_ORDER LSBFirst
217 static BOOL
has_alpha( enum wxr_format format
)
219 return (format
== WXR_FORMAT_A8R8G8B8
|| format
== WXR_FORMAT_B8G8R8A8
);
222 static enum wxr_format
get_format_without_alpha( enum wxr_format format
)
226 case WXR_FORMAT_A8R8G8B8
: return WXR_FORMAT_X8R8G8B8
;
227 case WXR_FORMAT_B8G8R8A8
: return WXR_FORMAT_B8G8R8X8
;
228 default: return format
;
232 static BOOL
get_xrender_template(const WineXRenderFormatTemplate
*fmt
, XRenderPictFormat
*templ
, unsigned long *mask
)
235 templ
->type
= PictTypeDirect
;
236 templ
->depth
= fmt
->depth
;
237 templ
->direct
.alpha
= fmt
->alpha
;
238 templ
->direct
.alphaMask
= fmt
->alphaMask
;
239 templ
->direct
.red
= fmt
->red
;
240 templ
->direct
.redMask
= fmt
->redMask
;
241 templ
->direct
.green
= fmt
->green
;
242 templ
->direct
.greenMask
= fmt
->greenMask
;
243 templ
->direct
.blue
= fmt
->blue
;
244 templ
->direct
.blueMask
= fmt
->blueMask
;
247 *mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
| PictFormatRed
| PictFormatRedMask
| PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
| PictFormatBlueMask
;
252 static BOOL
is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate
*fmt
)
254 if(fmt
->depth
!= default_visual
.depth
) return FALSE
;
255 if( (fmt
->redMask
<< fmt
->red
) != default_visual
.red_mask
) return FALSE
;
256 if( (fmt
->greenMask
<< fmt
->green
) != default_visual
.green_mask
) return FALSE
;
257 if( (fmt
->blueMask
<< fmt
->blue
) != default_visual
.blue_mask
) return FALSE
;
259 /* We never select a default ARGB visual */
260 if(fmt
->alphaMask
) return FALSE
;
264 static int load_xrender_formats(void)
269 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
271 XRenderPictFormat templ
;
273 if (i
== WXR_FORMAT_ROOT
)
275 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
,
276 DefaultVisual( gdi_display
, DefaultScreen(gdi_display
) ));
277 TRACE( "Loaded root pict_format with id=%#lx\n", pict_formats
[i
]->id
);
280 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template
[i
]))
282 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, default_visual
.visual
);
283 if (!pict_formats
[i
])
285 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
286 if (default_visual
.class == DirectColor
)
289 if (XMatchVisualInfo( gdi_display
, default_visual
.screen
,
290 default_visual
.depth
, TrueColor
, &info
))
292 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, info
.visual
);
293 if (pict_formats
[i
]) default_visual
= info
;
297 if (pict_formats
[i
]) default_format
= i
;
301 unsigned long mask
= 0;
302 get_xrender_template(&wxr_formats_template
[i
], &templ
, &mask
);
303 pict_formats
[i
] = pXRenderFindFormat(gdi_display
, mask
, &templ
, 0);
308 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats
[i
]->id
, i
);
314 /***********************************************************************
315 * X11DRV_XRender_Init
317 * Let's see if our XServer has the extension available
320 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
324 if (!client_side_with_render
) return NULL
;
325 if (!(xrender_handle
= dlopen(SONAME_LIBXRENDER
, RTLD_NOW
))) return NULL
;
327 #define LOAD_FUNCPTR(f) if((p##f = dlsym(xrender_handle, #f)) == NULL) return NULL
328 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = dlsym(xrender_handle, #f)
329 LOAD_FUNCPTR(XRenderAddGlyphs
);
330 LOAD_FUNCPTR(XRenderChangePicture
);
331 LOAD_FUNCPTR(XRenderComposite
);
332 LOAD_FUNCPTR(XRenderCompositeText16
);
333 LOAD_FUNCPTR(XRenderCreateGlyphSet
);
334 LOAD_FUNCPTR(XRenderCreatePicture
);
335 LOAD_FUNCPTR(XRenderFillRectangle
);
336 LOAD_FUNCPTR(XRenderFindFormat
);
337 LOAD_FUNCPTR(XRenderFindVisualFormat
);
338 LOAD_FUNCPTR(XRenderFreeGlyphSet
);
339 LOAD_FUNCPTR(XRenderFreePicture
);
340 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
);
341 LOAD_FUNCPTR(XRenderQueryExtension
);
342 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
343 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient
);
345 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
346 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
);
348 #undef LOAD_OPTIONAL_FUNCPTR
351 if (!pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
)) return NULL
;
353 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
354 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
356 ERR_(winediag
)("Wine has detected that you probably have a buggy version "
357 "of libXrender. Because of this client side font rendering "
358 "will be disabled. Please upgrade this library.\n");
362 if (!default_visual
.red_mask
|| !default_visual
.green_mask
|| !default_visual
.blue_mask
)
364 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
368 glyphsetCache
= calloc( sizeof(*glyphsetCache
), INIT_CACHE_SIZE
);
370 glyphsetCacheSize
= INIT_CACHE_SIZE
;
372 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
373 glyphsetCache
[i
].next
= i
+ 1;
374 glyphsetCache
[i
].count
= -1;
376 glyphsetCache
[i
-1].next
= -1;
378 return &xrender_funcs
;
381 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
382 static void get_xrender_color( struct xrender_physdev
*physdev
, COLORREF src_color
, XRenderColor
*dst_color
)
384 if (src_color
& (1 << 24)) /* PALETTEINDEX */
386 HPALETTE pal
= NtGdiGetDCObject( physdev
->dev
.hdc
, NTGDI_OBJ_PAL
);
387 PALETTEENTRY pal_ent
;
389 if (!get_palette_entries( pal
, LOWORD(src_color
), 1, &pal_ent
))
390 get_palette_entries( pal
, 0, 1, &pal_ent
);
391 dst_color
->red
= pal_ent
.peRed
* 257;
392 dst_color
->green
= pal_ent
.peGreen
* 257;
393 dst_color
->blue
= pal_ent
.peBlue
* 257;
397 if (src_color
>> 16 == 0x10ff) src_color
= 0; /* DIBINDEX */
399 dst_color
->red
= GetRValue( src_color
) * 257;
400 dst_color
->green
= GetGValue( src_color
) * 257;
401 dst_color
->blue
= GetBValue( src_color
) * 257;
404 if (physdev
->format
== WXR_FORMAT_MONO
&& !dst_color
->red
&& !dst_color
->green
&& !dst_color
->blue
)
405 dst_color
->alpha
= 0;
407 dst_color
->alpha
= 0xffff;
410 static enum wxr_format
get_xrender_format_from_bitmapinfo( const BITMAPINFO
*info
)
412 if (info
->bmiHeader
.biPlanes
!= 1) return WXR_INVALID_FORMAT
;
414 switch (info
->bmiHeader
.biBitCount
)
417 return WXR_FORMAT_MONO
;
422 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
423 return WXR_FORMAT_R8G8B8
;
426 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
428 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
431 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
433 if (info
->bmiHeader
.biBitCount
== wxr_formats_template
[i
].depth
&&
434 colors
[0] == (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
435 colors
[1] == (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
436 colors
[2] == (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
))
441 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
442 return (info
->bmiHeader
.biBitCount
== 16) ? WXR_FORMAT_X1R5G5B5
: WXR_FORMAT_A8R8G8B8
;
444 return WXR_INVALID_FORMAT
;
447 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
448 static void set_xrender_transformation(Picture src_pict
, double xscale
, double yscale
, int xoffset
, int yoffset
)
450 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
451 XTransform xform
= {{
452 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(xoffset
) },
453 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(yoffset
) },
454 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
457 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
461 static void update_xrender_clipping( struct xrender_physdev
*dev
, HRGN rgn
)
463 XRenderPictureAttributes pa
;
469 pXRenderChangePicture( gdi_display
, dev
->pict
, CPClipMask
, &pa
);
471 else if ((data
= X11DRV_GetRegionData( rgn
, 0 )))
473 pXRenderSetPictureClipRectangles( gdi_display
, dev
->pict
,
474 dev
->x11dev
->dc_rect
.left
, dev
->x11dev
->dc_rect
.top
,
475 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
481 static Picture
get_xrender_picture( struct xrender_physdev
*dev
, HRGN clip_rgn
, const RECT
*clip_rect
)
483 if (!dev
->pict
&& dev
->pict_format
)
485 XRenderPictureAttributes pa
;
487 pa
.subwindow_mode
= IncludeInferiors
;
488 dev
->pict
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
489 dev
->pict_format
, CPSubwindowMode
, &pa
);
490 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
491 dev
->pict
, dev
->dev
.hdc
, dev
->x11dev
->drawable
);
492 dev
->update_clip
= (dev
->region
!= 0);
497 HRGN rgn
= NtGdiCreateRectRgn( clip_rect
->left
, clip_rect
->top
, clip_rect
->right
, clip_rect
->bottom
);
498 if (clip_rgn
) NtGdiCombineRgn( rgn
, rgn
, clip_rgn
, RGN_AND
);
499 if (dev
->region
) NtGdiCombineRgn( rgn
, rgn
, dev
->region
, RGN_AND
);
500 update_xrender_clipping( dev
, rgn
);
501 NtGdiDeleteObjectApp( rgn
);
507 HRGN rgn
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
508 NtGdiCombineRgn( rgn
, clip_rgn
, dev
->region
, RGN_AND
);
509 update_xrender_clipping( dev
, rgn
);
510 NtGdiDeleteObjectApp( rgn
);
512 else update_xrender_clipping( dev
, clip_rgn
);
514 else if (dev
->update_clip
) update_xrender_clipping( dev
, dev
->region
);
516 dev
->update_clip
= (clip_rect
|| clip_rgn
); /* have to update again if we are using a custom region */
520 static Picture
get_xrender_picture_source( struct xrender_physdev
*dev
, BOOL repeat
)
522 if (!dev
->pict_src
&& dev
->pict_format
)
524 XRenderPictureAttributes pa
;
526 pa
.subwindow_mode
= IncludeInferiors
;
527 pa
.repeat
= repeat
? RepeatNormal
: RepeatNone
;
528 dev
->pict_src
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
529 dev
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
531 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
532 dev
->pict_src
, dev
->dev
.hdc
, dev
->x11dev
->drawable
, pa
.repeat
);
535 return dev
->pict_src
;
538 static void free_xrender_picture( struct xrender_physdev
*dev
)
540 if (dev
->pict
|| dev
->pict_src
)
542 XFlush( gdi_display
);
545 TRACE("freeing pict = %lx dc = %p\n", dev
->pict
, dev
->dev
.hdc
);
546 pXRenderFreePicture(gdi_display
, dev
->pict
);
551 TRACE("freeing pict = %lx dc = %p\n", dev
->pict_src
, dev
->dev
.hdc
);
552 pXRenderFreePicture(gdi_display
, dev
->pict_src
);
558 /* return a mask picture used to force alpha to 0 */
559 static Picture
get_no_alpha_mask(void)
561 static Pixmap pixmap
;
564 pthread_mutex_lock( &xrender_mutex
);
567 XRenderPictureAttributes pa
;
570 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
571 pa
.repeat
= RepeatNormal
;
572 pa
.component_alpha
= True
;
573 pict
= pXRenderCreatePicture( gdi_display
, pixmap
, pict_formats
[WXR_FORMAT_A8R8G8B8
],
574 CPRepeat
|CPComponentAlpha
, &pa
);
575 col
.red
= col
.green
= col
.blue
= 0xffff;
577 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
579 pthread_mutex_unlock( &xrender_mutex
);
583 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
585 if(p1
->hash
!= p2
->hash
) return TRUE
;
586 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
587 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
588 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
589 return wcsicmp( p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
592 static int LookupEntry(LFANDSIZE
*plfsz
)
596 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
598 if(glyphsetCache
[i
].count
== -1) break; /* reached free list so stop */
600 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
601 glyphsetCache
[i
].count
++;
603 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
604 glyphsetCache
[i
].next
= mru
;
607 TRACE("found font in cache %d\n", i
);
612 TRACE("font not in cache\n");
616 static void FreeEntry(int entry
)
620 for (type
= 0; type
< GLYPH_NBTYPES
; type
++)
622 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
623 gsCacheEntryFormat
* formatEntry
;
625 if( !glyphsetCache
[entry
].format
[type
][format
] )
628 formatEntry
= glyphsetCache
[entry
].format
[type
][format
];
630 if(formatEntry
->glyphset
) {
631 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
632 formatEntry
->glyphset
= 0;
634 if(formatEntry
->nrealized
) {
635 free( formatEntry
->realized
);
636 formatEntry
->realized
= NULL
;
637 free( formatEntry
->gis
);
638 formatEntry
->gis
= NULL
;
639 formatEntry
->nrealized
= 0;
643 glyphsetCache
[entry
].format
[type
][format
] = NULL
;
648 static int AllocEntry(void)
650 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
653 assert(glyphsetCache
[lastfree
].count
== -1);
654 glyphsetCache
[lastfree
].count
= 1;
656 lastfree
= glyphsetCache
[lastfree
].next
;
658 glyphsetCache
[best
].next
= mru
;
661 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
665 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
666 if(glyphsetCache
[i
].count
== 0) {
674 TRACE("freeing unused glyphset at cache %d\n", best
);
676 glyphsetCache
[best
].count
= 1;
678 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
679 glyphsetCache
[best
].next
= mru
;
687 TRACE("Growing cache\n");
689 glyphsetCache
= realloc( glyphsetCache
,
690 (glyphsetCacheSize
+ INIT_CACHE_SIZE
) * sizeof(*glyphsetCache
) );
692 for (best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
; i
++)
694 memset( &glyphsetCache
[i
], 0, sizeof(glyphsetCache
[i
]) );
695 glyphsetCache
[i
].next
= i
+ 1;
696 glyphsetCache
[i
].count
= -1;
698 glyphsetCache
[i
-1].next
= -1;
699 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
701 lastfree
= glyphsetCache
[best
].next
;
702 glyphsetCache
[best
].count
= 1;
703 glyphsetCache
[best
].next
= mru
;
705 TRACE("new free cache slot at %d\n", mru
);
709 static int GetCacheEntry( LFANDSIZE
*plfsz
)
714 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
717 entry
= glyphsetCache
+ ret
;
718 entry
->lfsz
= *plfsz
;
722 static void dec_ref_cache(int index
)
725 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
726 assert(glyphsetCache
[index
].count
> 0);
727 glyphsetCache
[index
].count
--;
730 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
732 DWORD hash
= 0, *ptr
, two_chars
;
736 hash
^= plfsz
->devsize
.cx
;
737 hash
^= plfsz
->devsize
.cy
;
738 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
740 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
742 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
744 pwc
= (WCHAR
*)&two_chars
;
746 *pwc
= RtlUpcaseUnicodeChar( *pwc
);
748 *pwc
= RtlUpcaseUnicodeChar( *pwc
);
756 static AA_Type
aa_type_from_flags( UINT aa_flags
)
758 switch (aa_flags
& 0x7f)
762 case WINE_GGO_GRAY16_BITMAP
:
764 case WINE_GGO_HRGB_BITMAP
:
766 case WINE_GGO_HBGR_BITMAP
:
768 case WINE_GGO_VRGB_BITMAP
:
770 case WINE_GGO_VBGR_BITMAP
:
773 FIXME( "unknown flags %x\n", aa_flags
);
778 static UINT
get_xft_aa_flags( const LOGFONTW
*lf
)
783 switch (lf
->lfQuality
)
785 case NONANTIALIASED_QUALITY
:
786 case ANTIALIASED_QUALITY
:
789 if (!(value
= XGetDefault( gdi_display
, "Xft", "antialias" ))) break;
790 TRACE( "got antialias '%s'\n", value
);
791 for (p
= value
; *p
; p
++) if ('A' <= *p
&& *p
<= 'Z') *p
+= 'a' - 'A'; /* to lower */
792 if (value
[0] == 'f' || value
[0] == 'n' || value
[0] == '0' || !strcmp( value
, "off" ))
797 ret
= GGO_GRAY4_BITMAP
;
799 case CLEARTYPE_QUALITY
:
800 case CLEARTYPE_NATURAL_QUALITY
:
801 if (!(value
= XGetDefault( gdi_display
, "Xft", "rgba" ))) break;
802 TRACE( "got rgba '%s'\n", value
);
803 if (!strcmp( value
, "rgb" )) ret
= WINE_GGO_HRGB_BITMAP
;
804 else if (!strcmp( value
, "bgr" )) ret
= WINE_GGO_HBGR_BITMAP
;
805 else if (!strcmp( value
, "vrgb" )) ret
= WINE_GGO_VRGB_BITMAP
;
806 else if (!strcmp( value
, "vbgr" )) ret
= WINE_GGO_VBGR_BITMAP
;
807 else if (!strcmp( value
, "none" )) ret
= GGO_GRAY4_BITMAP
;
813 /**********************************************************************
814 * xrenderdrv_SelectFont
816 static HFONT
xrenderdrv_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
819 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
820 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
824 NtGdiExtGetObjectW( hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
825 if (!*aa_flags
) *aa_flags
= get_xft_aa_flags( &lfsz
.lf
);
827 ret
= next
->funcs
->pSelectFont( next
, hfont
, aa_flags
);
832 case GGO_GRAY2_BITMAP
:
833 case GGO_GRAY4_BITMAP
:
834 case GGO_GRAY8_BITMAP
:
835 physdev
->aa_flags
= WINE_GGO_GRAY16_BITMAP
;
838 physdev
->aa_flags
= GGO_BITMAP
;
841 physdev
->aa_flags
= *aa_flags
;
845 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
846 (int)lfsz
.lf
.lfHeight
, (int)lfsz
.lf
.lfWidth
, (int)lfsz
.lf
.lfWeight
,
847 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
848 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
849 lfsz
.devsize
.cx
= X11DRV_XWStoDS( dev
->hdc
, lfsz
.lf
.lfWidth
);
850 lfsz
.devsize
.cy
= X11DRV_YWStoDS( dev
->hdc
, lfsz
.lf
.lfHeight
);
852 NtGdiGetTransform( dev
->hdc
, 0x204, &lfsz
.xform
);
853 TRACE("font transform %f %f %f %f\n", lfsz
.xform
.eM11
, lfsz
.xform
.eM12
,
854 lfsz
.xform
.eM21
, lfsz
.xform
.eM22
);
856 NtGdiGetDCDword( dev
->hdc
, NtGdiGetGraphicsMode
, &mode
);
857 if (mode
== GM_COMPATIBLE
)
859 lfsz
.lf
.lfOrientation
= lfsz
.lf
.lfEscapement
;
860 if (lfsz
.xform
.eM11
* lfsz
.xform
.eM22
< 0)
861 lfsz
.lf
.lfOrientation
= -lfsz
.lf
.lfOrientation
;
864 /* Not used fields, would break hashing */
865 lfsz
.xform
.eDx
= lfsz
.xform
.eDy
= 0;
867 lfsz_calc_hash(&lfsz
);
869 pthread_mutex_lock( &xrender_mutex
);
870 if (physdev
->cache_index
!= -1)
871 dec_ref_cache( physdev
->cache_index
);
872 physdev
->cache_index
= GetCacheEntry( &lfsz
);
873 pthread_mutex_unlock( &xrender_mutex
);
877 static void set_physdev_format( struct xrender_physdev
*physdev
, enum wxr_format format
)
879 if (physdev
->x11dev
->drawable
== DefaultRootWindow( gdi_display
))
880 physdev
->format
= WXR_FORMAT_ROOT
;
882 physdev
->format
= format
;
884 physdev
->pict_format
= pict_formats
[physdev
->format
];
887 static BOOL
create_xrender_dc( PHYSDEV
*pdev
, enum wxr_format format
)
889 X11DRV_PDEVICE
*x11dev
= get_x11drv_dev( *pdev
);
890 struct xrender_physdev
*physdev
= calloc( 1, sizeof(*physdev
) );
892 if (!physdev
) return FALSE
;
893 physdev
->x11dev
= x11dev
;
894 physdev
->cache_index
= -1;
895 set_physdev_format( physdev
, format
);
896 push_dc_driver( pdev
, &physdev
->dev
, &xrender_funcs
);
900 /* store the color mask data in the bitmap info structure */
901 static void set_color_info( XRenderPictFormat
*format
, BITMAPINFO
*info
)
903 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
905 info
->bmiHeader
.biPlanes
= 1;
906 info
->bmiHeader
.biBitCount
= pixmap_formats
[format
->depth
]->bits_per_pixel
;
907 info
->bmiHeader
.biCompression
= BI_RGB
;
908 info
->bmiHeader
.biClrUsed
= 0;
910 switch (info
->bmiHeader
.biBitCount
)
913 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
914 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
915 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
916 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
919 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
920 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
921 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
922 if (colors
[0] != 0xff0000 || colors
[1] != 0x00ff00 || colors
[2] != 0x0000ff)
923 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
929 /**********************************************************************
930 * xrenderdrv_CreateDC
932 static BOOL
xrenderdrv_CreateDC( PHYSDEV
*pdev
, LPCWSTR device
, LPCWSTR output
, const DEVMODEW
* initData
)
934 return create_xrender_dc( pdev
, default_format
);
937 /**********************************************************************
938 * xrenderdrv_CreateCompatibleDC
940 static BOOL
xrenderdrv_CreateCompatibleDC( PHYSDEV orig
, PHYSDEV
*pdev
)
942 if (orig
) /* chain to x11drv first */
944 orig
= GET_NEXT_PHYSDEV( orig
, pCreateCompatibleDC
);
945 if (!orig
->funcs
->pCreateCompatibleDC( orig
, pdev
)) return FALSE
;
947 /* otherwise we have been called by x11drv */
949 return create_xrender_dc( pdev
, WXR_FORMAT_MONO
);
952 /**********************************************************************
953 * xrenderdrv_DeleteDC
955 static BOOL
xrenderdrv_DeleteDC( PHYSDEV dev
)
957 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
959 free_xrender_picture( physdev
);
961 pthread_mutex_lock( &xrender_mutex
);
962 if (physdev
->cache_index
!= -1) dec_ref_cache( physdev
->cache_index
);
963 pthread_mutex_unlock( &xrender_mutex
);
969 /**********************************************************************
970 * xrenderdrv_ExtEscape
972 static INT
xrenderdrv_ExtEscape( PHYSDEV dev
, INT escape
, INT in_count
, LPCVOID in_data
,
973 INT out_count
, LPVOID out_data
)
975 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
977 dev
= GET_NEXT_PHYSDEV( dev
, pExtEscape
);
979 if (escape
== X11DRV_ESCAPE
&& in_data
&& in_count
>= sizeof(enum x11drv_escape_codes
))
981 if (*(const enum x11drv_escape_codes
*)in_data
== X11DRV_SET_DRAWABLE
)
983 BOOL ret
= dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
986 free_xrender_picture( physdev
);
987 set_physdev_format( physdev
, default_format
);
992 return dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
995 /***********************************************************************
996 * xrenderdrv_SetDeviceClipping
998 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev
, HRGN rgn
)
1000 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1002 physdev
->region
= rgn
;
1003 physdev
->update_clip
= TRUE
;
1005 dev
= GET_NEXT_PHYSDEV( dev
, pSetDeviceClipping
);
1006 dev
->funcs
->pSetDeviceClipping( dev
, rgn
);
1010 /************************************************************************
1013 * Helper to ExtTextOut. Must be called inside xrender_mutex
1015 static void UploadGlyph(struct xrender_physdev
*physDev
, UINT glyph
, enum glyph_type type
)
1017 unsigned int buflen
;
1022 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->cache_index
;
1023 gsCacheEntryFormat
*formatEntry
;
1024 UINT ggo_format
= physDev
->aa_flags
;
1025 AA_Type format
= aa_type_from_flags( physDev
->aa_flags
);
1026 enum wxr_format wxr_format
;
1027 static const char zero
[4];
1028 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
1030 if (type
== GLYPH_INDEX
) ggo_format
|= GGO_GLYPH_INDEX
;
1031 buflen
= NtGdiGetGlyphOutline( physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
, FALSE
);
1032 if(buflen
== GDI_ERROR
) {
1033 if(format
!= AA_None
) {
1035 physDev
->aa_flags
= GGO_BITMAP
;
1036 ggo_format
= (ggo_format
& GGO_GLYPH_INDEX
) | GGO_BITMAP
;
1037 buflen
= NtGdiGetGlyphOutline( physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
,
1040 if(buflen
== GDI_ERROR
) {
1041 WARN("GetGlyphOutlineW failed using default glyph\n");
1042 buflen
= NtGdiGetGlyphOutline( physDev
->dev
.hdc
, 0, ggo_format
, &gm
, 0, NULL
,
1044 if(buflen
== GDI_ERROR
) {
1045 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1046 buflen
= NtGdiGetGlyphOutline( physDev
->dev
.hdc
, 0x20, ggo_format
, &gm
, 0, NULL
,
1048 if(buflen
== GDI_ERROR
) {
1049 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1054 TRACE("Turning off antialiasing for this monochrome font\n");
1057 /* If there is nothing for the current type, we create the entry. */
1058 if( !entry
->format
[type
][format
] ) {
1059 entry
->format
[type
][format
] = calloc( 1, sizeof(gsCacheEntryFormat
) );
1061 formatEntry
= entry
->format
[type
][format
];
1063 if(formatEntry
->nrealized
<= glyph
) {
1064 size_t new_size
= (glyph
/ 128 + 1) * 128;
1066 formatEntry
->realized
= realloc( formatEntry
->realized
, new_size
* sizeof(BOOL
) );
1067 memset( formatEntry
->realized
+ formatEntry
->nrealized
, 0,
1068 (new_size
- formatEntry
->nrealized
) * sizeof(BOOL
) );
1070 formatEntry
->gis
= realloc( formatEntry
->gis
, new_size
* sizeof(formatEntry
->gis
[0]) );
1071 memset( formatEntry
->gis
+ formatEntry
->nrealized
, 0,
1072 (new_size
- formatEntry
->nrealized
) * sizeof(formatEntry
->gis
[0]) );
1074 formatEntry
->nrealized
= new_size
;
1078 if(formatEntry
->glyphset
== 0) {
1081 wxr_format
= WXR_FORMAT_GRAY
;
1088 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1092 ERR("aa = %d - not implemented\n", format
);
1095 wxr_format
= WXR_FORMAT_MONO
;
1099 formatEntry
->font_format
= pict_formats
[wxr_format
];
1100 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
1104 buf
= calloc( 1, buflen
);
1106 NtGdiGetGlyphOutline( physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
, FALSE
);
1108 gm
.gmBlackBoxX
= gm
.gmBlackBoxY
= 0; /* empty glyph */
1109 formatEntry
->realized
[glyph
] = TRUE
;
1111 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1113 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1114 (int)gm
.gmptGlyphOrigin
.x
, (int)gm
.gmptGlyphOrigin
.y
);
1116 gi
.width
= gm
.gmBlackBoxX
;
1117 gi
.height
= gm
.gmBlackBoxY
;
1118 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1119 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1120 gi
.xOff
= gm
.gmCellIncX
;
1121 gi
.yOff
= gm
.gmCellIncY
;
1123 if(TRACE_ON(xrender
)) {
1126 unsigned char *line
;
1128 if(format
== AA_None
) {
1129 pitch
= ((gi
.width
+ 31) / 32) * 4;
1130 for(i
= 0; i
< gi
.height
; i
++) {
1131 line
= (unsigned char*) buf
+ i
* pitch
;
1133 for(j
= 0; j
< pitch
* 8; j
++) {
1134 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1136 TRACE("%s\n", output
);
1139 static const char blks
[] = " .:;!o*#";
1143 pitch
= ((gi
.width
+ 3) / 4) * 4;
1144 for(i
= 0; i
< gi
.height
; i
++) {
1145 line
= (unsigned char*) buf
+ i
* pitch
;
1147 for(j
= 0; j
< pitch
; j
++) {
1148 str
[0] = blks
[line
[j
] >> 5];
1149 strcat(output
, str
);
1151 TRACE("%s\n", output
);
1157 if(formatEntry
->glyphset
) {
1158 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1159 unsigned char *byte
= (unsigned char*) buf
, c
;
1165 /* magic to flip bit order */
1166 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1167 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1168 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1173 else if ( format
!= AA_Grey
&&
1174 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1176 unsigned int i
, *data
= (unsigned int *)buf
;
1177 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1182 XRenderCompositeText seems to ignore 0x0 glyphs when
1183 AA_None, which means we lose the advance width of glyphs
1184 like the space. We'll pretend that such glyphs are 1x1
1189 gi
.width
= gi
.height
= 1;
1191 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1192 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1196 formatEntry
->gis
[glyph
] = gi
;
1199 /*************************************************************
1202 * Returns an appropriate Picture for tiling the text colour.
1203 * Call and use result within the xrender_mutex
1205 static Picture
get_tile_pict( enum wxr_format wxr_format
, const XRenderColor
*color
)
1211 XRenderColor current_color
;
1212 } tiles
[WXR_NB_FORMATS
], *tile
;
1214 tile
= &tiles
[wxr_format
];
1218 XRenderPictureAttributes pa
;
1219 XRenderPictFormat
*pict_format
= pict_formats
[wxr_format
];
1221 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_format
->depth
);
1223 pa
.repeat
= RepeatNormal
;
1224 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_format
, CPRepeat
, &pa
);
1226 /* init current_color to something different from text_pixel */
1227 tile
->current_color
= *color
;
1228 tile
->current_color
.red
^= 0xffff;
1230 if (wxr_format
== WXR_FORMAT_MONO
)
1232 /* for a 1bpp bitmap we always need a 1 in the tile */
1234 col
.red
= col
.green
= col
.blue
= 0;
1236 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1240 if (memcmp( color
, &tile
->current_color
, sizeof(*color
) ) && wxr_format
!= WXR_FORMAT_MONO
)
1242 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, color
, 0, 0, 1, 1);
1243 tile
->current_color
= *color
;
1248 /*************************************************************
1251 * Returns an appropriate Picture for masking with the specified alpha.
1252 * Call and use result within the xrender_mutex
1254 static Picture
get_mask_pict( int alpha
)
1256 static Pixmap pixmap
;
1257 static Picture pict
;
1258 static int current_alpha
;
1260 if (alpha
== 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1264 XRenderPictureAttributes pa
;
1266 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
1267 pa
.repeat
= RepeatNormal
;
1268 pict
= pXRenderCreatePicture( gdi_display
, pixmap
,
1269 pict_formats
[WXR_FORMAT_A8R8G8B8
], CPRepeat
, &pa
);
1273 if (alpha
!= current_alpha
)
1276 col
.red
= col
.green
= col
.blue
= 0;
1277 col
.alpha
= current_alpha
= alpha
;
1278 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
1283 /***********************************************************************
1284 * xrenderdrv_ExtTextOut
1286 static BOOL
xrenderdrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
,
1287 const RECT
*lprect
, LPCWSTR wstr
, UINT count
, const INT
*lpDx
)
1289 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1290 gsCacheEntry
*entry
;
1291 gsCacheEntryFormat
*formatEntry
;
1294 Picture pict
, tile_pict
= 0;
1296 POINT offset
, desired
, current
;
1297 int render_op
= PictOpOver
;
1300 enum glyph_type type
= (flags
& ETO_GLYPH_INDEX
) ? GLYPH_INDEX
: GLYPH_WCHAR
;
1302 NtGdiGetDCDword( physdev
->dev
.hdc
, NtGdiGetTextColor
, &text_color
);
1303 get_xrender_color( physdev
, text_color
, &col
);
1304 pict
= get_xrender_picture( physdev
, 0, (flags
& ETO_CLIPPED
) ? lprect
: NULL
);
1306 if(flags
& ETO_OPAQUE
)
1310 if (physdev
->format
== WXR_FORMAT_MONO
)
1311 /* use the inverse of the text color */
1312 bg
.red
= bg
.green
= bg
.blue
= bg
.alpha
= ~col
.alpha
;
1316 NtGdiGetDCDword( physdev
->dev
.hdc
, NtGdiGetBkColor
, &bg_color
);
1317 get_xrender_color( physdev
, bg_color
, &bg
);
1320 set_xrender_transformation( pict
, 1, 1, 0, 0 );
1321 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &bg
,
1322 physdev
->x11dev
->dc_rect
.left
+ lprect
->left
,
1323 physdev
->x11dev
->dc_rect
.top
+ lprect
->top
,
1324 lprect
->right
- lprect
->left
,
1325 lprect
->bottom
- lprect
->top
);
1326 add_device_bounds( physdev
->x11dev
, lprect
);
1329 if(count
== 0) return TRUE
;
1331 pthread_mutex_lock( &xrender_mutex
);
1333 entry
= glyphsetCache
+ physdev
->cache_index
;
1334 formatEntry
= entry
->format
[type
][aa_type_from_flags( physdev
->aa_flags
)];
1336 for(idx
= 0; idx
< count
; idx
++) {
1337 if( !formatEntry
) {
1338 UploadGlyph(physdev
, wstr
[idx
], type
);
1339 /* re-evaluate format entry since aa_flags may have changed */
1340 formatEntry
= entry
->format
[type
][aa_type_from_flags( physdev
->aa_flags
)];
1341 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1342 UploadGlyph(physdev
, wstr
[idx
], type
);
1347 WARN("could not upload requested glyphs\n");
1348 pthread_mutex_unlock( &xrender_mutex
);
1352 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1353 (int)(physdev
->x11dev
->dc_rect
.left
+ x
), (int)(physdev
->x11dev
->dc_rect
.top
+ y
));
1355 elts
= malloc( sizeof(XGlyphElt16
) * count
);
1357 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1358 So we pass zeros to the function and move to our starting position using the first
1359 element of the elts array. */
1361 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
;
1362 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
;
1363 offset
.x
= offset
.y
= 0;
1364 current
.x
= current
.y
= 0;
1366 tile_pict
= get_tile_pict(physdev
->format
, &col
);
1368 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1370 if (physdev
->format
== WXR_FORMAT_MONO
&& col
.red
== 0 && col
.green
== 0 && col
.blue
== 0)
1371 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1373 reset_bounds( &bounds
);
1374 for(idx
= 0; idx
< count
; idx
++)
1376 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1377 elts
[idx
].chars
= wstr
+ idx
;
1378 elts
[idx
].nchars
= 1;
1379 elts
[idx
].xOff
= desired
.x
- current
.x
;
1380 elts
[idx
].yOff
= desired
.y
- current
.y
;
1382 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1383 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1385 rect
.left
= desired
.x
- physdev
->x11dev
->dc_rect
.left
- formatEntry
->gis
[wstr
[idx
]].x
;
1386 rect
.top
= desired
.y
- physdev
->x11dev
->dc_rect
.top
- formatEntry
->gis
[wstr
[idx
]].y
;
1387 rect
.right
= rect
.left
+ formatEntry
->gis
[wstr
[idx
]].width
;
1388 rect
.bottom
= rect
.top
+ formatEntry
->gis
[wstr
[idx
]].height
;
1389 add_bounds_rect( &bounds
, &rect
);
1393 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1394 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1400 offset
.x
+= lpDx
[idx
* 2];
1401 offset
.y
+= lpDx
[idx
* 2 + 1];
1404 offset
.x
+= lpDx
[idx
];
1405 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
+ offset
.x
;
1406 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
+ offset
.y
;
1410 /* Make sure we don't have any transforms set from a previous call */
1411 set_xrender_transformation(pict
, 1, 1, 0, 0);
1412 pXRenderCompositeText16(gdi_display
, render_op
,
1415 formatEntry
->font_format
,
1416 0, 0, 0, 0, elts
, count
);
1419 pthread_mutex_unlock( &xrender_mutex
);
1420 add_device_bounds( physdev
->x11dev
, &bounds
);
1424 /* multiply the alpha channel of a picture */
1425 static void multiply_alpha( Picture pict
, XRenderPictFormat
*format
, int alpha
,
1426 int x
, int y
, int width
, int height
)
1428 XRenderPictureAttributes pa
;
1429 Pixmap src_pixmap
, mask_pixmap
;
1430 Picture src_pict
, mask_pict
;
1433 src_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1434 mask_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1435 pa
.repeat
= RepeatNormal
;
1436 src_pict
= pXRenderCreatePicture( gdi_display
, src_pixmap
, format
, CPRepeat
, &pa
);
1437 pa
.component_alpha
= True
;
1438 mask_pict
= pXRenderCreatePicture( gdi_display
, mask_pixmap
, format
, CPRepeat
|CPComponentAlpha
, &pa
);
1439 color
.red
= color
.green
= color
.blue
= color
.alpha
= 0xffff;
1440 pXRenderFillRectangle( gdi_display
, PictOpSrc
, src_pict
, &color
, 0, 0, 1, 1 );
1441 color
.alpha
= alpha
;
1442 pXRenderFillRectangle( gdi_display
, PictOpSrc
, mask_pict
, &color
, 0, 0, 1, 1 );
1443 pXRenderComposite( gdi_display
, PictOpInReverse
, src_pict
, mask_pict
, pict
,
1444 0, 0, 0, 0, x
, y
, width
, height
);
1445 pXRenderFreePicture( gdi_display
, src_pict
);
1446 pXRenderFreePicture( gdi_display
, mask_pict
);
1447 XFreePixmap( gdi_display
, src_pixmap
);
1448 XFreePixmap( gdi_display
, mask_pixmap
);
1451 /* Helper function for (stretched) blitting using xrender */
1452 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
1453 int x_src
, int y_src
, int width_src
, int height_src
,
1454 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1455 double xscale
, double yscale
)
1457 int x_offset
, y_offset
;
1461 x_src
+= width_src
+ 1;
1465 y_src
+= height_src
+ 1;
1469 x_dst
+= width_dst
+ 1;
1470 width_dst
= -width_dst
;
1474 y_dst
+= height_dst
+ 1;
1475 height_dst
= -height_dst
;
1478 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1479 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1480 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1481 if(xscale
!= 1.0 || yscale
!= 1.0)
1483 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1484 * in the wrong quadrant of the x-y plane.
1486 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1487 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1488 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1494 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1496 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
1497 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width_dst
, height_dst
);
1500 /* Helper function for (stretched) mono->color blitting using xrender */
1501 static void xrender_mono_blit( Picture src_pict
, Picture dst_pict
,
1502 enum wxr_format dst_format
, XRenderColor
*fg
, XRenderColor
*bg
,
1503 int x_src
, int y_src
, int width_src
, int height_src
,
1504 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1505 double xscale
, double yscale
)
1508 int x_offset
, y_offset
;
1513 x_src
+= width_src
+ 1;
1514 width_src
= -width_src
;
1518 y_src
+= height_src
+ 1;
1519 height_src
= -height_src
;
1523 x_dst
+= width_dst
+ 1;
1524 width_dst
= -width_dst
;
1528 y_dst
+= height_dst
+ 1;
1529 height_dst
= -height_dst
;
1532 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1533 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1536 pthread_mutex_lock( &xrender_mutex
);
1538 color
.alpha
= 0xffff; /* tile pict needs 100% alpha */
1539 tile_pict
= get_tile_pict( dst_format
, &color
);
1541 pXRenderFillRectangle( gdi_display
, PictOpSrc
, dst_pict
, fg
, x_dst
, y_dst
, width_dst
, height_dst
);
1543 if (xscale
!= 1.0 || yscale
!= 1.0)
1545 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1546 * in the wrong quadrant of the x-y plane.
1548 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1549 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1550 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1556 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1558 pXRenderComposite(gdi_display
, PictOpOver
, tile_pict
, src_pict
, dst_pict
,
1559 0, 0, x_offset
, y_offset
, x_dst
, y_dst
, width_dst
, height_dst
);
1560 pthread_mutex_unlock( &xrender_mutex
);
1562 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1563 if (bg
->alpha
!= 0xffff && (dst_format
== WXR_FORMAT_A8R8G8B8
|| dst_format
== WXR_FORMAT_B8G8R8A8
))
1564 multiply_alpha( dst_pict
, pict_formats
[dst_format
], bg
->alpha
,
1565 x_dst
, y_dst
, width_dst
, height_dst
);
1568 /* create a pixmap and render picture for an image */
1569 static DWORD
create_image_pixmap( BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1570 struct bitblt_coords
*src
, enum wxr_format format
,
1571 Pixmap
*pixmap
, Picture
*pict
, BOOL
*use_repeat
)
1574 int width
= src
->visrect
.right
- src
->visrect
.left
;
1575 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1576 int depth
= pict_formats
[format
]->depth
;
1577 struct gdi_image_bits dst_bits
;
1578 XRenderPictureAttributes pa
;
1582 image
= XCreateImage( gdi_display
, default_visual
.visual
, depth
, ZPixmap
, 0, NULL
,
1583 info
->bmiHeader
.biWidth
, height
, 32, 0 );
1584 if (!image
) return ERROR_OUTOFMEMORY
;
1586 ret
= copy_image_bits( info
, (format
== WXR_FORMAT_R8G8B8
), image
, bits
, &dst_bits
, src
, NULL
, ~0u );
1587 if (ret
) return ret
;
1589 image
->data
= dst_bits
.ptr
;
1591 *use_repeat
= (width
== 1 && height
== 1);
1592 pa
.repeat
= *use_repeat
? RepeatNormal
: RepeatNone
;
1594 *pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, depth
);
1595 gc
= XCreateGC( gdi_display
, *pixmap
, 0, NULL
);
1596 XPutImage( gdi_display
, *pixmap
, gc
, image
, src
->visrect
.left
, 0, 0, 0, width
, height
);
1597 *pict
= pXRenderCreatePicture( gdi_display
, *pixmap
, pict_formats
[format
], CPRepeat
, &pa
);
1598 XFreeGC( gdi_display
, gc
);
1600 /* make coordinates relative to the pixmap */
1601 src
->x
-= src
->visrect
.left
;
1602 src
->y
-= src
->visrect
.top
;
1603 OffsetRect( &src
->visrect
, -src
->visrect
.left
, -src
->visrect
.top
);
1606 XDestroyImage( image
);
1607 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
1611 static void xrender_stretch_blit( struct xrender_physdev
*physdev_src
, struct xrender_physdev
*physdev_dst
,
1612 Drawable drawable
, const struct bitblt_coords
*src
,
1613 const struct bitblt_coords
*dst
)
1616 Picture src_pict
= 0, dst_pict
, mask_pict
= 0;
1617 double xscale
= src
->width
/ (double)dst
->width
;
1618 double yscale
= src
->height
/ (double)dst
->height
;
1620 if (drawable
) /* using an intermediate pixmap */
1624 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, physdev_dst
->pict_format
, 0, NULL
);
1628 x_dst
= physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
;
1629 y_dst
= physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
;
1630 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
1633 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
1636 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
1638 DWORD text_color
, bg_color
;
1639 XRenderColor fg
, bg
;
1641 NtGdiGetDCDword( physdev_dst
->dev
.hdc
, NtGdiGetTextColor
, &text_color
);
1642 NtGdiGetDCDword( physdev_dst
->dev
.hdc
, NtGdiGetBkColor
, &bg_color
);
1643 get_xrender_color( physdev_dst
, text_color
, &fg
);
1644 get_xrender_color( physdev_dst
, bg_color
, &bg
);
1645 fg
.alpha
= bg
.alpha
= 0;
1647 xrender_mono_blit( src_pict
, dst_pict
, physdev_dst
->format
, &fg
, &bg
,
1648 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1649 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1650 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1652 else /* color -> color (can be at different depths) or mono -> mono */
1654 if (physdev_dst
->pict_format
->depth
== 32 && physdev_src
->pict_format
->depth
< 32)
1655 mask_pict
= get_no_alpha_mask();
1657 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
1658 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1659 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1660 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1663 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1667 static void xrender_put_image( Pixmap src_pixmap
, Picture src_pict
, Picture mask_pict
, HRGN clip
,
1668 XRenderPictFormat
*dst_format
, struct xrender_physdev
*physdev
,
1669 Drawable drawable
, struct bitblt_coords
*src
,
1670 struct bitblt_coords
*dst
, BOOL use_repeat
)
1674 double xscale
, yscale
;
1676 if (drawable
) /* using an intermediate pixmap */
1678 RGNDATA
*clip_data
= NULL
;
1680 if (clip
) clip_data
= X11DRV_GetRegionData( clip
, 0 );
1683 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, dst_format
, 0, NULL
);
1685 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
, 0, 0,
1686 (XRectangle
*)clip_data
->Buffer
, clip_data
->rdh
.nCount
);
1691 x_dst
= physdev
->x11dev
->dc_rect
.left
+ dst
->x
;
1692 y_dst
= physdev
->x11dev
->dc_rect
.top
+ dst
->y
;
1693 dst_pict
= get_xrender_picture( physdev
, clip
, &dst
->visrect
);
1698 xscale
= src
->width
/ (double)dst
->width
;
1699 yscale
= src
->height
/ (double)dst
->height
;
1701 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
1703 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
, src
->x
, src
->y
, src
->width
, src
->height
,
1704 x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1706 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1710 /***********************************************************************
1711 * xrenderdrv_StretchBlt
1713 static BOOL
xrenderdrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
1714 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
1716 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
1717 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
1718 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
1720 if (src_dev
->funcs
!= dst_dev
->funcs
)
1722 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pStretchBlt
);
1723 return dst_dev
->funcs
->pStretchBlt( dst_dev
, dst
, src_dev
, src
, rop
);
1726 /* XRender is of no use for color -> mono */
1727 if (physdev_dst
->format
== WXR_FORMAT_MONO
&& physdev_src
->format
!= WXR_FORMAT_MONO
)
1728 goto x11drv_fallback
;
1730 /* if not stretching, we only need to handle format conversion */
1731 if (!stretch
&& physdev_dst
->format
== physdev_src
->format
) goto x11drv_fallback
;
1737 struct bitblt_coords tmp
;
1739 /* make coordinates relative to tmp pixmap */
1741 tmp
.x
-= tmp
.visrect
.left
;
1742 tmp
.y
-= tmp
.visrect
.top
;
1743 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
1745 tmpGC
= XCreateGC( gdi_display
, physdev_dst
->x11dev
->drawable
, 0, NULL
);
1746 XSetSubwindowMode( gdi_display
, tmpGC
, IncludeInferiors
);
1747 XSetGraphicsExposures( gdi_display
, tmpGC
, False
);
1748 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, tmp
.visrect
.right
- tmp
.visrect
.left
,
1749 tmp
.visrect
.bottom
- tmp
.visrect
.top
, physdev_dst
->pict_format
->depth
);
1751 xrender_stretch_blit( physdev_src
, physdev_dst
, tmp_pixmap
, src
, &tmp
);
1752 execute_rop( physdev_dst
->x11dev
, tmp_pixmap
, tmpGC
, &dst
->visrect
, rop
);
1754 XFreePixmap( gdi_display
, tmp_pixmap
);
1755 XFreeGC( gdi_display
, tmpGC
);
1757 else xrender_stretch_blit( physdev_src
, physdev_dst
, 0, src
, dst
);
1759 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
1763 return X11DRV_StretchBlt( &physdev_dst
->x11dev
->dev
, dst
, &physdev_src
->x11dev
->dev
, src
, rop
);
1767 /***********************************************************************
1768 * xrenderdrv_PutImage
1770 static DWORD
xrenderdrv_PutImage( PHYSDEV dev
, HRGN clip
, BITMAPINFO
*info
,
1771 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
1772 struct bitblt_coords
*dst
, DWORD rop
)
1774 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1778 enum wxr_format src_format
, dst_format
;
1779 XRenderPictFormat
*pict_format
;
1781 Picture src_pict
, mask_pict
= 0;
1784 dst_format
= physdev
->format
;
1785 src_format
= get_xrender_format_from_bitmapinfo( info
);
1786 if (!(pict_format
= pict_formats
[src_format
])) goto update_format
;
1788 /* make sure we can create an image with the same bpp */
1789 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
1792 /* mono <-> color conversions not supported */
1793 if ((src_format
!= dst_format
) && (src_format
== WXR_FORMAT_MONO
|| dst_format
== WXR_FORMAT_MONO
))
1794 goto x11drv_fallback
;
1796 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
1798 if (!has_alpha( src_format
) && has_alpha( dst_format
)) mask_pict
= get_no_alpha_mask();
1800 ret
= create_image_pixmap( info
, bits
, src
, src_format
, &src_pixmap
, &src_pict
, &use_repeat
);
1803 struct bitblt_coords tmp
;
1807 BOOL restore_region
= add_extra_clipping_region( physdev
->x11dev
, clip
);
1809 /* make coordinates relative to tmp pixmap */
1811 tmp
.x
-= tmp
.visrect
.left
;
1812 tmp
.y
-= tmp
.visrect
.top
;
1813 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
1815 gc
= XCreateGC( gdi_display
, physdev
->x11dev
->drawable
, 0, NULL
);
1816 XSetSubwindowMode( gdi_display
, gc
, IncludeInferiors
);
1817 XSetGraphicsExposures( gdi_display
, gc
, False
);
1818 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
,
1819 tmp
.visrect
.right
- tmp
.visrect
.left
,
1820 tmp
.visrect
.bottom
- tmp
.visrect
.top
,
1821 physdev
->pict_format
->depth
);
1823 xrender_put_image( src_pixmap
, src_pict
, mask_pict
, NULL
, physdev
->pict_format
,
1824 NULL
, tmp_pixmap
, src
, &tmp
, use_repeat
);
1825 execute_rop( physdev
->x11dev
, tmp_pixmap
, gc
, &dst
->visrect
, rop
);
1827 XFreePixmap( gdi_display
, tmp_pixmap
);
1828 XFreeGC( gdi_display
, gc
);
1829 if (restore_region
) restore_clipping_region( physdev
->x11dev
);
1831 else xrender_put_image( src_pixmap
, src_pict
, mask_pict
, clip
,
1832 physdev
->pict_format
, physdev
, 0, src
, dst
, use_repeat
);
1834 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
1836 pXRenderFreePicture( gdi_display
, src_pict
);
1837 XFreePixmap( gdi_display
, src_pixmap
);
1842 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
1843 set_color_info( pict_formats
[dst_format
], info
);
1844 return ERROR_BAD_FORMAT
;
1847 dev
= GET_NEXT_PHYSDEV( dev
, pPutImage
);
1848 return dev
->funcs
->pPutImage( dev
, clip
, info
, bits
, src
, dst
, rop
);
1852 /***********************************************************************
1853 * xrenderdrv_BlendImage
1855 static DWORD
xrenderdrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1856 struct bitblt_coords
*src
, struct bitblt_coords
*dst
,
1857 BLENDFUNCTION func
)
1859 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1861 enum wxr_format format
;
1862 XRenderPictFormat
*pict_format
;
1863 Picture dst_pict
, src_pict
, mask_pict
;
1867 format
= get_xrender_format_from_bitmapinfo( info
);
1868 if (!(func
.AlphaFormat
& AC_SRC_ALPHA
))
1869 format
= get_format_without_alpha( format
);
1870 else if (format
!= WXR_FORMAT_A8R8G8B8
|| info
->bmiHeader
.biCompression
!= BI_RGB
)
1871 return ERROR_INVALID_PARAMETER
;
1873 if (!(pict_format
= pict_formats
[format
])) goto update_format
;
1875 /* make sure we can create an image with the same bpp */
1876 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
1879 if (format
== WXR_FORMAT_MONO
&& physdev
->format
!= WXR_FORMAT_MONO
)
1882 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
1884 ret
= create_image_pixmap( info
, bits
, src
, format
, &src_pixmap
, &src_pict
, &use_repeat
);
1887 double xscale
, yscale
;
1891 xscale
= src
->width
/ (double)dst
->width
;
1892 yscale
= src
->height
/ (double)dst
->height
;
1894 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
1896 dst_pict
= get_xrender_picture( physdev
, 0, &dst
->visrect
);
1898 pthread_mutex_lock( &xrender_mutex
);
1899 mask_pict
= get_mask_pict( func
.SourceConstantAlpha
* 257 );
1901 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
1902 src
->x
, src
->y
, src
->width
, src
->height
,
1903 physdev
->x11dev
->dc_rect
.left
+ dst
->x
,
1904 physdev
->x11dev
->dc_rect
.top
+ dst
->y
,
1905 dst
->width
, dst
->height
, xscale
, yscale
);
1907 pXRenderFreePicture( gdi_display
, src_pict
);
1908 XFreePixmap( gdi_display
, src_pixmap
);
1910 pthread_mutex_unlock( &xrender_mutex
);
1911 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
1916 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
1917 set_color_info( physdev
->pict_format
, info
);
1918 return ERROR_BAD_FORMAT
;
1922 /***********************************************************************
1923 * xrenderdrv_AlphaBlend
1925 static BOOL
xrenderdrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
1926 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
1928 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
1929 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
1930 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
1931 XRenderPictureAttributes pa
;
1932 Pixmap tmp_pixmap
= 0;
1933 double xscale
, yscale
;
1935 if (src_dev
->funcs
!= dst_dev
->funcs
)
1937 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pAlphaBlend
);
1938 return dst_dev
->funcs
->pAlphaBlend( dst_dev
, dst
, src_dev
, src
, blendfn
);
1941 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->format
!= WXR_FORMAT_A8R8G8B8
)
1943 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
1947 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
1949 xscale
= src
->width
/ (double)dst
->width
;
1950 yscale
= src
->height
/ (double)dst
->height
;
1952 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
1954 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
1956 /* mono -> color blending needs an intermediate color pixmap */
1957 XRenderColor fg
, bg
;
1958 int width
= src
->visrect
.right
- src
->visrect
.left
;
1959 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1961 /* blending doesn't use the destination DC colors */
1962 fg
.red
= fg
.green
= fg
.blue
= 0;
1963 bg
.red
= bg
.green
= bg
.blue
= 0xffff;
1964 fg
.alpha
= bg
.alpha
= 0xffff;
1966 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
,
1967 physdev_dst
->pict_format
->depth
);
1968 tmp_pict
= pXRenderCreatePicture( gdi_display
, tmp_pixmap
, physdev_dst
->pict_format
, 0, NULL
);
1970 xrender_mono_blit( src_pict
, tmp_pict
, physdev_dst
->format
, &fg
, &bg
,
1971 src
->visrect
.left
, src
->visrect
.top
, width
, height
, 0, 0, width
, height
, 1, 1 );
1973 else if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->pict_format
)
1975 /* we need a source picture with no alpha */
1976 enum wxr_format format
= get_format_without_alpha( physdev_src
->format
);
1977 if (format
!= physdev_src
->format
)
1979 pa
.subwindow_mode
= IncludeInferiors
;
1980 tmp_pict
= pXRenderCreatePicture( gdi_display
, physdev_src
->x11dev
->drawable
,
1981 pict_formats
[format
], CPSubwindowMode
, &pa
);
1985 if (tmp_pict
) src_pict
= tmp_pict
;
1987 pthread_mutex_lock( &xrender_mutex
);
1988 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
1990 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
1991 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1992 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1993 src
->width
, src
->height
,
1994 physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
,
1995 physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
,
1996 dst
->width
, dst
->height
, xscale
, yscale
);
1998 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
1999 if (tmp_pixmap
) XFreePixmap( gdi_display
, tmp_pixmap
);
2001 pthread_mutex_unlock( &xrender_mutex
);
2002 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
2006 /***********************************************************************
2007 * xrenderdrv_GradientFill
2009 static BOOL
xrenderdrv_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
2010 void *grad_array
, ULONG ngrad
, ULONG mode
)
2012 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2013 static const XFixed stops
[2] = { 0, 1 << 16 };
2014 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2015 XLinearGradient gradient
;
2016 XRenderColor colors
[2];
2017 Picture src_pict
, dst_pict
;
2019 const GRADIENT_RECT
*rect
= grad_array
;
2023 if (!pXRenderCreateLinearGradient
) goto fallback
;
2025 /* <= 16-bpp uses dithering */
2026 if (!physdev
->pict_format
|| physdev
->pict_format
->depth
<= 16) goto fallback
;
2030 case GRADIENT_FILL_RECT_H
:
2031 case GRADIENT_FILL_RECT_V
:
2032 for (i
= 0; i
< ngrad
; i
++, rect
++)
2034 const TRIVERTEX
*v1
= vert_array
+ rect
->UpperLeft
;
2035 const TRIVERTEX
*v2
= vert_array
+ rect
->LowerRight
;
2037 colors
[0].red
= v1
->Red
* 257 / 256;
2038 colors
[0].green
= v1
->Green
* 257 / 256;
2039 colors
[0].blue
= v1
->Blue
* 257 / 256;
2040 colors
[1].red
= v2
->Red
* 257 / 256;
2041 colors
[1].green
= v2
->Green
* 257 / 256;
2042 colors
[1].blue
= v2
->Blue
* 257 / 256;
2043 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2044 colors
[0].alpha
= colors
[1].alpha
= 65535;
2050 lp_to_dp( dev
->hdc
, pt
, 2 );
2051 if (mode
== GRADIENT_FILL_RECT_H
)
2053 gradient
.p1
.y
= gradient
.p2
.y
= 0;
2054 if (pt
[1].x
> pt
[0].x
)
2057 gradient
.p2
.x
= (pt
[1].x
- pt
[0].x
) << 16;
2061 gradient
.p1
.x
= (pt
[0].x
- pt
[1].x
) << 16;
2067 gradient
.p1
.x
= gradient
.p2
.x
= 0;
2068 if (pt
[1].y
> pt
[0].y
)
2071 gradient
.p2
.y
= (pt
[1].y
- pt
[0].y
) << 16;
2075 gradient
.p1
.y
= (pt
[0].y
- pt
[1].y
) << 16;
2080 rc
.left
= min( pt
[0].x
, pt
[1].x
);
2081 rc
.top
= min( pt
[0].y
, pt
[1].y
);
2082 rc
.right
= max( pt
[0].x
, pt
[1].x
);
2083 rc
.bottom
= max( pt
[0].y
, pt
[1].y
);
2085 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2086 (int)mode
, wine_dbgstr_rect( &rc
),
2087 colors
[0].red
, colors
[0].green
, colors
[0].blue
, colors
[0].alpha
,
2088 colors
[1].red
, colors
[1].green
, colors
[1].blue
, colors
[1].alpha
);
2090 dst_pict
= get_xrender_picture( physdev
, 0, NULL
);
2092 src_pict
= pXRenderCreateLinearGradient( gdi_display
, &gradient
, stops
, colors
, 2 );
2093 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
,
2094 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
2095 physdev
->x11dev
->dc_rect
.left
+ rc
.left
,
2096 physdev
->x11dev
->dc_rect
.top
+ rc
.top
,
2097 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, 1, 1 );
2098 pXRenderFreePicture( gdi_display
, src_pict
);
2099 add_device_bounds( physdev
->x11dev
, &rc
);
2106 dev
= GET_NEXT_PHYSDEV( dev
, pGradientFill
);
2107 return dev
->funcs
->pGradientFill( dev
, vert_array
, nvert
, grad_array
, ngrad
, mode
);
2110 /***********************************************************************
2111 * xrenderdrv_SelectBrush
2113 static HBRUSH
xrenderdrv_SelectBrush( PHYSDEV dev
, HBRUSH hbrush
, const struct brush_pattern
*pattern
)
2115 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2117 XVisualInfo vis
= default_visual
;
2118 XRenderPictFormat
*format
= physdev
->pict_format
;
2120 if (!pattern
) goto x11drv_fallback
;
2121 if (pattern
->info
->bmiHeader
.biBitCount
== 1) goto x11drv_fallback
;
2122 if (physdev
->format
== WXR_FORMAT_MONO
) goto x11drv_fallback
;
2124 vis
.depth
= format
->depth
;
2125 vis
.red_mask
= format
->direct
.redMask
<< format
->direct
.red
;
2126 vis
.green_mask
= format
->direct
.greenMask
<< format
->direct
.green
;
2127 vis
.blue_mask
= format
->direct
.blueMask
<< format
->direct
.blue
;
2129 pixmap
= create_pixmap_from_image( physdev
->dev
.hdc
, &vis
, pattern
->info
,
2130 &pattern
->bits
, pattern
->usage
);
2131 if (!pixmap
) return 0;
2133 if (physdev
->x11dev
->brush
.pixmap
) XFreePixmap( gdi_display
, physdev
->x11dev
->brush
.pixmap
);
2134 physdev
->x11dev
->brush
.pixmap
= pixmap
;
2135 physdev
->x11dev
->brush
.fillStyle
= FillTiled
;
2136 physdev
->x11dev
->brush
.pixel
= 0; /* ignored */
2137 physdev
->x11dev
->brush
.style
= BS_PATTERN
;
2141 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBrush
);
2142 return dev
->funcs
->pSelectBrush( dev
, hbrush
, pattern
);
2146 static const struct gdi_dc_funcs xrender_funcs
=
2148 NULL
, /* pAbortDoc */
2149 NULL
, /* pAbortPath */
2150 xrenderdrv_AlphaBlend
, /* pAlphaBlend */
2151 NULL
, /* pAngleArc */
2154 NULL
, /* pBeginPath */
2155 xrenderdrv_BlendImage
, /* pBlendImage */
2157 NULL
, /* pCloseFigure */
2158 xrenderdrv_CreateCompatibleDC
, /* pCreateCompatibleDC */
2159 xrenderdrv_CreateDC
, /* pCreateDC */
2160 xrenderdrv_DeleteDC
, /* pDeleteDC */
2161 NULL
, /* pDeleteObject */
2162 NULL
, /* pEllipse */
2164 NULL
, /* pEndPage */
2165 NULL
, /* pEndPath */
2166 NULL
, /* pEnumFonts */
2167 xrenderdrv_ExtEscape
, /* pExtEscape */
2168 NULL
, /* pExtFloodFill */
2169 xrenderdrv_ExtTextOut
, /* pExtTextOut */
2170 NULL
, /* pFillPath */
2171 NULL
, /* pFillRgn */
2172 NULL
, /* pFontIsLinked */
2173 NULL
, /* pFrameRgn */
2174 NULL
, /* pGetBoundsRect */
2175 NULL
, /* pGetCharABCWidths */
2176 NULL
, /* pGetCharABCWidthsI */
2177 NULL
, /* pGetCharWidth */
2178 NULL
, /* pGetCharWidthInfo */
2179 NULL
, /* pGetDeviceCaps */
2180 NULL
, /* pGetDeviceGammaRamp */
2181 NULL
, /* pGetFontData */
2182 NULL
, /* pGetFontRealizationInfo */
2183 NULL
, /* pGetFontUnicodeRanges */
2184 NULL
, /* pGetGlyphIndices */
2185 NULL
, /* pGetGlyphOutline */
2186 NULL
, /* pGetICMProfile */
2187 NULL
, /* pGetImage */
2188 NULL
, /* pGetKerningPairs */
2189 NULL
, /* pGetNearestColor */
2190 NULL
, /* pGetOutlineTextMetrics */
2191 NULL
, /* pGetPixel */
2192 NULL
, /* pGetSystemPaletteEntries */
2193 NULL
, /* pGetTextCharsetInfo */
2194 NULL
, /* pGetTextExtentExPoint */
2195 NULL
, /* pGetTextExtentExPointI */
2196 NULL
, /* pGetTextFace */
2197 NULL
, /* pGetTextMetrics */
2198 xrenderdrv_GradientFill
, /* pGradientFill */
2199 NULL
, /* pInvertRgn */
2202 NULL
, /* pPaintRgn */
2205 NULL
, /* pPolyBezier */
2206 NULL
, /* pPolyBezierTo */
2207 NULL
, /* pPolyDraw */
2208 NULL
, /* pPolyPolygon */
2209 NULL
, /* pPolyPolyline */
2210 NULL
, /* pPolylineTo */
2211 xrenderdrv_PutImage
, /* pPutImage */
2212 NULL
, /* pRealizeDefaultPalette */
2213 NULL
, /* pRealizePalette */
2214 NULL
, /* pRectangle */
2215 NULL
, /* pResetDC */
2216 NULL
, /* pRoundRect */
2217 NULL
, /* pSelectBitmap */
2218 xrenderdrv_SelectBrush
, /* pSelectBrush */
2219 xrenderdrv_SelectFont
, /* pSelectFont */
2220 NULL
, /* pSelectPen */
2221 NULL
, /* pSetBkColor */
2222 NULL
, /* pSetBoundsRect */
2223 NULL
, /* pSetDCBrushColor */
2224 NULL
, /* pSetDCPenColor */
2225 NULL
, /* pSetDIBitsToDevice */
2226 xrenderdrv_SetDeviceClipping
, /* pSetDeviceClipping */
2227 NULL
, /* pSetDeviceGammaRamp */
2228 NULL
, /* pSetPixel */
2229 NULL
, /* pSetTextColor */
2230 NULL
, /* pStartDoc */
2231 NULL
, /* pStartPage */
2232 xrenderdrv_StretchBlt
, /* pStretchBlt */
2233 NULL
, /* pStretchDIBits */
2234 NULL
, /* pStrokeAndFillPath */
2235 NULL
, /* pStrokePath */
2236 NULL
, /* pUnrealizePalette */
2237 NULL
, /* pD3DKMTCheckVidPnExclusiveOwnership */
2238 NULL
, /* pD3DKMTCloseAdapter */
2239 NULL
, /* pD3DKMTOpenAdapterFromLuid */
2240 NULL
, /* pD3DKMTQueryVideoMemoryInfo */
2241 NULL
, /* pD3DKMTSetVidPnSourceOwner */
2242 GDI_PRIORITY_GRAPHICS_DRV
+ 10 /* priority */
2245 #else /* SONAME_LIBXRENDER */
2247 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
2249 TRACE("XRender support not compiled in.\n");
2253 #endif /* SONAME_LIBXRENDER */