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 WINE_DEFAULT_DEBUG_CHANNEL(xrender
);
43 #ifdef SONAME_LIBXRENDER
45 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
48 #include <X11/extensions/Xrender.h>
50 #ifndef RepeatNone /* added in 0.10 */
52 #define RepeatNormal 1
54 #define RepeatReflect 3
72 WXR_INVALID_FORMAT
= WXR_NB_FORMATS
75 typedef struct wine_xrender_format_template
79 unsigned int alphaMask
;
83 unsigned int greenMask
;
85 unsigned int blueMask
;
86 } WineXRenderFormatTemplate
;
88 static const WineXRenderFormatTemplate wxr_formats_template
[WXR_NB_FORMATS
] =
90 /* Format depth alpha mask red mask green mask blue mask*/
91 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
92 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
93 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
94 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
95 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
96 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
97 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
98 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
99 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
101 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
105 static enum wxr_format default_format
= WXR_INVALID_FORMAT
;
106 static XRenderPictFormat
*pict_formats
[WXR_NB_FORMATS
+ 1 /* invalid format */];
112 SIZE devsize
; /* size in device coords */
116 #define INITIAL_REALIZED_BUF_SIZE 128
118 enum glyph_type
{ GLYPH_INDEX
, GLYPH_WCHAR
, GLYPH_NBTYPES
};
120 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
125 XRenderPictFormat
*font_format
;
129 } gsCacheEntryFormat
;
134 gsCacheEntryFormat
*format
[GLYPH_NBTYPES
][AA_MAXVALUE
];
139 struct xrender_physdev
141 struct gdi_physdev dev
;
142 X11DRV_PDEVICE
*x11dev
;
144 enum wxr_format format
;
150 XRenderPictFormat
*pict_format
;
153 static inline struct xrender_physdev
*get_xrender_dev( PHYSDEV dev
)
155 return (struct xrender_physdev
*)dev
;
158 static const struct gdi_dc_funcs xrender_funcs
;
160 static gsCacheEntry
*glyphsetCache
= NULL
;
161 static DWORD glyphsetCacheSize
= 0;
162 static INT lastfree
= -1;
165 #define INIT_CACHE_SIZE 10
167 static void *xrender_handle
;
169 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
170 MAKE_FUNCPTR(XRenderAddGlyphs
)
171 MAKE_FUNCPTR(XRenderChangePicture
)
172 MAKE_FUNCPTR(XRenderComposite
)
173 MAKE_FUNCPTR(XRenderCompositeText16
)
174 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
175 MAKE_FUNCPTR(XRenderCreatePicture
)
176 MAKE_FUNCPTR(XRenderFillRectangle
)
177 MAKE_FUNCPTR(XRenderFindFormat
)
178 MAKE_FUNCPTR(XRenderFindVisualFormat
)
179 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
180 MAKE_FUNCPTR(XRenderFreePicture
)
181 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
182 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
183 MAKE_FUNCPTR(XRenderCreateLinearGradient
)
185 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
186 MAKE_FUNCPTR(XRenderSetPictureTransform
)
188 MAKE_FUNCPTR(XRenderQueryExtension
)
192 static CRITICAL_SECTION xrender_cs
;
193 static CRITICAL_SECTION_DEBUG critsect_debug
=
196 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
197 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
199 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
201 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
202 ( ( (ULONG)_x4 << 24 ) | \
203 ( (ULONG)_x3 << 16 ) | \
204 ( (ULONG)_x2 << 8 ) | \
207 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
209 #define GASP_GRIDFIT 0x01
210 #define GASP_DOGRAY 0x02
212 #ifdef WORDS_BIGENDIAN
213 #define get_be_word(x) (x)
214 #define NATIVE_BYTE_ORDER MSBFirst
216 #define get_be_word(x) RtlUshortByteSwap(x)
217 #define NATIVE_BYTE_ORDER LSBFirst
220 static BOOL
has_alpha( enum wxr_format format
)
222 return (format
== WXR_FORMAT_A8R8G8B8
|| format
== WXR_FORMAT_B8G8R8A8
);
225 static enum wxr_format
get_format_without_alpha( enum wxr_format format
)
229 case WXR_FORMAT_A8R8G8B8
: return WXR_FORMAT_X8R8G8B8
;
230 case WXR_FORMAT_B8G8R8A8
: return WXR_FORMAT_B8G8R8X8
;
231 default: return format
;
235 static BOOL
get_xrender_template(const WineXRenderFormatTemplate
*fmt
, XRenderPictFormat
*templ
, unsigned long *mask
)
238 templ
->type
= PictTypeDirect
;
239 templ
->depth
= fmt
->depth
;
240 templ
->direct
.alpha
= fmt
->alpha
;
241 templ
->direct
.alphaMask
= fmt
->alphaMask
;
242 templ
->direct
.red
= fmt
->red
;
243 templ
->direct
.redMask
= fmt
->redMask
;
244 templ
->direct
.green
= fmt
->green
;
245 templ
->direct
.greenMask
= fmt
->greenMask
;
246 templ
->direct
.blue
= fmt
->blue
;
247 templ
->direct
.blueMask
= fmt
->blueMask
;
250 *mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
| PictFormatRed
| PictFormatRedMask
| PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
| PictFormatBlueMask
;
255 static BOOL
is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate
*fmt
)
257 if(fmt
->depth
!= default_visual
.depth
) return FALSE
;
258 if( (fmt
->redMask
<< fmt
->red
) != default_visual
.red_mask
) return FALSE
;
259 if( (fmt
->greenMask
<< fmt
->green
) != default_visual
.green_mask
) return FALSE
;
260 if( (fmt
->blueMask
<< fmt
->blue
) != default_visual
.blue_mask
) return FALSE
;
262 /* We never select a default ARGB visual */
263 if(fmt
->alphaMask
) return FALSE
;
267 static int load_xrender_formats(void)
272 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
274 XRenderPictFormat templ
;
276 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template
[i
]))
278 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, default_visual
.visual
);
279 if (!pict_formats
[i
])
281 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
282 if (default_visual
.class == DirectColor
)
285 if (XMatchVisualInfo( gdi_display
, default_visual
.screen
,
286 default_visual
.depth
, TrueColor
, &info
))
288 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, info
.visual
);
289 if (pict_formats
[i
]) default_visual
= info
;
293 if (pict_formats
[i
]) default_format
= i
;
297 unsigned long mask
= 0;
298 get_xrender_template(&wxr_formats_template
[i
], &templ
, &mask
);
299 pict_formats
[i
] = pXRenderFindFormat(gdi_display
, mask
, &templ
, 0);
304 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats
[i
]->id
, i
);
310 /***********************************************************************
311 * X11DRV_XRender_Init
313 * Let's see if our XServer has the extension available
316 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
320 if (!client_side_with_render
) return NULL
;
321 if (!(xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0))) return NULL
;
323 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
324 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
325 LOAD_FUNCPTR(XRenderAddGlyphs
);
326 LOAD_FUNCPTR(XRenderChangePicture
);
327 LOAD_FUNCPTR(XRenderComposite
);
328 LOAD_FUNCPTR(XRenderCompositeText16
);
329 LOAD_FUNCPTR(XRenderCreateGlyphSet
);
330 LOAD_FUNCPTR(XRenderCreatePicture
);
331 LOAD_FUNCPTR(XRenderFillRectangle
);
332 LOAD_FUNCPTR(XRenderFindFormat
);
333 LOAD_FUNCPTR(XRenderFindVisualFormat
);
334 LOAD_FUNCPTR(XRenderFreeGlyphSet
);
335 LOAD_FUNCPTR(XRenderFreePicture
);
336 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
);
337 LOAD_FUNCPTR(XRenderQueryExtension
);
338 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
339 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient
);
341 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
342 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
);
344 #undef LOAD_OPTIONAL_FUNCPTR
347 if (!pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
)) return NULL
;
349 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
350 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
352 ERR_(winediag
)("Wine has detected that you probably have a buggy version "
353 "of libXrender. Because of this client side font rendering "
354 "will be disabled. Please upgrade this library.\n");
358 if (!default_visual
.red_mask
|| !default_visual
.green_mask
|| !default_visual
.blue_mask
)
360 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
364 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
365 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
367 glyphsetCacheSize
= INIT_CACHE_SIZE
;
369 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
370 glyphsetCache
[i
].next
= i
+ 1;
371 glyphsetCache
[i
].count
= -1;
373 glyphsetCache
[i
-1].next
= -1;
375 return &xrender_funcs
;
378 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
379 static void get_xrender_color( struct xrender_physdev
*physdev
, COLORREF src_color
, XRenderColor
*dst_color
)
381 if (src_color
& (1 << 24)) /* PALETTEINDEX */
383 HPALETTE pal
= GetCurrentObject( physdev
->dev
.hdc
, OBJ_PAL
);
384 PALETTEENTRY pal_ent
;
386 if (!GetPaletteEntries( pal
, LOWORD(src_color
), 1, &pal_ent
))
387 GetPaletteEntries( pal
, 0, 1, &pal_ent
);
388 dst_color
->red
= pal_ent
.peRed
* 257;
389 dst_color
->green
= pal_ent
.peGreen
* 257;
390 dst_color
->blue
= pal_ent
.peBlue
* 257;
394 if (src_color
>> 16 == 0x10ff) src_color
= 0; /* DIBINDEX */
396 dst_color
->red
= GetRValue( src_color
) * 257;
397 dst_color
->green
= GetGValue( src_color
) * 257;
398 dst_color
->blue
= GetBValue( src_color
) * 257;
401 if (physdev
->format
== WXR_FORMAT_MONO
&& !dst_color
->red
&& !dst_color
->green
&& !dst_color
->blue
)
402 dst_color
->alpha
= 0;
404 dst_color
->alpha
= 0xffff;
407 static enum wxr_format
get_xrender_format_from_bitmapinfo( const BITMAPINFO
*info
)
409 if (info
->bmiHeader
.biPlanes
!= 1) return WXR_INVALID_FORMAT
;
411 switch (info
->bmiHeader
.biBitCount
)
414 return WXR_FORMAT_MONO
;
419 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
420 return WXR_FORMAT_R8G8B8
;
423 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
425 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
428 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
430 if (info
->bmiHeader
.biBitCount
== wxr_formats_template
[i
].depth
&&
431 colors
[0] == (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
432 colors
[1] == (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
433 colors
[2] == (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
))
438 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
439 return (info
->bmiHeader
.biBitCount
== 16) ? WXR_FORMAT_X1R5G5B5
: WXR_FORMAT_A8R8G8B8
;
441 return WXR_INVALID_FORMAT
;
444 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
445 static void set_xrender_transformation(Picture src_pict
, double xscale
, double yscale
, int xoffset
, int yoffset
)
447 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
448 XTransform xform
= {{
449 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(xoffset
) },
450 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(yoffset
) },
451 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
454 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
458 static void update_xrender_clipping( struct xrender_physdev
*dev
, HRGN rgn
)
460 XRenderPictureAttributes pa
;
466 pXRenderChangePicture( gdi_display
, dev
->pict
, CPClipMask
, &pa
);
468 else if ((data
= X11DRV_GetRegionData( rgn
, 0 )))
470 pXRenderSetPictureClipRectangles( gdi_display
, dev
->pict
,
471 dev
->x11dev
->dc_rect
.left
, dev
->x11dev
->dc_rect
.top
,
472 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
473 HeapFree( GetProcessHeap(), 0, data
);
478 static Picture
get_xrender_picture( struct xrender_physdev
*dev
, HRGN clip_rgn
, const RECT
*clip_rect
)
480 if (!dev
->pict
&& dev
->pict_format
)
482 XRenderPictureAttributes pa
;
484 pa
.subwindow_mode
= IncludeInferiors
;
485 dev
->pict
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
486 dev
->pict_format
, CPSubwindowMode
, &pa
);
487 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
488 dev
->pict
, dev
->dev
.hdc
, dev
->x11dev
->drawable
);
489 dev
->update_clip
= (dev
->region
!= 0);
494 HRGN rgn
= CreateRectRgnIndirect( clip_rect
);
495 if (clip_rgn
) CombineRgn( rgn
, rgn
, clip_rgn
, RGN_AND
);
496 if (dev
->region
) CombineRgn( rgn
, rgn
, dev
->region
, RGN_AND
);
497 update_xrender_clipping( dev
, rgn
);
504 HRGN rgn
= CreateRectRgn( 0, 0, 0, 0 );
505 CombineRgn( rgn
, clip_rgn
, dev
->region
, RGN_AND
);
506 update_xrender_clipping( dev
, rgn
);
509 else update_xrender_clipping( dev
, clip_rgn
);
511 else if (dev
->update_clip
) update_xrender_clipping( dev
, dev
->region
);
513 dev
->update_clip
= (clip_rect
|| clip_rgn
); /* have to update again if we are using a custom region */
517 static Picture
get_xrender_picture_source( struct xrender_physdev
*dev
, BOOL repeat
)
519 if (!dev
->pict_src
&& dev
->pict_format
)
521 XRenderPictureAttributes pa
;
523 pa
.subwindow_mode
= IncludeInferiors
;
524 pa
.repeat
= repeat
? RepeatNormal
: RepeatNone
;
525 dev
->pict_src
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
526 dev
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
528 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
529 dev
->pict_src
, dev
->dev
.hdc
, dev
->x11dev
->drawable
, pa
.repeat
);
532 return dev
->pict_src
;
535 static void free_xrender_picture( struct xrender_physdev
*dev
)
537 if (dev
->pict
|| dev
->pict_src
)
539 XFlush( gdi_display
);
542 TRACE("freeing pict = %lx dc = %p\n", dev
->pict
, dev
->dev
.hdc
);
543 pXRenderFreePicture(gdi_display
, dev
->pict
);
548 TRACE("freeing pict = %lx dc = %p\n", dev
->pict_src
, dev
->dev
.hdc
);
549 pXRenderFreePicture(gdi_display
, dev
->pict_src
);
555 /* return a mask picture used to force alpha to 0 */
556 static Picture
get_no_alpha_mask(void)
558 static Pixmap pixmap
;
561 EnterCriticalSection( &xrender_cs
);
564 XRenderPictureAttributes pa
;
567 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
568 pa
.repeat
= RepeatNormal
;
569 pa
.component_alpha
= True
;
570 pict
= pXRenderCreatePicture( gdi_display
, pixmap
, pict_formats
[WXR_FORMAT_A8R8G8B8
],
571 CPRepeat
|CPComponentAlpha
, &pa
);
572 col
.red
= col
.green
= col
.blue
= 0xffff;
574 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
576 LeaveCriticalSection( &xrender_cs
);
580 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
582 if(p1
->hash
!= p2
->hash
) return TRUE
;
583 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
584 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
585 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
586 return strcmpiW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
589 static int LookupEntry(LFANDSIZE
*plfsz
)
593 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
595 if(glyphsetCache
[i
].count
== -1) break; /* reached free list so stop */
597 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
598 glyphsetCache
[i
].count
++;
600 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
601 glyphsetCache
[i
].next
= mru
;
604 TRACE("found font in cache %d\n", i
);
609 TRACE("font not in cache\n");
613 static void FreeEntry(int entry
)
617 for (type
= 0; type
< GLYPH_NBTYPES
; type
++)
619 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
620 gsCacheEntryFormat
* formatEntry
;
622 if( !glyphsetCache
[entry
].format
[type
][format
] )
625 formatEntry
= glyphsetCache
[entry
].format
[type
][format
];
627 if(formatEntry
->glyphset
) {
628 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
629 formatEntry
->glyphset
= 0;
631 if(formatEntry
->nrealized
) {
632 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
633 formatEntry
->realized
= NULL
;
634 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
635 formatEntry
->gis
= NULL
;
636 formatEntry
->nrealized
= 0;
639 HeapFree(GetProcessHeap(), 0, formatEntry
);
640 glyphsetCache
[entry
].format
[type
][format
] = NULL
;
645 static int AllocEntry(void)
647 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
650 assert(glyphsetCache
[lastfree
].count
== -1);
651 glyphsetCache
[lastfree
].count
= 1;
653 lastfree
= glyphsetCache
[lastfree
].next
;
655 glyphsetCache
[best
].next
= mru
;
658 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
662 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
663 if(glyphsetCache
[i
].count
== 0) {
671 TRACE("freeing unused glyphset at cache %d\n", best
);
673 glyphsetCache
[best
].count
= 1;
675 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
676 glyphsetCache
[best
].next
= mru
;
684 TRACE("Growing cache\n");
687 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
689 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
690 * sizeof(*glyphsetCache
));
692 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
693 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
694 * sizeof(*glyphsetCache
));
696 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
698 glyphsetCache
[i
].next
= i
+ 1;
699 glyphsetCache
[i
].count
= -1;
701 glyphsetCache
[i
-1].next
= -1;
702 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
704 lastfree
= glyphsetCache
[best
].next
;
705 glyphsetCache
[best
].count
= 1;
706 glyphsetCache
[best
].next
= mru
;
708 TRACE("new free cache slot at %d\n", mru
);
712 static int GetCacheEntry( LFANDSIZE
*plfsz
)
717 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
720 entry
= glyphsetCache
+ ret
;
721 entry
->lfsz
= *plfsz
;
725 static void dec_ref_cache(int index
)
728 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
729 assert(glyphsetCache
[index
].count
> 0);
730 glyphsetCache
[index
].count
--;
733 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
735 DWORD hash
= 0, *ptr
, two_chars
;
739 hash
^= plfsz
->devsize
.cx
;
740 hash
^= plfsz
->devsize
.cy
;
741 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
743 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
745 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
747 pwc
= (WCHAR
*)&two_chars
;
749 *pwc
= toupperW(*pwc
);
751 *pwc
= toupperW(*pwc
);
759 static AA_Type
aa_type_from_flags( UINT aa_flags
)
761 switch (aa_flags
& 0x7f)
765 case WINE_GGO_GRAY16_BITMAP
:
767 case WINE_GGO_HRGB_BITMAP
:
769 case WINE_GGO_HBGR_BITMAP
:
771 case WINE_GGO_VRGB_BITMAP
:
773 case WINE_GGO_VBGR_BITMAP
:
776 FIXME( "unknown flags %x\n", aa_flags
);
781 static UINT
get_xft_aa_flags( const LOGFONTW
*lf
)
786 switch (lf
->lfQuality
)
788 case NONANTIALIASED_QUALITY
:
789 case ANTIALIASED_QUALITY
:
792 if (!(value
= XGetDefault( gdi_display
, "Xft", "antialias" ))) break;
793 TRACE( "got antialias '%s'\n", value
);
794 if (tolower(value
[0]) == 'f' || tolower(value
[0]) == 'n' ||
795 value
[0] == '0' || !strcasecmp( value
, "off" ))
800 ret
= GGO_GRAY4_BITMAP
;
802 case CLEARTYPE_QUALITY
:
803 case CLEARTYPE_NATURAL_QUALITY
:
804 if (!(value
= XGetDefault( gdi_display
, "Xft", "rgba" ))) break;
805 TRACE( "got rgba '%s'\n", value
);
806 if (!strcmp( value
, "rgb" )) ret
= WINE_GGO_HRGB_BITMAP
;
807 else if (!strcmp( value
, "bgr" )) ret
= WINE_GGO_HBGR_BITMAP
;
808 else if (!strcmp( value
, "vrgb" )) ret
= WINE_GGO_VRGB_BITMAP
;
809 else if (!strcmp( value
, "vbgr" )) ret
= WINE_GGO_VBGR_BITMAP
;
810 else if (!strcmp( value
, "none" )) ret
= GGO_GRAY4_BITMAP
;
816 /**********************************************************************
817 * xrenderdrv_SelectFont
819 static HFONT
xrenderdrv_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
822 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
823 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
826 GetObjectW( hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
827 if (!*aa_flags
) *aa_flags
= get_xft_aa_flags( &lfsz
.lf
);
829 ret
= next
->funcs
->pSelectFont( next
, hfont
, aa_flags
);
834 case GGO_GRAY2_BITMAP
:
835 case GGO_GRAY4_BITMAP
:
836 case GGO_GRAY8_BITMAP
:
837 physdev
->aa_flags
= WINE_GGO_GRAY16_BITMAP
;
840 physdev
->aa_flags
= GGO_BITMAP
;
843 physdev
->aa_flags
= *aa_flags
;
847 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
848 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
849 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
850 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
851 lfsz
.devsize
.cx
= X11DRV_XWStoDS( dev
->hdc
, lfsz
.lf
.lfWidth
);
852 lfsz
.devsize
.cy
= X11DRV_YWStoDS( dev
->hdc
, lfsz
.lf
.lfHeight
);
854 GetTransform( dev
->hdc
, 0x204, &lfsz
.xform
);
855 TRACE("font transform %f %f %f %f\n", lfsz
.xform
.eM11
, lfsz
.xform
.eM12
,
856 lfsz
.xform
.eM21
, lfsz
.xform
.eM22
);
858 if (GetGraphicsMode( dev
->hdc
) == GM_COMPATIBLE
)
860 lfsz
.lf
.lfOrientation
= lfsz
.lf
.lfEscapement
;
861 if (lfsz
.xform
.eM11
* lfsz
.xform
.eM22
< 0)
862 lfsz
.lf
.lfOrientation
= -lfsz
.lf
.lfOrientation
;
865 /* Not used fields, would break hashing */
866 lfsz
.xform
.eDx
= lfsz
.xform
.eDy
= 0;
868 lfsz_calc_hash(&lfsz
);
870 EnterCriticalSection(&xrender_cs
);
871 if (physdev
->cache_index
!= -1)
872 dec_ref_cache( physdev
->cache_index
);
873 physdev
->cache_index
= GetCacheEntry( &lfsz
);
874 LeaveCriticalSection(&xrender_cs
);
878 static BOOL
create_xrender_dc( PHYSDEV
*pdev
, enum wxr_format format
)
880 X11DRV_PDEVICE
*x11dev
= get_x11drv_dev( *pdev
);
881 struct xrender_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
883 if (!physdev
) return FALSE
;
884 physdev
->x11dev
= x11dev
;
885 physdev
->cache_index
= -1;
886 physdev
->format
= format
;
887 physdev
->pict_format
= pict_formats
[format
];
888 push_dc_driver( pdev
, &physdev
->dev
, &xrender_funcs
);
892 /* store the color mask data in the bitmap info structure */
893 static void set_color_info( XRenderPictFormat
*format
, BITMAPINFO
*info
)
895 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
897 info
->bmiHeader
.biPlanes
= 1;
898 info
->bmiHeader
.biBitCount
= pixmap_formats
[format
->depth
]->bits_per_pixel
;
899 info
->bmiHeader
.biCompression
= BI_RGB
;
900 info
->bmiHeader
.biClrUsed
= 0;
902 switch (info
->bmiHeader
.biBitCount
)
905 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
906 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
907 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
908 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
911 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
912 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
913 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
914 if (colors
[0] != 0xff0000 || colors
[1] != 0x00ff00 || colors
[2] != 0x0000ff)
915 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
921 /**********************************************************************
922 * xrenderdrv_CreateDC
924 static BOOL
xrenderdrv_CreateDC( PHYSDEV
*pdev
, LPCWSTR driver
, LPCWSTR device
,
925 LPCWSTR output
, const DEVMODEW
* initData
)
927 return create_xrender_dc( pdev
, default_format
);
930 /**********************************************************************
931 * xrenderdrv_CreateCompatibleDC
933 static BOOL
xrenderdrv_CreateCompatibleDC( PHYSDEV orig
, PHYSDEV
*pdev
)
935 if (orig
) /* chain to x11drv first */
937 orig
= GET_NEXT_PHYSDEV( orig
, pCreateCompatibleDC
);
938 if (!orig
->funcs
->pCreateCompatibleDC( orig
, pdev
)) return FALSE
;
940 /* otherwise we have been called by x11drv */
942 return create_xrender_dc( pdev
, WXR_FORMAT_MONO
);
945 /**********************************************************************
946 * xrenderdrv_DeleteDC
948 static BOOL
xrenderdrv_DeleteDC( PHYSDEV dev
)
950 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
952 free_xrender_picture( physdev
);
954 EnterCriticalSection( &xrender_cs
);
955 if (physdev
->cache_index
!= -1) dec_ref_cache( physdev
->cache_index
);
956 LeaveCriticalSection( &xrender_cs
);
958 HeapFree( GetProcessHeap(), 0, physdev
);
962 /**********************************************************************
963 * xrenderdrv_ExtEscape
965 static INT
xrenderdrv_ExtEscape( PHYSDEV dev
, INT escape
, INT in_count
, LPCVOID in_data
,
966 INT out_count
, LPVOID out_data
)
968 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
970 dev
= GET_NEXT_PHYSDEV( dev
, pExtEscape
);
972 if (escape
== X11DRV_ESCAPE
&& in_data
&& in_count
>= sizeof(enum x11drv_escape_codes
))
974 if (*(const enum x11drv_escape_codes
*)in_data
== X11DRV_SET_DRAWABLE
)
976 BOOL ret
= dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
977 if (ret
) free_xrender_picture( physdev
); /* pict format doesn't change, only drawable */
981 return dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
984 /***********************************************************************
985 * xrenderdrv_SetDeviceClipping
987 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev
, HRGN rgn
)
989 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
991 physdev
->region
= rgn
;
992 physdev
->update_clip
= TRUE
;
994 dev
= GET_NEXT_PHYSDEV( dev
, pSetDeviceClipping
);
995 dev
->funcs
->pSetDeviceClipping( dev
, rgn
);
999 /************************************************************************
1002 * Helper to ExtTextOut. Must be called inside xrender_cs
1004 static void UploadGlyph(struct xrender_physdev
*physDev
, UINT glyph
, enum glyph_type type
)
1006 unsigned int buflen
;
1011 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->cache_index
;
1012 gsCacheEntryFormat
*formatEntry
;
1013 UINT ggo_format
= physDev
->aa_flags
;
1014 AA_Type format
= aa_type_from_flags( physDev
->aa_flags
);
1015 enum wxr_format wxr_format
;
1016 static const char zero
[4];
1017 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
1019 if (type
== GLYPH_INDEX
) ggo_format
|= GGO_GLYPH_INDEX
;
1020 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1021 if(buflen
== GDI_ERROR
) {
1022 if(format
!= AA_None
) {
1024 physDev
->aa_flags
= GGO_BITMAP
;
1025 ggo_format
= (ggo_format
& GGO_GLYPH_INDEX
) | GGO_BITMAP
;
1026 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1028 if(buflen
== GDI_ERROR
) {
1029 WARN("GetGlyphOutlineW failed using default glyph\n");
1030 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0, ggo_format
, &gm
, 0, NULL
, &identity
);
1031 if(buflen
== GDI_ERROR
) {
1032 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1033 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0x20, ggo_format
, &gm
, 0, NULL
, &identity
);
1034 if(buflen
== GDI_ERROR
) {
1035 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1040 TRACE("Turning off antialiasing for this monochrome font\n");
1043 /* If there is nothing for the current type, we create the entry. */
1044 if( !entry
->format
[type
][format
] ) {
1045 entry
->format
[type
][format
] = HeapAlloc(GetProcessHeap(),
1047 sizeof(gsCacheEntryFormat
));
1049 formatEntry
= entry
->format
[type
][format
];
1051 if(formatEntry
->nrealized
<= glyph
) {
1052 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
1054 if (formatEntry
->realized
)
1055 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
1057 formatEntry
->realized
,
1058 formatEntry
->nrealized
* sizeof(BOOL
));
1060 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
1062 formatEntry
->nrealized
* sizeof(BOOL
));
1064 if (formatEntry
->gis
)
1065 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
1068 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1070 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
1072 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1076 if(formatEntry
->glyphset
== 0) {
1079 wxr_format
= WXR_FORMAT_GRAY
;
1086 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1090 ERR("aa = %d - not implemented\n", format
);
1093 wxr_format
= WXR_FORMAT_MONO
;
1097 formatEntry
->font_format
= pict_formats
[wxr_format
];
1098 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
1102 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
1104 GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
1106 gm
.gmBlackBoxX
= gm
.gmBlackBoxY
= 0; /* empty glyph */
1107 formatEntry
->realized
[glyph
] = TRUE
;
1109 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1111 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1112 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1114 gi
.width
= gm
.gmBlackBoxX
;
1115 gi
.height
= gm
.gmBlackBoxY
;
1116 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1117 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1118 gi
.xOff
= gm
.gmCellIncX
;
1119 gi
.yOff
= gm
.gmCellIncY
;
1121 if(TRACE_ON(xrender
)) {
1124 unsigned char *line
;
1126 if(format
== AA_None
) {
1127 pitch
= ((gi
.width
+ 31) / 32) * 4;
1128 for(i
= 0; i
< gi
.height
; i
++) {
1129 line
= (unsigned char*) buf
+ i
* pitch
;
1131 for(j
= 0; j
< pitch
* 8; j
++) {
1132 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1134 TRACE("%s\n", output
);
1137 static const char blks
[] = " .:;!o*#";
1141 pitch
= ((gi
.width
+ 3) / 4) * 4;
1142 for(i
= 0; i
< gi
.height
; i
++) {
1143 line
= (unsigned char*) buf
+ i
* pitch
;
1145 for(j
= 0; j
< pitch
; j
++) {
1146 str
[0] = blks
[line
[j
] >> 5];
1147 strcat(output
, str
);
1149 TRACE("%s\n", output
);
1155 if(formatEntry
->glyphset
) {
1156 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1157 unsigned char *byte
= (unsigned char*) buf
, c
;
1163 /* magic to flip bit order */
1164 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1165 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1166 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1171 else if ( format
!= AA_Grey
&&
1172 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1174 unsigned int i
, *data
= (unsigned int *)buf
;
1175 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1180 XRenderCompositeText seems to ignore 0x0 glyphs when
1181 AA_None, which means we lose the advance width of glyphs
1182 like the space. We'll pretend that such glyphs are 1x1
1187 gi
.width
= gi
.height
= 1;
1189 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1190 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1193 HeapFree(GetProcessHeap(), 0, buf
);
1194 formatEntry
->gis
[glyph
] = gi
;
1197 /*************************************************************
1200 * Returns an appropriate Picture for tiling the text colour.
1201 * Call and use result within the xrender_cs
1203 static Picture
get_tile_pict( enum wxr_format wxr_format
, const XRenderColor
*color
)
1209 XRenderColor current_color
;
1210 } tiles
[WXR_NB_FORMATS
], *tile
;
1212 tile
= &tiles
[wxr_format
];
1216 XRenderPictureAttributes pa
;
1217 XRenderPictFormat
*pict_format
= pict_formats
[wxr_format
];
1219 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_format
->depth
);
1221 pa
.repeat
= RepeatNormal
;
1222 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_format
, CPRepeat
, &pa
);
1224 /* init current_color to something different from text_pixel */
1225 tile
->current_color
= *color
;
1226 tile
->current_color
.red
^= 0xffff;
1228 if (wxr_format
== WXR_FORMAT_MONO
)
1230 /* for a 1bpp bitmap we always need a 1 in the tile */
1232 col
.red
= col
.green
= col
.blue
= 0;
1234 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1238 if (memcmp( color
, &tile
->current_color
, sizeof(*color
) ) && wxr_format
!= WXR_FORMAT_MONO
)
1240 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, color
, 0, 0, 1, 1);
1241 tile
->current_color
= *color
;
1246 /*************************************************************
1249 * Returns an appropriate Picture for masking with the specified alpha.
1250 * Call and use result within the xrender_cs
1252 static Picture
get_mask_pict( int alpha
)
1254 static Pixmap pixmap
;
1255 static Picture pict
;
1256 static int current_alpha
;
1258 if (alpha
== 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1262 XRenderPictureAttributes pa
;
1264 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
1265 pa
.repeat
= RepeatNormal
;
1266 pict
= pXRenderCreatePicture( gdi_display
, pixmap
,
1267 pict_formats
[WXR_FORMAT_A8R8G8B8
], CPRepeat
, &pa
);
1271 if (alpha
!= current_alpha
)
1274 col
.red
= col
.green
= col
.blue
= 0;
1275 col
.alpha
= current_alpha
= alpha
;
1276 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
1281 /***********************************************************************
1282 * xrenderdrv_ExtTextOut
1284 static BOOL
xrenderdrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
,
1285 const RECT
*lprect
, LPCWSTR wstr
, UINT count
, const INT
*lpDx
)
1287 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1288 gsCacheEntry
*entry
;
1289 gsCacheEntryFormat
*formatEntry
;
1291 Picture pict
, tile_pict
= 0;
1293 POINT offset
, desired
, current
;
1294 int render_op
= PictOpOver
;
1297 enum glyph_type type
= (flags
& ETO_GLYPH_INDEX
) ? GLYPH_INDEX
: GLYPH_WCHAR
;
1299 get_xrender_color( physdev
, GetTextColor( physdev
->dev
.hdc
), &col
);
1300 pict
= get_xrender_picture( physdev
, 0, (flags
& ETO_CLIPPED
) ? lprect
: NULL
);
1302 if(flags
& ETO_OPAQUE
)
1306 if (physdev
->format
== WXR_FORMAT_MONO
)
1307 /* use the inverse of the text color */
1308 bg
.red
= bg
.green
= bg
.blue
= bg
.alpha
= ~col
.alpha
;
1310 get_xrender_color( physdev
, GetBkColor( physdev
->dev
.hdc
), &bg
);
1312 set_xrender_transformation( pict
, 1, 1, 0, 0 );
1313 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &bg
,
1314 physdev
->x11dev
->dc_rect
.left
+ lprect
->left
,
1315 physdev
->x11dev
->dc_rect
.top
+ lprect
->top
,
1316 lprect
->right
- lprect
->left
,
1317 lprect
->bottom
- lprect
->top
);
1318 add_device_bounds( physdev
->x11dev
, lprect
);
1321 if(count
== 0) return TRUE
;
1323 EnterCriticalSection(&xrender_cs
);
1325 entry
= glyphsetCache
+ physdev
->cache_index
;
1326 formatEntry
= entry
->format
[type
][aa_type_from_flags( physdev
->aa_flags
)];
1328 for(idx
= 0; idx
< count
; idx
++) {
1329 if( !formatEntry
) {
1330 UploadGlyph(physdev
, wstr
[idx
], type
);
1331 /* re-evaluate format entry since aa_flags may have changed */
1332 formatEntry
= entry
->format
[type
][aa_type_from_flags( physdev
->aa_flags
)];
1333 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1334 UploadGlyph(physdev
, wstr
[idx
], type
);
1339 WARN("could not upload requested glyphs\n");
1340 LeaveCriticalSection(&xrender_cs
);
1344 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1345 physdev
->x11dev
->dc_rect
.left
+ x
, physdev
->x11dev
->dc_rect
.top
+ y
);
1347 elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1349 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1350 So we pass zeros to the function and move to our starting position using the first
1351 element of the elts array. */
1353 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
;
1354 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
;
1355 offset
.x
= offset
.y
= 0;
1356 current
.x
= current
.y
= 0;
1358 tile_pict
= get_tile_pict(physdev
->format
, &col
);
1360 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1362 if (physdev
->format
== WXR_FORMAT_MONO
&& col
.red
== 0 && col
.green
== 0 && col
.blue
== 0)
1363 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1365 reset_bounds( &bounds
);
1366 for(idx
= 0; idx
< count
; idx
++)
1368 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1369 elts
[idx
].chars
= wstr
+ idx
;
1370 elts
[idx
].nchars
= 1;
1371 elts
[idx
].xOff
= desired
.x
- current
.x
;
1372 elts
[idx
].yOff
= desired
.y
- current
.y
;
1374 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1375 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1377 rect
.left
= desired
.x
- physdev
->x11dev
->dc_rect
.left
- formatEntry
->gis
[wstr
[idx
]].x
;
1378 rect
.top
= desired
.y
- physdev
->x11dev
->dc_rect
.top
- formatEntry
->gis
[wstr
[idx
]].y
;
1379 rect
.right
= rect
.left
+ formatEntry
->gis
[wstr
[idx
]].width
;
1380 rect
.bottom
= rect
.top
+ formatEntry
->gis
[wstr
[idx
]].height
;
1381 add_bounds_rect( &bounds
, &rect
);
1385 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1386 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1392 offset
.x
+= lpDx
[idx
* 2];
1393 offset
.y
+= lpDx
[idx
* 2 + 1];
1396 offset
.x
+= lpDx
[idx
];
1397 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
+ offset
.x
;
1398 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
+ offset
.y
;
1402 /* Make sure we don't have any transforms set from a previous call */
1403 set_xrender_transformation(pict
, 1, 1, 0, 0);
1404 pXRenderCompositeText16(gdi_display
, render_op
,
1407 formatEntry
->font_format
,
1408 0, 0, 0, 0, elts
, count
);
1409 HeapFree(GetProcessHeap(), 0, elts
);
1411 LeaveCriticalSection(&xrender_cs
);
1412 add_device_bounds( physdev
->x11dev
, &bounds
);
1416 /* multiply the alpha channel of a picture */
1417 static void multiply_alpha( Picture pict
, XRenderPictFormat
*format
, int alpha
,
1418 int x
, int y
, int width
, int height
)
1420 XRenderPictureAttributes pa
;
1421 Pixmap src_pixmap
, mask_pixmap
;
1422 Picture src_pict
, mask_pict
;
1425 src_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1426 mask_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1427 pa
.repeat
= RepeatNormal
;
1428 src_pict
= pXRenderCreatePicture( gdi_display
, src_pixmap
, format
, CPRepeat
, &pa
);
1429 pa
.component_alpha
= True
;
1430 mask_pict
= pXRenderCreatePicture( gdi_display
, mask_pixmap
, format
, CPRepeat
|CPComponentAlpha
, &pa
);
1431 color
.red
= color
.green
= color
.blue
= color
.alpha
= 0xffff;
1432 pXRenderFillRectangle( gdi_display
, PictOpSrc
, src_pict
, &color
, 0, 0, 1, 1 );
1433 color
.alpha
= alpha
;
1434 pXRenderFillRectangle( gdi_display
, PictOpSrc
, mask_pict
, &color
, 0, 0, 1, 1 );
1435 pXRenderComposite( gdi_display
, PictOpInReverse
, src_pict
, mask_pict
, pict
,
1436 0, 0, 0, 0, x
, y
, width
, height
);
1437 pXRenderFreePicture( gdi_display
, src_pict
);
1438 pXRenderFreePicture( gdi_display
, mask_pict
);
1439 XFreePixmap( gdi_display
, src_pixmap
);
1440 XFreePixmap( gdi_display
, mask_pixmap
);
1443 /* Helper function for (stretched) blitting using xrender */
1444 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
1445 int x_src
, int y_src
, int width_src
, int height_src
,
1446 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1447 double xscale
, double yscale
)
1449 int x_offset
, y_offset
;
1453 x_src
+= width_src
+ 1;
1454 width_src
= -width_src
;
1458 y_src
+= height_src
+ 1;
1459 height_src
= -height_src
;
1463 x_dst
+= width_dst
+ 1;
1464 width_dst
= -width_dst
;
1468 y_dst
+= height_dst
+ 1;
1469 height_dst
= -height_dst
;
1472 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1473 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1474 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1475 if(xscale
!= 1.0 || yscale
!= 1.0)
1477 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1478 * in the wrong quadrant of the x-y plane.
1480 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1481 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1482 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1488 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1490 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
1491 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width_dst
, height_dst
);
1494 /* Helper function for (stretched) mono->color blitting using xrender */
1495 static void xrender_mono_blit( Picture src_pict
, Picture dst_pict
,
1496 enum wxr_format dst_format
, XRenderColor
*fg
, XRenderColor
*bg
,
1497 int x_src
, int y_src
, int width_src
, int height_src
,
1498 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1499 double xscale
, double yscale
)
1502 int x_offset
, y_offset
;
1507 x_src
+= width_src
+ 1;
1508 width_src
= -width_src
;
1512 y_src
+= height_src
+ 1;
1513 height_src
= -height_src
;
1517 x_dst
+= width_dst
+ 1;
1518 width_dst
= -width_dst
;
1522 y_dst
+= height_dst
+ 1;
1523 height_dst
= -height_dst
;
1526 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1527 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1530 EnterCriticalSection( &xrender_cs
);
1532 color
.alpha
= 0xffff; /* tile pict needs 100% alpha */
1533 tile_pict
= get_tile_pict( dst_format
, &color
);
1535 pXRenderFillRectangle( gdi_display
, PictOpSrc
, dst_pict
, fg
, x_dst
, y_dst
, width_dst
, height_dst
);
1537 if (xscale
!= 1.0 || yscale
!= 1.0)
1539 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1540 * in the wrong quadrant of the x-y plane.
1542 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1543 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1544 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1550 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1552 pXRenderComposite(gdi_display
, PictOpOver
, tile_pict
, src_pict
, dst_pict
,
1553 0, 0, x_offset
, y_offset
, x_dst
, y_dst
, width_dst
, height_dst
);
1554 LeaveCriticalSection( &xrender_cs
);
1556 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1557 if (bg
->alpha
!= 0xffff && (dst_format
== WXR_FORMAT_A8R8G8B8
|| dst_format
== WXR_FORMAT_B8G8R8A8
))
1558 multiply_alpha( dst_pict
, pict_formats
[dst_format
], bg
->alpha
,
1559 x_dst
, y_dst
, width_dst
, height_dst
);
1562 /* create a pixmap and render picture for an image */
1563 static DWORD
create_image_pixmap( BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1564 struct bitblt_coords
*src
, enum wxr_format format
,
1565 Pixmap
*pixmap
, Picture
*pict
, BOOL
*use_repeat
)
1568 int width
= src
->visrect
.right
- src
->visrect
.left
;
1569 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1570 int depth
= pict_formats
[format
]->depth
;
1571 struct gdi_image_bits dst_bits
;
1572 XRenderPictureAttributes pa
;
1576 image
= XCreateImage( gdi_display
, default_visual
.visual
, depth
, ZPixmap
, 0, NULL
,
1577 info
->bmiHeader
.biWidth
, height
, 32, 0 );
1578 if (!image
) return ERROR_OUTOFMEMORY
;
1580 ret
= copy_image_bits( info
, (format
== WXR_FORMAT_R8G8B8
), image
, bits
, &dst_bits
, src
, NULL
, ~0u );
1581 if (ret
) return ret
;
1583 image
->data
= dst_bits
.ptr
;
1585 *use_repeat
= (width
== 1 && height
== 1);
1586 pa
.repeat
= *use_repeat
? RepeatNormal
: RepeatNone
;
1588 *pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, depth
);
1589 gc
= XCreateGC( gdi_display
, *pixmap
, 0, NULL
);
1590 XPutImage( gdi_display
, *pixmap
, gc
, image
, src
->visrect
.left
, 0, 0, 0, width
, height
);
1591 *pict
= pXRenderCreatePicture( gdi_display
, *pixmap
, pict_formats
[format
], CPRepeat
, &pa
);
1592 XFreeGC( gdi_display
, gc
);
1594 /* make coordinates relative to the pixmap */
1595 src
->x
-= src
->visrect
.left
;
1596 src
->y
-= src
->visrect
.top
;
1597 OffsetRect( &src
->visrect
, -src
->visrect
.left
, -src
->visrect
.top
);
1600 XDestroyImage( image
);
1601 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
1605 static void xrender_stretch_blit( struct xrender_physdev
*physdev_src
, struct xrender_physdev
*physdev_dst
,
1606 Drawable drawable
, const struct bitblt_coords
*src
,
1607 const struct bitblt_coords
*dst
)
1610 Picture src_pict
= 0, dst_pict
, mask_pict
= 0;
1611 double xscale
= src
->width
/ (double)dst
->width
;
1612 double yscale
= src
->height
/ (double)dst
->height
;
1614 if (drawable
) /* using an intermediate pixmap */
1618 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, physdev_dst
->pict_format
, 0, NULL
);
1622 x_dst
= physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
;
1623 y_dst
= physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
;
1624 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
1627 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
1630 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
1632 XRenderColor fg
, bg
;
1634 get_xrender_color( physdev_dst
, GetTextColor( physdev_dst
->dev
.hdc
), &fg
);
1635 get_xrender_color( physdev_dst
, GetBkColor( physdev_dst
->dev
.hdc
), &bg
);
1636 fg
.alpha
= bg
.alpha
= 0;
1638 xrender_mono_blit( src_pict
, dst_pict
, physdev_dst
->format
, &fg
, &bg
,
1639 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1640 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1641 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1643 else /* color -> color (can be at different depths) or mono -> mono */
1645 if (physdev_dst
->pict_format
->depth
== 32 && physdev_src
->pict_format
->depth
< 32)
1646 mask_pict
= get_no_alpha_mask();
1648 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
1649 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1650 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1651 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1654 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1658 static void xrender_put_image( Pixmap src_pixmap
, Picture src_pict
, Picture mask_pict
, HRGN clip
,
1659 XRenderPictFormat
*dst_format
, struct xrender_physdev
*physdev
,
1660 Drawable drawable
, struct bitblt_coords
*src
,
1661 struct bitblt_coords
*dst
, BOOL use_repeat
)
1665 double xscale
, yscale
;
1667 if (drawable
) /* using an intermediate pixmap */
1669 RGNDATA
*clip_data
= NULL
;
1671 if (clip
) clip_data
= X11DRV_GetRegionData( clip
, 0 );
1674 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, dst_format
, 0, NULL
);
1676 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
, 0, 0,
1677 (XRectangle
*)clip_data
->Buffer
, clip_data
->rdh
.nCount
);
1678 HeapFree( GetProcessHeap(), 0, clip_data
);
1682 x_dst
= physdev
->x11dev
->dc_rect
.left
+ dst
->x
;
1683 y_dst
= physdev
->x11dev
->dc_rect
.top
+ dst
->y
;
1684 dst_pict
= get_xrender_picture( physdev
, clip
, &dst
->visrect
);
1689 xscale
= src
->width
/ (double)dst
->width
;
1690 yscale
= src
->height
/ (double)dst
->height
;
1692 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
1694 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
, src
->x
, src
->y
, src
->width
, src
->height
,
1695 x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1697 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1701 /***********************************************************************
1702 * xrenderdrv_StretchBlt
1704 static BOOL
xrenderdrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
1705 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
1707 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
1708 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
1709 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
1711 if (src_dev
->funcs
!= dst_dev
->funcs
)
1713 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pStretchBlt
);
1714 return dst_dev
->funcs
->pStretchBlt( dst_dev
, dst
, src_dev
, src
, rop
);
1717 /* XRender is of no use for color -> mono */
1718 if (physdev_dst
->format
== WXR_FORMAT_MONO
&& physdev_src
->format
!= WXR_FORMAT_MONO
)
1719 goto x11drv_fallback
;
1721 /* if not stretching, we only need to handle format conversion */
1722 if (!stretch
&& physdev_dst
->format
== physdev_src
->format
) goto x11drv_fallback
;
1728 struct bitblt_coords tmp
;
1730 /* make coordinates relative to tmp pixmap */
1732 tmp
.x
-= tmp
.visrect
.left
;
1733 tmp
.y
-= tmp
.visrect
.top
;
1734 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
1736 tmpGC
= XCreateGC( gdi_display
, physdev_dst
->x11dev
->drawable
, 0, NULL
);
1737 XSetSubwindowMode( gdi_display
, tmpGC
, IncludeInferiors
);
1738 XSetGraphicsExposures( gdi_display
, tmpGC
, False
);
1739 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, tmp
.visrect
.right
- tmp
.visrect
.left
,
1740 tmp
.visrect
.bottom
- tmp
.visrect
.top
, physdev_dst
->pict_format
->depth
);
1742 xrender_stretch_blit( physdev_src
, physdev_dst
, tmp_pixmap
, src
, &tmp
);
1743 execute_rop( physdev_dst
->x11dev
, tmp_pixmap
, tmpGC
, &dst
->visrect
, rop
);
1745 XFreePixmap( gdi_display
, tmp_pixmap
);
1746 XFreeGC( gdi_display
, tmpGC
);
1748 else xrender_stretch_blit( physdev_src
, physdev_dst
, 0, src
, dst
);
1750 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
1754 return X11DRV_StretchBlt( &physdev_dst
->x11dev
->dev
, dst
, &physdev_src
->x11dev
->dev
, src
, rop
);
1758 /***********************************************************************
1759 * xrenderdrv_PutImage
1761 static DWORD
xrenderdrv_PutImage( PHYSDEV dev
, HRGN clip
, BITMAPINFO
*info
,
1762 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
1763 struct bitblt_coords
*dst
, DWORD rop
)
1765 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1769 enum wxr_format src_format
, dst_format
;
1770 XRenderPictFormat
*pict_format
;
1772 Picture src_pict
, mask_pict
= 0;
1775 dst_format
= physdev
->format
;
1776 src_format
= get_xrender_format_from_bitmapinfo( info
);
1777 if (!(pict_format
= pict_formats
[src_format
])) goto update_format
;
1779 /* make sure we can create an image with the same bpp */
1780 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
1783 /* mono <-> color conversions not supported */
1784 if ((src_format
!= dst_format
) && (src_format
== WXR_FORMAT_MONO
|| dst_format
== WXR_FORMAT_MONO
))
1785 goto x11drv_fallback
;
1787 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
1789 if (!has_alpha( src_format
) && has_alpha( dst_format
)) mask_pict
= get_no_alpha_mask();
1791 ret
= create_image_pixmap( info
, bits
, src
, src_format
, &src_pixmap
, &src_pict
, &use_repeat
);
1794 struct bitblt_coords tmp
;
1798 BOOL restore_region
= add_extra_clipping_region( physdev
->x11dev
, clip
);
1800 /* make coordinates relative to tmp pixmap */
1802 tmp
.x
-= tmp
.visrect
.left
;
1803 tmp
.y
-= tmp
.visrect
.top
;
1804 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
1806 gc
= XCreateGC( gdi_display
, physdev
->x11dev
->drawable
, 0, NULL
);
1807 XSetSubwindowMode( gdi_display
, gc
, IncludeInferiors
);
1808 XSetGraphicsExposures( gdi_display
, gc
, False
);
1809 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
,
1810 tmp
.visrect
.right
- tmp
.visrect
.left
,
1811 tmp
.visrect
.bottom
- tmp
.visrect
.top
,
1812 physdev
->pict_format
->depth
);
1814 xrender_put_image( src_pixmap
, src_pict
, mask_pict
, NULL
, physdev
->pict_format
,
1815 NULL
, tmp_pixmap
, src
, &tmp
, use_repeat
);
1816 execute_rop( physdev
->x11dev
, tmp_pixmap
, gc
, &dst
->visrect
, rop
);
1818 XFreePixmap( gdi_display
, tmp_pixmap
);
1819 XFreeGC( gdi_display
, gc
);
1820 if (restore_region
) restore_clipping_region( physdev
->x11dev
);
1822 else xrender_put_image( src_pixmap
, src_pict
, mask_pict
, clip
,
1823 physdev
->pict_format
, physdev
, 0, src
, dst
, use_repeat
);
1825 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
1827 pXRenderFreePicture( gdi_display
, src_pict
);
1828 XFreePixmap( gdi_display
, src_pixmap
);
1833 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
1834 set_color_info( pict_formats
[dst_format
], info
);
1835 return ERROR_BAD_FORMAT
;
1838 dev
= GET_NEXT_PHYSDEV( dev
, pPutImage
);
1839 return dev
->funcs
->pPutImage( dev
, clip
, info
, bits
, src
, dst
, rop
);
1843 /***********************************************************************
1844 * xrenderdrv_BlendImage
1846 static DWORD
xrenderdrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1847 struct bitblt_coords
*src
, struct bitblt_coords
*dst
,
1848 BLENDFUNCTION func
)
1850 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1852 enum wxr_format format
;
1853 XRenderPictFormat
*pict_format
;
1854 Picture dst_pict
, src_pict
, mask_pict
;
1858 format
= get_xrender_format_from_bitmapinfo( info
);
1859 if (!(func
.AlphaFormat
& AC_SRC_ALPHA
))
1860 format
= get_format_without_alpha( format
);
1861 else if (format
!= WXR_FORMAT_A8R8G8B8
|| info
->bmiHeader
.biCompression
!= BI_RGB
)
1862 return ERROR_INVALID_PARAMETER
;
1864 if (!(pict_format
= pict_formats
[format
])) goto update_format
;
1866 /* make sure we can create an image with the same bpp */
1867 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
1870 if (format
== WXR_FORMAT_MONO
&& physdev
->format
!= WXR_FORMAT_MONO
)
1873 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
1875 ret
= create_image_pixmap( info
, bits
, src
, format
, &src_pixmap
, &src_pict
, &use_repeat
);
1878 double xscale
, yscale
;
1882 xscale
= src
->width
/ (double)dst
->width
;
1883 yscale
= src
->height
/ (double)dst
->height
;
1885 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
1887 dst_pict
= get_xrender_picture( physdev
, 0, &dst
->visrect
);
1889 EnterCriticalSection( &xrender_cs
);
1890 mask_pict
= get_mask_pict( func
.SourceConstantAlpha
* 257 );
1892 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
1893 src
->x
, src
->y
, src
->width
, src
->height
,
1894 physdev
->x11dev
->dc_rect
.left
+ dst
->x
,
1895 physdev
->x11dev
->dc_rect
.top
+ dst
->y
,
1896 dst
->width
, dst
->height
, xscale
, yscale
);
1898 pXRenderFreePicture( gdi_display
, src_pict
);
1899 XFreePixmap( gdi_display
, src_pixmap
);
1901 LeaveCriticalSection( &xrender_cs
);
1902 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
1907 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
1908 set_color_info( physdev
->pict_format
, info
);
1909 return ERROR_BAD_FORMAT
;
1913 /***********************************************************************
1914 * xrenderdrv_AlphaBlend
1916 static BOOL
xrenderdrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
1917 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
1919 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
1920 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
1921 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
1922 XRenderPictureAttributes pa
;
1923 Pixmap tmp_pixmap
= 0;
1924 double xscale
, yscale
;
1926 if (src_dev
->funcs
!= dst_dev
->funcs
)
1928 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pAlphaBlend
);
1929 return dst_dev
->funcs
->pAlphaBlend( dst_dev
, dst
, src_dev
, src
, blendfn
);
1932 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->format
!= WXR_FORMAT_A8R8G8B8
)
1934 SetLastError( ERROR_INVALID_PARAMETER
);
1938 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
1940 xscale
= src
->width
/ (double)dst
->width
;
1941 yscale
= src
->height
/ (double)dst
->height
;
1943 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
1945 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
1947 /* mono -> color blending needs an intermediate color pixmap */
1948 XRenderColor fg
, bg
;
1949 int width
= src
->visrect
.right
- src
->visrect
.left
;
1950 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1952 /* blending doesn't use the destination DC colors */
1953 fg
.red
= fg
.green
= fg
.blue
= 0;
1954 bg
.red
= bg
.green
= bg
.blue
= 0xffff;
1955 fg
.alpha
= bg
.alpha
= 0xffff;
1957 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
,
1958 physdev_dst
->pict_format
->depth
);
1959 tmp_pict
= pXRenderCreatePicture( gdi_display
, tmp_pixmap
, physdev_dst
->pict_format
, 0, NULL
);
1961 xrender_mono_blit( src_pict
, tmp_pict
, physdev_dst
->format
, &fg
, &bg
,
1962 src
->visrect
.left
, src
->visrect
.top
, width
, height
, 0, 0, width
, height
, 1, 1 );
1964 else if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->pict_format
)
1966 /* we need a source picture with no alpha */
1967 enum wxr_format format
= get_format_without_alpha( physdev_src
->format
);
1968 if (format
!= physdev_src
->format
)
1970 pa
.subwindow_mode
= IncludeInferiors
;
1971 tmp_pict
= pXRenderCreatePicture( gdi_display
, physdev_src
->x11dev
->drawable
,
1972 pict_formats
[format
], CPSubwindowMode
, &pa
);
1976 if (tmp_pict
) src_pict
= tmp_pict
;
1978 EnterCriticalSection( &xrender_cs
);
1979 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
1981 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
1982 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1983 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1984 src
->width
, src
->height
,
1985 physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
,
1986 physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
,
1987 dst
->width
, dst
->height
, xscale
, yscale
);
1989 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
1990 if (tmp_pixmap
) XFreePixmap( gdi_display
, tmp_pixmap
);
1992 LeaveCriticalSection( &xrender_cs
);
1993 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
1997 /***********************************************************************
1998 * xrenderdrv_GradientFill
2000 static BOOL
xrenderdrv_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
2001 void * grad_array
, ULONG ngrad
, ULONG mode
)
2003 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2004 static const XFixed stops
[2] = { 0, 1 << 16 };
2005 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2006 XLinearGradient gradient
;
2007 XRenderColor colors
[2];
2008 Picture src_pict
, dst_pict
;
2010 const GRADIENT_RECT
*rect
= grad_array
;
2014 if (!pXRenderCreateLinearGradient
) goto fallback
;
2016 /* <= 16-bpp uses dithering */
2017 if (!physdev
->pict_format
|| physdev
->pict_format
->depth
<= 16) goto fallback
;
2021 case GRADIENT_FILL_RECT_H
:
2022 case GRADIENT_FILL_RECT_V
:
2023 for (i
= 0; i
< ngrad
; i
++, rect
++)
2025 const TRIVERTEX
*v1
= vert_array
+ rect
->UpperLeft
;
2026 const TRIVERTEX
*v2
= vert_array
+ rect
->LowerRight
;
2028 colors
[0].red
= v1
->Red
* 257 / 256;
2029 colors
[0].green
= v1
->Green
* 257 / 256;
2030 colors
[0].blue
= v1
->Blue
* 257 / 256;
2031 colors
[1].red
= v2
->Red
* 257 / 256;
2032 colors
[1].green
= v2
->Green
* 257 / 256;
2033 colors
[1].blue
= v2
->Blue
* 257 / 256;
2034 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2035 colors
[0].alpha
= colors
[1].alpha
= 65535;
2041 LPtoDP( dev
->hdc
, pt
, 2 );
2042 if (mode
== GRADIENT_FILL_RECT_H
)
2044 gradient
.p1
.y
= gradient
.p2
.y
= 0;
2045 if (pt
[1].x
> pt
[0].x
)
2048 gradient
.p2
.x
= (pt
[1].x
- pt
[0].x
) << 16;
2052 gradient
.p1
.x
= (pt
[0].x
- pt
[1].x
) << 16;
2058 gradient
.p1
.x
= gradient
.p2
.x
= 0;
2059 if (pt
[1].y
> pt
[0].y
)
2062 gradient
.p2
.y
= (pt
[1].y
- pt
[0].y
) << 16;
2066 gradient
.p1
.y
= (pt
[0].y
- pt
[1].y
) << 16;
2071 rc
.left
= min( pt
[0].x
, pt
[1].x
);
2072 rc
.top
= min( pt
[0].y
, pt
[1].y
);
2073 rc
.right
= max( pt
[0].x
, pt
[1].x
);
2074 rc
.bottom
= max( pt
[0].y
, pt
[1].y
);
2076 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2077 mode
, wine_dbgstr_rect( &rc
),
2078 colors
[0].red
, colors
[0].green
, colors
[0].blue
, colors
[0].alpha
,
2079 colors
[1].red
, colors
[1].green
, colors
[1].blue
, colors
[1].alpha
);
2081 dst_pict
= get_xrender_picture( physdev
, 0, NULL
);
2083 src_pict
= pXRenderCreateLinearGradient( gdi_display
, &gradient
, stops
, colors
, 2 );
2084 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
,
2085 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
2086 physdev
->x11dev
->dc_rect
.left
+ rc
.left
,
2087 physdev
->x11dev
->dc_rect
.top
+ rc
.top
,
2088 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, 1, 1 );
2089 pXRenderFreePicture( gdi_display
, src_pict
);
2090 add_device_bounds( physdev
->x11dev
, &rc
);
2097 dev
= GET_NEXT_PHYSDEV( dev
, pGradientFill
);
2098 return dev
->funcs
->pGradientFill( dev
, vert_array
, nvert
, grad_array
, ngrad
, mode
);
2101 /***********************************************************************
2102 * xrenderdrv_SelectBrush
2104 static HBRUSH
xrenderdrv_SelectBrush( PHYSDEV dev
, HBRUSH hbrush
, const struct brush_pattern
*pattern
)
2106 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2108 XVisualInfo vis
= default_visual
;
2109 XRenderPictFormat
*format
= physdev
->pict_format
;
2111 if (!pattern
) goto x11drv_fallback
;
2112 if (pattern
->info
->bmiHeader
.biBitCount
== 1) goto x11drv_fallback
;
2113 if (physdev
->format
== WXR_FORMAT_MONO
) goto x11drv_fallback
;
2115 vis
.depth
= format
->depth
;
2116 vis
.red_mask
= format
->direct
.redMask
<< format
->direct
.red
;
2117 vis
.green_mask
= format
->direct
.greenMask
<< format
->direct
.green
;
2118 vis
.blue_mask
= format
->direct
.blueMask
<< format
->direct
.blue
;
2120 pixmap
= create_pixmap_from_image( physdev
->dev
.hdc
, &vis
, pattern
->info
,
2121 &pattern
->bits
, pattern
->usage
);
2122 if (!pixmap
) return 0;
2124 if (physdev
->x11dev
->brush
.pixmap
) XFreePixmap( gdi_display
, physdev
->x11dev
->brush
.pixmap
);
2125 physdev
->x11dev
->brush
.pixmap
= pixmap
;
2126 physdev
->x11dev
->brush
.fillStyle
= FillTiled
;
2127 physdev
->x11dev
->brush
.pixel
= 0; /* ignored */
2128 physdev
->x11dev
->brush
.style
= BS_PATTERN
;
2132 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBrush
);
2133 return dev
->funcs
->pSelectBrush( dev
, hbrush
, pattern
);
2137 static const struct gdi_dc_funcs xrender_funcs
=
2139 NULL
, /* pAbortDoc */
2140 NULL
, /* pAbortPath */
2141 xrenderdrv_AlphaBlend
, /* pAlphaBlend */
2142 NULL
, /* pAngleArc */
2145 NULL
, /* pBeginPath */
2146 xrenderdrv_BlendImage
, /* pBlendImage */
2148 NULL
, /* pCloseFigure */
2149 xrenderdrv_CreateCompatibleDC
, /* pCreateCompatibleDC */
2150 xrenderdrv_CreateDC
, /* pCreateDC */
2151 xrenderdrv_DeleteDC
, /* pDeleteDC */
2152 NULL
, /* pDeleteObject */
2153 NULL
, /* pDeviceCapabilities */
2154 NULL
, /* pEllipse */
2156 NULL
, /* pEndPage */
2157 NULL
, /* pEndPath */
2158 NULL
, /* pEnumFonts */
2159 NULL
, /* pEnumICMProfiles */
2160 NULL
, /* pExcludeClipRect */
2161 NULL
, /* pExtDeviceMode */
2162 xrenderdrv_ExtEscape
, /* pExtEscape */
2163 NULL
, /* pExtFloodFill */
2164 NULL
, /* pExtSelectClipRgn */
2165 xrenderdrv_ExtTextOut
, /* pExtTextOut */
2166 NULL
, /* pFillPath */
2167 NULL
, /* pFillRgn */
2168 NULL
, /* pFlattenPath */
2169 NULL
, /* pFontIsLinked */
2170 NULL
, /* pFrameRgn */
2171 NULL
, /* pGdiComment */
2172 NULL
, /* pGetBoundsRect */
2173 NULL
, /* pGetCharABCWidths */
2174 NULL
, /* pGetCharABCWidthsI */
2175 NULL
, /* pGetCharWidth */
2176 NULL
, /* pGetDeviceCaps */
2177 NULL
, /* pGetDeviceGammaRamp */
2178 NULL
, /* pGetFontData */
2179 NULL
, /* pGetFontRealizationInfo */
2180 NULL
, /* pGetFontUnicodeRanges */
2181 NULL
, /* pGetGlyphIndices */
2182 NULL
, /* pGetGlyphOutline */
2183 NULL
, /* pGetICMProfile */
2184 NULL
, /* pGetImage */
2185 NULL
, /* pGetKerningPairs */
2186 NULL
, /* pGetNearestColor */
2187 NULL
, /* pGetOutlineTextMetrics */
2188 NULL
, /* pGetPixel */
2189 NULL
, /* pGetSystemPaletteEntries */
2190 NULL
, /* pGetTextCharsetInfo */
2191 NULL
, /* pGetTextExtentExPoint */
2192 NULL
, /* pGetTextExtentExPointI */
2193 NULL
, /* pGetTextFace */
2194 NULL
, /* pGetTextMetrics */
2195 xrenderdrv_GradientFill
, /* pGradientFill */
2196 NULL
, /* pIntersectClipRect */
2197 NULL
, /* pInvertRgn */
2199 NULL
, /* pModifyWorldTransform */
2201 NULL
, /* pOffsetClipRgn */
2202 NULL
, /* pOffsetViewportOrg */
2203 NULL
, /* pOffsetWindowOrg */
2204 NULL
, /* pPaintRgn */
2207 NULL
, /* pPolyBezier */
2208 NULL
, /* pPolyBezierTo */
2209 NULL
, /* pPolyDraw */
2210 NULL
, /* pPolyPolygon */
2211 NULL
, /* pPolyPolyline */
2212 NULL
, /* pPolygon */
2213 NULL
, /* pPolyline */
2214 NULL
, /* pPolylineTo */
2215 xrenderdrv_PutImage
, /* pPutImage */
2216 NULL
, /* pRealizeDefaultPalette */
2217 NULL
, /* pRealizePalette */
2218 NULL
, /* pRectangle */
2219 NULL
, /* pResetDC */
2220 NULL
, /* pRestoreDC */
2221 NULL
, /* pRoundRect */
2223 NULL
, /* pScaleViewportExt */
2224 NULL
, /* pScaleWindowExt */
2225 NULL
, /* pSelectBitmap */
2226 xrenderdrv_SelectBrush
, /* pSelectBrush */
2227 NULL
, /* pSelectClipPath */
2228 xrenderdrv_SelectFont
, /* pSelectFont */
2229 NULL
, /* pSelectPalette */
2230 NULL
, /* pSelectPen */
2231 NULL
, /* pSetArcDirection */
2232 NULL
, /* pSetBkColor */
2233 NULL
, /* pSetBkMode */
2234 NULL
, /* pSetBoundsRect */
2235 NULL
, /* pSetDCBrushColor */
2236 NULL
, /* pSetDCPenColor */
2237 NULL
, /* pSetDIBitsToDevice */
2238 xrenderdrv_SetDeviceClipping
, /* pSetDeviceClipping */
2239 NULL
, /* pSetDeviceGammaRamp */
2240 NULL
, /* pSetLayout */
2241 NULL
, /* pSetMapMode */
2242 NULL
, /* pSetMapperFlags */
2243 NULL
, /* pSetPixel */
2244 NULL
, /* pSetPolyFillMode */
2245 NULL
, /* pSetROP2 */
2246 NULL
, /* pSetRelAbs */
2247 NULL
, /* pSetStretchBltMode */
2248 NULL
, /* pSetTextAlign */
2249 NULL
, /* pSetTextCharacterExtra */
2250 NULL
, /* pSetTextColor */
2251 NULL
, /* pSetTextJustification */
2252 NULL
, /* pSetViewportExt */
2253 NULL
, /* pSetViewportOrg */
2254 NULL
, /* pSetWindowExt */
2255 NULL
, /* pSetWindowOrg */
2256 NULL
, /* pSetWorldTransform */
2257 NULL
, /* pStartDoc */
2258 NULL
, /* pStartPage */
2259 xrenderdrv_StretchBlt
, /* pStretchBlt */
2260 NULL
, /* pStretchDIBits */
2261 NULL
, /* pStrokeAndFillPath */
2262 NULL
, /* pStrokePath */
2263 NULL
, /* pUnrealizePalette */
2264 NULL
, /* pWidenPath */
2265 NULL
, /* wine_get_wgl_driver */
2266 GDI_PRIORITY_GRAPHICS_DRV
+ 10 /* priority */
2269 #else /* SONAME_LIBXRENDER */
2271 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
2273 TRACE("XRender support not compiled in.\n");
2277 #endif /* SONAME_LIBXRENDER */