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
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
71 WXR_FORMAT_ROOT
, /* placeholder for the format to use on the root window */
73 WXR_INVALID_FORMAT
= WXR_NB_FORMATS
76 typedef struct wine_xrender_format_template
80 unsigned int alphaMask
;
84 unsigned int greenMask
;
86 unsigned int blueMask
;
87 } WineXRenderFormatTemplate
;
89 static const WineXRenderFormatTemplate wxr_formats_template
[WXR_NB_FORMATS
] =
91 /* Format depth alpha mask red mask green mask blue mask*/
92 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
93 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
94 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
95 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
96 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
97 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
98 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
99 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
100 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
101 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
102 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
103 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
106 static enum wxr_format default_format
= WXR_INVALID_FORMAT
;
107 static XRenderPictFormat
*pict_formats
[WXR_NB_FORMATS
+ 1 /* invalid format */];
113 SIZE devsize
; /* size in device coords */
117 #define INITIAL_REALIZED_BUF_SIZE 128
119 enum glyph_type
{ GLYPH_INDEX
, GLYPH_WCHAR
, GLYPH_NBTYPES
};
121 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
126 XRenderPictFormat
*font_format
;
130 } gsCacheEntryFormat
;
135 gsCacheEntryFormat
*format
[GLYPH_NBTYPES
][AA_MAXVALUE
];
140 struct xrender_physdev
142 struct gdi_physdev dev
;
143 X11DRV_PDEVICE
*x11dev
;
145 enum wxr_format format
;
151 XRenderPictFormat
*pict_format
;
154 static inline struct xrender_physdev
*get_xrender_dev( PHYSDEV dev
)
156 return (struct xrender_physdev
*)dev
;
159 static const struct gdi_dc_funcs xrender_funcs
;
161 static gsCacheEntry
*glyphsetCache
= NULL
;
162 static DWORD glyphsetCacheSize
= 0;
163 static INT lastfree
= -1;
166 #define INIT_CACHE_SIZE 10
168 static void *xrender_handle
;
170 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
171 MAKE_FUNCPTR(XRenderAddGlyphs
)
172 MAKE_FUNCPTR(XRenderChangePicture
)
173 MAKE_FUNCPTR(XRenderComposite
)
174 MAKE_FUNCPTR(XRenderCompositeText16
)
175 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
176 MAKE_FUNCPTR(XRenderCreatePicture
)
177 MAKE_FUNCPTR(XRenderFillRectangle
)
178 MAKE_FUNCPTR(XRenderFindFormat
)
179 MAKE_FUNCPTR(XRenderFindVisualFormat
)
180 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
181 MAKE_FUNCPTR(XRenderFreePicture
)
182 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
183 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
184 MAKE_FUNCPTR(XRenderCreateLinearGradient
)
186 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
187 MAKE_FUNCPTR(XRenderSetPictureTransform
)
189 MAKE_FUNCPTR(XRenderQueryExtension
)
193 static CRITICAL_SECTION xrender_cs
;
194 static CRITICAL_SECTION_DEBUG critsect_debug
=
197 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
198 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
200 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
202 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
203 ( ( (ULONG)_x4 << 24 ) | \
204 ( (ULONG)_x3 << 16 ) | \
205 ( (ULONG)_x2 << 8 ) | \
208 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
210 #define GASP_GRIDFIT 0x01
211 #define GASP_DOGRAY 0x02
213 #ifdef WORDS_BIGENDIAN
214 #define get_be_word(x) (x)
215 #define NATIVE_BYTE_ORDER MSBFirst
217 #define get_be_word(x) RtlUshortByteSwap(x)
218 #define NATIVE_BYTE_ORDER LSBFirst
221 static BOOL
has_alpha( enum wxr_format format
)
223 return (format
== WXR_FORMAT_A8R8G8B8
|| format
== WXR_FORMAT_B8G8R8A8
);
226 static enum wxr_format
get_format_without_alpha( enum wxr_format format
)
230 case WXR_FORMAT_A8R8G8B8
: return WXR_FORMAT_X8R8G8B8
;
231 case WXR_FORMAT_B8G8R8A8
: return WXR_FORMAT_B8G8R8X8
;
232 default: return format
;
236 static BOOL
get_xrender_template(const WineXRenderFormatTemplate
*fmt
, XRenderPictFormat
*templ
, unsigned long *mask
)
239 templ
->type
= PictTypeDirect
;
240 templ
->depth
= fmt
->depth
;
241 templ
->direct
.alpha
= fmt
->alpha
;
242 templ
->direct
.alphaMask
= fmt
->alphaMask
;
243 templ
->direct
.red
= fmt
->red
;
244 templ
->direct
.redMask
= fmt
->redMask
;
245 templ
->direct
.green
= fmt
->green
;
246 templ
->direct
.greenMask
= fmt
->greenMask
;
247 templ
->direct
.blue
= fmt
->blue
;
248 templ
->direct
.blueMask
= fmt
->blueMask
;
251 *mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
| PictFormatRed
| PictFormatRedMask
| PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
| PictFormatBlueMask
;
256 static BOOL
is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate
*fmt
)
258 if(fmt
->depth
!= default_visual
.depth
) return FALSE
;
259 if( (fmt
->redMask
<< fmt
->red
) != default_visual
.red_mask
) return FALSE
;
260 if( (fmt
->greenMask
<< fmt
->green
) != default_visual
.green_mask
) return FALSE
;
261 if( (fmt
->blueMask
<< fmt
->blue
) != default_visual
.blue_mask
) return FALSE
;
263 /* We never select a default ARGB visual */
264 if(fmt
->alphaMask
) return FALSE
;
268 static int load_xrender_formats(void)
273 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
275 XRenderPictFormat templ
;
277 if (i
== WXR_FORMAT_ROOT
)
279 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
,
280 DefaultVisual( gdi_display
, DefaultScreen(gdi_display
) ));
281 TRACE( "Loaded root pict_format with id=%#lx\n", pict_formats
[i
]->id
);
284 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template
[i
]))
286 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, default_visual
.visual
);
287 if (!pict_formats
[i
])
289 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
290 if (default_visual
.class == DirectColor
)
293 if (XMatchVisualInfo( gdi_display
, default_visual
.screen
,
294 default_visual
.depth
, TrueColor
, &info
))
296 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, info
.visual
);
297 if (pict_formats
[i
]) default_visual
= info
;
301 if (pict_formats
[i
]) default_format
= i
;
305 unsigned long mask
= 0;
306 get_xrender_template(&wxr_formats_template
[i
], &templ
, &mask
);
307 pict_formats
[i
] = pXRenderFindFormat(gdi_display
, mask
, &templ
, 0);
312 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats
[i
]->id
, i
);
318 /***********************************************************************
319 * X11DRV_XRender_Init
321 * Let's see if our XServer has the extension available
324 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
328 if (!client_side_with_render
) return NULL
;
329 if (!(xrender_handle
= dlopen(SONAME_LIBXRENDER
, RTLD_NOW
))) return NULL
;
331 #define LOAD_FUNCPTR(f) if((p##f = dlsym(xrender_handle, #f)) == NULL) return NULL
332 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = dlsym(xrender_handle, #f)
333 LOAD_FUNCPTR(XRenderAddGlyphs
);
334 LOAD_FUNCPTR(XRenderChangePicture
);
335 LOAD_FUNCPTR(XRenderComposite
);
336 LOAD_FUNCPTR(XRenderCompositeText16
);
337 LOAD_FUNCPTR(XRenderCreateGlyphSet
);
338 LOAD_FUNCPTR(XRenderCreatePicture
);
339 LOAD_FUNCPTR(XRenderFillRectangle
);
340 LOAD_FUNCPTR(XRenderFindFormat
);
341 LOAD_FUNCPTR(XRenderFindVisualFormat
);
342 LOAD_FUNCPTR(XRenderFreeGlyphSet
);
343 LOAD_FUNCPTR(XRenderFreePicture
);
344 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
);
345 LOAD_FUNCPTR(XRenderQueryExtension
);
346 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
347 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient
);
349 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
350 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
);
352 #undef LOAD_OPTIONAL_FUNCPTR
355 if (!pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
)) return NULL
;
357 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
358 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
360 ERR_(winediag
)("Wine has detected that you probably have a buggy version "
361 "of libXrender. Because of this client side font rendering "
362 "will be disabled. Please upgrade this library.\n");
366 if (!default_visual
.red_mask
|| !default_visual
.green_mask
|| !default_visual
.blue_mask
)
368 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
372 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
373 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
375 glyphsetCacheSize
= INIT_CACHE_SIZE
;
377 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
378 glyphsetCache
[i
].next
= i
+ 1;
379 glyphsetCache
[i
].count
= -1;
381 glyphsetCache
[i
-1].next
= -1;
383 return &xrender_funcs
;
386 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
387 static void get_xrender_color( struct xrender_physdev
*physdev
, COLORREF src_color
, XRenderColor
*dst_color
)
389 if (src_color
& (1 << 24)) /* PALETTEINDEX */
391 HPALETTE pal
= GetCurrentObject( physdev
->dev
.hdc
, OBJ_PAL
);
392 PALETTEENTRY pal_ent
;
394 if (!GetPaletteEntries( pal
, LOWORD(src_color
), 1, &pal_ent
))
395 GetPaletteEntries( pal
, 0, 1, &pal_ent
);
396 dst_color
->red
= pal_ent
.peRed
* 257;
397 dst_color
->green
= pal_ent
.peGreen
* 257;
398 dst_color
->blue
= pal_ent
.peBlue
* 257;
402 if (src_color
>> 16 == 0x10ff) src_color
= 0; /* DIBINDEX */
404 dst_color
->red
= GetRValue( src_color
) * 257;
405 dst_color
->green
= GetGValue( src_color
) * 257;
406 dst_color
->blue
= GetBValue( src_color
) * 257;
409 if (physdev
->format
== WXR_FORMAT_MONO
&& !dst_color
->red
&& !dst_color
->green
&& !dst_color
->blue
)
410 dst_color
->alpha
= 0;
412 dst_color
->alpha
= 0xffff;
415 static enum wxr_format
get_xrender_format_from_bitmapinfo( const BITMAPINFO
*info
)
417 if (info
->bmiHeader
.biPlanes
!= 1) return WXR_INVALID_FORMAT
;
419 switch (info
->bmiHeader
.biBitCount
)
422 return WXR_FORMAT_MONO
;
427 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
428 return WXR_FORMAT_R8G8B8
;
431 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
433 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
436 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
438 if (info
->bmiHeader
.biBitCount
== wxr_formats_template
[i
].depth
&&
439 colors
[0] == (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
440 colors
[1] == (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
441 colors
[2] == (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
))
446 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
447 return (info
->bmiHeader
.biBitCount
== 16) ? WXR_FORMAT_X1R5G5B5
: WXR_FORMAT_A8R8G8B8
;
449 return WXR_INVALID_FORMAT
;
452 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
453 static void set_xrender_transformation(Picture src_pict
, double xscale
, double yscale
, int xoffset
, int yoffset
)
455 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
456 XTransform xform
= {{
457 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(xoffset
) },
458 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(yoffset
) },
459 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
462 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
466 static void update_xrender_clipping( struct xrender_physdev
*dev
, HRGN rgn
)
468 XRenderPictureAttributes pa
;
474 pXRenderChangePicture( gdi_display
, dev
->pict
, CPClipMask
, &pa
);
476 else if ((data
= X11DRV_GetRegionData( rgn
, 0 )))
478 pXRenderSetPictureClipRectangles( gdi_display
, dev
->pict
,
479 dev
->x11dev
->dc_rect
.left
, dev
->x11dev
->dc_rect
.top
,
480 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
481 HeapFree( GetProcessHeap(), 0, data
);
486 static Picture
get_xrender_picture( struct xrender_physdev
*dev
, HRGN clip_rgn
, const RECT
*clip_rect
)
488 if (!dev
->pict
&& dev
->pict_format
)
490 XRenderPictureAttributes pa
;
492 pa
.subwindow_mode
= IncludeInferiors
;
493 dev
->pict
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
494 dev
->pict_format
, CPSubwindowMode
, &pa
);
495 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
496 dev
->pict
, dev
->dev
.hdc
, dev
->x11dev
->drawable
);
497 dev
->update_clip
= (dev
->region
!= 0);
502 HRGN rgn
= CreateRectRgnIndirect( clip_rect
);
503 if (clip_rgn
) CombineRgn( rgn
, rgn
, clip_rgn
, RGN_AND
);
504 if (dev
->region
) CombineRgn( rgn
, rgn
, dev
->region
, RGN_AND
);
505 update_xrender_clipping( dev
, rgn
);
512 HRGN rgn
= CreateRectRgn( 0, 0, 0, 0 );
513 CombineRgn( rgn
, clip_rgn
, dev
->region
, RGN_AND
);
514 update_xrender_clipping( dev
, rgn
);
517 else update_xrender_clipping( dev
, clip_rgn
);
519 else if (dev
->update_clip
) update_xrender_clipping( dev
, dev
->region
);
521 dev
->update_clip
= (clip_rect
|| clip_rgn
); /* have to update again if we are using a custom region */
525 static Picture
get_xrender_picture_source( struct xrender_physdev
*dev
, BOOL repeat
)
527 if (!dev
->pict_src
&& dev
->pict_format
)
529 XRenderPictureAttributes pa
;
531 pa
.subwindow_mode
= IncludeInferiors
;
532 pa
.repeat
= repeat
? RepeatNormal
: RepeatNone
;
533 dev
->pict_src
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
534 dev
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
536 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
537 dev
->pict_src
, dev
->dev
.hdc
, dev
->x11dev
->drawable
, pa
.repeat
);
540 return dev
->pict_src
;
543 static void free_xrender_picture( struct xrender_physdev
*dev
)
545 if (dev
->pict
|| dev
->pict_src
)
547 XFlush( gdi_display
);
550 TRACE("freeing pict = %lx dc = %p\n", dev
->pict
, dev
->dev
.hdc
);
551 pXRenderFreePicture(gdi_display
, dev
->pict
);
556 TRACE("freeing pict = %lx dc = %p\n", dev
->pict_src
, dev
->dev
.hdc
);
557 pXRenderFreePicture(gdi_display
, dev
->pict_src
);
563 /* return a mask picture used to force alpha to 0 */
564 static Picture
get_no_alpha_mask(void)
566 static Pixmap pixmap
;
569 EnterCriticalSection( &xrender_cs
);
572 XRenderPictureAttributes pa
;
575 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
576 pa
.repeat
= RepeatNormal
;
577 pa
.component_alpha
= True
;
578 pict
= pXRenderCreatePicture( gdi_display
, pixmap
, pict_formats
[WXR_FORMAT_A8R8G8B8
],
579 CPRepeat
|CPComponentAlpha
, &pa
);
580 col
.red
= col
.green
= col
.blue
= 0xffff;
582 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
584 LeaveCriticalSection( &xrender_cs
);
588 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
590 if(p1
->hash
!= p2
->hash
) return TRUE
;
591 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
592 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
593 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
594 return strcmpiW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
597 static int LookupEntry(LFANDSIZE
*plfsz
)
601 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
603 if(glyphsetCache
[i
].count
== -1) break; /* reached free list so stop */
605 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
606 glyphsetCache
[i
].count
++;
608 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
609 glyphsetCache
[i
].next
= mru
;
612 TRACE("found font in cache %d\n", i
);
617 TRACE("font not in cache\n");
621 static void FreeEntry(int entry
)
625 for (type
= 0; type
< GLYPH_NBTYPES
; type
++)
627 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
628 gsCacheEntryFormat
* formatEntry
;
630 if( !glyphsetCache
[entry
].format
[type
][format
] )
633 formatEntry
= glyphsetCache
[entry
].format
[type
][format
];
635 if(formatEntry
->glyphset
) {
636 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
637 formatEntry
->glyphset
= 0;
639 if(formatEntry
->nrealized
) {
640 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
641 formatEntry
->realized
= NULL
;
642 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
643 formatEntry
->gis
= NULL
;
644 formatEntry
->nrealized
= 0;
647 HeapFree(GetProcessHeap(), 0, formatEntry
);
648 glyphsetCache
[entry
].format
[type
][format
] = NULL
;
653 static int AllocEntry(void)
655 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
658 assert(glyphsetCache
[lastfree
].count
== -1);
659 glyphsetCache
[lastfree
].count
= 1;
661 lastfree
= glyphsetCache
[lastfree
].next
;
663 glyphsetCache
[best
].next
= mru
;
666 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
670 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
671 if(glyphsetCache
[i
].count
== 0) {
679 TRACE("freeing unused glyphset at cache %d\n", best
);
681 glyphsetCache
[best
].count
= 1;
683 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
684 glyphsetCache
[best
].next
= mru
;
692 TRACE("Growing cache\n");
695 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
697 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
698 * sizeof(*glyphsetCache
));
700 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
701 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
702 * sizeof(*glyphsetCache
));
704 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
706 glyphsetCache
[i
].next
= i
+ 1;
707 glyphsetCache
[i
].count
= -1;
709 glyphsetCache
[i
-1].next
= -1;
710 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
712 lastfree
= glyphsetCache
[best
].next
;
713 glyphsetCache
[best
].count
= 1;
714 glyphsetCache
[best
].next
= mru
;
716 TRACE("new free cache slot at %d\n", mru
);
720 static int GetCacheEntry( LFANDSIZE
*plfsz
)
725 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
728 entry
= glyphsetCache
+ ret
;
729 entry
->lfsz
= *plfsz
;
733 static void dec_ref_cache(int index
)
736 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
737 assert(glyphsetCache
[index
].count
> 0);
738 glyphsetCache
[index
].count
--;
741 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
743 DWORD hash
= 0, *ptr
, two_chars
;
747 hash
^= plfsz
->devsize
.cx
;
748 hash
^= plfsz
->devsize
.cy
;
749 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
751 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
753 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
755 pwc
= (WCHAR
*)&two_chars
;
757 *pwc
= toupperW(*pwc
);
759 *pwc
= toupperW(*pwc
);
767 static AA_Type
aa_type_from_flags( UINT aa_flags
)
769 switch (aa_flags
& 0x7f)
773 case WINE_GGO_GRAY16_BITMAP
:
775 case WINE_GGO_HRGB_BITMAP
:
777 case WINE_GGO_HBGR_BITMAP
:
779 case WINE_GGO_VRGB_BITMAP
:
781 case WINE_GGO_VBGR_BITMAP
:
784 FIXME( "unknown flags %x\n", aa_flags
);
789 static UINT
get_xft_aa_flags( const LOGFONTW
*lf
)
794 switch (lf
->lfQuality
)
796 case NONANTIALIASED_QUALITY
:
797 case ANTIALIASED_QUALITY
:
800 if (!(value
= XGetDefault( gdi_display
, "Xft", "antialias" ))) break;
801 TRACE( "got antialias '%s'\n", value
);
802 if (tolower(value
[0]) == 'f' || tolower(value
[0]) == 'n' ||
803 value
[0] == '0' || !_strnicmp( value
, "off", -1 ))
808 ret
= GGO_GRAY4_BITMAP
;
810 case CLEARTYPE_QUALITY
:
811 case CLEARTYPE_NATURAL_QUALITY
:
812 if (!(value
= XGetDefault( gdi_display
, "Xft", "rgba" ))) break;
813 TRACE( "got rgba '%s'\n", value
);
814 if (!strcmp( value
, "rgb" )) ret
= WINE_GGO_HRGB_BITMAP
;
815 else if (!strcmp( value
, "bgr" )) ret
= WINE_GGO_HBGR_BITMAP
;
816 else if (!strcmp( value
, "vrgb" )) ret
= WINE_GGO_VRGB_BITMAP
;
817 else if (!strcmp( value
, "vbgr" )) ret
= WINE_GGO_VBGR_BITMAP
;
818 else if (!strcmp( value
, "none" )) ret
= GGO_GRAY4_BITMAP
;
824 /**********************************************************************
825 * xrenderdrv_SelectFont
827 static HFONT CDECL
xrenderdrv_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
830 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
831 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
834 GetObjectW( hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
835 if (!*aa_flags
) *aa_flags
= get_xft_aa_flags( &lfsz
.lf
);
837 ret
= next
->funcs
->pSelectFont( next
, hfont
, aa_flags
);
842 case GGO_GRAY2_BITMAP
:
843 case GGO_GRAY4_BITMAP
:
844 case GGO_GRAY8_BITMAP
:
845 physdev
->aa_flags
= WINE_GGO_GRAY16_BITMAP
;
848 physdev
->aa_flags
= GGO_BITMAP
;
851 physdev
->aa_flags
= *aa_flags
;
855 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
856 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
857 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
858 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
859 lfsz
.devsize
.cx
= X11DRV_XWStoDS( dev
->hdc
, lfsz
.lf
.lfWidth
);
860 lfsz
.devsize
.cy
= X11DRV_YWStoDS( dev
->hdc
, lfsz
.lf
.lfHeight
);
862 GetTransform( dev
->hdc
, 0x204, &lfsz
.xform
);
863 TRACE("font transform %f %f %f %f\n", lfsz
.xform
.eM11
, lfsz
.xform
.eM12
,
864 lfsz
.xform
.eM21
, lfsz
.xform
.eM22
);
866 if (GetGraphicsMode( dev
->hdc
) == GM_COMPATIBLE
)
868 lfsz
.lf
.lfOrientation
= lfsz
.lf
.lfEscapement
;
869 if (lfsz
.xform
.eM11
* lfsz
.xform
.eM22
< 0)
870 lfsz
.lf
.lfOrientation
= -lfsz
.lf
.lfOrientation
;
873 /* Not used fields, would break hashing */
874 lfsz
.xform
.eDx
= lfsz
.xform
.eDy
= 0;
876 lfsz_calc_hash(&lfsz
);
878 EnterCriticalSection(&xrender_cs
);
879 if (physdev
->cache_index
!= -1)
880 dec_ref_cache( physdev
->cache_index
);
881 physdev
->cache_index
= GetCacheEntry( &lfsz
);
882 LeaveCriticalSection(&xrender_cs
);
886 static void set_physdev_format( struct xrender_physdev
*physdev
, enum wxr_format format
)
888 if (physdev
->x11dev
->drawable
== DefaultRootWindow( gdi_display
))
889 physdev
->format
= WXR_FORMAT_ROOT
;
891 physdev
->format
= format
;
893 physdev
->pict_format
= pict_formats
[physdev
->format
];
896 static BOOL
create_xrender_dc( PHYSDEV
*pdev
, enum wxr_format format
)
898 X11DRV_PDEVICE
*x11dev
= get_x11drv_dev( *pdev
);
899 struct xrender_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
901 if (!physdev
) return FALSE
;
902 physdev
->x11dev
= x11dev
;
903 physdev
->cache_index
= -1;
904 set_physdev_format( physdev
, format
);
905 push_dc_driver( pdev
, &physdev
->dev
, &xrender_funcs
);
909 /* store the color mask data in the bitmap info structure */
910 static void set_color_info( XRenderPictFormat
*format
, BITMAPINFO
*info
)
912 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
914 info
->bmiHeader
.biPlanes
= 1;
915 info
->bmiHeader
.biBitCount
= pixmap_formats
[format
->depth
]->bits_per_pixel
;
916 info
->bmiHeader
.biCompression
= BI_RGB
;
917 info
->bmiHeader
.biClrUsed
= 0;
919 switch (info
->bmiHeader
.biBitCount
)
922 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
923 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
924 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
925 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
928 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
929 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
930 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
931 if (colors
[0] != 0xff0000 || colors
[1] != 0x00ff00 || colors
[2] != 0x0000ff)
932 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
938 /**********************************************************************
939 * xrenderdrv_CreateDC
941 static BOOL CDECL
xrenderdrv_CreateDC( PHYSDEV
*pdev
, LPCWSTR device
, LPCWSTR output
,
942 const DEVMODEW
* initData
)
944 return create_xrender_dc( pdev
, default_format
);
947 /**********************************************************************
948 * xrenderdrv_CreateCompatibleDC
950 static BOOL CDECL
xrenderdrv_CreateCompatibleDC( PHYSDEV orig
, PHYSDEV
*pdev
)
952 if (orig
) /* chain to x11drv first */
954 orig
= GET_NEXT_PHYSDEV( orig
, pCreateCompatibleDC
);
955 if (!orig
->funcs
->pCreateCompatibleDC( orig
, pdev
)) return FALSE
;
957 /* otherwise we have been called by x11drv */
959 return create_xrender_dc( pdev
, WXR_FORMAT_MONO
);
962 /**********************************************************************
963 * xrenderdrv_DeleteDC
965 static BOOL CDECL
xrenderdrv_DeleteDC( PHYSDEV dev
)
967 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
969 free_xrender_picture( physdev
);
971 EnterCriticalSection( &xrender_cs
);
972 if (physdev
->cache_index
!= -1) dec_ref_cache( physdev
->cache_index
);
973 LeaveCriticalSection( &xrender_cs
);
975 HeapFree( GetProcessHeap(), 0, physdev
);
979 /**********************************************************************
980 * xrenderdrv_ExtEscape
982 static INT CDECL
xrenderdrv_ExtEscape( PHYSDEV dev
, INT escape
, INT in_count
, LPCVOID in_data
,
983 INT out_count
, LPVOID out_data
)
985 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
987 dev
= GET_NEXT_PHYSDEV( dev
, pExtEscape
);
989 if (escape
== X11DRV_ESCAPE
&& in_data
&& in_count
>= sizeof(enum x11drv_escape_codes
))
991 if (*(const enum x11drv_escape_codes
*)in_data
== X11DRV_SET_DRAWABLE
)
993 BOOL ret
= dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
996 free_xrender_picture( physdev
);
997 set_physdev_format( physdev
, default_format
);
1002 return dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
1005 /***********************************************************************
1006 * xrenderdrv_SetDeviceClipping
1008 static void CDECL
xrenderdrv_SetDeviceClipping( PHYSDEV dev
, HRGN rgn
)
1010 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1012 physdev
->region
= rgn
;
1013 physdev
->update_clip
= TRUE
;
1015 dev
= GET_NEXT_PHYSDEV( dev
, pSetDeviceClipping
);
1016 dev
->funcs
->pSetDeviceClipping( dev
, rgn
);
1020 /************************************************************************
1023 * Helper to ExtTextOut. Must be called inside xrender_cs
1025 static void UploadGlyph(struct xrender_physdev
*physDev
, UINT glyph
, enum glyph_type type
)
1027 unsigned int buflen
;
1032 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->cache_index
;
1033 gsCacheEntryFormat
*formatEntry
;
1034 UINT ggo_format
= physDev
->aa_flags
;
1035 AA_Type format
= aa_type_from_flags( physDev
->aa_flags
);
1036 enum wxr_format wxr_format
;
1037 static const char zero
[4];
1038 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
1040 if (type
== GLYPH_INDEX
) ggo_format
|= GGO_GLYPH_INDEX
;
1041 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1042 if(buflen
== GDI_ERROR
) {
1043 if(format
!= AA_None
) {
1045 physDev
->aa_flags
= GGO_BITMAP
;
1046 ggo_format
= (ggo_format
& GGO_GLYPH_INDEX
) | GGO_BITMAP
;
1047 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1049 if(buflen
== GDI_ERROR
) {
1050 WARN("GetGlyphOutlineW failed using default glyph\n");
1051 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0, ggo_format
, &gm
, 0, NULL
, &identity
);
1052 if(buflen
== GDI_ERROR
) {
1053 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1054 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0x20, ggo_format
, &gm
, 0, NULL
, &identity
);
1055 if(buflen
== GDI_ERROR
) {
1056 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1061 TRACE("Turning off antialiasing for this monochrome font\n");
1064 /* If there is nothing for the current type, we create the entry. */
1065 if( !entry
->format
[type
][format
] ) {
1066 entry
->format
[type
][format
] = HeapAlloc(GetProcessHeap(),
1068 sizeof(gsCacheEntryFormat
));
1070 formatEntry
= entry
->format
[type
][format
];
1072 if(formatEntry
->nrealized
<= glyph
) {
1073 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
1075 if (formatEntry
->realized
)
1076 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
1078 formatEntry
->realized
,
1079 formatEntry
->nrealized
* sizeof(BOOL
));
1081 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
1083 formatEntry
->nrealized
* sizeof(BOOL
));
1085 if (formatEntry
->gis
)
1086 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
1089 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1091 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
1093 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1097 if(formatEntry
->glyphset
== 0) {
1100 wxr_format
= WXR_FORMAT_GRAY
;
1107 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1111 ERR("aa = %d - not implemented\n", format
);
1114 wxr_format
= WXR_FORMAT_MONO
;
1118 formatEntry
->font_format
= pict_formats
[wxr_format
];
1119 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
1123 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
1125 GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
1127 gm
.gmBlackBoxX
= gm
.gmBlackBoxY
= 0; /* empty glyph */
1128 formatEntry
->realized
[glyph
] = TRUE
;
1130 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1132 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1133 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1135 gi
.width
= gm
.gmBlackBoxX
;
1136 gi
.height
= gm
.gmBlackBoxY
;
1137 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1138 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1139 gi
.xOff
= gm
.gmCellIncX
;
1140 gi
.yOff
= gm
.gmCellIncY
;
1142 if(TRACE_ON(xrender
)) {
1145 unsigned char *line
;
1147 if(format
== AA_None
) {
1148 pitch
= ((gi
.width
+ 31) / 32) * 4;
1149 for(i
= 0; i
< gi
.height
; i
++) {
1150 line
= (unsigned char*) buf
+ i
* pitch
;
1152 for(j
= 0; j
< pitch
* 8; j
++) {
1153 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1155 TRACE("%s\n", output
);
1158 static const char blks
[] = " .:;!o*#";
1162 pitch
= ((gi
.width
+ 3) / 4) * 4;
1163 for(i
= 0; i
< gi
.height
; i
++) {
1164 line
= (unsigned char*) buf
+ i
* pitch
;
1166 for(j
= 0; j
< pitch
; j
++) {
1167 str
[0] = blks
[line
[j
] >> 5];
1168 strcat(output
, str
);
1170 TRACE("%s\n", output
);
1176 if(formatEntry
->glyphset
) {
1177 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1178 unsigned char *byte
= (unsigned char*) buf
, c
;
1184 /* magic to flip bit order */
1185 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1186 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1187 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1192 else if ( format
!= AA_Grey
&&
1193 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1195 unsigned int i
, *data
= (unsigned int *)buf
;
1196 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1201 XRenderCompositeText seems to ignore 0x0 glyphs when
1202 AA_None, which means we lose the advance width of glyphs
1203 like the space. We'll pretend that such glyphs are 1x1
1208 gi
.width
= gi
.height
= 1;
1210 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1211 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1214 HeapFree(GetProcessHeap(), 0, buf
);
1215 formatEntry
->gis
[glyph
] = gi
;
1218 /*************************************************************
1221 * Returns an appropriate Picture for tiling the text colour.
1222 * Call and use result within the xrender_cs
1224 static Picture
get_tile_pict( enum wxr_format wxr_format
, const XRenderColor
*color
)
1230 XRenderColor current_color
;
1231 } tiles
[WXR_NB_FORMATS
], *tile
;
1233 tile
= &tiles
[wxr_format
];
1237 XRenderPictureAttributes pa
;
1238 XRenderPictFormat
*pict_format
= pict_formats
[wxr_format
];
1240 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_format
->depth
);
1242 pa
.repeat
= RepeatNormal
;
1243 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_format
, CPRepeat
, &pa
);
1245 /* init current_color to something different from text_pixel */
1246 tile
->current_color
= *color
;
1247 tile
->current_color
.red
^= 0xffff;
1249 if (wxr_format
== WXR_FORMAT_MONO
)
1251 /* for a 1bpp bitmap we always need a 1 in the tile */
1253 col
.red
= col
.green
= col
.blue
= 0;
1255 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1259 if (memcmp( color
, &tile
->current_color
, sizeof(*color
) ) && wxr_format
!= WXR_FORMAT_MONO
)
1261 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, color
, 0, 0, 1, 1);
1262 tile
->current_color
= *color
;
1267 /*************************************************************
1270 * Returns an appropriate Picture for masking with the specified alpha.
1271 * Call and use result within the xrender_cs
1273 static Picture
get_mask_pict( int alpha
)
1275 static Pixmap pixmap
;
1276 static Picture pict
;
1277 static int current_alpha
;
1279 if (alpha
== 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1283 XRenderPictureAttributes pa
;
1285 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
1286 pa
.repeat
= RepeatNormal
;
1287 pict
= pXRenderCreatePicture( gdi_display
, pixmap
,
1288 pict_formats
[WXR_FORMAT_A8R8G8B8
], CPRepeat
, &pa
);
1292 if (alpha
!= current_alpha
)
1295 col
.red
= col
.green
= col
.blue
= 0;
1296 col
.alpha
= current_alpha
= alpha
;
1297 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
1302 /***********************************************************************
1303 * xrenderdrv_ExtTextOut
1305 static BOOL CDECL
xrenderdrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
,
1306 const RECT
*lprect
, LPCWSTR wstr
, UINT count
, const INT
*lpDx
)
1308 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1309 gsCacheEntry
*entry
;
1310 gsCacheEntryFormat
*formatEntry
;
1312 Picture pict
, tile_pict
= 0;
1314 POINT offset
, desired
, current
;
1315 int render_op
= PictOpOver
;
1318 enum glyph_type type
= (flags
& ETO_GLYPH_INDEX
) ? GLYPH_INDEX
: GLYPH_WCHAR
;
1320 get_xrender_color( physdev
, GetTextColor( physdev
->dev
.hdc
), &col
);
1321 pict
= get_xrender_picture( physdev
, 0, (flags
& ETO_CLIPPED
) ? lprect
: NULL
);
1323 if(flags
& ETO_OPAQUE
)
1327 if (physdev
->format
== WXR_FORMAT_MONO
)
1328 /* use the inverse of the text color */
1329 bg
.red
= bg
.green
= bg
.blue
= bg
.alpha
= ~col
.alpha
;
1331 get_xrender_color( physdev
, GetBkColor( physdev
->dev
.hdc
), &bg
);
1333 set_xrender_transformation( pict
, 1, 1, 0, 0 );
1334 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &bg
,
1335 physdev
->x11dev
->dc_rect
.left
+ lprect
->left
,
1336 physdev
->x11dev
->dc_rect
.top
+ lprect
->top
,
1337 lprect
->right
- lprect
->left
,
1338 lprect
->bottom
- lprect
->top
);
1339 add_device_bounds( physdev
->x11dev
, lprect
);
1342 if(count
== 0) return TRUE
;
1344 EnterCriticalSection(&xrender_cs
);
1346 entry
= glyphsetCache
+ physdev
->cache_index
;
1347 formatEntry
= entry
->format
[type
][aa_type_from_flags( physdev
->aa_flags
)];
1349 for(idx
= 0; idx
< count
; idx
++) {
1350 if( !formatEntry
) {
1351 UploadGlyph(physdev
, wstr
[idx
], type
);
1352 /* re-evaluate format entry since aa_flags may have changed */
1353 formatEntry
= entry
->format
[type
][aa_type_from_flags( physdev
->aa_flags
)];
1354 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1355 UploadGlyph(physdev
, wstr
[idx
], type
);
1360 WARN("could not upload requested glyphs\n");
1361 LeaveCriticalSection(&xrender_cs
);
1365 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1366 physdev
->x11dev
->dc_rect
.left
+ x
, physdev
->x11dev
->dc_rect
.top
+ y
);
1368 elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1370 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1371 So we pass zeros to the function and move to our starting position using the first
1372 element of the elts array. */
1374 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
;
1375 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
;
1376 offset
.x
= offset
.y
= 0;
1377 current
.x
= current
.y
= 0;
1379 tile_pict
= get_tile_pict(physdev
->format
, &col
);
1381 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1383 if (physdev
->format
== WXR_FORMAT_MONO
&& col
.red
== 0 && col
.green
== 0 && col
.blue
== 0)
1384 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1386 reset_bounds( &bounds
);
1387 for(idx
= 0; idx
< count
; idx
++)
1389 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1390 elts
[idx
].chars
= wstr
+ idx
;
1391 elts
[idx
].nchars
= 1;
1392 elts
[idx
].xOff
= desired
.x
- current
.x
;
1393 elts
[idx
].yOff
= desired
.y
- current
.y
;
1395 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1396 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1398 rect
.left
= desired
.x
- physdev
->x11dev
->dc_rect
.left
- formatEntry
->gis
[wstr
[idx
]].x
;
1399 rect
.top
= desired
.y
- physdev
->x11dev
->dc_rect
.top
- formatEntry
->gis
[wstr
[idx
]].y
;
1400 rect
.right
= rect
.left
+ formatEntry
->gis
[wstr
[idx
]].width
;
1401 rect
.bottom
= rect
.top
+ formatEntry
->gis
[wstr
[idx
]].height
;
1402 add_bounds_rect( &bounds
, &rect
);
1406 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1407 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1413 offset
.x
+= lpDx
[idx
* 2];
1414 offset
.y
+= lpDx
[idx
* 2 + 1];
1417 offset
.x
+= lpDx
[idx
];
1418 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
+ offset
.x
;
1419 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
+ offset
.y
;
1423 /* Make sure we don't have any transforms set from a previous call */
1424 set_xrender_transformation(pict
, 1, 1, 0, 0);
1425 pXRenderCompositeText16(gdi_display
, render_op
,
1428 formatEntry
->font_format
,
1429 0, 0, 0, 0, elts
, count
);
1430 HeapFree(GetProcessHeap(), 0, elts
);
1432 LeaveCriticalSection(&xrender_cs
);
1433 add_device_bounds( physdev
->x11dev
, &bounds
);
1437 /* multiply the alpha channel of a picture */
1438 static void multiply_alpha( Picture pict
, XRenderPictFormat
*format
, int alpha
,
1439 int x
, int y
, int width
, int height
)
1441 XRenderPictureAttributes pa
;
1442 Pixmap src_pixmap
, mask_pixmap
;
1443 Picture src_pict
, mask_pict
;
1446 src_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1447 mask_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1448 pa
.repeat
= RepeatNormal
;
1449 src_pict
= pXRenderCreatePicture( gdi_display
, src_pixmap
, format
, CPRepeat
, &pa
);
1450 pa
.component_alpha
= True
;
1451 mask_pict
= pXRenderCreatePicture( gdi_display
, mask_pixmap
, format
, CPRepeat
|CPComponentAlpha
, &pa
);
1452 color
.red
= color
.green
= color
.blue
= color
.alpha
= 0xffff;
1453 pXRenderFillRectangle( gdi_display
, PictOpSrc
, src_pict
, &color
, 0, 0, 1, 1 );
1454 color
.alpha
= alpha
;
1455 pXRenderFillRectangle( gdi_display
, PictOpSrc
, mask_pict
, &color
, 0, 0, 1, 1 );
1456 pXRenderComposite( gdi_display
, PictOpInReverse
, src_pict
, mask_pict
, pict
,
1457 0, 0, 0, 0, x
, y
, width
, height
);
1458 pXRenderFreePicture( gdi_display
, src_pict
);
1459 pXRenderFreePicture( gdi_display
, mask_pict
);
1460 XFreePixmap( gdi_display
, src_pixmap
);
1461 XFreePixmap( gdi_display
, mask_pixmap
);
1464 /* Helper function for (stretched) blitting using xrender */
1465 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
1466 int x_src
, int y_src
, int width_src
, int height_src
,
1467 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1468 double xscale
, double yscale
)
1470 int x_offset
, y_offset
;
1474 x_src
+= width_src
+ 1;
1478 y_src
+= height_src
+ 1;
1482 x_dst
+= width_dst
+ 1;
1483 width_dst
= -width_dst
;
1487 y_dst
+= height_dst
+ 1;
1488 height_dst
= -height_dst
;
1491 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1492 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1493 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1494 if(xscale
!= 1.0 || yscale
!= 1.0)
1496 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1497 * in the wrong quadrant of the x-y plane.
1499 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1500 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1501 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1507 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1509 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
1510 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width_dst
, height_dst
);
1513 /* Helper function for (stretched) mono->color blitting using xrender */
1514 static void xrender_mono_blit( Picture src_pict
, Picture dst_pict
,
1515 enum wxr_format dst_format
, XRenderColor
*fg
, XRenderColor
*bg
,
1516 int x_src
, int y_src
, int width_src
, int height_src
,
1517 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1518 double xscale
, double yscale
)
1521 int x_offset
, y_offset
;
1526 x_src
+= width_src
+ 1;
1527 width_src
= -width_src
;
1531 y_src
+= height_src
+ 1;
1532 height_src
= -height_src
;
1536 x_dst
+= width_dst
+ 1;
1537 width_dst
= -width_dst
;
1541 y_dst
+= height_dst
+ 1;
1542 height_dst
= -height_dst
;
1545 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1546 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1549 EnterCriticalSection( &xrender_cs
);
1551 color
.alpha
= 0xffff; /* tile pict needs 100% alpha */
1552 tile_pict
= get_tile_pict( dst_format
, &color
);
1554 pXRenderFillRectangle( gdi_display
, PictOpSrc
, dst_pict
, fg
, x_dst
, y_dst
, width_dst
, height_dst
);
1556 if (xscale
!= 1.0 || yscale
!= 1.0)
1558 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1559 * in the wrong quadrant of the x-y plane.
1561 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1562 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1563 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1569 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1571 pXRenderComposite(gdi_display
, PictOpOver
, tile_pict
, src_pict
, dst_pict
,
1572 0, 0, x_offset
, y_offset
, x_dst
, y_dst
, width_dst
, height_dst
);
1573 LeaveCriticalSection( &xrender_cs
);
1575 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1576 if (bg
->alpha
!= 0xffff && (dst_format
== WXR_FORMAT_A8R8G8B8
|| dst_format
== WXR_FORMAT_B8G8R8A8
))
1577 multiply_alpha( dst_pict
, pict_formats
[dst_format
], bg
->alpha
,
1578 x_dst
, y_dst
, width_dst
, height_dst
);
1581 /* create a pixmap and render picture for an image */
1582 static DWORD
create_image_pixmap( BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1583 struct bitblt_coords
*src
, enum wxr_format format
,
1584 Pixmap
*pixmap
, Picture
*pict
, BOOL
*use_repeat
)
1587 int width
= src
->visrect
.right
- src
->visrect
.left
;
1588 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1589 int depth
= pict_formats
[format
]->depth
;
1590 struct gdi_image_bits dst_bits
;
1591 XRenderPictureAttributes pa
;
1595 image
= XCreateImage( gdi_display
, default_visual
.visual
, depth
, ZPixmap
, 0, NULL
,
1596 info
->bmiHeader
.biWidth
, height
, 32, 0 );
1597 if (!image
) return ERROR_OUTOFMEMORY
;
1599 ret
= copy_image_bits( info
, (format
== WXR_FORMAT_R8G8B8
), image
, bits
, &dst_bits
, src
, NULL
, ~0u );
1600 if (ret
) return ret
;
1602 image
->data
= dst_bits
.ptr
;
1604 *use_repeat
= (width
== 1 && height
== 1);
1605 pa
.repeat
= *use_repeat
? RepeatNormal
: RepeatNone
;
1607 *pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, depth
);
1608 gc
= XCreateGC( gdi_display
, *pixmap
, 0, NULL
);
1609 XPutImage( gdi_display
, *pixmap
, gc
, image
, src
->visrect
.left
, 0, 0, 0, width
, height
);
1610 *pict
= pXRenderCreatePicture( gdi_display
, *pixmap
, pict_formats
[format
], CPRepeat
, &pa
);
1611 XFreeGC( gdi_display
, gc
);
1613 /* make coordinates relative to the pixmap */
1614 src
->x
-= src
->visrect
.left
;
1615 src
->y
-= src
->visrect
.top
;
1616 OffsetRect( &src
->visrect
, -src
->visrect
.left
, -src
->visrect
.top
);
1619 XDestroyImage( image
);
1620 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
1624 static void xrender_stretch_blit( struct xrender_physdev
*physdev_src
, struct xrender_physdev
*physdev_dst
,
1625 Drawable drawable
, const struct bitblt_coords
*src
,
1626 const struct bitblt_coords
*dst
)
1629 Picture src_pict
= 0, dst_pict
, mask_pict
= 0;
1630 double xscale
= src
->width
/ (double)dst
->width
;
1631 double yscale
= src
->height
/ (double)dst
->height
;
1633 if (drawable
) /* using an intermediate pixmap */
1637 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, physdev_dst
->pict_format
, 0, NULL
);
1641 x_dst
= physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
;
1642 y_dst
= physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
;
1643 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
1646 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
1649 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
1651 XRenderColor fg
, bg
;
1653 get_xrender_color( physdev_dst
, GetTextColor( physdev_dst
->dev
.hdc
), &fg
);
1654 get_xrender_color( physdev_dst
, GetBkColor( physdev_dst
->dev
.hdc
), &bg
);
1655 fg
.alpha
= bg
.alpha
= 0;
1657 xrender_mono_blit( src_pict
, dst_pict
, physdev_dst
->format
, &fg
, &bg
,
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
);
1662 else /* color -> color (can be at different depths) or mono -> mono */
1664 if (physdev_dst
->pict_format
->depth
== 32 && physdev_src
->pict_format
->depth
< 32)
1665 mask_pict
= get_no_alpha_mask();
1667 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
1668 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1669 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1670 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1673 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1677 static void xrender_put_image( Pixmap src_pixmap
, Picture src_pict
, Picture mask_pict
, HRGN clip
,
1678 XRenderPictFormat
*dst_format
, struct xrender_physdev
*physdev
,
1679 Drawable drawable
, struct bitblt_coords
*src
,
1680 struct bitblt_coords
*dst
, BOOL use_repeat
)
1684 double xscale
, yscale
;
1686 if (drawable
) /* using an intermediate pixmap */
1688 RGNDATA
*clip_data
= NULL
;
1690 if (clip
) clip_data
= X11DRV_GetRegionData( clip
, 0 );
1693 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, dst_format
, 0, NULL
);
1695 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
, 0, 0,
1696 (XRectangle
*)clip_data
->Buffer
, clip_data
->rdh
.nCount
);
1697 HeapFree( GetProcessHeap(), 0, clip_data
);
1701 x_dst
= physdev
->x11dev
->dc_rect
.left
+ dst
->x
;
1702 y_dst
= physdev
->x11dev
->dc_rect
.top
+ dst
->y
;
1703 dst_pict
= get_xrender_picture( physdev
, clip
, &dst
->visrect
);
1708 xscale
= src
->width
/ (double)dst
->width
;
1709 yscale
= src
->height
/ (double)dst
->height
;
1711 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
1713 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
, src
->x
, src
->y
, src
->width
, src
->height
,
1714 x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1716 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1720 /***********************************************************************
1721 * xrenderdrv_StretchBlt
1723 static BOOL CDECL
xrenderdrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
1724 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
1726 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
1727 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
1728 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
1730 if (src_dev
->funcs
!= dst_dev
->funcs
)
1732 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pStretchBlt
);
1733 return dst_dev
->funcs
->pStretchBlt( dst_dev
, dst
, src_dev
, src
, rop
);
1736 /* XRender is of no use for color -> mono */
1737 if (physdev_dst
->format
== WXR_FORMAT_MONO
&& physdev_src
->format
!= WXR_FORMAT_MONO
)
1738 goto x11drv_fallback
;
1740 /* if not stretching, we only need to handle format conversion */
1741 if (!stretch
&& physdev_dst
->format
== physdev_src
->format
) goto x11drv_fallback
;
1747 struct bitblt_coords tmp
;
1749 /* make coordinates relative to tmp pixmap */
1751 tmp
.x
-= tmp
.visrect
.left
;
1752 tmp
.y
-= tmp
.visrect
.top
;
1753 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
1755 tmpGC
= XCreateGC( gdi_display
, physdev_dst
->x11dev
->drawable
, 0, NULL
);
1756 XSetSubwindowMode( gdi_display
, tmpGC
, IncludeInferiors
);
1757 XSetGraphicsExposures( gdi_display
, tmpGC
, False
);
1758 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, tmp
.visrect
.right
- tmp
.visrect
.left
,
1759 tmp
.visrect
.bottom
- tmp
.visrect
.top
, physdev_dst
->pict_format
->depth
);
1761 xrender_stretch_blit( physdev_src
, physdev_dst
, tmp_pixmap
, src
, &tmp
);
1762 execute_rop( physdev_dst
->x11dev
, tmp_pixmap
, tmpGC
, &dst
->visrect
, rop
);
1764 XFreePixmap( gdi_display
, tmp_pixmap
);
1765 XFreeGC( gdi_display
, tmpGC
);
1767 else xrender_stretch_blit( physdev_src
, physdev_dst
, 0, src
, dst
);
1769 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
1773 return X11DRV_StretchBlt( &physdev_dst
->x11dev
->dev
, dst
, &physdev_src
->x11dev
->dev
, src
, rop
);
1777 /***********************************************************************
1778 * xrenderdrv_PutImage
1780 static DWORD CDECL
xrenderdrv_PutImage( PHYSDEV dev
, HRGN clip
, BITMAPINFO
*info
,
1781 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
1782 struct bitblt_coords
*dst
, DWORD rop
)
1784 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1788 enum wxr_format src_format
, dst_format
;
1789 XRenderPictFormat
*pict_format
;
1791 Picture src_pict
, mask_pict
= 0;
1794 dst_format
= physdev
->format
;
1795 src_format
= get_xrender_format_from_bitmapinfo( info
);
1796 if (!(pict_format
= pict_formats
[src_format
])) goto update_format
;
1798 /* make sure we can create an image with the same bpp */
1799 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
1802 /* mono <-> color conversions not supported */
1803 if ((src_format
!= dst_format
) && (src_format
== WXR_FORMAT_MONO
|| dst_format
== WXR_FORMAT_MONO
))
1804 goto x11drv_fallback
;
1806 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
1808 if (!has_alpha( src_format
) && has_alpha( dst_format
)) mask_pict
= get_no_alpha_mask();
1810 ret
= create_image_pixmap( info
, bits
, src
, src_format
, &src_pixmap
, &src_pict
, &use_repeat
);
1813 struct bitblt_coords tmp
;
1817 BOOL restore_region
= add_extra_clipping_region( physdev
->x11dev
, clip
);
1819 /* make coordinates relative to tmp pixmap */
1821 tmp
.x
-= tmp
.visrect
.left
;
1822 tmp
.y
-= tmp
.visrect
.top
;
1823 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
1825 gc
= XCreateGC( gdi_display
, physdev
->x11dev
->drawable
, 0, NULL
);
1826 XSetSubwindowMode( gdi_display
, gc
, IncludeInferiors
);
1827 XSetGraphicsExposures( gdi_display
, gc
, False
);
1828 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
,
1829 tmp
.visrect
.right
- tmp
.visrect
.left
,
1830 tmp
.visrect
.bottom
- tmp
.visrect
.top
,
1831 physdev
->pict_format
->depth
);
1833 xrender_put_image( src_pixmap
, src_pict
, mask_pict
, NULL
, physdev
->pict_format
,
1834 NULL
, tmp_pixmap
, src
, &tmp
, use_repeat
);
1835 execute_rop( physdev
->x11dev
, tmp_pixmap
, gc
, &dst
->visrect
, rop
);
1837 XFreePixmap( gdi_display
, tmp_pixmap
);
1838 XFreeGC( gdi_display
, gc
);
1839 if (restore_region
) restore_clipping_region( physdev
->x11dev
);
1841 else xrender_put_image( src_pixmap
, src_pict
, mask_pict
, clip
,
1842 physdev
->pict_format
, physdev
, 0, src
, dst
, use_repeat
);
1844 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
1846 pXRenderFreePicture( gdi_display
, src_pict
);
1847 XFreePixmap( gdi_display
, src_pixmap
);
1852 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
1853 set_color_info( pict_formats
[dst_format
], info
);
1854 return ERROR_BAD_FORMAT
;
1857 dev
= GET_NEXT_PHYSDEV( dev
, pPutImage
);
1858 return dev
->funcs
->pPutImage( dev
, clip
, info
, bits
, src
, dst
, rop
);
1862 /***********************************************************************
1863 * xrenderdrv_BlendImage
1865 static DWORD CDECL
xrenderdrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1866 struct bitblt_coords
*src
, struct bitblt_coords
*dst
,
1867 BLENDFUNCTION func
)
1869 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1871 enum wxr_format format
;
1872 XRenderPictFormat
*pict_format
;
1873 Picture dst_pict
, src_pict
, mask_pict
;
1877 format
= get_xrender_format_from_bitmapinfo( info
);
1878 if (!(func
.AlphaFormat
& AC_SRC_ALPHA
))
1879 format
= get_format_without_alpha( format
);
1880 else if (format
!= WXR_FORMAT_A8R8G8B8
|| info
->bmiHeader
.biCompression
!= BI_RGB
)
1881 return ERROR_INVALID_PARAMETER
;
1883 if (!(pict_format
= pict_formats
[format
])) goto update_format
;
1885 /* make sure we can create an image with the same bpp */
1886 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
1889 if (format
== WXR_FORMAT_MONO
&& physdev
->format
!= WXR_FORMAT_MONO
)
1892 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
1894 ret
= create_image_pixmap( info
, bits
, src
, format
, &src_pixmap
, &src_pict
, &use_repeat
);
1897 double xscale
, yscale
;
1901 xscale
= src
->width
/ (double)dst
->width
;
1902 yscale
= src
->height
/ (double)dst
->height
;
1904 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
1906 dst_pict
= get_xrender_picture( physdev
, 0, &dst
->visrect
);
1908 EnterCriticalSection( &xrender_cs
);
1909 mask_pict
= get_mask_pict( func
.SourceConstantAlpha
* 257 );
1911 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
1912 src
->x
, src
->y
, src
->width
, src
->height
,
1913 physdev
->x11dev
->dc_rect
.left
+ dst
->x
,
1914 physdev
->x11dev
->dc_rect
.top
+ dst
->y
,
1915 dst
->width
, dst
->height
, xscale
, yscale
);
1917 pXRenderFreePicture( gdi_display
, src_pict
);
1918 XFreePixmap( gdi_display
, src_pixmap
);
1920 LeaveCriticalSection( &xrender_cs
);
1921 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
1926 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
1927 set_color_info( physdev
->pict_format
, info
);
1928 return ERROR_BAD_FORMAT
;
1932 /***********************************************************************
1933 * xrenderdrv_AlphaBlend
1935 static BOOL CDECL
xrenderdrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
1936 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
1938 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
1939 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
1940 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
1941 XRenderPictureAttributes pa
;
1942 Pixmap tmp_pixmap
= 0;
1943 double xscale
, yscale
;
1945 if (src_dev
->funcs
!= dst_dev
->funcs
)
1947 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pAlphaBlend
);
1948 return dst_dev
->funcs
->pAlphaBlend( dst_dev
, dst
, src_dev
, src
, blendfn
);
1951 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->format
!= WXR_FORMAT_A8R8G8B8
)
1953 SetLastError( ERROR_INVALID_PARAMETER
);
1957 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
1959 xscale
= src
->width
/ (double)dst
->width
;
1960 yscale
= src
->height
/ (double)dst
->height
;
1962 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
1964 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
1966 /* mono -> color blending needs an intermediate color pixmap */
1967 XRenderColor fg
, bg
;
1968 int width
= src
->visrect
.right
- src
->visrect
.left
;
1969 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1971 /* blending doesn't use the destination DC colors */
1972 fg
.red
= fg
.green
= fg
.blue
= 0;
1973 bg
.red
= bg
.green
= bg
.blue
= 0xffff;
1974 fg
.alpha
= bg
.alpha
= 0xffff;
1976 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
,
1977 physdev_dst
->pict_format
->depth
);
1978 tmp_pict
= pXRenderCreatePicture( gdi_display
, tmp_pixmap
, physdev_dst
->pict_format
, 0, NULL
);
1980 xrender_mono_blit( src_pict
, tmp_pict
, physdev_dst
->format
, &fg
, &bg
,
1981 src
->visrect
.left
, src
->visrect
.top
, width
, height
, 0, 0, width
, height
, 1, 1 );
1983 else if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->pict_format
)
1985 /* we need a source picture with no alpha */
1986 enum wxr_format format
= get_format_without_alpha( physdev_src
->format
);
1987 if (format
!= physdev_src
->format
)
1989 pa
.subwindow_mode
= IncludeInferiors
;
1990 tmp_pict
= pXRenderCreatePicture( gdi_display
, physdev_src
->x11dev
->drawable
,
1991 pict_formats
[format
], CPSubwindowMode
, &pa
);
1995 if (tmp_pict
) src_pict
= tmp_pict
;
1997 EnterCriticalSection( &xrender_cs
);
1998 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
2000 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2001 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
2002 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
2003 src
->width
, src
->height
,
2004 physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
,
2005 physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
,
2006 dst
->width
, dst
->height
, xscale
, yscale
);
2008 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
2009 if (tmp_pixmap
) XFreePixmap( gdi_display
, tmp_pixmap
);
2011 LeaveCriticalSection( &xrender_cs
);
2012 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
2016 /***********************************************************************
2017 * xrenderdrv_GradientFill
2019 static BOOL CDECL
xrenderdrv_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
2020 void * grad_array
, ULONG ngrad
, ULONG mode
)
2022 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2023 static const XFixed stops
[2] = { 0, 1 << 16 };
2024 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2025 XLinearGradient gradient
;
2026 XRenderColor colors
[2];
2027 Picture src_pict
, dst_pict
;
2029 const GRADIENT_RECT
*rect
= grad_array
;
2033 if (!pXRenderCreateLinearGradient
) goto fallback
;
2035 /* <= 16-bpp uses dithering */
2036 if (!physdev
->pict_format
|| physdev
->pict_format
->depth
<= 16) goto fallback
;
2040 case GRADIENT_FILL_RECT_H
:
2041 case GRADIENT_FILL_RECT_V
:
2042 for (i
= 0; i
< ngrad
; i
++, rect
++)
2044 const TRIVERTEX
*v1
= vert_array
+ rect
->UpperLeft
;
2045 const TRIVERTEX
*v2
= vert_array
+ rect
->LowerRight
;
2047 colors
[0].red
= v1
->Red
* 257 / 256;
2048 colors
[0].green
= v1
->Green
* 257 / 256;
2049 colors
[0].blue
= v1
->Blue
* 257 / 256;
2050 colors
[1].red
= v2
->Red
* 257 / 256;
2051 colors
[1].green
= v2
->Green
* 257 / 256;
2052 colors
[1].blue
= v2
->Blue
* 257 / 256;
2053 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2054 colors
[0].alpha
= colors
[1].alpha
= 65535;
2060 LPtoDP( dev
->hdc
, pt
, 2 );
2061 if (mode
== GRADIENT_FILL_RECT_H
)
2063 gradient
.p1
.y
= gradient
.p2
.y
= 0;
2064 if (pt
[1].x
> pt
[0].x
)
2067 gradient
.p2
.x
= (pt
[1].x
- pt
[0].x
) << 16;
2071 gradient
.p1
.x
= (pt
[0].x
- pt
[1].x
) << 16;
2077 gradient
.p1
.x
= gradient
.p2
.x
= 0;
2078 if (pt
[1].y
> pt
[0].y
)
2081 gradient
.p2
.y
= (pt
[1].y
- pt
[0].y
) << 16;
2085 gradient
.p1
.y
= (pt
[0].y
- pt
[1].y
) << 16;
2090 rc
.left
= min( pt
[0].x
, pt
[1].x
);
2091 rc
.top
= min( pt
[0].y
, pt
[1].y
);
2092 rc
.right
= max( pt
[0].x
, pt
[1].x
);
2093 rc
.bottom
= max( pt
[0].y
, pt
[1].y
);
2095 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2096 mode
, wine_dbgstr_rect( &rc
),
2097 colors
[0].red
, colors
[0].green
, colors
[0].blue
, colors
[0].alpha
,
2098 colors
[1].red
, colors
[1].green
, colors
[1].blue
, colors
[1].alpha
);
2100 dst_pict
= get_xrender_picture( physdev
, 0, NULL
);
2102 src_pict
= pXRenderCreateLinearGradient( gdi_display
, &gradient
, stops
, colors
, 2 );
2103 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
,
2104 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
2105 physdev
->x11dev
->dc_rect
.left
+ rc
.left
,
2106 physdev
->x11dev
->dc_rect
.top
+ rc
.top
,
2107 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, 1, 1 );
2108 pXRenderFreePicture( gdi_display
, src_pict
);
2109 add_device_bounds( physdev
->x11dev
, &rc
);
2116 dev
= GET_NEXT_PHYSDEV( dev
, pGradientFill
);
2117 return dev
->funcs
->pGradientFill( dev
, vert_array
, nvert
, grad_array
, ngrad
, mode
);
2120 /***********************************************************************
2121 * xrenderdrv_SelectBrush
2123 static HBRUSH CDECL
xrenderdrv_SelectBrush( PHYSDEV dev
, HBRUSH hbrush
, const struct brush_pattern
*pattern
)
2125 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2127 XVisualInfo vis
= default_visual
;
2128 XRenderPictFormat
*format
= physdev
->pict_format
;
2130 if (!pattern
) goto x11drv_fallback
;
2131 if (pattern
->info
->bmiHeader
.biBitCount
== 1) goto x11drv_fallback
;
2132 if (physdev
->format
== WXR_FORMAT_MONO
) goto x11drv_fallback
;
2134 vis
.depth
= format
->depth
;
2135 vis
.red_mask
= format
->direct
.redMask
<< format
->direct
.red
;
2136 vis
.green_mask
= format
->direct
.greenMask
<< format
->direct
.green
;
2137 vis
.blue_mask
= format
->direct
.blueMask
<< format
->direct
.blue
;
2139 pixmap
= create_pixmap_from_image( physdev
->dev
.hdc
, &vis
, pattern
->info
,
2140 &pattern
->bits
, pattern
->usage
);
2141 if (!pixmap
) return 0;
2143 if (physdev
->x11dev
->brush
.pixmap
) XFreePixmap( gdi_display
, physdev
->x11dev
->brush
.pixmap
);
2144 physdev
->x11dev
->brush
.pixmap
= pixmap
;
2145 physdev
->x11dev
->brush
.fillStyle
= FillTiled
;
2146 physdev
->x11dev
->brush
.pixel
= 0; /* ignored */
2147 physdev
->x11dev
->brush
.style
= BS_PATTERN
;
2151 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBrush
);
2152 return dev
->funcs
->pSelectBrush( dev
, hbrush
, pattern
);
2156 static const struct gdi_dc_funcs xrender_funcs
=
2158 NULL
, /* pAbortDoc */
2159 NULL
, /* pAbortPath */
2160 xrenderdrv_AlphaBlend
, /* pAlphaBlend */
2161 NULL
, /* pAngleArc */
2164 NULL
, /* pBeginPath */
2165 xrenderdrv_BlendImage
, /* pBlendImage */
2167 NULL
, /* pCloseFigure */
2168 xrenderdrv_CreateCompatibleDC
, /* pCreateCompatibleDC */
2169 xrenderdrv_CreateDC
, /* pCreateDC */
2170 xrenderdrv_DeleteDC
, /* pDeleteDC */
2171 NULL
, /* pDeleteObject */
2172 NULL
, /* pEllipse */
2174 NULL
, /* pEndPage */
2175 NULL
, /* pEndPath */
2176 NULL
, /* pEnumFonts */
2177 xrenderdrv_ExtEscape
, /* pExtEscape */
2178 NULL
, /* pExtFloodFill */
2179 xrenderdrv_ExtTextOut
, /* pExtTextOut */
2180 NULL
, /* pFillPath */
2181 NULL
, /* pFillRgn */
2182 NULL
, /* pFontIsLinked */
2183 NULL
, /* pFrameRgn */
2184 NULL
, /* pGetBoundsRect */
2185 NULL
, /* pGetCharABCWidths */
2186 NULL
, /* pGetCharABCWidthsI */
2187 NULL
, /* pGetCharWidth */
2188 NULL
, /* pGetCharWidthInfo */
2189 NULL
, /* pGetDeviceCaps */
2190 NULL
, /* pGetDeviceGammaRamp */
2191 NULL
, /* pGetFontData */
2192 NULL
, /* pGetFontRealizationInfo */
2193 NULL
, /* pGetFontUnicodeRanges */
2194 NULL
, /* pGetGlyphIndices */
2195 NULL
, /* pGetGlyphOutline */
2196 NULL
, /* pGetICMProfile */
2197 NULL
, /* pGetImage */
2198 NULL
, /* pGetKerningPairs */
2199 NULL
, /* pGetNearestColor */
2200 NULL
, /* pGetOutlineTextMetrics */
2201 NULL
, /* pGetPixel */
2202 NULL
, /* pGetSystemPaletteEntries */
2203 NULL
, /* pGetTextCharsetInfo */
2204 NULL
, /* pGetTextExtentExPoint */
2205 NULL
, /* pGetTextExtentExPointI */
2206 NULL
, /* pGetTextFace */
2207 NULL
, /* pGetTextMetrics */
2208 xrenderdrv_GradientFill
, /* pGradientFill */
2209 NULL
, /* pInvertRgn */
2212 NULL
, /* pPaintRgn */
2215 NULL
, /* pPolyBezier */
2216 NULL
, /* pPolyBezierTo */
2217 NULL
, /* pPolyDraw */
2218 NULL
, /* pPolyPolygon */
2219 NULL
, /* pPolyPolyline */
2220 NULL
, /* pPolylineTo */
2221 xrenderdrv_PutImage
, /* pPutImage */
2222 NULL
, /* pRealizeDefaultPalette */
2223 NULL
, /* pRealizePalette */
2224 NULL
, /* pRectangle */
2225 NULL
, /* pResetDC */
2226 NULL
, /* pRoundRect */
2227 NULL
, /* pSelectBitmap */
2228 xrenderdrv_SelectBrush
, /* pSelectBrush */
2229 xrenderdrv_SelectFont
, /* pSelectFont */
2230 NULL
, /* pSelectPen */
2231 NULL
, /* pSetBkColor */
2232 NULL
, /* pSetBoundsRect */
2233 NULL
, /* pSetDCBrushColor */
2234 NULL
, /* pSetDCPenColor */
2235 NULL
, /* pSetDIBitsToDevice */
2236 xrenderdrv_SetDeviceClipping
, /* pSetDeviceClipping */
2237 NULL
, /* pSetDeviceGammaRamp */
2238 NULL
, /* pSetPixel */
2239 NULL
, /* pSetTextColor */
2240 NULL
, /* pStartDoc */
2241 NULL
, /* pStartPage */
2242 xrenderdrv_StretchBlt
, /* pStretchBlt */
2243 NULL
, /* pStretchDIBits */
2244 NULL
, /* pStrokeAndFillPath */
2245 NULL
, /* pStrokePath */
2246 NULL
, /* pUnrealizePalette */
2247 NULL
, /* pD3DKMTCheckVidPnExclusiveOwnership */
2248 NULL
, /* pD3DKMTSetVidPnSourceOwner */
2249 NULL
, /* wine_get_wgl_driver */
2250 GDI_PRIORITY_GRAPHICS_DRV
+ 10 /* priority */
2253 #else /* SONAME_LIBXRENDER */
2255 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
2257 TRACE("XRender support not compiled in.\n");
2261 #endif /* SONAME_LIBXRENDER */