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
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
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0))) return NULL
;
331 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
332 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
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' || !strcasecmp( value
, "off" ))
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
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
xrenderdrv_CreateDC( PHYSDEV
*pdev
, LPCWSTR driver
, LPCWSTR device
,
942 LPCWSTR output
, const DEVMODEW
* initData
)
944 return create_xrender_dc( pdev
, default_format
);
947 /**********************************************************************
948 * xrenderdrv_CreateCompatibleDC
950 static BOOL
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
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
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 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
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;
1475 width_src
= -width_src
;
1479 y_src
+= height_src
+ 1;
1480 height_src
= -height_src
;
1484 x_dst
+= width_dst
+ 1;
1485 width_dst
= -width_dst
;
1489 y_dst
+= height_dst
+ 1;
1490 height_dst
= -height_dst
;
1493 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1494 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1495 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1496 if(xscale
!= 1.0 || yscale
!= 1.0)
1498 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1499 * in the wrong quadrant of the x-y plane.
1501 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1502 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1503 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1509 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1511 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
1512 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width_dst
, height_dst
);
1515 /* Helper function for (stretched) mono->color blitting using xrender */
1516 static void xrender_mono_blit( Picture src_pict
, Picture dst_pict
,
1517 enum wxr_format dst_format
, XRenderColor
*fg
, XRenderColor
*bg
,
1518 int x_src
, int y_src
, int width_src
, int height_src
,
1519 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1520 double xscale
, double yscale
)
1523 int x_offset
, y_offset
;
1528 x_src
+= width_src
+ 1;
1529 width_src
= -width_src
;
1533 y_src
+= height_src
+ 1;
1534 height_src
= -height_src
;
1538 x_dst
+= width_dst
+ 1;
1539 width_dst
= -width_dst
;
1543 y_dst
+= height_dst
+ 1;
1544 height_dst
= -height_dst
;
1547 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1548 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1551 EnterCriticalSection( &xrender_cs
);
1553 color
.alpha
= 0xffff; /* tile pict needs 100% alpha */
1554 tile_pict
= get_tile_pict( dst_format
, &color
);
1556 pXRenderFillRectangle( gdi_display
, PictOpSrc
, dst_pict
, fg
, x_dst
, y_dst
, width_dst
, height_dst
);
1558 if (xscale
!= 1.0 || yscale
!= 1.0)
1560 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1561 * in the wrong quadrant of the x-y plane.
1563 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1564 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1565 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1571 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1573 pXRenderComposite(gdi_display
, PictOpOver
, tile_pict
, src_pict
, dst_pict
,
1574 0, 0, x_offset
, y_offset
, x_dst
, y_dst
, width_dst
, height_dst
);
1575 LeaveCriticalSection( &xrender_cs
);
1577 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1578 if (bg
->alpha
!= 0xffff && (dst_format
== WXR_FORMAT_A8R8G8B8
|| dst_format
== WXR_FORMAT_B8G8R8A8
))
1579 multiply_alpha( dst_pict
, pict_formats
[dst_format
], bg
->alpha
,
1580 x_dst
, y_dst
, width_dst
, height_dst
);
1583 /* create a pixmap and render picture for an image */
1584 static DWORD
create_image_pixmap( BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1585 struct bitblt_coords
*src
, enum wxr_format format
,
1586 Pixmap
*pixmap
, Picture
*pict
, BOOL
*use_repeat
)
1589 int width
= src
->visrect
.right
- src
->visrect
.left
;
1590 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1591 int depth
= pict_formats
[format
]->depth
;
1592 struct gdi_image_bits dst_bits
;
1593 XRenderPictureAttributes pa
;
1597 image
= XCreateImage( gdi_display
, default_visual
.visual
, depth
, ZPixmap
, 0, NULL
,
1598 info
->bmiHeader
.biWidth
, height
, 32, 0 );
1599 if (!image
) return ERROR_OUTOFMEMORY
;
1601 ret
= copy_image_bits( info
, (format
== WXR_FORMAT_R8G8B8
), image
, bits
, &dst_bits
, src
, NULL
, ~0u );
1602 if (ret
) return ret
;
1604 image
->data
= dst_bits
.ptr
;
1606 *use_repeat
= (width
== 1 && height
== 1);
1607 pa
.repeat
= *use_repeat
? RepeatNormal
: RepeatNone
;
1609 *pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, depth
);
1610 gc
= XCreateGC( gdi_display
, *pixmap
, 0, NULL
);
1611 XPutImage( gdi_display
, *pixmap
, gc
, image
, src
->visrect
.left
, 0, 0, 0, width
, height
);
1612 *pict
= pXRenderCreatePicture( gdi_display
, *pixmap
, pict_formats
[format
], CPRepeat
, &pa
);
1613 XFreeGC( gdi_display
, gc
);
1615 /* make coordinates relative to the pixmap */
1616 src
->x
-= src
->visrect
.left
;
1617 src
->y
-= src
->visrect
.top
;
1618 OffsetRect( &src
->visrect
, -src
->visrect
.left
, -src
->visrect
.top
);
1621 XDestroyImage( image
);
1622 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
1626 static void xrender_stretch_blit( struct xrender_physdev
*physdev_src
, struct xrender_physdev
*physdev_dst
,
1627 Drawable drawable
, const struct bitblt_coords
*src
,
1628 const struct bitblt_coords
*dst
)
1631 Picture src_pict
= 0, dst_pict
, mask_pict
= 0;
1632 double xscale
= src
->width
/ (double)dst
->width
;
1633 double yscale
= src
->height
/ (double)dst
->height
;
1635 if (drawable
) /* using an intermediate pixmap */
1639 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, physdev_dst
->pict_format
, 0, NULL
);
1643 x_dst
= physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
;
1644 y_dst
= physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
;
1645 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
1648 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
1651 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
1653 XRenderColor fg
, bg
;
1655 get_xrender_color( physdev_dst
, GetTextColor( physdev_dst
->dev
.hdc
), &fg
);
1656 get_xrender_color( physdev_dst
, GetBkColor( physdev_dst
->dev
.hdc
), &bg
);
1657 fg
.alpha
= bg
.alpha
= 0;
1659 xrender_mono_blit( src_pict
, dst_pict
, physdev_dst
->format
, &fg
, &bg
,
1660 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1661 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1662 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1664 else /* color -> color (can be at different depths) or mono -> mono */
1666 if (physdev_dst
->pict_format
->depth
== 32 && physdev_src
->pict_format
->depth
< 32)
1667 mask_pict
= get_no_alpha_mask();
1669 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
1670 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1671 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1672 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1675 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1679 static void xrender_put_image( Pixmap src_pixmap
, Picture src_pict
, Picture mask_pict
, HRGN clip
,
1680 XRenderPictFormat
*dst_format
, struct xrender_physdev
*physdev
,
1681 Drawable drawable
, struct bitblt_coords
*src
,
1682 struct bitblt_coords
*dst
, BOOL use_repeat
)
1686 double xscale
, yscale
;
1688 if (drawable
) /* using an intermediate pixmap */
1690 RGNDATA
*clip_data
= NULL
;
1692 if (clip
) clip_data
= X11DRV_GetRegionData( clip
, 0 );
1695 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, dst_format
, 0, NULL
);
1697 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
, 0, 0,
1698 (XRectangle
*)clip_data
->Buffer
, clip_data
->rdh
.nCount
);
1699 HeapFree( GetProcessHeap(), 0, clip_data
);
1703 x_dst
= physdev
->x11dev
->dc_rect
.left
+ dst
->x
;
1704 y_dst
= physdev
->x11dev
->dc_rect
.top
+ dst
->y
;
1705 dst_pict
= get_xrender_picture( physdev
, clip
, &dst
->visrect
);
1710 xscale
= src
->width
/ (double)dst
->width
;
1711 yscale
= src
->height
/ (double)dst
->height
;
1713 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
1715 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
, src
->x
, src
->y
, src
->width
, src
->height
,
1716 x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1718 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1722 /***********************************************************************
1723 * xrenderdrv_StretchBlt
1725 static BOOL
xrenderdrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
1726 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
1728 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
1729 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
1730 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
1732 if (src_dev
->funcs
!= dst_dev
->funcs
)
1734 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pStretchBlt
);
1735 return dst_dev
->funcs
->pStretchBlt( dst_dev
, dst
, src_dev
, src
, rop
);
1738 /* XRender is of no use for color -> mono */
1739 if (physdev_dst
->format
== WXR_FORMAT_MONO
&& physdev_src
->format
!= WXR_FORMAT_MONO
)
1740 goto x11drv_fallback
;
1742 /* if not stretching, we only need to handle format conversion */
1743 if (!stretch
&& physdev_dst
->format
== physdev_src
->format
) goto x11drv_fallback
;
1749 struct bitblt_coords tmp
;
1751 /* make coordinates relative to tmp pixmap */
1753 tmp
.x
-= tmp
.visrect
.left
;
1754 tmp
.y
-= tmp
.visrect
.top
;
1755 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
1757 tmpGC
= XCreateGC( gdi_display
, physdev_dst
->x11dev
->drawable
, 0, NULL
);
1758 XSetSubwindowMode( gdi_display
, tmpGC
, IncludeInferiors
);
1759 XSetGraphicsExposures( gdi_display
, tmpGC
, False
);
1760 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, tmp
.visrect
.right
- tmp
.visrect
.left
,
1761 tmp
.visrect
.bottom
- tmp
.visrect
.top
, physdev_dst
->pict_format
->depth
);
1763 xrender_stretch_blit( physdev_src
, physdev_dst
, tmp_pixmap
, src
, &tmp
);
1764 execute_rop( physdev_dst
->x11dev
, tmp_pixmap
, tmpGC
, &dst
->visrect
, rop
);
1766 XFreePixmap( gdi_display
, tmp_pixmap
);
1767 XFreeGC( gdi_display
, tmpGC
);
1769 else xrender_stretch_blit( physdev_src
, physdev_dst
, 0, src
, dst
);
1771 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
1775 return X11DRV_StretchBlt( &physdev_dst
->x11dev
->dev
, dst
, &physdev_src
->x11dev
->dev
, src
, rop
);
1779 /***********************************************************************
1780 * xrenderdrv_PutImage
1782 static DWORD
xrenderdrv_PutImage( PHYSDEV dev
, HRGN clip
, BITMAPINFO
*info
,
1783 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
1784 struct bitblt_coords
*dst
, DWORD rop
)
1786 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1790 enum wxr_format src_format
, dst_format
;
1791 XRenderPictFormat
*pict_format
;
1793 Picture src_pict
, mask_pict
= 0;
1796 dst_format
= physdev
->format
;
1797 src_format
= get_xrender_format_from_bitmapinfo( info
);
1798 if (!(pict_format
= pict_formats
[src_format
])) goto update_format
;
1800 /* make sure we can create an image with the same bpp */
1801 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
1804 /* mono <-> color conversions not supported */
1805 if ((src_format
!= dst_format
) && (src_format
== WXR_FORMAT_MONO
|| dst_format
== WXR_FORMAT_MONO
))
1806 goto x11drv_fallback
;
1808 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
1810 if (!has_alpha( src_format
) && has_alpha( dst_format
)) mask_pict
= get_no_alpha_mask();
1812 ret
= create_image_pixmap( info
, bits
, src
, src_format
, &src_pixmap
, &src_pict
, &use_repeat
);
1815 struct bitblt_coords tmp
;
1819 BOOL restore_region
= add_extra_clipping_region( physdev
->x11dev
, clip
);
1821 /* make coordinates relative to tmp pixmap */
1823 tmp
.x
-= tmp
.visrect
.left
;
1824 tmp
.y
-= tmp
.visrect
.top
;
1825 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
1827 gc
= XCreateGC( gdi_display
, physdev
->x11dev
->drawable
, 0, NULL
);
1828 XSetSubwindowMode( gdi_display
, gc
, IncludeInferiors
);
1829 XSetGraphicsExposures( gdi_display
, gc
, False
);
1830 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
,
1831 tmp
.visrect
.right
- tmp
.visrect
.left
,
1832 tmp
.visrect
.bottom
- tmp
.visrect
.top
,
1833 physdev
->pict_format
->depth
);
1835 xrender_put_image( src_pixmap
, src_pict
, mask_pict
, NULL
, physdev
->pict_format
,
1836 NULL
, tmp_pixmap
, src
, &tmp
, use_repeat
);
1837 execute_rop( physdev
->x11dev
, tmp_pixmap
, gc
, &dst
->visrect
, rop
);
1839 XFreePixmap( gdi_display
, tmp_pixmap
);
1840 XFreeGC( gdi_display
, gc
);
1841 if (restore_region
) restore_clipping_region( physdev
->x11dev
);
1843 else xrender_put_image( src_pixmap
, src_pict
, mask_pict
, clip
,
1844 physdev
->pict_format
, physdev
, 0, src
, dst
, use_repeat
);
1846 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
1848 pXRenderFreePicture( gdi_display
, src_pict
);
1849 XFreePixmap( gdi_display
, src_pixmap
);
1854 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
1855 set_color_info( pict_formats
[dst_format
], info
);
1856 return ERROR_BAD_FORMAT
;
1859 dev
= GET_NEXT_PHYSDEV( dev
, pPutImage
);
1860 return dev
->funcs
->pPutImage( dev
, clip
, info
, bits
, src
, dst
, rop
);
1864 /***********************************************************************
1865 * xrenderdrv_BlendImage
1867 static DWORD
xrenderdrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1868 struct bitblt_coords
*src
, struct bitblt_coords
*dst
,
1869 BLENDFUNCTION func
)
1871 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1873 enum wxr_format format
;
1874 XRenderPictFormat
*pict_format
;
1875 Picture dst_pict
, src_pict
, mask_pict
;
1879 format
= get_xrender_format_from_bitmapinfo( info
);
1880 if (!(func
.AlphaFormat
& AC_SRC_ALPHA
))
1881 format
= get_format_without_alpha( format
);
1882 else if (format
!= WXR_FORMAT_A8R8G8B8
|| info
->bmiHeader
.biCompression
!= BI_RGB
)
1883 return ERROR_INVALID_PARAMETER
;
1885 if (!(pict_format
= pict_formats
[format
])) goto update_format
;
1887 /* make sure we can create an image with the same bpp */
1888 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
1891 if (format
== WXR_FORMAT_MONO
&& physdev
->format
!= WXR_FORMAT_MONO
)
1894 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
1896 ret
= create_image_pixmap( info
, bits
, src
, format
, &src_pixmap
, &src_pict
, &use_repeat
);
1899 double xscale
, yscale
;
1903 xscale
= src
->width
/ (double)dst
->width
;
1904 yscale
= src
->height
/ (double)dst
->height
;
1906 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
1908 dst_pict
= get_xrender_picture( physdev
, 0, &dst
->visrect
);
1910 EnterCriticalSection( &xrender_cs
);
1911 mask_pict
= get_mask_pict( func
.SourceConstantAlpha
* 257 );
1913 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
1914 src
->x
, src
->y
, src
->width
, src
->height
,
1915 physdev
->x11dev
->dc_rect
.left
+ dst
->x
,
1916 physdev
->x11dev
->dc_rect
.top
+ dst
->y
,
1917 dst
->width
, dst
->height
, xscale
, yscale
);
1919 pXRenderFreePicture( gdi_display
, src_pict
);
1920 XFreePixmap( gdi_display
, src_pixmap
);
1922 LeaveCriticalSection( &xrender_cs
);
1923 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
1928 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
1929 set_color_info( physdev
->pict_format
, info
);
1930 return ERROR_BAD_FORMAT
;
1934 /***********************************************************************
1935 * xrenderdrv_AlphaBlend
1937 static BOOL
xrenderdrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
1938 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
1940 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
1941 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
1942 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
1943 XRenderPictureAttributes pa
;
1944 Pixmap tmp_pixmap
= 0;
1945 double xscale
, yscale
;
1947 if (src_dev
->funcs
!= dst_dev
->funcs
)
1949 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pAlphaBlend
);
1950 return dst_dev
->funcs
->pAlphaBlend( dst_dev
, dst
, src_dev
, src
, blendfn
);
1953 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->format
!= WXR_FORMAT_A8R8G8B8
)
1955 SetLastError( ERROR_INVALID_PARAMETER
);
1959 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
1961 xscale
= src
->width
/ (double)dst
->width
;
1962 yscale
= src
->height
/ (double)dst
->height
;
1964 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
1966 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
1968 /* mono -> color blending needs an intermediate color pixmap */
1969 XRenderColor fg
, bg
;
1970 int width
= src
->visrect
.right
- src
->visrect
.left
;
1971 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1973 /* blending doesn't use the destination DC colors */
1974 fg
.red
= fg
.green
= fg
.blue
= 0;
1975 bg
.red
= bg
.green
= bg
.blue
= 0xffff;
1976 fg
.alpha
= bg
.alpha
= 0xffff;
1978 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
,
1979 physdev_dst
->pict_format
->depth
);
1980 tmp_pict
= pXRenderCreatePicture( gdi_display
, tmp_pixmap
, physdev_dst
->pict_format
, 0, NULL
);
1982 xrender_mono_blit( src_pict
, tmp_pict
, physdev_dst
->format
, &fg
, &bg
,
1983 src
->visrect
.left
, src
->visrect
.top
, width
, height
, 0, 0, width
, height
, 1, 1 );
1985 else if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->pict_format
)
1987 /* we need a source picture with no alpha */
1988 enum wxr_format format
= get_format_without_alpha( physdev_src
->format
);
1989 if (format
!= physdev_src
->format
)
1991 pa
.subwindow_mode
= IncludeInferiors
;
1992 tmp_pict
= pXRenderCreatePicture( gdi_display
, physdev_src
->x11dev
->drawable
,
1993 pict_formats
[format
], CPSubwindowMode
, &pa
);
1997 if (tmp_pict
) src_pict
= tmp_pict
;
1999 EnterCriticalSection( &xrender_cs
);
2000 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
2002 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2003 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
2004 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
2005 src
->width
, src
->height
,
2006 physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
,
2007 physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
,
2008 dst
->width
, dst
->height
, xscale
, yscale
);
2010 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
2011 if (tmp_pixmap
) XFreePixmap( gdi_display
, tmp_pixmap
);
2013 LeaveCriticalSection( &xrender_cs
);
2014 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
2018 /***********************************************************************
2019 * xrenderdrv_GradientFill
2021 static BOOL
xrenderdrv_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
2022 void * grad_array
, ULONG ngrad
, ULONG mode
)
2024 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2025 static const XFixed stops
[2] = { 0, 1 << 16 };
2026 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2027 XLinearGradient gradient
;
2028 XRenderColor colors
[2];
2029 Picture src_pict
, dst_pict
;
2031 const GRADIENT_RECT
*rect
= grad_array
;
2035 if (!pXRenderCreateLinearGradient
) goto fallback
;
2037 /* <= 16-bpp uses dithering */
2038 if (!physdev
->pict_format
|| physdev
->pict_format
->depth
<= 16) goto fallback
;
2042 case GRADIENT_FILL_RECT_H
:
2043 case GRADIENT_FILL_RECT_V
:
2044 for (i
= 0; i
< ngrad
; i
++, rect
++)
2046 const TRIVERTEX
*v1
= vert_array
+ rect
->UpperLeft
;
2047 const TRIVERTEX
*v2
= vert_array
+ rect
->LowerRight
;
2049 colors
[0].red
= v1
->Red
* 257 / 256;
2050 colors
[0].green
= v1
->Green
* 257 / 256;
2051 colors
[0].blue
= v1
->Blue
* 257 / 256;
2052 colors
[1].red
= v2
->Red
* 257 / 256;
2053 colors
[1].green
= v2
->Green
* 257 / 256;
2054 colors
[1].blue
= v2
->Blue
* 257 / 256;
2055 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2056 colors
[0].alpha
= colors
[1].alpha
= 65535;
2062 LPtoDP( dev
->hdc
, pt
, 2 );
2063 if (mode
== GRADIENT_FILL_RECT_H
)
2065 gradient
.p1
.y
= gradient
.p2
.y
= 0;
2066 if (pt
[1].x
> pt
[0].x
)
2069 gradient
.p2
.x
= (pt
[1].x
- pt
[0].x
) << 16;
2073 gradient
.p1
.x
= (pt
[0].x
- pt
[1].x
) << 16;
2079 gradient
.p1
.x
= gradient
.p2
.x
= 0;
2080 if (pt
[1].y
> pt
[0].y
)
2083 gradient
.p2
.y
= (pt
[1].y
- pt
[0].y
) << 16;
2087 gradient
.p1
.y
= (pt
[0].y
- pt
[1].y
) << 16;
2092 rc
.left
= min( pt
[0].x
, pt
[1].x
);
2093 rc
.top
= min( pt
[0].y
, pt
[1].y
);
2094 rc
.right
= max( pt
[0].x
, pt
[1].x
);
2095 rc
.bottom
= max( pt
[0].y
, pt
[1].y
);
2097 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2098 mode
, wine_dbgstr_rect( &rc
),
2099 colors
[0].red
, colors
[0].green
, colors
[0].blue
, colors
[0].alpha
,
2100 colors
[1].red
, colors
[1].green
, colors
[1].blue
, colors
[1].alpha
);
2102 dst_pict
= get_xrender_picture( physdev
, 0, NULL
);
2104 src_pict
= pXRenderCreateLinearGradient( gdi_display
, &gradient
, stops
, colors
, 2 );
2105 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
,
2106 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
2107 physdev
->x11dev
->dc_rect
.left
+ rc
.left
,
2108 physdev
->x11dev
->dc_rect
.top
+ rc
.top
,
2109 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, 1, 1 );
2110 pXRenderFreePicture( gdi_display
, src_pict
);
2111 add_device_bounds( physdev
->x11dev
, &rc
);
2118 dev
= GET_NEXT_PHYSDEV( dev
, pGradientFill
);
2119 return dev
->funcs
->pGradientFill( dev
, vert_array
, nvert
, grad_array
, ngrad
, mode
);
2122 /***********************************************************************
2123 * xrenderdrv_SelectBrush
2125 static HBRUSH
xrenderdrv_SelectBrush( PHYSDEV dev
, HBRUSH hbrush
, const struct brush_pattern
*pattern
)
2127 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2129 XVisualInfo vis
= default_visual
;
2130 XRenderPictFormat
*format
= physdev
->pict_format
;
2132 if (!pattern
) goto x11drv_fallback
;
2133 if (pattern
->info
->bmiHeader
.biBitCount
== 1) goto x11drv_fallback
;
2134 if (physdev
->format
== WXR_FORMAT_MONO
) goto x11drv_fallback
;
2136 vis
.depth
= format
->depth
;
2137 vis
.red_mask
= format
->direct
.redMask
<< format
->direct
.red
;
2138 vis
.green_mask
= format
->direct
.greenMask
<< format
->direct
.green
;
2139 vis
.blue_mask
= format
->direct
.blueMask
<< format
->direct
.blue
;
2141 pixmap
= create_pixmap_from_image( physdev
->dev
.hdc
, &vis
, pattern
->info
,
2142 &pattern
->bits
, pattern
->usage
);
2143 if (!pixmap
) return 0;
2145 if (physdev
->x11dev
->brush
.pixmap
) XFreePixmap( gdi_display
, physdev
->x11dev
->brush
.pixmap
);
2146 physdev
->x11dev
->brush
.pixmap
= pixmap
;
2147 physdev
->x11dev
->brush
.fillStyle
= FillTiled
;
2148 physdev
->x11dev
->brush
.pixel
= 0; /* ignored */
2149 physdev
->x11dev
->brush
.style
= BS_PATTERN
;
2153 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBrush
);
2154 return dev
->funcs
->pSelectBrush( dev
, hbrush
, pattern
);
2158 static const struct gdi_dc_funcs xrender_funcs
=
2160 NULL
, /* pAbortDoc */
2161 NULL
, /* pAbortPath */
2162 xrenderdrv_AlphaBlend
, /* pAlphaBlend */
2163 NULL
, /* pAngleArc */
2166 NULL
, /* pBeginPath */
2167 xrenderdrv_BlendImage
, /* pBlendImage */
2169 NULL
, /* pCloseFigure */
2170 xrenderdrv_CreateCompatibleDC
, /* pCreateCompatibleDC */
2171 xrenderdrv_CreateDC
, /* pCreateDC */
2172 xrenderdrv_DeleteDC
, /* pDeleteDC */
2173 NULL
, /* pDeleteObject */
2174 NULL
, /* pDeviceCapabilities */
2175 NULL
, /* pEllipse */
2177 NULL
, /* pEndPage */
2178 NULL
, /* pEndPath */
2179 NULL
, /* pEnumFonts */
2180 NULL
, /* pEnumICMProfiles */
2181 NULL
, /* pExcludeClipRect */
2182 NULL
, /* pExtDeviceMode */
2183 xrenderdrv_ExtEscape
, /* pExtEscape */
2184 NULL
, /* pExtFloodFill */
2185 NULL
, /* pExtSelectClipRgn */
2186 xrenderdrv_ExtTextOut
, /* pExtTextOut */
2187 NULL
, /* pFillPath */
2188 NULL
, /* pFillRgn */
2189 NULL
, /* pFlattenPath */
2190 NULL
, /* pFontIsLinked */
2191 NULL
, /* pFrameRgn */
2192 NULL
, /* pGdiComment */
2193 NULL
, /* pGetBoundsRect */
2194 NULL
, /* pGetCharABCWidths */
2195 NULL
, /* pGetCharABCWidthsI */
2196 NULL
, /* pGetCharWidth */
2197 NULL
, /* pGetDeviceCaps */
2198 NULL
, /* pGetDeviceGammaRamp */
2199 NULL
, /* pGetFontData */
2200 NULL
, /* pGetFontRealizationInfo */
2201 NULL
, /* pGetFontUnicodeRanges */
2202 NULL
, /* pGetGlyphIndices */
2203 NULL
, /* pGetGlyphOutline */
2204 NULL
, /* pGetICMProfile */
2205 NULL
, /* pGetImage */
2206 NULL
, /* pGetKerningPairs */
2207 NULL
, /* pGetNearestColor */
2208 NULL
, /* pGetOutlineTextMetrics */
2209 NULL
, /* pGetPixel */
2210 NULL
, /* pGetSystemPaletteEntries */
2211 NULL
, /* pGetTextCharsetInfo */
2212 NULL
, /* pGetTextExtentExPoint */
2213 NULL
, /* pGetTextExtentExPointI */
2214 NULL
, /* pGetTextFace */
2215 NULL
, /* pGetTextMetrics */
2216 xrenderdrv_GradientFill
, /* pGradientFill */
2217 NULL
, /* pIntersectClipRect */
2218 NULL
, /* pInvertRgn */
2220 NULL
, /* pModifyWorldTransform */
2222 NULL
, /* pOffsetClipRgn */
2223 NULL
, /* pOffsetViewportOrg */
2224 NULL
, /* pOffsetWindowOrg */
2225 NULL
, /* pPaintRgn */
2228 NULL
, /* pPolyBezier */
2229 NULL
, /* pPolyBezierTo */
2230 NULL
, /* pPolyDraw */
2231 NULL
, /* pPolyPolygon */
2232 NULL
, /* pPolyPolyline */
2233 NULL
, /* pPolygon */
2234 NULL
, /* pPolyline */
2235 NULL
, /* pPolylineTo */
2236 xrenderdrv_PutImage
, /* pPutImage */
2237 NULL
, /* pRealizeDefaultPalette */
2238 NULL
, /* pRealizePalette */
2239 NULL
, /* pRectangle */
2240 NULL
, /* pResetDC */
2241 NULL
, /* pRestoreDC */
2242 NULL
, /* pRoundRect */
2244 NULL
, /* pScaleViewportExt */
2245 NULL
, /* pScaleWindowExt */
2246 NULL
, /* pSelectBitmap */
2247 xrenderdrv_SelectBrush
, /* pSelectBrush */
2248 NULL
, /* pSelectClipPath */
2249 xrenderdrv_SelectFont
, /* pSelectFont */
2250 NULL
, /* pSelectPalette */
2251 NULL
, /* pSelectPen */
2252 NULL
, /* pSetArcDirection */
2253 NULL
, /* pSetBkColor */
2254 NULL
, /* pSetBkMode */
2255 NULL
, /* pSetBoundsRect */
2256 NULL
, /* pSetDCBrushColor */
2257 NULL
, /* pSetDCPenColor */
2258 NULL
, /* pSetDIBitsToDevice */
2259 xrenderdrv_SetDeviceClipping
, /* pSetDeviceClipping */
2260 NULL
, /* pSetDeviceGammaRamp */
2261 NULL
, /* pSetLayout */
2262 NULL
, /* pSetMapMode */
2263 NULL
, /* pSetMapperFlags */
2264 NULL
, /* pSetPixel */
2265 NULL
, /* pSetPolyFillMode */
2266 NULL
, /* pSetROP2 */
2267 NULL
, /* pSetRelAbs */
2268 NULL
, /* pSetStretchBltMode */
2269 NULL
, /* pSetTextAlign */
2270 NULL
, /* pSetTextCharacterExtra */
2271 NULL
, /* pSetTextColor */
2272 NULL
, /* pSetTextJustification */
2273 NULL
, /* pSetViewportExt */
2274 NULL
, /* pSetViewportOrg */
2275 NULL
, /* pSetWindowExt */
2276 NULL
, /* pSetWindowOrg */
2277 NULL
, /* pSetWorldTransform */
2278 NULL
, /* pStartDoc */
2279 NULL
, /* pStartPage */
2280 xrenderdrv_StretchBlt
, /* pStretchBlt */
2281 NULL
, /* pStretchDIBits */
2282 NULL
, /* pStrokeAndFillPath */
2283 NULL
, /* pStrokePath */
2284 NULL
, /* pUnrealizePalette */
2285 NULL
, /* pWidenPath */
2286 NULL
, /* wine_get_wgl_driver */
2287 NULL
, /* wine_get_vulkan_driver */
2288 GDI_PRIORITY_GRAPHICS_DRV
+ 10 /* priority */
2291 #else /* SONAME_LIBXRENDER */
2293 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
2295 TRACE("XRender support not compiled in.\n");
2299 #endif /* SONAME_LIBXRENDER */