2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
6 * Copyright 2011 Alexandre Julliard
9 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
37 #include "wine/library.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(xrender
);
43 #ifdef SONAME_LIBXRENDER
45 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
48 #include <X11/extensions/Xrender.h>
50 #ifndef RepeatNone /* added in 0.10 */
52 #define RepeatNormal 1
54 #define RepeatReflect 3
72 WXR_INVALID_FORMAT
= WXR_NB_FORMATS
75 typedef struct wine_xrender_format_template
79 unsigned int alphaMask
;
83 unsigned int greenMask
;
85 unsigned int blueMask
;
86 } WineXRenderFormatTemplate
;
88 static const WineXRenderFormatTemplate wxr_formats_template
[WXR_NB_FORMATS
] =
90 /* Format depth alpha mask red mask green mask blue mask*/
91 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
92 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
93 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
94 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
95 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
96 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
97 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
98 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
99 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
101 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
105 static const ColorShifts wxr_color_shifts
[WXR_NB_FORMATS
] =
107 /* format phys red phys green phys blue log red log green log blue */
108 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
109 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
110 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
111 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
112 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
113 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
114 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
115 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
116 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
117 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
118 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
122 static enum wxr_format default_format
= WXR_INVALID_FORMAT
;
123 static XRenderPictFormat
*pict_formats
[WXR_NB_FORMATS
+ 1 /* invalid format */];
129 SIZE devsize
; /* size in device coords */
133 #define INITIAL_REALIZED_BUF_SIZE 128
135 enum glyph_type
{ GLYPH_INDEX
, GLYPH_WCHAR
, GLYPH_NBTYPES
};
137 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
142 XRenderPictFormat
*font_format
;
146 } gsCacheEntryFormat
;
151 gsCacheEntryFormat
*format
[GLYPH_NBTYPES
][AA_MAXVALUE
];
156 struct xrender_physdev
158 struct gdi_physdev dev
;
159 X11DRV_PDEVICE
*x11dev
;
161 enum wxr_format format
;
167 XRenderPictFormat
*pict_format
;
170 static inline struct xrender_physdev
*get_xrender_dev( PHYSDEV dev
)
172 return (struct xrender_physdev
*)dev
;
175 static const struct gdi_dc_funcs xrender_funcs
;
177 static gsCacheEntry
*glyphsetCache
= NULL
;
178 static DWORD glyphsetCacheSize
= 0;
179 static INT lastfree
= -1;
182 #define INIT_CACHE_SIZE 10
184 static void *xrender_handle
;
186 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
187 MAKE_FUNCPTR(XRenderAddGlyphs
)
188 MAKE_FUNCPTR(XRenderChangePicture
)
189 MAKE_FUNCPTR(XRenderComposite
)
190 MAKE_FUNCPTR(XRenderCompositeText16
)
191 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
192 MAKE_FUNCPTR(XRenderCreatePicture
)
193 MAKE_FUNCPTR(XRenderFillRectangle
)
194 MAKE_FUNCPTR(XRenderFindFormat
)
195 MAKE_FUNCPTR(XRenderFindVisualFormat
)
196 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
197 MAKE_FUNCPTR(XRenderFreePicture
)
198 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
199 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
200 MAKE_FUNCPTR(XRenderCreateLinearGradient
)
202 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
203 MAKE_FUNCPTR(XRenderSetPictureTransform
)
205 MAKE_FUNCPTR(XRenderQueryExtension
)
209 static CRITICAL_SECTION xrender_cs
;
210 static CRITICAL_SECTION_DEBUG critsect_debug
=
213 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
214 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
216 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
218 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
219 ( ( (ULONG)_x4 << 24 ) | \
220 ( (ULONG)_x3 << 16 ) | \
221 ( (ULONG)_x2 << 8 ) | \
224 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
226 #define GASP_GRIDFIT 0x01
227 #define GASP_DOGRAY 0x02
229 #ifdef WORDS_BIGENDIAN
230 #define get_be_word(x) (x)
231 #define NATIVE_BYTE_ORDER MSBFirst
233 #define get_be_word(x) RtlUshortByteSwap(x)
234 #define NATIVE_BYTE_ORDER LSBFirst
237 static BOOL
has_alpha( enum wxr_format format
)
239 return (format
== WXR_FORMAT_A8R8G8B8
|| format
== WXR_FORMAT_B8G8R8A8
);
242 static enum wxr_format
get_format_without_alpha( enum wxr_format format
)
246 case WXR_FORMAT_A8R8G8B8
: return WXR_FORMAT_X8R8G8B8
;
247 case WXR_FORMAT_B8G8R8A8
: return WXR_FORMAT_B8G8R8X8
;
248 default: return format
;
252 static BOOL
get_xrender_template(const WineXRenderFormatTemplate
*fmt
, XRenderPictFormat
*templ
, unsigned long *mask
)
255 templ
->type
= PictTypeDirect
;
256 templ
->depth
= fmt
->depth
;
257 templ
->direct
.alpha
= fmt
->alpha
;
258 templ
->direct
.alphaMask
= fmt
->alphaMask
;
259 templ
->direct
.red
= fmt
->red
;
260 templ
->direct
.redMask
= fmt
->redMask
;
261 templ
->direct
.green
= fmt
->green
;
262 templ
->direct
.greenMask
= fmt
->greenMask
;
263 templ
->direct
.blue
= fmt
->blue
;
264 templ
->direct
.blueMask
= fmt
->blueMask
;
267 *mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
| PictFormatRed
| PictFormatRedMask
| PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
| PictFormatBlueMask
;
272 static BOOL
is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate
*fmt
)
274 if(fmt
->depth
!= default_visual
.depth
) return FALSE
;
275 if( (fmt
->redMask
<< fmt
->red
) != default_visual
.red_mask
) return FALSE
;
276 if( (fmt
->greenMask
<< fmt
->green
) != default_visual
.green_mask
) return FALSE
;
277 if( (fmt
->blueMask
<< fmt
->blue
) != default_visual
.blue_mask
) return FALSE
;
279 /* We never select a default ARGB visual */
280 if(fmt
->alphaMask
) return FALSE
;
284 static int load_xrender_formats(void)
289 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
291 XRenderPictFormat templ
;
293 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template
[i
]))
295 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, default_visual
.visual
);
296 if (!pict_formats
[i
])
298 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
299 if (default_visual
.class == DirectColor
)
302 if (XMatchVisualInfo( gdi_display
, default_visual
.screen
,
303 default_visual
.depth
, TrueColor
, &info
))
305 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, info
.visual
);
306 if (pict_formats
[i
]) default_visual
= info
;
310 if (pict_formats
[i
]) default_format
= i
;
314 unsigned long mask
= 0;
315 get_xrender_template(&wxr_formats_template
[i
], &templ
, &mask
);
316 pict_formats
[i
] = pXRenderFindFormat(gdi_display
, mask
, &templ
, 0);
321 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats
[i
]->id
, i
);
327 /***********************************************************************
328 * X11DRV_XRender_Init
330 * Let's see if our XServer has the extension available
333 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
337 if (!client_side_with_render
) return NULL
;
338 if (!(xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0))) return NULL
;
340 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
341 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
342 LOAD_FUNCPTR(XRenderAddGlyphs
);
343 LOAD_FUNCPTR(XRenderChangePicture
);
344 LOAD_FUNCPTR(XRenderComposite
);
345 LOAD_FUNCPTR(XRenderCompositeText16
);
346 LOAD_FUNCPTR(XRenderCreateGlyphSet
);
347 LOAD_FUNCPTR(XRenderCreatePicture
);
348 LOAD_FUNCPTR(XRenderFillRectangle
);
349 LOAD_FUNCPTR(XRenderFindFormat
);
350 LOAD_FUNCPTR(XRenderFindVisualFormat
);
351 LOAD_FUNCPTR(XRenderFreeGlyphSet
);
352 LOAD_FUNCPTR(XRenderFreePicture
);
353 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
);
354 LOAD_FUNCPTR(XRenderQueryExtension
);
355 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
356 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient
);
358 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
359 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
);
361 #undef LOAD_OPTIONAL_FUNCPTR
364 if (!pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
)) return NULL
;
366 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
367 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
369 ERR_(winediag
)("Wine has detected that you probably have a buggy version "
370 "of libXrender. Because of this client side font rendering "
371 "will be disabled. Please upgrade this library.\n");
375 if (!default_visual
.red_mask
|| !default_visual
.green_mask
|| !default_visual
.blue_mask
)
377 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
381 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
382 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
384 glyphsetCacheSize
= INIT_CACHE_SIZE
;
386 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
387 glyphsetCache
[i
].next
= i
+ 1;
388 glyphsetCache
[i
].count
= -1;
390 glyphsetCache
[i
-1].next
= -1;
392 return &xrender_funcs
;
395 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
396 static void get_xrender_color( struct xrender_physdev
*physdev
, COLORREF src_color
, XRenderColor
*dst_color
)
398 if (src_color
& (1 << 24)) /* PALETTEINDEX */
400 HPALETTE pal
= GetCurrentObject( physdev
->dev
.hdc
, OBJ_PAL
);
401 PALETTEENTRY pal_ent
;
403 if (!GetPaletteEntries( pal
, LOWORD(src_color
), 1, &pal_ent
))
404 GetPaletteEntries( pal
, 0, 1, &pal_ent
);
405 dst_color
->red
= pal_ent
.peRed
* 257;
406 dst_color
->green
= pal_ent
.peGreen
* 257;
407 dst_color
->blue
= pal_ent
.peBlue
* 257;
411 if (src_color
>> 16 == 0x10ff) src_color
= 0; /* DIBINDEX */
413 dst_color
->red
= GetRValue( src_color
) * 257;
414 dst_color
->green
= GetGValue( src_color
) * 257;
415 dst_color
->blue
= GetBValue( src_color
) * 257;
418 if (physdev
->format
== WXR_FORMAT_MONO
&& !dst_color
->red
&& !dst_color
->green
&& !dst_color
->blue
)
419 dst_color
->alpha
= 0;
421 dst_color
->alpha
= 0xffff;
424 static enum wxr_format
get_xrender_format_from_bitmapinfo( const BITMAPINFO
*info
)
426 if (info
->bmiHeader
.biPlanes
!= 1) return WXR_INVALID_FORMAT
;
428 switch (info
->bmiHeader
.biBitCount
)
431 return WXR_FORMAT_MONO
;
436 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
437 return WXR_FORMAT_R8G8B8
;
440 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
442 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
445 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
447 if (info
->bmiHeader
.biBitCount
== wxr_formats_template
[i
].depth
&&
448 colors
[0] == (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
449 colors
[1] == (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
450 colors
[2] == (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
))
455 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
456 return (info
->bmiHeader
.biBitCount
== 16) ? WXR_FORMAT_X1R5G5B5
: WXR_FORMAT_A8R8G8B8
;
458 return WXR_INVALID_FORMAT
;
461 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
462 static void set_xrender_transformation(Picture src_pict
, double xscale
, double yscale
, int xoffset
, int yoffset
)
464 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
465 XTransform xform
= {{
466 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(xoffset
) },
467 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(yoffset
) },
468 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
471 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
475 static void update_xrender_clipping( struct xrender_physdev
*dev
, HRGN rgn
)
477 XRenderPictureAttributes pa
;
483 pXRenderChangePicture( gdi_display
, dev
->pict
, CPClipMask
, &pa
);
485 else if ((data
= X11DRV_GetRegionData( rgn
, 0 )))
487 pXRenderSetPictureClipRectangles( gdi_display
, dev
->pict
,
488 dev
->x11dev
->dc_rect
.left
, dev
->x11dev
->dc_rect
.top
,
489 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
490 HeapFree( GetProcessHeap(), 0, data
);
495 static Picture
get_xrender_picture( struct xrender_physdev
*dev
, HRGN clip_rgn
, const RECT
*clip_rect
)
497 if (!dev
->pict
&& dev
->pict_format
)
499 XRenderPictureAttributes pa
;
501 pa
.subwindow_mode
= IncludeInferiors
;
502 dev
->pict
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
503 dev
->pict_format
, CPSubwindowMode
, &pa
);
504 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
505 dev
->pict
, dev
->dev
.hdc
, dev
->x11dev
->drawable
);
506 dev
->update_clip
= (dev
->region
!= 0);
511 HRGN rgn
= CreateRectRgnIndirect( clip_rect
);
512 if (clip_rgn
) CombineRgn( rgn
, rgn
, clip_rgn
, RGN_AND
);
513 if (dev
->region
) CombineRgn( rgn
, rgn
, dev
->region
, RGN_AND
);
514 update_xrender_clipping( dev
, rgn
);
521 HRGN rgn
= CreateRectRgn( 0, 0, 0, 0 );
522 CombineRgn( rgn
, clip_rgn
, dev
->region
, RGN_AND
);
523 update_xrender_clipping( dev
, rgn
);
526 else update_xrender_clipping( dev
, clip_rgn
);
528 else if (dev
->update_clip
) update_xrender_clipping( dev
, dev
->region
);
530 dev
->update_clip
= (clip_rect
|| clip_rgn
); /* have to update again if we are using a custom region */
534 static Picture
get_xrender_picture_source( struct xrender_physdev
*dev
, BOOL repeat
)
536 if (!dev
->pict_src
&& dev
->pict_format
)
538 XRenderPictureAttributes pa
;
540 pa
.subwindow_mode
= IncludeInferiors
;
541 pa
.repeat
= repeat
? RepeatNormal
: RepeatNone
;
542 dev
->pict_src
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
543 dev
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
545 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
546 dev
->pict_src
, dev
->dev
.hdc
, dev
->x11dev
->drawable
, pa
.repeat
);
549 return dev
->pict_src
;
552 static void free_xrender_picture( struct xrender_physdev
*dev
)
554 if (dev
->pict
|| dev
->pict_src
)
556 XFlush( gdi_display
);
559 TRACE("freeing pict = %lx dc = %p\n", dev
->pict
, dev
->dev
.hdc
);
560 pXRenderFreePicture(gdi_display
, dev
->pict
);
565 TRACE("freeing pict = %lx dc = %p\n", dev
->pict_src
, dev
->dev
.hdc
);
566 pXRenderFreePicture(gdi_display
, dev
->pict_src
);
572 /* return a mask picture used to force alpha to 0 */
573 static Picture
get_no_alpha_mask(void)
575 static Pixmap pixmap
;
578 EnterCriticalSection( &xrender_cs
);
581 XRenderPictureAttributes pa
;
584 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
585 pa
.repeat
= RepeatNormal
;
586 pa
.component_alpha
= True
;
587 pict
= pXRenderCreatePicture( gdi_display
, pixmap
, pict_formats
[WXR_FORMAT_A8R8G8B8
],
588 CPRepeat
|CPComponentAlpha
, &pa
);
589 col
.red
= col
.green
= col
.blue
= 0xffff;
591 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
593 LeaveCriticalSection( &xrender_cs
);
597 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
599 if(p1
->hash
!= p2
->hash
) return TRUE
;
600 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
601 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
602 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
603 return strcmpiW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
607 static void walk_cache(void)
611 EnterCriticalSection(&xrender_cs
);
612 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
613 TRACE("item %d\n", i
);
614 LeaveCriticalSection(&xrender_cs
);
618 static int LookupEntry(LFANDSIZE
*plfsz
)
622 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
624 if(glyphsetCache
[i
].count
== -1) break; /* reached free list so stop */
626 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
627 glyphsetCache
[i
].count
++;
629 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
630 glyphsetCache
[i
].next
= mru
;
633 TRACE("found font in cache %d\n", i
);
638 TRACE("font not in cache\n");
642 static void FreeEntry(int entry
)
646 for (type
= 0; type
< GLYPH_NBTYPES
; type
++)
648 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
649 gsCacheEntryFormat
* formatEntry
;
651 if( !glyphsetCache
[entry
].format
[type
][format
] )
654 formatEntry
= glyphsetCache
[entry
].format
[type
][format
];
656 if(formatEntry
->glyphset
) {
657 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
658 formatEntry
->glyphset
= 0;
660 if(formatEntry
->nrealized
) {
661 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
662 formatEntry
->realized
= NULL
;
663 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
664 formatEntry
->gis
= NULL
;
665 formatEntry
->nrealized
= 0;
668 HeapFree(GetProcessHeap(), 0, formatEntry
);
669 glyphsetCache
[entry
].format
[type
][format
] = NULL
;
674 static int AllocEntry(void)
676 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
679 assert(glyphsetCache
[lastfree
].count
== -1);
680 glyphsetCache
[lastfree
].count
= 1;
682 lastfree
= glyphsetCache
[lastfree
].next
;
684 glyphsetCache
[best
].next
= mru
;
687 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
691 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
692 if(glyphsetCache
[i
].count
== 0) {
700 TRACE("freeing unused glyphset at cache %d\n", best
);
702 glyphsetCache
[best
].count
= 1;
704 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
705 glyphsetCache
[best
].next
= mru
;
713 TRACE("Growing cache\n");
716 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
718 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
719 * sizeof(*glyphsetCache
));
721 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
722 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
723 * sizeof(*glyphsetCache
));
725 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
727 glyphsetCache
[i
].next
= i
+ 1;
728 glyphsetCache
[i
].count
= -1;
730 glyphsetCache
[i
-1].next
= -1;
731 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
733 lastfree
= glyphsetCache
[best
].next
;
734 glyphsetCache
[best
].count
= 1;
735 glyphsetCache
[best
].next
= mru
;
737 TRACE("new free cache slot at %d\n", mru
);
741 static int GetCacheEntry( LFANDSIZE
*plfsz
)
746 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
749 entry
= glyphsetCache
+ ret
;
750 entry
->lfsz
= *plfsz
;
754 static void dec_ref_cache(int index
)
757 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
758 assert(glyphsetCache
[index
].count
> 0);
759 glyphsetCache
[index
].count
--;
762 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
764 DWORD hash
= 0, *ptr
, two_chars
;
768 hash
^= plfsz
->devsize
.cx
;
769 hash
^= plfsz
->devsize
.cy
;
770 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
772 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
774 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
776 pwc
= (WCHAR
*)&two_chars
;
778 *pwc
= toupperW(*pwc
);
780 *pwc
= toupperW(*pwc
);
788 static AA_Type
aa_type_from_flags( UINT aa_flags
)
790 switch (aa_flags
& 0x7f)
794 case WINE_GGO_GRAY16_BITMAP
:
796 case WINE_GGO_HRGB_BITMAP
:
798 case WINE_GGO_HBGR_BITMAP
:
800 case WINE_GGO_VRGB_BITMAP
:
802 case WINE_GGO_VBGR_BITMAP
:
805 FIXME( "unknown flags %x\n", aa_flags
);
810 static UINT
get_xft_aa_flags( const LOGFONTW
*lf
)
815 switch (lf
->lfQuality
)
817 case NONANTIALIASED_QUALITY
:
818 case ANTIALIASED_QUALITY
:
821 if (!(value
= XGetDefault( gdi_display
, "Xft", "antialias" ))) break;
822 TRACE( "got antialias '%s'\n", value
);
823 if (tolower(value
[0]) == 'f' || tolower(value
[0]) == 'n' ||
824 value
[0] == '0' || !strcasecmp( value
, "off" ))
829 ret
= GGO_GRAY4_BITMAP
;
831 case CLEARTYPE_QUALITY
:
832 case CLEARTYPE_NATURAL_QUALITY
:
833 if (!(value
= XGetDefault( gdi_display
, "Xft", "rgba" ))) break;
834 TRACE( "got rgba '%s'\n", value
);
835 if (!strcmp( value
, "rgb" )) ret
= WINE_GGO_HRGB_BITMAP
;
836 else if (!strcmp( value
, "bgr" )) ret
= WINE_GGO_HBGR_BITMAP
;
837 else if (!strcmp( value
, "vrgb" )) ret
= WINE_GGO_VRGB_BITMAP
;
838 else if (!strcmp( value
, "vbgr" )) ret
= WINE_GGO_VBGR_BITMAP
;
839 else if (!strcmp( value
, "none" )) ret
= GGO_GRAY4_BITMAP
;
845 /**********************************************************************
846 * xrenderdrv_SelectFont
848 static HFONT
xrenderdrv_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
851 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
852 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
855 GetObjectW( hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
856 if (!*aa_flags
) *aa_flags
= get_xft_aa_flags( &lfsz
.lf
);
858 ret
= next
->funcs
->pSelectFont( next
, hfont
, aa_flags
);
863 case GGO_GRAY2_BITMAP
:
864 case GGO_GRAY4_BITMAP
:
865 case GGO_GRAY8_BITMAP
:
866 physdev
->aa_flags
= WINE_GGO_GRAY16_BITMAP
;
869 physdev
->aa_flags
= GGO_BITMAP
;
872 physdev
->aa_flags
= *aa_flags
;
876 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
877 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
878 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
879 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
880 lfsz
.devsize
.cx
= X11DRV_XWStoDS( dev
->hdc
, lfsz
.lf
.lfWidth
);
881 lfsz
.devsize
.cy
= X11DRV_YWStoDS( dev
->hdc
, lfsz
.lf
.lfHeight
);
883 GetTransform( dev
->hdc
, 0x204, &lfsz
.xform
);
884 TRACE("font transform %f %f %f %f\n", lfsz
.xform
.eM11
, lfsz
.xform
.eM12
,
885 lfsz
.xform
.eM21
, lfsz
.xform
.eM22
);
887 if (GetGraphicsMode( dev
->hdc
) == GM_COMPATIBLE
)
889 lfsz
.lf
.lfOrientation
= lfsz
.lf
.lfEscapement
;
890 if (lfsz
.xform
.eM11
* lfsz
.xform
.eM22
< 0)
891 lfsz
.lf
.lfOrientation
= -lfsz
.lf
.lfOrientation
;
894 /* Not used fields, would break hashing */
895 lfsz
.xform
.eDx
= lfsz
.xform
.eDy
= 0;
897 lfsz_calc_hash(&lfsz
);
899 EnterCriticalSection(&xrender_cs
);
900 if (physdev
->cache_index
!= -1)
901 dec_ref_cache( physdev
->cache_index
);
902 physdev
->cache_index
= GetCacheEntry( &lfsz
);
903 LeaveCriticalSection(&xrender_cs
);
907 static BOOL
create_xrender_dc( PHYSDEV
*pdev
, enum wxr_format format
)
909 X11DRV_PDEVICE
*x11dev
= get_x11drv_dev( *pdev
);
910 struct xrender_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
912 if (!physdev
) return FALSE
;
913 physdev
->x11dev
= x11dev
;
914 physdev
->cache_index
= -1;
915 physdev
->format
= format
;
916 physdev
->pict_format
= pict_formats
[format
];
917 push_dc_driver( pdev
, &physdev
->dev
, &xrender_funcs
);
921 /* store the color mask data in the bitmap info structure */
922 static void set_color_info( XRenderPictFormat
*format
, BITMAPINFO
*info
)
924 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
926 info
->bmiHeader
.biPlanes
= 1;
927 info
->bmiHeader
.biBitCount
= pixmap_formats
[format
->depth
]->bits_per_pixel
;
928 info
->bmiHeader
.biCompression
= BI_RGB
;
929 info
->bmiHeader
.biClrUsed
= 0;
931 switch (info
->bmiHeader
.biBitCount
)
934 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
935 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
936 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
937 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
940 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
941 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
942 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
943 if (colors
[0] != 0xff0000 || colors
[1] != 0x00ff00 || colors
[2] != 0x0000ff)
944 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
950 /**********************************************************************
951 * xrenderdrv_CreateDC
953 static BOOL
xrenderdrv_CreateDC( PHYSDEV
*pdev
, LPCWSTR driver
, LPCWSTR device
,
954 LPCWSTR output
, const DEVMODEW
* initData
)
956 return create_xrender_dc( pdev
, default_format
);
959 /**********************************************************************
960 * xrenderdrv_CreateCompatibleDC
962 static BOOL
xrenderdrv_CreateCompatibleDC( PHYSDEV orig
, PHYSDEV
*pdev
)
964 if (orig
) /* chain to x11drv first */
966 orig
= GET_NEXT_PHYSDEV( orig
, pCreateCompatibleDC
);
967 if (!orig
->funcs
->pCreateCompatibleDC( orig
, pdev
)) return FALSE
;
969 /* otherwise we have been called by x11drv */
971 return create_xrender_dc( pdev
, WXR_FORMAT_MONO
);
974 /**********************************************************************
975 * xrenderdrv_DeleteDC
977 static BOOL
xrenderdrv_DeleteDC( PHYSDEV dev
)
979 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
981 free_xrender_picture( physdev
);
983 EnterCriticalSection( &xrender_cs
);
984 if (physdev
->cache_index
!= -1) dec_ref_cache( physdev
->cache_index
);
985 LeaveCriticalSection( &xrender_cs
);
987 HeapFree( GetProcessHeap(), 0, physdev
);
991 /**********************************************************************
992 * xrenderdrv_ExtEscape
994 static INT
xrenderdrv_ExtEscape( PHYSDEV dev
, INT escape
, INT in_count
, LPCVOID in_data
,
995 INT out_count
, LPVOID out_data
)
997 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
999 dev
= GET_NEXT_PHYSDEV( dev
, pExtEscape
);
1001 if (escape
== X11DRV_ESCAPE
&& in_data
&& in_count
>= sizeof(enum x11drv_escape_codes
))
1003 if (*(const enum x11drv_escape_codes
*)in_data
== X11DRV_SET_DRAWABLE
)
1005 BOOL ret
= dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
1006 if (ret
) free_xrender_picture( physdev
); /* pict format doesn't change, only drawable */
1010 return dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
1013 /***********************************************************************
1014 * xrenderdrv_SetDeviceClipping
1016 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev
, HRGN rgn
)
1018 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1020 physdev
->region
= rgn
;
1021 physdev
->update_clip
= TRUE
;
1023 dev
= GET_NEXT_PHYSDEV( dev
, pSetDeviceClipping
);
1024 dev
->funcs
->pSetDeviceClipping( dev
, rgn
);
1028 /************************************************************************
1031 * Helper to ExtTextOut. Must be called inside xrender_cs
1033 static void UploadGlyph(struct xrender_physdev
*physDev
, UINT glyph
, enum glyph_type type
)
1035 unsigned int buflen
;
1040 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->cache_index
;
1041 gsCacheEntryFormat
*formatEntry
;
1042 UINT ggo_format
= physDev
->aa_flags
;
1043 AA_Type format
= aa_type_from_flags( physDev
->aa_flags
);
1044 enum wxr_format wxr_format
;
1045 static const char zero
[4];
1046 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
1048 if (type
== GLYPH_INDEX
) ggo_format
|= GGO_GLYPH_INDEX
;
1049 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1050 if(buflen
== GDI_ERROR
) {
1051 if(format
!= AA_None
) {
1053 physDev
->aa_flags
= GGO_BITMAP
;
1054 ggo_format
= (ggo_format
& GGO_GLYPH_INDEX
) | GGO_BITMAP
;
1055 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1057 if(buflen
== GDI_ERROR
) {
1058 WARN("GetGlyphOutlineW failed using default glyph\n");
1059 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0, ggo_format
, &gm
, 0, NULL
, &identity
);
1060 if(buflen
== GDI_ERROR
) {
1061 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1062 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0x20, ggo_format
, &gm
, 0, NULL
, &identity
);
1063 if(buflen
== GDI_ERROR
) {
1064 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1069 TRACE("Turning off antialiasing for this monochrome font\n");
1072 /* If there is nothing for the current type, we create the entry. */
1073 if( !entry
->format
[type
][format
] ) {
1074 entry
->format
[type
][format
] = HeapAlloc(GetProcessHeap(),
1076 sizeof(gsCacheEntryFormat
));
1078 formatEntry
= entry
->format
[type
][format
];
1080 if(formatEntry
->nrealized
<= glyph
) {
1081 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
1083 if (formatEntry
->realized
)
1084 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
1086 formatEntry
->realized
,
1087 formatEntry
->nrealized
* sizeof(BOOL
));
1089 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
1091 formatEntry
->nrealized
* sizeof(BOOL
));
1093 if (formatEntry
->gis
)
1094 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
1097 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1099 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
1101 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1105 if(formatEntry
->glyphset
== 0) {
1108 wxr_format
= WXR_FORMAT_GRAY
;
1115 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1119 ERR("aa = %d - not implemented\n", format
);
1122 wxr_format
= WXR_FORMAT_MONO
;
1126 formatEntry
->font_format
= pict_formats
[wxr_format
];
1127 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
1131 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
1132 GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
1133 formatEntry
->realized
[glyph
] = TRUE
;
1135 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1137 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1138 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1140 gi
.width
= gm
.gmBlackBoxX
;
1141 gi
.height
= gm
.gmBlackBoxY
;
1142 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1143 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1144 gi
.xOff
= gm
.gmCellIncX
;
1145 gi
.yOff
= gm
.gmCellIncY
;
1147 if(TRACE_ON(xrender
)) {
1150 unsigned char *line
;
1152 if(format
== AA_None
) {
1153 pitch
= ((gi
.width
+ 31) / 32) * 4;
1154 for(i
= 0; i
< gi
.height
; i
++) {
1155 line
= (unsigned char*) buf
+ i
* pitch
;
1157 for(j
= 0; j
< pitch
* 8; j
++) {
1158 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1160 TRACE("%s\n", output
);
1163 static const char blks
[] = " .:;!o*#";
1167 pitch
= ((gi
.width
+ 3) / 4) * 4;
1168 for(i
= 0; i
< gi
.height
; i
++) {
1169 line
= (unsigned char*) buf
+ i
* pitch
;
1171 for(j
= 0; j
< pitch
; j
++) {
1172 str
[0] = blks
[line
[j
] >> 5];
1173 strcat(output
, str
);
1175 TRACE("%s\n", output
);
1181 if(formatEntry
->glyphset
) {
1182 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1183 unsigned char *byte
= (unsigned char*) buf
, c
;
1189 /* magic to flip bit order */
1190 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1191 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1192 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1197 else if ( format
!= AA_Grey
&&
1198 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1200 unsigned int i
, *data
= (unsigned int *)buf
;
1201 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1206 XRenderCompositeText seems to ignore 0x0 glyphs when
1207 AA_None, which means we lose the advance width of glyphs
1208 like the space. We'll pretend that such glyphs are 1x1
1213 gi
.width
= gi
.height
= 1;
1215 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1216 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1219 HeapFree(GetProcessHeap(), 0, buf
);
1220 formatEntry
->gis
[glyph
] = gi
;
1223 /*************************************************************
1226 * Returns an appropriate Picture for tiling the text colour.
1227 * Call and use result within the xrender_cs
1229 static Picture
get_tile_pict( enum wxr_format wxr_format
, const XRenderColor
*color
)
1235 XRenderColor current_color
;
1236 } tiles
[WXR_NB_FORMATS
], *tile
;
1238 tile
= &tiles
[wxr_format
];
1242 XRenderPictureAttributes pa
;
1243 XRenderPictFormat
*pict_format
= pict_formats
[wxr_format
];
1245 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_format
->depth
);
1247 pa
.repeat
= RepeatNormal
;
1248 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_format
, CPRepeat
, &pa
);
1250 /* init current_color to something different from text_pixel */
1251 tile
->current_color
= *color
;
1252 tile
->current_color
.red
^= 0xffff;
1254 if (wxr_format
== WXR_FORMAT_MONO
)
1256 /* for a 1bpp bitmap we always need a 1 in the tile */
1258 col
.red
= col
.green
= col
.blue
= 0;
1260 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1264 if (memcmp( color
, &tile
->current_color
, sizeof(*color
) ) && wxr_format
!= WXR_FORMAT_MONO
)
1266 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, color
, 0, 0, 1, 1);
1267 tile
->current_color
= *color
;
1272 /*************************************************************
1275 * Returns an appropriate Picture for masking with the specified alpha.
1276 * Call and use result within the xrender_cs
1278 static Picture
get_mask_pict( int alpha
)
1280 static Pixmap pixmap
;
1281 static Picture pict
;
1282 static int current_alpha
;
1284 if (alpha
== 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1288 XRenderPictureAttributes pa
;
1290 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
1291 pa
.repeat
= RepeatNormal
;
1292 pict
= pXRenderCreatePicture( gdi_display
, pixmap
,
1293 pict_formats
[WXR_FORMAT_A8R8G8B8
], CPRepeat
, &pa
);
1297 if (alpha
!= current_alpha
)
1300 col
.red
= col
.green
= col
.blue
= 0;
1301 col
.alpha
= current_alpha
= alpha
;
1302 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
1307 /***********************************************************************
1308 * xrenderdrv_ExtTextOut
1310 static BOOL
xrenderdrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
,
1311 const RECT
*lprect
, LPCWSTR wstr
, UINT count
, const INT
*lpDx
)
1313 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1314 gsCacheEntry
*entry
;
1315 gsCacheEntryFormat
*formatEntry
;
1317 Picture pict
, tile_pict
= 0;
1319 POINT offset
, desired
, current
;
1320 int render_op
= PictOpOver
;
1323 enum glyph_type type
= (flags
& ETO_GLYPH_INDEX
) ? GLYPH_INDEX
: GLYPH_WCHAR
;
1325 get_xrender_color( physdev
, GetTextColor( physdev
->dev
.hdc
), &col
);
1326 pict
= get_xrender_picture( physdev
, 0, (flags
& ETO_CLIPPED
) ? lprect
: NULL
);
1328 if(flags
& ETO_OPAQUE
)
1332 if (physdev
->format
== WXR_FORMAT_MONO
)
1333 /* use the inverse of the text color */
1334 bg
.red
= bg
.green
= bg
.blue
= bg
.alpha
= ~col
.alpha
;
1336 get_xrender_color( physdev
, GetBkColor( physdev
->dev
.hdc
), &bg
);
1338 set_xrender_transformation( pict
, 1, 1, 0, 0 );
1339 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &bg
,
1340 physdev
->x11dev
->dc_rect
.left
+ lprect
->left
,
1341 physdev
->x11dev
->dc_rect
.top
+ lprect
->top
,
1342 lprect
->right
- lprect
->left
,
1343 lprect
->bottom
- lprect
->top
);
1344 add_device_bounds( physdev
->x11dev
, lprect
);
1347 if(count
== 0) return TRUE
;
1349 EnterCriticalSection(&xrender_cs
);
1351 entry
= glyphsetCache
+ physdev
->cache_index
;
1352 formatEntry
= entry
->format
[type
][aa_type_from_flags( physdev
->aa_flags
)];
1354 for(idx
= 0; idx
< count
; idx
++) {
1355 if( !formatEntry
) {
1356 UploadGlyph(physdev
, wstr
[idx
], type
);
1357 /* re-evaluate format entry since aa_flags may have changed */
1358 formatEntry
= entry
->format
[type
][aa_type_from_flags( physdev
->aa_flags
)];
1359 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1360 UploadGlyph(physdev
, wstr
[idx
], type
);
1365 WARN("could not upload requested glyphs\n");
1366 LeaveCriticalSection(&xrender_cs
);
1370 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1371 physdev
->x11dev
->dc_rect
.left
+ x
, physdev
->x11dev
->dc_rect
.top
+ y
);
1373 elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1375 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1376 So we pass zeros to the function and move to our starting position using the first
1377 element of the elts array. */
1379 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
;
1380 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
;
1381 offset
.x
= offset
.y
= 0;
1382 current
.x
= current
.y
= 0;
1384 tile_pict
= get_tile_pict(physdev
->format
, &col
);
1386 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1388 if (physdev
->format
== WXR_FORMAT_MONO
&& col
.red
== 0 && col
.green
== 0 && col
.blue
== 0)
1389 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1391 reset_bounds( &bounds
);
1392 for(idx
= 0; idx
< count
; idx
++)
1394 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1395 elts
[idx
].chars
= wstr
+ idx
;
1396 elts
[idx
].nchars
= 1;
1397 elts
[idx
].xOff
= desired
.x
- current
.x
;
1398 elts
[idx
].yOff
= desired
.y
- current
.y
;
1400 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1401 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1403 rect
.left
= desired
.x
- physdev
->x11dev
->dc_rect
.left
- formatEntry
->gis
[wstr
[idx
]].x
;
1404 rect
.top
= desired
.y
- physdev
->x11dev
->dc_rect
.top
- formatEntry
->gis
[wstr
[idx
]].y
;
1405 rect
.right
= rect
.left
+ formatEntry
->gis
[wstr
[idx
]].width
;
1406 rect
.bottom
= rect
.top
+ formatEntry
->gis
[wstr
[idx
]].height
;
1407 add_bounds_rect( &bounds
, &rect
);
1411 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1412 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1418 offset
.x
+= lpDx
[idx
* 2];
1419 offset
.y
+= lpDx
[idx
* 2 + 1];
1422 offset
.x
+= lpDx
[idx
];
1423 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
+ offset
.x
;
1424 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
+ offset
.y
;
1428 /* Make sure we don't have any transforms set from a previous call */
1429 set_xrender_transformation(pict
, 1, 1, 0, 0);
1430 pXRenderCompositeText16(gdi_display
, render_op
,
1433 formatEntry
->font_format
,
1434 0, 0, 0, 0, elts
, count
);
1435 HeapFree(GetProcessHeap(), 0, elts
);
1437 LeaveCriticalSection(&xrender_cs
);
1438 add_device_bounds( physdev
->x11dev
, &bounds
);
1442 /* multiply the alpha channel of a picture */
1443 static void multiply_alpha( Picture pict
, XRenderPictFormat
*format
, int alpha
,
1444 int x
, int y
, int width
, int height
)
1446 XRenderPictureAttributes pa
;
1447 Pixmap src_pixmap
, mask_pixmap
;
1448 Picture src_pict
, mask_pict
;
1451 src_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1452 mask_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1453 pa
.repeat
= RepeatNormal
;
1454 src_pict
= pXRenderCreatePicture( gdi_display
, src_pixmap
, format
, CPRepeat
, &pa
);
1455 pa
.component_alpha
= True
;
1456 mask_pict
= pXRenderCreatePicture( gdi_display
, mask_pixmap
, format
, CPRepeat
|CPComponentAlpha
, &pa
);
1457 color
.red
= color
.green
= color
.blue
= color
.alpha
= 0xffff;
1458 pXRenderFillRectangle( gdi_display
, PictOpSrc
, src_pict
, &color
, 0, 0, 1, 1 );
1459 color
.alpha
= alpha
;
1460 pXRenderFillRectangle( gdi_display
, PictOpSrc
, mask_pict
, &color
, 0, 0, 1, 1 );
1461 pXRenderComposite( gdi_display
, PictOpInReverse
, src_pict
, mask_pict
, pict
,
1462 0, 0, 0, 0, x
, y
, width
, height
);
1463 pXRenderFreePicture( gdi_display
, src_pict
);
1464 pXRenderFreePicture( gdi_display
, mask_pict
);
1465 XFreePixmap( gdi_display
, src_pixmap
);
1466 XFreePixmap( gdi_display
, mask_pixmap
);
1469 /* Helper function for (stretched) blitting using xrender */
1470 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
1471 int x_src
, int y_src
, int width_src
, int height_src
,
1472 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1473 double xscale
, double yscale
)
1475 int x_offset
, y_offset
;
1479 x_src
+= width_src
+ 1;
1480 width_src
= -width_src
;
1484 y_src
+= height_src
+ 1;
1485 height_src
= -height_src
;
1489 x_dst
+= width_dst
+ 1;
1490 width_dst
= -width_dst
;
1494 y_dst
+= height_dst
+ 1;
1495 height_dst
= -height_dst
;
1498 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1499 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1500 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1501 if(xscale
!= 1.0 || yscale
!= 1.0)
1503 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1504 * in the wrong quadrant of the x-y plane.
1506 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1507 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1508 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1514 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1516 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
1517 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width_dst
, height_dst
);
1520 /* Helper function for (stretched) mono->color blitting using xrender */
1521 static void xrender_mono_blit( Picture src_pict
, Picture dst_pict
,
1522 enum wxr_format dst_format
, XRenderColor
*fg
, XRenderColor
*bg
,
1523 int x_src
, int y_src
, int width_src
, int height_src
,
1524 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1525 double xscale
, double yscale
)
1528 int x_offset
, y_offset
;
1533 x_src
+= width_src
+ 1;
1534 width_src
= -width_src
;
1538 y_src
+= height_src
+ 1;
1539 height_src
= -height_src
;
1543 x_dst
+= width_dst
+ 1;
1544 width_dst
= -width_dst
;
1548 y_dst
+= height_dst
+ 1;
1549 height_dst
= -height_dst
;
1552 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1553 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1556 EnterCriticalSection( &xrender_cs
);
1558 color
.alpha
= 0xffff; /* tile pict needs 100% alpha */
1559 tile_pict
= get_tile_pict( dst_format
, &color
);
1561 pXRenderFillRectangle( gdi_display
, PictOpSrc
, dst_pict
, fg
, x_dst
, y_dst
, width_dst
, height_dst
);
1563 if (xscale
!= 1.0 || yscale
!= 1.0)
1565 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1566 * in the wrong quadrant of the x-y plane.
1568 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1569 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1570 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1576 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1578 pXRenderComposite(gdi_display
, PictOpOver
, tile_pict
, src_pict
, dst_pict
,
1579 0, 0, x_offset
, y_offset
, x_dst
, y_dst
, width_dst
, height_dst
);
1580 LeaveCriticalSection( &xrender_cs
);
1582 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1583 if (bg
->alpha
!= 0xffff && (dst_format
== WXR_FORMAT_A8R8G8B8
|| dst_format
== WXR_FORMAT_B8G8R8A8
))
1584 multiply_alpha( dst_pict
, pict_formats
[dst_format
], bg
->alpha
,
1585 x_dst
, y_dst
, width_dst
, height_dst
);
1588 /* create a pixmap and render picture for an image */
1589 static DWORD
create_image_pixmap( BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1590 struct bitblt_coords
*src
, enum wxr_format format
,
1591 Pixmap
*pixmap
, Picture
*pict
, BOOL
*use_repeat
)
1594 int width
= src
->visrect
.right
- src
->visrect
.left
;
1595 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1596 int depth
= pict_formats
[format
]->depth
;
1597 struct gdi_image_bits dst_bits
;
1598 XRenderPictureAttributes pa
;
1602 image
= XCreateImage( gdi_display
, default_visual
.visual
, depth
, ZPixmap
, 0, NULL
,
1603 info
->bmiHeader
.biWidth
, height
, 32, 0 );
1604 if (!image
) return ERROR_OUTOFMEMORY
;
1606 ret
= copy_image_bits( info
, (format
== WXR_FORMAT_R8G8B8
), image
, bits
, &dst_bits
, src
, NULL
, ~0u );
1607 if (ret
) return ret
;
1609 image
->data
= dst_bits
.ptr
;
1611 *use_repeat
= (width
== 1 && height
== 1);
1612 pa
.repeat
= *use_repeat
? RepeatNormal
: RepeatNone
;
1614 *pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, depth
);
1615 gc
= XCreateGC( gdi_display
, *pixmap
, 0, NULL
);
1616 XPutImage( gdi_display
, *pixmap
, gc
, image
, src
->visrect
.left
, 0, 0, 0, width
, height
);
1617 *pict
= pXRenderCreatePicture( gdi_display
, *pixmap
, pict_formats
[format
], CPRepeat
, &pa
);
1618 XFreeGC( gdi_display
, gc
);
1620 /* make coordinates relative to the pixmap */
1621 src
->x
-= src
->visrect
.left
;
1622 src
->y
-= src
->visrect
.top
;
1623 OffsetRect( &src
->visrect
, -src
->visrect
.left
, -src
->visrect
.top
);
1626 XDestroyImage( image
);
1627 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
1631 static void xrender_stretch_blit( struct xrender_physdev
*physdev_src
, struct xrender_physdev
*physdev_dst
,
1632 Drawable drawable
, const struct bitblt_coords
*src
,
1633 const struct bitblt_coords
*dst
)
1636 Picture src_pict
= 0, dst_pict
, mask_pict
= 0;
1637 double xscale
= src
->width
/ (double)dst
->width
;
1638 double yscale
= src
->height
/ (double)dst
->height
;
1640 if (drawable
) /* using an intermediate pixmap */
1644 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, physdev_dst
->pict_format
, 0, NULL
);
1648 x_dst
= physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
;
1649 y_dst
= physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
;
1650 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
1653 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
1656 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
1658 XRenderColor fg
, bg
;
1660 get_xrender_color( physdev_dst
, GetTextColor( physdev_dst
->dev
.hdc
), &fg
);
1661 get_xrender_color( physdev_dst
, GetBkColor( physdev_dst
->dev
.hdc
), &bg
);
1662 fg
.alpha
= bg
.alpha
= 0;
1664 xrender_mono_blit( src_pict
, dst_pict
, physdev_dst
->format
, &fg
, &bg
,
1665 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1666 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1667 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1669 else /* color -> color (can be at different depths) or mono -> mono */
1671 if (physdev_dst
->pict_format
->depth
== 32 && physdev_src
->pict_format
->depth
< 32)
1672 mask_pict
= get_no_alpha_mask();
1674 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
1675 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1676 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1677 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1680 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1684 static void xrender_put_image( Pixmap src_pixmap
, Picture src_pict
, Picture mask_pict
, HRGN clip
,
1685 XRenderPictFormat
*dst_format
, struct xrender_physdev
*physdev
,
1686 Drawable drawable
, struct bitblt_coords
*src
,
1687 struct bitblt_coords
*dst
, BOOL use_repeat
)
1691 double xscale
, yscale
;
1693 if (drawable
) /* using an intermediate pixmap */
1695 RGNDATA
*clip_data
= NULL
;
1697 if (clip
) clip_data
= X11DRV_GetRegionData( clip
, 0 );
1700 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, dst_format
, 0, NULL
);
1702 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
, 0, 0,
1703 (XRectangle
*)clip_data
->Buffer
, clip_data
->rdh
.nCount
);
1704 HeapFree( GetProcessHeap(), 0, clip_data
);
1708 x_dst
= physdev
->x11dev
->dc_rect
.left
+ dst
->x
;
1709 y_dst
= physdev
->x11dev
->dc_rect
.top
+ dst
->y
;
1710 dst_pict
= get_xrender_picture( physdev
, clip
, &dst
->visrect
);
1715 xscale
= src
->width
/ (double)dst
->width
;
1716 yscale
= src
->height
/ (double)dst
->height
;
1718 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
1720 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
, src
->x
, src
->y
, src
->width
, src
->height
,
1721 x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1723 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1727 /***********************************************************************
1728 * xrenderdrv_StretchBlt
1730 static BOOL
xrenderdrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
1731 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
1733 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
1734 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
1735 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
1737 if (src_dev
->funcs
!= dst_dev
->funcs
)
1739 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pStretchBlt
);
1740 return dst_dev
->funcs
->pStretchBlt( dst_dev
, dst
, src_dev
, src
, rop
);
1743 /* XRender is of no use for color -> mono */
1744 if (physdev_dst
->format
== WXR_FORMAT_MONO
&& physdev_src
->format
!= WXR_FORMAT_MONO
)
1745 goto x11drv_fallback
;
1747 /* if not stretching, we only need to handle format conversion */
1748 if (!stretch
&& physdev_dst
->format
== physdev_src
->format
) goto x11drv_fallback
;
1754 struct bitblt_coords tmp
;
1756 /* make coordinates relative to tmp pixmap */
1758 tmp
.x
-= tmp
.visrect
.left
;
1759 tmp
.y
-= tmp
.visrect
.top
;
1760 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
1762 tmpGC
= XCreateGC( gdi_display
, physdev_dst
->x11dev
->drawable
, 0, NULL
);
1763 XSetSubwindowMode( gdi_display
, tmpGC
, IncludeInferiors
);
1764 XSetGraphicsExposures( gdi_display
, tmpGC
, False
);
1765 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, tmp
.visrect
.right
- tmp
.visrect
.left
,
1766 tmp
.visrect
.bottom
- tmp
.visrect
.top
, physdev_dst
->pict_format
->depth
);
1768 xrender_stretch_blit( physdev_src
, physdev_dst
, tmp_pixmap
, src
, &tmp
);
1769 execute_rop( physdev_dst
->x11dev
, tmp_pixmap
, tmpGC
, &dst
->visrect
, rop
);
1771 XFreePixmap( gdi_display
, tmp_pixmap
);
1772 XFreeGC( gdi_display
, tmpGC
);
1774 else xrender_stretch_blit( physdev_src
, physdev_dst
, 0, src
, dst
);
1776 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
1780 return X11DRV_StretchBlt( &physdev_dst
->x11dev
->dev
, dst
, &physdev_src
->x11dev
->dev
, src
, rop
);
1784 /***********************************************************************
1785 * xrenderdrv_PutImage
1787 static DWORD
xrenderdrv_PutImage( PHYSDEV dev
, HRGN clip
, BITMAPINFO
*info
,
1788 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
1789 struct bitblt_coords
*dst
, DWORD rop
)
1791 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1795 enum wxr_format src_format
, dst_format
;
1796 XRenderPictFormat
*pict_format
;
1798 Picture src_pict
, mask_pict
= 0;
1801 dst_format
= physdev
->format
;
1802 src_format
= get_xrender_format_from_bitmapinfo( info
);
1803 if (!(pict_format
= pict_formats
[src_format
])) goto update_format
;
1805 /* make sure we can create an image with the same bpp */
1806 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
1809 /* mono <-> color conversions not supported */
1810 if ((src_format
!= dst_format
) && (src_format
== WXR_FORMAT_MONO
|| dst_format
== WXR_FORMAT_MONO
))
1811 goto x11drv_fallback
;
1813 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
1815 if (!has_alpha( src_format
) && has_alpha( dst_format
)) mask_pict
= get_no_alpha_mask();
1817 ret
= create_image_pixmap( info
, bits
, src
, src_format
, &src_pixmap
, &src_pict
, &use_repeat
);
1820 struct bitblt_coords tmp
;
1824 BOOL restore_region
= add_extra_clipping_region( physdev
->x11dev
, clip
);
1826 /* make coordinates relative to tmp pixmap */
1828 tmp
.x
-= tmp
.visrect
.left
;
1829 tmp
.y
-= tmp
.visrect
.top
;
1830 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
1832 gc
= XCreateGC( gdi_display
, physdev
->x11dev
->drawable
, 0, NULL
);
1833 XSetSubwindowMode( gdi_display
, gc
, IncludeInferiors
);
1834 XSetGraphicsExposures( gdi_display
, gc
, False
);
1835 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
,
1836 tmp
.visrect
.right
- tmp
.visrect
.left
,
1837 tmp
.visrect
.bottom
- tmp
.visrect
.top
,
1838 physdev
->pict_format
->depth
);
1840 xrender_put_image( src_pixmap
, src_pict
, mask_pict
, NULL
, physdev
->pict_format
,
1841 NULL
, tmp_pixmap
, src
, &tmp
, use_repeat
);
1842 execute_rop( physdev
->x11dev
, tmp_pixmap
, gc
, &dst
->visrect
, rop
);
1844 XFreePixmap( gdi_display
, tmp_pixmap
);
1845 XFreeGC( gdi_display
, gc
);
1846 if (restore_region
) restore_clipping_region( physdev
->x11dev
);
1848 else xrender_put_image( src_pixmap
, src_pict
, mask_pict
, clip
,
1849 physdev
->pict_format
, physdev
, 0, src
, dst
, use_repeat
);
1851 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
1853 pXRenderFreePicture( gdi_display
, src_pict
);
1854 XFreePixmap( gdi_display
, src_pixmap
);
1859 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
1860 set_color_info( pict_formats
[dst_format
], info
);
1861 return ERROR_BAD_FORMAT
;
1864 dev
= GET_NEXT_PHYSDEV( dev
, pPutImage
);
1865 return dev
->funcs
->pPutImage( dev
, clip
, info
, bits
, src
, dst
, rop
);
1869 /***********************************************************************
1870 * xrenderdrv_BlendImage
1872 static DWORD
xrenderdrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1873 struct bitblt_coords
*src
, struct bitblt_coords
*dst
,
1874 BLENDFUNCTION func
)
1876 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1878 enum wxr_format format
;
1879 XRenderPictFormat
*pict_format
;
1880 Picture dst_pict
, src_pict
, mask_pict
;
1884 format
= get_xrender_format_from_bitmapinfo( info
);
1885 if (!(func
.AlphaFormat
& AC_SRC_ALPHA
))
1886 format
= get_format_without_alpha( format
);
1887 else if (format
!= WXR_FORMAT_A8R8G8B8
|| info
->bmiHeader
.biCompression
!= BI_RGB
)
1888 return ERROR_INVALID_PARAMETER
;
1890 if (!(pict_format
= pict_formats
[format
])) goto update_format
;
1892 /* make sure we can create an image with the same bpp */
1893 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
1896 if (format
== WXR_FORMAT_MONO
&& physdev
->format
!= WXR_FORMAT_MONO
)
1899 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
1901 ret
= create_image_pixmap( info
, bits
, src
, format
, &src_pixmap
, &src_pict
, &use_repeat
);
1904 double xscale
, yscale
;
1908 xscale
= src
->width
/ (double)dst
->width
;
1909 yscale
= src
->height
/ (double)dst
->height
;
1911 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
1913 dst_pict
= get_xrender_picture( physdev
, 0, &dst
->visrect
);
1915 EnterCriticalSection( &xrender_cs
);
1916 mask_pict
= get_mask_pict( func
.SourceConstantAlpha
* 257 );
1918 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
1919 src
->x
, src
->y
, src
->width
, src
->height
,
1920 physdev
->x11dev
->dc_rect
.left
+ dst
->x
,
1921 physdev
->x11dev
->dc_rect
.top
+ dst
->y
,
1922 dst
->width
, dst
->height
, xscale
, yscale
);
1924 pXRenderFreePicture( gdi_display
, src_pict
);
1925 XFreePixmap( gdi_display
, src_pixmap
);
1927 LeaveCriticalSection( &xrender_cs
);
1928 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
1933 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
1934 set_color_info( physdev
->pict_format
, info
);
1935 return ERROR_BAD_FORMAT
;
1939 /***********************************************************************
1940 * xrenderdrv_AlphaBlend
1942 static BOOL
xrenderdrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
1943 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
1945 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
1946 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
1947 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
1948 XRenderPictureAttributes pa
;
1949 Pixmap tmp_pixmap
= 0;
1950 double xscale
, yscale
;
1952 if (src_dev
->funcs
!= dst_dev
->funcs
)
1954 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pAlphaBlend
);
1955 return dst_dev
->funcs
->pAlphaBlend( dst_dev
, dst
, src_dev
, src
, blendfn
);
1958 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->format
!= WXR_FORMAT_A8R8G8B8
)
1960 SetLastError( ERROR_INVALID_PARAMETER
);
1964 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
1966 xscale
= src
->width
/ (double)dst
->width
;
1967 yscale
= src
->height
/ (double)dst
->height
;
1969 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
1971 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
1973 /* mono -> color blending needs an intermediate color pixmap */
1974 XRenderColor fg
, bg
;
1975 int width
= src
->visrect
.right
- src
->visrect
.left
;
1976 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1978 /* blending doesn't use the destination DC colors */
1979 fg
.red
= fg
.green
= fg
.blue
= 0;
1980 bg
.red
= bg
.green
= bg
.blue
= 0xffff;
1981 fg
.alpha
= bg
.alpha
= 0xffff;
1983 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
,
1984 physdev_dst
->pict_format
->depth
);
1985 tmp_pict
= pXRenderCreatePicture( gdi_display
, tmp_pixmap
, physdev_dst
->pict_format
, 0, NULL
);
1987 xrender_mono_blit( src_pict
, tmp_pict
, physdev_dst
->format
, &fg
, &bg
,
1988 src
->visrect
.left
, src
->visrect
.top
, width
, height
, 0, 0, width
, height
, 1, 1 );
1990 else if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->pict_format
)
1992 /* we need a source picture with no alpha */
1993 enum wxr_format format
= get_format_without_alpha( physdev_src
->format
);
1994 if (format
!= physdev_src
->format
)
1996 pa
.subwindow_mode
= IncludeInferiors
;
1997 tmp_pict
= pXRenderCreatePicture( gdi_display
, physdev_src
->x11dev
->drawable
,
1998 pict_formats
[format
], CPSubwindowMode
, &pa
);
2002 if (tmp_pict
) src_pict
= tmp_pict
;
2004 EnterCriticalSection( &xrender_cs
);
2005 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
2007 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2008 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
2009 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
2010 src
->width
, src
->height
,
2011 physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
,
2012 physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
,
2013 dst
->width
, dst
->height
, xscale
, yscale
);
2015 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
2016 if (tmp_pixmap
) XFreePixmap( gdi_display
, tmp_pixmap
);
2018 LeaveCriticalSection( &xrender_cs
);
2019 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
2023 /***********************************************************************
2024 * xrenderdrv_GradientFill
2026 static BOOL
xrenderdrv_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
2027 void * grad_array
, ULONG ngrad
, ULONG mode
)
2029 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2030 static const XFixed stops
[2] = { 0, 1 << 16 };
2031 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2032 XLinearGradient gradient
;
2033 XRenderColor colors
[2];
2034 Picture src_pict
, dst_pict
;
2036 const GRADIENT_RECT
*rect
= grad_array
;
2040 if (!pXRenderCreateLinearGradient
) goto fallback
;
2042 /* <= 16-bpp uses dithering */
2043 if (!physdev
->pict_format
|| physdev
->pict_format
->depth
<= 16) goto fallback
;
2047 case GRADIENT_FILL_RECT_H
:
2048 case GRADIENT_FILL_RECT_V
:
2049 for (i
= 0; i
< ngrad
; i
++, rect
++)
2051 const TRIVERTEX
*v1
= vert_array
+ rect
->UpperLeft
;
2052 const TRIVERTEX
*v2
= vert_array
+ rect
->LowerRight
;
2054 colors
[0].red
= v1
->Red
* 257 / 256;
2055 colors
[0].green
= v1
->Green
* 257 / 256;
2056 colors
[0].blue
= v1
->Blue
* 257 / 256;
2057 colors
[1].red
= v2
->Red
* 257 / 256;
2058 colors
[1].green
= v2
->Green
* 257 / 256;
2059 colors
[1].blue
= v2
->Blue
* 257 / 256;
2060 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2061 colors
[0].alpha
= colors
[1].alpha
= 65535;
2067 LPtoDP( dev
->hdc
, pt
, 2 );
2068 if (mode
== GRADIENT_FILL_RECT_H
)
2070 gradient
.p1
.y
= gradient
.p2
.y
= 0;
2071 if (pt
[1].x
> pt
[0].x
)
2074 gradient
.p2
.x
= (pt
[1].x
- pt
[0].x
) << 16;
2078 gradient
.p1
.x
= (pt
[0].x
- pt
[1].x
) << 16;
2084 gradient
.p1
.x
= gradient
.p2
.x
= 0;
2085 if (pt
[1].y
> pt
[0].y
)
2088 gradient
.p2
.y
= (pt
[1].y
- pt
[0].y
) << 16;
2092 gradient
.p1
.y
= (pt
[0].y
- pt
[1].y
) << 16;
2097 rc
.left
= min( pt
[0].x
, pt
[1].x
);
2098 rc
.top
= min( pt
[0].y
, pt
[1].y
);
2099 rc
.right
= max( pt
[0].x
, pt
[1].x
);
2100 rc
.bottom
= max( pt
[0].y
, pt
[1].y
);
2102 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2103 mode
, wine_dbgstr_rect( &rc
),
2104 colors
[0].red
, colors
[0].green
, colors
[0].blue
, colors
[0].alpha
,
2105 colors
[1].red
, colors
[1].green
, colors
[1].blue
, colors
[1].alpha
);
2107 dst_pict
= get_xrender_picture( physdev
, 0, NULL
);
2109 src_pict
= pXRenderCreateLinearGradient( gdi_display
, &gradient
, stops
, colors
, 2 );
2110 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
,
2111 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
2112 physdev
->x11dev
->dc_rect
.left
+ rc
.left
,
2113 physdev
->x11dev
->dc_rect
.top
+ rc
.top
,
2114 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, 1, 1 );
2115 pXRenderFreePicture( gdi_display
, src_pict
);
2116 add_device_bounds( physdev
->x11dev
, &rc
);
2123 dev
= GET_NEXT_PHYSDEV( dev
, pGradientFill
);
2124 return dev
->funcs
->pGradientFill( dev
, vert_array
, nvert
, grad_array
, ngrad
, mode
);
2127 /***********************************************************************
2128 * xrenderdrv_SelectBrush
2130 static HBRUSH
xrenderdrv_SelectBrush( PHYSDEV dev
, HBRUSH hbrush
, const struct brush_pattern
*pattern
)
2132 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2134 XVisualInfo vis
= default_visual
;
2135 XRenderPictFormat
*format
= physdev
->pict_format
;
2137 if (!pattern
) goto x11drv_fallback
;
2138 if (pattern
->info
->bmiHeader
.biBitCount
== 1) goto x11drv_fallback
;
2139 if (physdev
->format
== WXR_FORMAT_MONO
) goto x11drv_fallback
;
2141 vis
.depth
= format
->depth
;
2142 vis
.red_mask
= format
->direct
.redMask
<< format
->direct
.red
;
2143 vis
.green_mask
= format
->direct
.greenMask
<< format
->direct
.green
;
2144 vis
.blue_mask
= format
->direct
.blueMask
<< format
->direct
.blue
;
2146 pixmap
= create_pixmap_from_image( physdev
->dev
.hdc
, &vis
, pattern
->info
,
2147 &pattern
->bits
, pattern
->usage
);
2148 if (!pixmap
) return 0;
2150 if (physdev
->x11dev
->brush
.pixmap
) XFreePixmap( gdi_display
, physdev
->x11dev
->brush
.pixmap
);
2151 physdev
->x11dev
->brush
.pixmap
= pixmap
;
2152 physdev
->x11dev
->brush
.fillStyle
= FillTiled
;
2153 physdev
->x11dev
->brush
.pixel
= 0; /* ignored */
2154 physdev
->x11dev
->brush
.style
= BS_PATTERN
;
2158 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBrush
);
2159 return dev
->funcs
->pSelectBrush( dev
, hbrush
, pattern
);
2163 static const struct gdi_dc_funcs xrender_funcs
=
2165 NULL
, /* pAbortDoc */
2166 NULL
, /* pAbortPath */
2167 xrenderdrv_AlphaBlend
, /* pAlphaBlend */
2168 NULL
, /* pAngleArc */
2171 NULL
, /* pBeginPath */
2172 xrenderdrv_BlendImage
, /* pBlendImage */
2174 NULL
, /* pCloseFigure */
2175 xrenderdrv_CreateCompatibleDC
, /* pCreateCompatibleDC */
2176 xrenderdrv_CreateDC
, /* pCreateDC */
2177 xrenderdrv_DeleteDC
, /* pDeleteDC */
2178 NULL
, /* pDeleteObject */
2179 NULL
, /* pDeviceCapabilities */
2180 NULL
, /* pEllipse */
2182 NULL
, /* pEndPage */
2183 NULL
, /* pEndPath */
2184 NULL
, /* pEnumFonts */
2185 NULL
, /* pEnumICMProfiles */
2186 NULL
, /* pExcludeClipRect */
2187 NULL
, /* pExtDeviceMode */
2188 xrenderdrv_ExtEscape
, /* pExtEscape */
2189 NULL
, /* pExtFloodFill */
2190 NULL
, /* pExtSelectClipRgn */
2191 xrenderdrv_ExtTextOut
, /* pExtTextOut */
2192 NULL
, /* pFillPath */
2193 NULL
, /* pFillRgn */
2194 NULL
, /* pFlattenPath */
2195 NULL
, /* pFontIsLinked */
2196 NULL
, /* pFrameRgn */
2197 NULL
, /* pGdiComment */
2198 NULL
, /* pGdiRealizationInfo */
2199 NULL
, /* pGetBoundsRect */
2200 NULL
, /* pGetCharABCWidths */
2201 NULL
, /* pGetCharABCWidthsI */
2202 NULL
, /* pGetCharWidth */
2203 NULL
, /* pGetDeviceCaps */
2204 NULL
, /* pGetDeviceGammaRamp */
2205 NULL
, /* pGetFontData */
2206 NULL
, /* pGetFontUnicodeRanges */
2207 NULL
, /* pGetGlyphIndices */
2208 NULL
, /* pGetGlyphOutline */
2209 NULL
, /* pGetICMProfile */
2210 NULL
, /* pGetImage */
2211 NULL
, /* pGetKerningPairs */
2212 NULL
, /* pGetNearestColor */
2213 NULL
, /* pGetOutlineTextMetrics */
2214 NULL
, /* pGetPixel */
2215 NULL
, /* pGetSystemPaletteEntries */
2216 NULL
, /* pGetTextCharsetInfo */
2217 NULL
, /* pGetTextExtentExPoint */
2218 NULL
, /* pGetTextExtentExPointI */
2219 NULL
, /* pGetTextFace */
2220 NULL
, /* pGetTextMetrics */
2221 xrenderdrv_GradientFill
, /* pGradientFill */
2222 NULL
, /* pIntersectClipRect */
2223 NULL
, /* pInvertRgn */
2225 NULL
, /* pModifyWorldTransform */
2227 NULL
, /* pOffsetClipRgn */
2228 NULL
, /* pOffsetViewportOrg */
2229 NULL
, /* pOffsetWindowOrg */
2230 NULL
, /* pPaintRgn */
2233 NULL
, /* pPolyBezier */
2234 NULL
, /* pPolyBezierTo */
2235 NULL
, /* pPolyDraw */
2236 NULL
, /* pPolyPolygon */
2237 NULL
, /* pPolyPolyline */
2238 NULL
, /* pPolygon */
2239 NULL
, /* pPolyline */
2240 NULL
, /* pPolylineTo */
2241 xrenderdrv_PutImage
, /* pPutImage */
2242 NULL
, /* pRealizeDefaultPalette */
2243 NULL
, /* pRealizePalette */
2244 NULL
, /* pRectangle */
2245 NULL
, /* pResetDC */
2246 NULL
, /* pRestoreDC */
2247 NULL
, /* pRoundRect */
2249 NULL
, /* pScaleViewportExt */
2250 NULL
, /* pScaleWindowExt */
2251 NULL
, /* pSelectBitmap */
2252 xrenderdrv_SelectBrush
, /* pSelectBrush */
2253 NULL
, /* pSelectClipPath */
2254 xrenderdrv_SelectFont
, /* pSelectFont */
2255 NULL
, /* pSelectPalette */
2256 NULL
, /* pSelectPen */
2257 NULL
, /* pSetArcDirection */
2258 NULL
, /* pSetBkColor */
2259 NULL
, /* pSetBkMode */
2260 NULL
, /* pSetBoundsRect */
2261 NULL
, /* pSetDCBrushColor */
2262 NULL
, /* pSetDCPenColor */
2263 NULL
, /* pSetDIBitsToDevice */
2264 xrenderdrv_SetDeviceClipping
, /* pSetDeviceClipping */
2265 NULL
, /* pSetDeviceGammaRamp */
2266 NULL
, /* pSetLayout */
2267 NULL
, /* pSetMapMode */
2268 NULL
, /* pSetMapperFlags */
2269 NULL
, /* pSetPixel */
2270 NULL
, /* pSetPolyFillMode */
2271 NULL
, /* pSetROP2 */
2272 NULL
, /* pSetRelAbs */
2273 NULL
, /* pSetStretchBltMode */
2274 NULL
, /* pSetTextAlign */
2275 NULL
, /* pSetTextCharacterExtra */
2276 NULL
, /* pSetTextColor */
2277 NULL
, /* pSetTextJustification */
2278 NULL
, /* pSetViewportExt */
2279 NULL
, /* pSetViewportOrg */
2280 NULL
, /* pSetWindowExt */
2281 NULL
, /* pSetWindowOrg */
2282 NULL
, /* pSetWorldTransform */
2283 NULL
, /* pStartDoc */
2284 NULL
, /* pStartPage */
2285 xrenderdrv_StretchBlt
, /* pStretchBlt */
2286 NULL
, /* pStretchDIBits */
2287 NULL
, /* pStrokeAndFillPath */
2288 NULL
, /* pStrokePath */
2289 NULL
, /* pUnrealizePalette */
2290 NULL
, /* pWidenPath */
2291 NULL
, /* wine_get_wgl_driver */
2292 GDI_PRIORITY_GRAPHICS_DRV
+ 10 /* priority */
2295 #else /* SONAME_LIBXRENDER */
2297 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
2299 TRACE("XRender support not compiled in.\n");
2303 #endif /* SONAME_LIBXRENDER */