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 int using_client_side_fonts
= FALSE
;
43 WINE_DEFAULT_DEBUG_CHANNEL(xrender
);
45 #ifdef SONAME_LIBXRENDER
47 static BOOL X11DRV_XRender_Installed
= FALSE
;
50 #include <X11/extensions/Xrender.h>
52 #ifndef RepeatNone /* added in 0.10 */
54 #define RepeatNormal 1
56 #define RepeatReflect 3
74 WXR_INVALID_FORMAT
= WXR_NB_FORMATS
77 typedef struct wine_xrender_format_template
81 unsigned int alphaMask
;
85 unsigned int greenMask
;
87 unsigned int blueMask
;
88 } WineXRenderFormatTemplate
;
90 static const WineXRenderFormatTemplate wxr_formats_template
[WXR_NB_FORMATS
] =
92 /* Format depth alpha mask red mask green mask blue mask*/
93 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
94 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
95 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
96 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
97 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
98 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
99 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
101 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
103 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
107 static enum wxr_format default_format
;
108 static XRenderPictFormat
*pict_formats
[WXR_NB_FORMATS
+ 1 /* invalid format */];
114 SIZE devsize
; /* size in device coords */
118 #define INITIAL_REALIZED_BUF_SIZE 128
120 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
125 XRenderPictFormat
*font_format
;
130 } gsCacheEntryFormat
;
136 gsCacheEntryFormat
* format
[AA_MAXVALUE
];
141 struct xrender_physdev
143 struct gdi_physdev dev
;
144 X11DRV_PDEVICE
*x11dev
;
145 enum wxr_format format
;
150 XRenderPictFormat
*pict_format
;
153 static inline struct xrender_physdev
*get_xrender_dev( PHYSDEV dev
)
155 return (struct xrender_physdev
*)dev
;
158 static const struct gdi_dc_funcs xrender_funcs
;
160 static gsCacheEntry
*glyphsetCache
= NULL
;
161 static DWORD glyphsetCacheSize
= 0;
162 static INT lastfree
= -1;
165 #define INIT_CACHE_SIZE 10
167 static int antialias
= 1;
169 static void *xrender_handle
;
171 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
172 MAKE_FUNCPTR(XRenderAddGlyphs
)
173 MAKE_FUNCPTR(XRenderComposite
)
174 MAKE_FUNCPTR(XRenderCompositeString8
)
175 MAKE_FUNCPTR(XRenderCompositeString16
)
176 MAKE_FUNCPTR(XRenderCompositeString32
)
177 MAKE_FUNCPTR(XRenderCompositeText16
)
178 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
179 MAKE_FUNCPTR(XRenderCreatePicture
)
180 MAKE_FUNCPTR(XRenderFillRectangle
)
181 MAKE_FUNCPTR(XRenderFindFormat
)
182 MAKE_FUNCPTR(XRenderFindVisualFormat
)
183 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
184 MAKE_FUNCPTR(XRenderFreePicture
)
185 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
186 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
187 MAKE_FUNCPTR(XRenderSetPictureTransform
)
189 MAKE_FUNCPTR(XRenderQueryExtension
)
191 #ifdef SONAME_LIBFONTCONFIG
192 #include <fontconfig/fontconfig.h>
193 MAKE_FUNCPTR(FcConfigSubstitute
)
194 MAKE_FUNCPTR(FcDefaultSubstitute
)
195 MAKE_FUNCPTR(FcFontMatch
)
197 MAKE_FUNCPTR(FcPatternCreate
)
198 MAKE_FUNCPTR(FcPatternDestroy
)
199 MAKE_FUNCPTR(FcPatternAddInteger
)
200 MAKE_FUNCPTR(FcPatternAddString
)
201 MAKE_FUNCPTR(FcPatternGetBool
)
202 MAKE_FUNCPTR(FcPatternGetInteger
)
203 MAKE_FUNCPTR(FcPatternGetString
)
204 static void *fontconfig_handle
;
205 static BOOL fontconfig_installed
;
210 static CRITICAL_SECTION xrender_cs
;
211 static CRITICAL_SECTION_DEBUG critsect_debug
=
214 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
215 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
217 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
219 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
220 ( ( (ULONG)_x4 << 24 ) | \
221 ( (ULONG)_x3 << 16 ) | \
222 ( (ULONG)_x2 << 8 ) | \
225 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
227 #define GASP_GRIDFIT 0x01
228 #define GASP_DOGRAY 0x02
230 #ifdef WORDS_BIGENDIAN
231 #define get_be_word(x) (x)
232 #define NATIVE_BYTE_ORDER MSBFirst
234 #define get_be_word(x) RtlUshortByteSwap(x)
235 #define NATIVE_BYTE_ORDER LSBFirst
238 static enum wxr_format
get_format_without_alpha( enum wxr_format format
)
242 case WXR_FORMAT_A8R8G8B8
: return WXR_FORMAT_X8R8G8B8
;
243 case WXR_FORMAT_B8G8R8A8
: return WXR_FORMAT_B8G8R8X8
;
244 default: return format
;
248 static BOOL
get_xrender_template(const WineXRenderFormatTemplate
*fmt
, XRenderPictFormat
*templ
, unsigned long *mask
)
251 templ
->type
= PictTypeDirect
;
252 templ
->depth
= fmt
->depth
;
253 templ
->direct
.alpha
= fmt
->alpha
;
254 templ
->direct
.alphaMask
= fmt
->alphaMask
;
255 templ
->direct
.red
= fmt
->red
;
256 templ
->direct
.redMask
= fmt
->redMask
;
257 templ
->direct
.green
= fmt
->green
;
258 templ
->direct
.greenMask
= fmt
->greenMask
;
259 templ
->direct
.blue
= fmt
->blue
;
260 templ
->direct
.blueMask
= fmt
->blueMask
;
263 *mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
| PictFormatRed
| PictFormatRedMask
| PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
| PictFormatBlueMask
;
268 static BOOL
is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate
*fmt
)
270 if(fmt
->depth
!= screen_depth
)
272 if( (fmt
->redMask
<< fmt
->red
) != visual
->red_mask
)
274 if( (fmt
->greenMask
<< fmt
->green
) != visual
->green_mask
)
276 if( (fmt
->blueMask
<< fmt
->blue
) != visual
->blue_mask
)
279 /* We never select a default ARGB visual */
286 static int load_xrender_formats(void)
291 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
293 XRenderPictFormat templ
;
295 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template
[i
]))
298 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, visual
);
299 if (!pict_formats
[i
])
301 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
302 if (visual
->class == DirectColor
)
305 if (XMatchVisualInfo( gdi_display
, DefaultScreen(gdi_display
),
306 screen_depth
, TrueColor
, &info
))
308 pict_formats
[i
] = pXRenderFindVisualFormat(gdi_display
, info
.visual
);
309 if (pict_formats
[i
]) visual
= info
.visual
;
314 if (pict_formats
[i
]) default_format
= i
;
318 unsigned long mask
= 0;
319 get_xrender_template(&wxr_formats_template
[i
], &templ
, &mask
);
322 pict_formats
[i
] = pXRenderFindFormat(gdi_display
, mask
, &templ
, 0);
328 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats
[i
]->id
, i
);
334 /***********************************************************************
335 * X11DRV_XRender_Init
337 * Let's see if our XServer has the extension available
340 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
344 if (client_side_with_render
&&
345 (xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0)))
348 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
349 LOAD_FUNCPTR(XRenderAddGlyphs
)
350 LOAD_FUNCPTR(XRenderComposite
)
351 LOAD_FUNCPTR(XRenderCompositeString8
)
352 LOAD_FUNCPTR(XRenderCompositeString16
)
353 LOAD_FUNCPTR(XRenderCompositeString32
)
354 LOAD_FUNCPTR(XRenderCompositeText16
)
355 LOAD_FUNCPTR(XRenderCreateGlyphSet
)
356 LOAD_FUNCPTR(XRenderCreatePicture
)
357 LOAD_FUNCPTR(XRenderFillRectangle
)
358 LOAD_FUNCPTR(XRenderFindFormat
)
359 LOAD_FUNCPTR(XRenderFindVisualFormat
)
360 LOAD_FUNCPTR(XRenderFreeGlyphSet
)
361 LOAD_FUNCPTR(XRenderFreePicture
)
362 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
)
363 LOAD_FUNCPTR(XRenderQueryExtension
)
365 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
366 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
367 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
)
368 #undef LOAD_OPTIONAL_FUNCPTR
372 X11DRV_XRender_Installed
= pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
);
374 if(X11DRV_XRender_Installed
) {
375 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
376 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
380 "Wine has detected that you probably have a buggy version\n"
381 "of libXrender.so . Because of this client side font rendering\n"
382 "will be disabled. Please upgrade this library.\n");
383 X11DRV_XRender_Installed
= FALSE
;
387 if (!visual
->red_mask
|| !visual
->green_mask
|| !visual
->blue_mask
) {
388 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
389 X11DRV_XRender_Installed
= FALSE
;
394 #ifdef SONAME_LIBFONTCONFIG
395 if ((fontconfig_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0)))
397 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fontconfig_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
398 LOAD_FUNCPTR(FcConfigSubstitute
);
399 LOAD_FUNCPTR(FcDefaultSubstitute
);
400 LOAD_FUNCPTR(FcFontMatch
);
401 LOAD_FUNCPTR(FcInit
);
402 LOAD_FUNCPTR(FcPatternCreate
);
403 LOAD_FUNCPTR(FcPatternDestroy
);
404 LOAD_FUNCPTR(FcPatternAddInteger
);
405 LOAD_FUNCPTR(FcPatternAddString
);
406 LOAD_FUNCPTR(FcPatternGetBool
);
407 LOAD_FUNCPTR(FcPatternGetInteger
);
408 LOAD_FUNCPTR(FcPatternGetString
);
410 fontconfig_installed
= pFcInit();
412 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG
"\n" );
416 if(X11DRV_XRender_Installed
|| client_side_with_core
)
418 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
419 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
421 glyphsetCacheSize
= INIT_CACHE_SIZE
;
423 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
424 glyphsetCache
[i
].next
= i
+ 1;
425 glyphsetCache
[i
].count
= -1;
427 glyphsetCache
[i
-1].next
= -1;
428 using_client_side_fonts
= 1;
430 if(!X11DRV_XRender_Installed
) {
431 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
432 if(screen_depth
<= 8 || !client_side_antialias_with_core
)
435 if(screen_depth
<= 8 || !client_side_antialias_with_render
)
438 return &xrender_funcs
;
440 TRACE("Using X11 core fonts\n");
444 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
445 static void get_xrender_color( XRenderPictFormat
*pf
, int src_color
, XRenderColor
*dst_color
)
447 if(pf
->direct
.redMask
)
448 dst_color
->red
= ((src_color
>> pf
->direct
.red
) & pf
->direct
.redMask
) * 65535/pf
->direct
.redMask
;
452 if(pf
->direct
.greenMask
)
453 dst_color
->green
= ((src_color
>> pf
->direct
.green
) & pf
->direct
.greenMask
) * 65535/pf
->direct
.greenMask
;
455 dst_color
->green
= 0;
457 if(pf
->direct
.blueMask
)
458 dst_color
->blue
= ((src_color
>> pf
->direct
.blue
) & pf
->direct
.blueMask
) * 65535/pf
->direct
.blueMask
;
462 dst_color
->alpha
= 0xffff;
465 static enum wxr_format
get_xrender_format_from_color_shifts(int depth
, ColorShifts
*shifts
)
467 int redMask
, greenMask
, blueMask
;
470 if (depth
== 1) return WXR_FORMAT_MONO
;
472 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
473 if (!shifts
) return default_format
;
475 redMask
= shifts
->physicalRed
.max
<< shifts
->physicalRed
.shift
;
476 greenMask
= shifts
->physicalGreen
.max
<< shifts
->physicalGreen
.shift
;
477 blueMask
= shifts
->physicalBlue
.max
<< shifts
->physicalBlue
.shift
;
479 /* Try to locate a format which matches the specification of the dibsection. */
480 for(i
= 0; i
< WXR_NB_FORMATS
; i
++)
482 if( depth
== wxr_formats_template
[i
].depth
&&
483 redMask
== (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
484 greenMask
== (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
485 blueMask
== (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
) )
489 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
490 ERR("No XRender format found!\n");
491 return WXR_INVALID_FORMAT
;
494 static enum wxr_format
get_xrender_format_from_bitmapinfo( const BITMAPINFO
*info
, BOOL use_alpha
)
496 if (info
->bmiHeader
.biPlanes
!= 1) return WXR_INVALID_FORMAT
;
498 switch (info
->bmiHeader
.biBitCount
)
501 return WXR_FORMAT_MONO
;
506 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
507 return WXR_FORMAT_R8G8B8
;
510 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
512 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
515 for (i
= 0; i
< WXR_NB_FORMATS
; i
++)
517 if (info
->bmiHeader
.biBitCount
== wxr_formats_template
[i
].depth
&&
518 colors
[0] == (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
519 colors
[1] == (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
520 colors
[2] == (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
))
525 if (info
->bmiHeader
.biCompression
!= BI_RGB
) break;
526 if (info
->bmiHeader
.biBitCount
== 16) return WXR_FORMAT_X1R5G5B5
;
527 return use_alpha
? WXR_FORMAT_A8R8G8B8
: WXR_FORMAT_X8R8G8B8
;
529 return WXR_INVALID_FORMAT
;
532 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
533 static void set_xrender_transformation(Picture src_pict
, double xscale
, double yscale
, int xoffset
, int yoffset
)
535 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
536 XTransform xform
= {{
537 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(xoffset
) },
538 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(yoffset
) },
539 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
542 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
546 /* check if we can use repeating instead of scaling for the specified source DC */
547 static BOOL
use_source_repeat( struct xrender_physdev
*dev
)
549 return (dev
->x11dev
->bitmap
&&
550 dev
->x11dev
->drawable_rect
.right
- dev
->x11dev
->drawable_rect
.left
== 1 &&
551 dev
->x11dev
->drawable_rect
.bottom
- dev
->x11dev
->drawable_rect
.top
== 1);
554 static Picture
get_xrender_picture( struct xrender_physdev
*dev
, HRGN clip_rgn
, const RECT
*clip_rect
)
556 if (!dev
->pict
&& dev
->pict_format
)
558 XRenderPictureAttributes pa
;
561 pa
.subwindow_mode
= IncludeInferiors
;
562 dev
->pict
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
563 dev
->pict_format
, CPSubwindowMode
, &pa
);
565 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
566 dev
->pict
, dev
->dev
.hdc
, dev
->x11dev
->drawable
);
567 dev
->update_clip
= TRUE
;
570 if (dev
->update_clip
)
577 rgn
= CreateRectRgnIndirect( clip_rect
);
578 if (clip_rgn
) CombineRgn( rgn
, rgn
, clip_rgn
, RGN_AND
);
579 CombineRgn( rgn
, rgn
, dev
->x11dev
->region
, RGN_AND
);
583 rgn
= CreateRectRgn( 0, 0, 0, 0 );
584 CombineRgn( rgn
, clip_rgn
, dev
->x11dev
->region
, RGN_AND
);
587 if ((clip_data
= X11DRV_GetRegionData( rgn
? rgn
: dev
->x11dev
->region
, 0 )))
590 pXRenderSetPictureClipRectangles( gdi_display
, dev
->pict
,
591 dev
->x11dev
->dc_rect
.left
, dev
->x11dev
->dc_rect
.top
,
592 (XRectangle
*)clip_data
->Buffer
, clip_data
->rdh
.nCount
);
594 HeapFree( GetProcessHeap(), 0, clip_data
);
596 dev
->update_clip
= (rgn
!= 0); /* have to update again if we are using a custom region */
597 if (rgn
) DeleteObject( rgn
);
602 static Picture
get_xrender_picture_source( struct xrender_physdev
*dev
, BOOL repeat
)
604 if (!dev
->pict_src
&& dev
->pict_format
)
606 XRenderPictureAttributes pa
;
609 pa
.subwindow_mode
= IncludeInferiors
;
610 pa
.repeat
= repeat
? RepeatNormal
: RepeatNone
;
611 dev
->pict_src
= pXRenderCreatePicture( gdi_display
, dev
->x11dev
->drawable
,
612 dev
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
615 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
616 dev
->pict_src
, dev
->dev
.hdc
, dev
->x11dev
->drawable
, pa
.repeat
);
619 return dev
->pict_src
;
622 static void free_xrender_picture( struct xrender_physdev
*dev
)
624 if (dev
->pict
|| dev
->pict_src
)
627 XFlush( gdi_display
);
630 TRACE("freeing pict = %lx dc = %p\n", dev
->pict
, dev
->dev
.hdc
);
631 pXRenderFreePicture(gdi_display
, dev
->pict
);
636 TRACE("freeing pict = %lx dc = %p\n", dev
->pict_src
, dev
->dev
.hdc
);
637 pXRenderFreePicture(gdi_display
, dev
->pict_src
);
642 dev
->pict_format
= NULL
;
645 static void update_xrender_drawable( struct xrender_physdev
*dev
)
647 free_xrender_picture( dev
);
648 dev
->format
= get_xrender_format_from_color_shifts( dev
->x11dev
->depth
, dev
->x11dev
->color_shifts
);
649 dev
->pict_format
= pict_formats
[dev
->format
];
652 /* return a mask picture used to force alpha to 0 */
653 static Picture
get_no_alpha_mask(void)
655 static Pixmap pixmap
;
661 XRenderPictureAttributes pa
;
664 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
665 pa
.repeat
= RepeatNormal
;
666 pa
.component_alpha
= True
;
667 pict
= pXRenderCreatePicture( gdi_display
, pixmap
, pict_formats
[WXR_FORMAT_A8R8G8B8
],
668 CPRepeat
|CPComponentAlpha
, &pa
);
669 col
.red
= col
.green
= col
.blue
= 0xffff;
671 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
677 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
679 if(p1
->hash
!= p2
->hash
) return TRUE
;
680 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
681 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
682 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
683 return strcmpiW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
687 static void walk_cache(void)
691 EnterCriticalSection(&xrender_cs
);
692 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
693 TRACE("item %d\n", i
);
694 LeaveCriticalSection(&xrender_cs
);
698 static int LookupEntry(LFANDSIZE
*plfsz
)
702 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
704 if(glyphsetCache
[i
].count
== -1) break; /* reached free list so stop */
706 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
707 glyphsetCache
[i
].count
++;
709 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
710 glyphsetCache
[i
].next
= mru
;
713 TRACE("found font in cache %d\n", i
);
718 TRACE("font not in cache\n");
722 static void FreeEntry(int entry
)
726 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
727 gsCacheEntryFormat
* formatEntry
;
729 if( !glyphsetCache
[entry
].format
[format
] )
732 formatEntry
= glyphsetCache
[entry
].format
[format
];
734 if(formatEntry
->glyphset
) {
736 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
738 formatEntry
->glyphset
= 0;
740 if(formatEntry
->nrealized
) {
741 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
742 formatEntry
->realized
= NULL
;
743 if(formatEntry
->bitmaps
) {
744 for(i
= 0; i
< formatEntry
->nrealized
; i
++)
745 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
[i
]);
746 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
);
747 formatEntry
->bitmaps
= NULL
;
749 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
750 formatEntry
->gis
= NULL
;
751 formatEntry
->nrealized
= 0;
754 HeapFree(GetProcessHeap(), 0, formatEntry
);
755 glyphsetCache
[entry
].format
[format
] = NULL
;
759 static int AllocEntry(void)
761 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
764 assert(glyphsetCache
[lastfree
].count
== -1);
765 glyphsetCache
[lastfree
].count
= 1;
767 lastfree
= glyphsetCache
[lastfree
].next
;
769 glyphsetCache
[best
].next
= mru
;
772 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
776 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
777 if(glyphsetCache
[i
].count
== 0) {
785 TRACE("freeing unused glyphset at cache %d\n", best
);
787 glyphsetCache
[best
].count
= 1;
789 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
790 glyphsetCache
[best
].next
= mru
;
798 TRACE("Growing cache\n");
801 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
803 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
804 * sizeof(*glyphsetCache
));
806 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
807 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
808 * sizeof(*glyphsetCache
));
810 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
812 glyphsetCache
[i
].next
= i
+ 1;
813 glyphsetCache
[i
].count
= -1;
815 glyphsetCache
[i
-1].next
= -1;
816 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
818 lastfree
= glyphsetCache
[best
].next
;
819 glyphsetCache
[best
].count
= 1;
820 glyphsetCache
[best
].next
= mru
;
822 TRACE("new free cache slot at %d\n", mru
);
826 static BOOL
get_gasp_flags(HDC hdc
, WORD
*flags
)
836 size
= GetFontData(hdc
, MS_GASP_TAG
, 0, NULL
, 0);
837 if(size
== GDI_ERROR
)
840 gasp
= buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
841 GetFontData(hdc
, MS_GASP_TAG
, 0, gasp
, size
);
843 GetTextMetricsW(hdc
, &tm
);
844 ppem
= abs(X11DRV_YWStoDS(hdc
, tm
.tmAscent
+ tm
.tmDescent
- tm
.tmInternalLeading
));
847 num_recs
= get_be_word(*gasp
);
851 *flags
= get_be_word(*(gasp
+ 1));
852 if(ppem
<= get_be_word(*gasp
))
856 TRACE("got flags %04x for ppem %d\n", *flags
, ppem
);
858 HeapFree(GetProcessHeap(), 0, buffer
);
862 static AA_Type
get_antialias_type( HDC hdc
, BOOL subpixel
, BOOL hinter
)
866 UINT font_smoothing_type
, font_smoothing_orientation
;
868 if (X11DRV_XRender_Installed
&& subpixel
&&
869 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE
, 0, &font_smoothing_type
, 0) &&
870 font_smoothing_type
== FE_FONTSMOOTHINGCLEARTYPE
)
872 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION
, 0,
873 &font_smoothing_orientation
, 0) &&
874 font_smoothing_orientation
== FE_FONTSMOOTHINGORIENTATIONBGR
)
881 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
882 But, Wine's subpixel rendering can support the portrait mode.
885 else if (!hinter
|| !get_gasp_flags(hdc
, &flags
) || flags
& GASP_DOGRAY
)
893 static int GetCacheEntry( HDC hdc
, LFANDSIZE
*plfsz
)
898 static int hinter
= -1;
899 static int subpixel
= -1;
902 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
905 entry
= glyphsetCache
+ ret
;
906 entry
->lfsz
= *plfsz
;
907 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
908 assert( !entry
->format
[format
] );
911 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
913 if(hinter
== -1 || subpixel
== -1)
915 RASTERIZER_STATUS status
;
916 GetRasterizerCaps(&status
, sizeof(status
));
917 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
918 subpixel
= status
.wFlags
& WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
921 switch (plfsz
->lf
.lfQuality
)
923 case ANTIALIASED_QUALITY
:
924 entry
->aa_default
= get_antialias_type( hdc
, FALSE
, hinter
);
925 return ret
; /* ignore further configuration */
926 case CLEARTYPE_QUALITY
:
927 case CLEARTYPE_NATURAL_QUALITY
:
928 entry
->aa_default
= get_antialias_type( hdc
, subpixel
, hinter
);
930 case DEFAULT_QUALITY
:
934 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING
, 0, &font_smoothing
, 0) &&
937 entry
->aa_default
= get_antialias_type( hdc
, subpixel
, hinter
);
940 entry
->aa_default
= AA_None
;
944 font_smoothing
= TRUE
; /* default to enabled */
945 #ifdef SONAME_LIBFONTCONFIG
946 if (fontconfig_installed
)
948 FcPattern
*match
, *pattern
= pFcPatternCreate();
950 char family
[LF_FACESIZE
* 4];
952 WideCharToMultiByte( CP_UTF8
, 0, plfsz
->lf
.lfFaceName
, -1, family
, sizeof(family
), NULL
, NULL
);
953 pFcPatternAddString( pattern
, FC_FAMILY
, (FcChar8
*)family
);
954 if (plfsz
->lf
.lfWeight
!= FW_DONTCARE
)
957 switch (plfsz
->lf
.lfWeight
)
959 case FW_THIN
: weight
= FC_WEIGHT_THIN
; break;
960 case FW_EXTRALIGHT
: weight
= FC_WEIGHT_EXTRALIGHT
; break;
961 case FW_LIGHT
: weight
= FC_WEIGHT_LIGHT
; break;
962 case FW_NORMAL
: weight
= FC_WEIGHT_NORMAL
; break;
963 case FW_MEDIUM
: weight
= FC_WEIGHT_MEDIUM
; break;
964 case FW_SEMIBOLD
: weight
= FC_WEIGHT_SEMIBOLD
; break;
965 case FW_BOLD
: weight
= FC_WEIGHT_BOLD
; break;
966 case FW_EXTRABOLD
: weight
= FC_WEIGHT_EXTRABOLD
; break;
967 case FW_HEAVY
: weight
= FC_WEIGHT_HEAVY
; break;
968 default: weight
= (plfsz
->lf
.lfWeight
- 80) / 4; break;
970 pFcPatternAddInteger( pattern
, FC_WEIGHT
, weight
);
972 pFcPatternAddInteger( pattern
, FC_SLANT
, plfsz
->lf
.lfItalic
? FC_SLANT_ITALIC
: FC_SLANT_ROMAN
);
973 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
974 pFcDefaultSubstitute( pattern
);
975 if ((match
= pFcFontMatch( NULL
, pattern
, &result
)))
980 if (pFcPatternGetBool( match
, FC_ANTIALIAS
, 0, &antialias
) != FcResultMatch
)
982 if (pFcPatternGetInteger( match
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
985 if (pFcPatternGetString( match
, FC_FILE
, 0, &file
) != FcResultMatch
) file
= NULL
;
987 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
988 rgba
, antialias
, debugstr_w(plfsz
->lf
.lfFaceName
), debugstr_a((char *)file
) );
992 case FC_RGBA_RGB
: entry
->aa_default
= AA_RGB
; break;
993 case FC_RGBA_BGR
: entry
->aa_default
= AA_BGR
; break;
994 case FC_RGBA_VRGB
: entry
->aa_default
= AA_VRGB
; break;
995 case FC_RGBA_VBGR
: entry
->aa_default
= AA_VBGR
; break;
996 case FC_RGBA_NONE
: entry
->aa_default
= AA_Grey
; break;
999 if (!antialias
) font_smoothing
= FALSE
;
1000 pFcPatternDestroy( match
);
1002 pFcPatternDestroy( pattern
);
1004 #endif /* SONAME_LIBFONTCONFIG */
1006 /* now check Xft resources */
1009 BOOL antialias
= TRUE
;
1012 if ((value
= XGetDefault( gdi_display
, "Xft", "antialias" )))
1014 if (tolower(value
[0]) == 'f' || tolower(value
[0]) == 'n' ||
1015 value
[0] == '0' || !strcasecmp( value
, "off" ))
1018 if ((value
= XGetDefault( gdi_display
, "Xft", "rgba" )))
1020 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value
, antialias
);
1021 if (!strcmp( value
, "rgb" )) entry
->aa_default
= AA_RGB
;
1022 else if (!strcmp( value
, "bgr" )) entry
->aa_default
= AA_BGR
;
1023 else if (!strcmp( value
, "vrgb" )) entry
->aa_default
= AA_VRGB
;
1024 else if (!strcmp( value
, "vbgr" )) entry
->aa_default
= AA_VBGR
;
1025 else if (!strcmp( value
, "none" )) entry
->aa_default
= AA_Grey
;
1027 wine_tsx11_unlock();
1028 if (!antialias
) font_smoothing
= FALSE
;
1031 if (!font_smoothing
) entry
->aa_default
= AA_None
;
1033 /* we can't support subpixel without xrender */
1034 if (!X11DRV_XRender_Installed
&& entry
->aa_default
> AA_Grey
) entry
->aa_default
= AA_Grey
;
1037 entry
->aa_default
= AA_None
;
1042 static void dec_ref_cache(int index
)
1045 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
1046 assert(glyphsetCache
[index
].count
> 0);
1047 glyphsetCache
[index
].count
--;
1050 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
1052 DWORD hash
= 0, *ptr
, two_chars
;
1056 hash
^= plfsz
->devsize
.cx
;
1057 hash
^= plfsz
->devsize
.cy
;
1058 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
1060 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
1062 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
1064 pwc
= (WCHAR
*)&two_chars
;
1066 *pwc
= toupperW(*pwc
);
1068 *pwc
= toupperW(*pwc
);
1076 /***********************************************************************
1077 * X11DRV_XRender_Finalize
1079 void X11DRV_XRender_Finalize(void)
1083 EnterCriticalSection(&xrender_cs
);
1084 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
1086 LeaveCriticalSection(&xrender_cs
);
1089 /**********************************************************************
1090 * xrenderdrv_SelectFont
1092 static HFONT
xrenderdrv_SelectFont( PHYSDEV dev
, HFONT hfont
, HANDLE gdiFont
)
1094 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1097 if (!GetObjectW( hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
)) return HGDI_ERROR
;
1101 dev
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
1102 return dev
->funcs
->pSelectFont( dev
, hfont
, gdiFont
);
1105 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1106 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
1107 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
1108 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
1109 lfsz
.devsize
.cx
= X11DRV_XWStoDS( dev
->hdc
, lfsz
.lf
.lfWidth
);
1110 lfsz
.devsize
.cy
= X11DRV_YWStoDS( dev
->hdc
, lfsz
.lf
.lfHeight
);
1112 GetTransform( dev
->hdc
, 0x204, &lfsz
.xform
);
1113 TRACE("font transform %f %f %f %f\n", lfsz
.xform
.eM11
, lfsz
.xform
.eM12
,
1114 lfsz
.xform
.eM21
, lfsz
.xform
.eM22
);
1116 /* Not used fields, would break hashing */
1117 lfsz
.xform
.eDx
= lfsz
.xform
.eDy
= 0;
1119 lfsz_calc_hash(&lfsz
);
1121 EnterCriticalSection(&xrender_cs
);
1122 if (physdev
->cache_index
!= -1)
1123 dec_ref_cache( physdev
->cache_index
);
1124 physdev
->cache_index
= GetCacheEntry( dev
->hdc
, &lfsz
);
1125 LeaveCriticalSection(&xrender_cs
);
1126 physdev
->x11dev
->has_gdi_font
= TRUE
;
1130 static BOOL
create_xrender_dc( PHYSDEV
*pdev
)
1132 X11DRV_PDEVICE
*x11dev
= get_x11drv_dev( *pdev
);
1133 struct xrender_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
1135 if (!physdev
) return FALSE
;
1136 physdev
->x11dev
= x11dev
;
1137 physdev
->cache_index
= -1;
1138 physdev
->format
= get_xrender_format_from_color_shifts( x11dev
->depth
, x11dev
->color_shifts
);
1139 physdev
->pict_format
= pict_formats
[physdev
->format
];
1140 push_dc_driver( pdev
, &physdev
->dev
, &xrender_funcs
);
1144 /* store the color mask data in the bitmap info structure */
1145 static void set_color_info( XRenderPictFormat
*format
, BITMAPINFO
*info
)
1147 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
1149 info
->bmiHeader
.biPlanes
= 1;
1150 info
->bmiHeader
.biBitCount
= pixmap_formats
[format
->depth
]->bits_per_pixel
;
1151 info
->bmiHeader
.biCompression
= BI_RGB
;
1152 info
->bmiHeader
.biClrUsed
= 0;
1154 switch (info
->bmiHeader
.biBitCount
)
1157 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
1158 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
1159 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
1160 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1163 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
1164 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
1165 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
1166 if (colors
[0] != 0xff0000 || colors
[1] != 0x00ff00 || colors
[2] != 0x0000ff)
1167 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1173 /**********************************************************************
1174 * xrenderdrv_CreateDC
1176 static BOOL
xrenderdrv_CreateDC( PHYSDEV
*pdev
, LPCWSTR driver
, LPCWSTR device
,
1177 LPCWSTR output
, const DEVMODEW
* initData
)
1179 return create_xrender_dc( pdev
);
1182 /**********************************************************************
1183 * xrenderdrv_CreateCompatibleDC
1185 static BOOL
xrenderdrv_CreateCompatibleDC( PHYSDEV orig
, PHYSDEV
*pdev
)
1187 if (orig
) /* chain to x11drv first */
1189 orig
= GET_NEXT_PHYSDEV( orig
, pCreateCompatibleDC
);
1190 if (!orig
->funcs
->pCreateCompatibleDC( orig
, pdev
)) return FALSE
;
1192 /* otherwise we have been called by x11drv */
1194 return create_xrender_dc( pdev
);
1197 /**********************************************************************
1198 * xrenderdrv_DeleteDC
1200 static BOOL
xrenderdrv_DeleteDC( PHYSDEV dev
)
1202 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1204 free_xrender_picture( physdev
);
1206 EnterCriticalSection( &xrender_cs
);
1207 if (physdev
->cache_index
!= -1) dec_ref_cache( physdev
->cache_index
);
1208 LeaveCriticalSection( &xrender_cs
);
1210 HeapFree( GetProcessHeap(), 0, physdev
);
1214 /**********************************************************************
1215 * xrenderdrv_ExtEscape
1217 static INT
xrenderdrv_ExtEscape( PHYSDEV dev
, INT escape
, INT in_count
, LPCVOID in_data
,
1218 INT out_count
, LPVOID out_data
)
1220 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1222 dev
= GET_NEXT_PHYSDEV( dev
, pExtEscape
);
1224 if (escape
== X11DRV_ESCAPE
&& in_data
&& in_count
>= sizeof(enum x11drv_escape_codes
))
1226 if (*(const enum x11drv_escape_codes
*)in_data
== X11DRV_SET_DRAWABLE
)
1228 BOOL ret
= dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
1229 if (ret
) update_xrender_drawable( physdev
);
1233 return dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
1236 /****************************************************************************
1237 * xrenderdrv_CreateBitmap
1239 static BOOL
xrenderdrv_CreateBitmap( PHYSDEV dev
, HBITMAP hbitmap
)
1241 XRenderPictFormat
*pict_format
= NULL
;
1245 if (!GetObjectW( hbitmap
, sizeof(bitmap
), &bitmap
)) return FALSE
;
1247 if (bitmap
.bmPlanes
== 1 && bitmap
.bmBitsPixel
== screen_bpp
)
1249 switch (bitmap
.bmBitsPixel
)
1251 case 16: pict_format
= pict_formats
[WXR_FORMAT_R5G6B5
]; break;
1252 case 24: pict_format
= pict_formats
[WXR_FORMAT_R8G8B8
]; break;
1253 case 32: pict_format
= pict_formats
[WXR_FORMAT_A8R8G8B8
]; break;
1259 X11DRV_PALETTE_ComputeColorShifts( &shifts
,
1260 pict_format
->direct
.redMask
<< pict_format
->direct
.red
,
1261 pict_format
->direct
.greenMask
<< pict_format
->direct
.green
,
1262 pict_format
->direct
.blueMask
<< pict_format
->direct
.blue
);
1263 return X11DRV_create_phys_bitmap( hbitmap
, &bitmap
, pict_format
->depth
, TRUE
, &shifts
);
1266 dev
= GET_NEXT_PHYSDEV( dev
, pCreateBitmap
);
1267 return dev
->funcs
->pCreateBitmap( dev
, hbitmap
);
1270 /****************************************************************************
1271 * xrenderdrv_DeleteBitmap
1273 static BOOL
xrenderdrv_DeleteBitmap( HBITMAP hbitmap
)
1275 return X11DRV_DeleteBitmap( hbitmap
);
1278 /***********************************************************************
1279 * xrenderdrv_SelectBitmap
1281 static HBITMAP
xrenderdrv_SelectBitmap( PHYSDEV dev
, HBITMAP hbitmap
)
1284 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1286 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBitmap
);
1287 ret
= dev
->funcs
->pSelectBitmap( dev
, hbitmap
);
1288 if (ret
) update_xrender_drawable( physdev
);
1292 /***********************************************************************
1293 * xrenderdrv_GetImage
1295 static DWORD
xrenderdrv_GetImage( PHYSDEV dev
, HBITMAP hbitmap
, BITMAPINFO
*info
,
1296 struct gdi_image_bits
*bits
, struct bitblt_coords
*src
)
1298 if (hbitmap
) return X11DRV_GetImage( dev
, hbitmap
, info
, bits
, src
);
1299 dev
= GET_NEXT_PHYSDEV( dev
, pGetImage
);
1300 return dev
->funcs
->pGetImage( dev
, hbitmap
, info
, bits
, src
);
1303 /***********************************************************************
1304 * xrenderdrv_SetDeviceClipping
1306 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev
, HRGN vis_rgn
, HRGN clip_rgn
)
1308 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1310 physdev
->update_clip
= TRUE
;
1312 dev
= GET_NEXT_PHYSDEV( dev
, pSetDeviceClipping
);
1313 dev
->funcs
->pSetDeviceClipping( dev
, vis_rgn
, clip_rgn
);
1317 BOOL
X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP
*physBitmap
, int bits_pixel
, const DIBSECTION
*dib
)
1319 XRenderPictFormat
*pict_format
;
1321 const DWORD
*bitfields
;
1322 static const DWORD bitfields_32
[3] = {0xff0000, 0x00ff00, 0x0000ff};
1323 static const DWORD bitfields_16
[3] = {0x7c00, 0x03e0, 0x001f};
1326 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1327 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1328 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1329 if (!X11DRV_XRender_Installed
|| bits_pixel
<= 8)
1332 if(dib
->dsBmih
.biCompression
== BI_BITFIELDS
)
1333 bitfields
= dib
->dsBitfields
;
1334 else if(bits_pixel
== 24 || bits_pixel
== 32)
1335 bitfields
= bitfields_32
;
1337 bitfields
= bitfields_16
;
1339 X11DRV_PALETTE_ComputeColorShifts(&shifts
, bitfields
[0], bitfields
[1], bitfields
[2]);
1340 pict_format
= pict_formats
[get_xrender_format_from_color_shifts(dib
->dsBm
.bmBitsPixel
, &shifts
)];
1342 /* Common formats should be in our picture format table. */
1345 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1346 dib
->dsBm
.bmBitsPixel
, bitfields
[0], bitfields
[1], bitfields
[2]);
1350 physBitmap
->pixmap_depth
= pict_format
->depth
;
1351 physBitmap
->trueColor
= TRUE
;
1352 physBitmap
->pixmap_color_shifts
= shifts
;
1356 /************************************************************************
1359 * Helper to ExtTextOut. Must be called inside xrender_cs
1361 static void UploadGlyph(struct xrender_physdev
*physDev
, int glyph
, AA_Type format
)
1363 unsigned int buflen
;
1368 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->cache_index
;
1369 gsCacheEntryFormat
*formatEntry
;
1370 UINT ggo_format
= GGO_GLYPH_INDEX
;
1371 enum wxr_format wxr_format
;
1372 static const char zero
[4];
1373 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
1377 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
1380 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
1383 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
1386 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
1389 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
1393 ERR("aa = %d - not implemented\n", format
);
1395 ggo_format
|= GGO_BITMAP
;
1399 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1400 if(buflen
== GDI_ERROR
) {
1401 if(format
!= AA_None
) {
1403 entry
->aa_default
= AA_None
;
1404 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
1405 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1407 if(buflen
== GDI_ERROR
) {
1408 WARN("GetGlyphOutlineW failed using default glyph\n");
1409 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0, ggo_format
, &gm
, 0, NULL
, &identity
);
1410 if(buflen
== GDI_ERROR
) {
1411 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1412 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0x20, ggo_format
, &gm
, 0, NULL
, &identity
);
1413 if(buflen
== GDI_ERROR
) {
1414 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1419 TRACE("Turning off antialiasing for this monochrome font\n");
1422 /* If there is nothing for the current type, we create the entry. */
1423 if( !entry
->format
[format
] ) {
1424 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
1426 sizeof(gsCacheEntryFormat
));
1428 formatEntry
= entry
->format
[format
];
1430 if(formatEntry
->nrealized
<= glyph
) {
1431 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
1433 if (formatEntry
->realized
)
1434 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
1436 formatEntry
->realized
,
1437 formatEntry
->nrealized
* sizeof(BOOL
));
1439 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
1441 formatEntry
->nrealized
* sizeof(BOOL
));
1443 if(!X11DRV_XRender_Installed
) {
1444 if (formatEntry
->bitmaps
)
1445 formatEntry
->bitmaps
= HeapReAlloc(GetProcessHeap(),
1447 formatEntry
->bitmaps
,
1448 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
1450 formatEntry
->bitmaps
= HeapAlloc(GetProcessHeap(),
1452 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
1454 if (formatEntry
->gis
)
1455 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
1458 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1460 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
1462 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1466 if(formatEntry
->glyphset
== 0 && X11DRV_XRender_Installed
) {
1469 wxr_format
= WXR_FORMAT_GRAY
;
1476 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1480 ERR("aa = %d - not implemented\n", format
);
1482 wxr_format
= WXR_FORMAT_MONO
;
1487 formatEntry
->font_format
= pict_formats
[wxr_format
];
1488 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
1489 wine_tsx11_unlock();
1493 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
1494 GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
1495 formatEntry
->realized
[glyph
] = TRUE
;
1497 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1499 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1500 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1502 gi
.width
= gm
.gmBlackBoxX
;
1503 gi
.height
= gm
.gmBlackBoxY
;
1504 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1505 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1506 gi
.xOff
= gm
.gmCellIncX
;
1507 gi
.yOff
= gm
.gmCellIncY
;
1509 if(TRACE_ON(xrender
)) {
1512 unsigned char *line
;
1514 if(format
== AA_None
) {
1515 pitch
= ((gi
.width
+ 31) / 32) * 4;
1516 for(i
= 0; i
< gi
.height
; i
++) {
1517 line
= (unsigned char*) buf
+ i
* pitch
;
1519 for(j
= 0; j
< pitch
* 8; j
++) {
1520 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1522 TRACE("%s\n", output
);
1525 static const char blks
[] = " .:;!o*#";
1529 pitch
= ((gi
.width
+ 3) / 4) * 4;
1530 for(i
= 0; i
< gi
.height
; i
++) {
1531 line
= (unsigned char*) buf
+ i
* pitch
;
1533 for(j
= 0; j
< pitch
; j
++) {
1534 str
[0] = blks
[line
[j
] >> 5];
1535 strcat(output
, str
);
1537 TRACE("%s\n", output
);
1543 if(formatEntry
->glyphset
) {
1544 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1545 unsigned char *byte
= (unsigned char*) buf
, c
;
1551 /* magic to flip bit order */
1552 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1553 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1554 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1559 else if ( format
!= AA_Grey
&&
1560 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1562 unsigned int i
, *data
= (unsigned int *)buf
;
1563 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1568 XRenderCompositeText seems to ignore 0x0 glyphs when
1569 AA_None, which means we lose the advance width of glyphs
1570 like the space. We'll pretend that such glyphs are 1x1
1575 gi
.width
= gi
.height
= 1;
1578 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1579 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1580 wine_tsx11_unlock();
1581 HeapFree(GetProcessHeap(), 0, buf
);
1583 formatEntry
->bitmaps
[glyph
] = buf
;
1586 formatEntry
->gis
[glyph
] = gi
;
1589 static void SharpGlyphMono(struct xrender_physdev
*physDev
, INT x
, INT y
,
1590 void *bitmap
, XGlyphInfo
*gi
)
1592 unsigned char *srcLine
= bitmap
, *src
;
1593 unsigned char bits
, bitsMask
;
1594 int width
= gi
->width
;
1595 int stride
= ((width
+ 31) & ~31) >> 3;
1596 int height
= gi
->height
;
1600 TRACE("%d, %d\n", x
, y
);
1609 bitsMask
= 0x80; /* FreeType is always MSB first */
1615 if (bits
& bitsMask
)
1623 bitsMask
= bitsMask
>> 1;
1629 } while (bits
& bitsMask
);
1630 XFillRectangle (gdi_display
, physDev
->x11dev
->drawable
,
1631 physDev
->x11dev
->gc
, xspan
, y
, lenspan
, 1);
1643 bitsMask
= bitsMask
>> 1;
1649 } while (!(bits
& bitsMask
));
1656 static void SharpGlyphGray(struct xrender_physdev
*physDev
, INT x
, INT y
,
1657 void *bitmap
, XGlyphInfo
*gi
)
1659 unsigned char *srcLine
= bitmap
, *src
, bits
;
1660 int width
= gi
->width
;
1661 int stride
= ((width
+ 3) & ~3);
1662 int height
= gi
->height
;
1687 } while (bits
>= 0x80);
1688 XFillRectangle (gdi_display
, physDev
->x11dev
->drawable
,
1689 physDev
->x11dev
->gc
, xspan
, y
, lenspan
, 1);
1702 } while (bits
< 0x80);
1710 static void ExamineBitfield (DWORD mask
, int *shift
, int *len
)
1715 while ((mask
& 1) == 0)
1721 while ((mask
& 1) == 1)
1730 static DWORD
GetField (DWORD pixel
, int shift
, int len
)
1732 pixel
= pixel
& (((1 << (len
)) - 1) << shift
);
1733 pixel
= pixel
<< (32 - (shift
+ len
)) >> 24;
1736 pixel
|= (pixel
>> len
);
1743 static DWORD
PutField (DWORD pixel
, int shift
, int len
)
1745 shift
= shift
- (8 - len
);
1747 pixel
&= (((1 << len
) - 1) << (8 - len
));
1755 static void SmoothGlyphGray(XImage
*image
, int x
, int y
, void *bitmap
, XGlyphInfo
*gi
,
1761 BYTE
*maskLine
, *mask
, m
;
1766 BYTE src_r
, src_g
, src_b
;
1771 height
= gi
->height
;
1774 maskStride
= (width
+ 3) & ~3;
1776 ExamineBitfield (image
->red_mask
, &r_shift
, &r_len
);
1777 ExamineBitfield (image
->green_mask
, &g_shift
, &g_len
);
1778 ExamineBitfield (image
->blue_mask
, &b_shift
, &b_len
);
1780 src_r
= GetField(color
, r_shift
, r_len
);
1781 src_g
= GetField(color
, g_shift
, g_len
);
1782 src_b
= GetField(color
, b_shift
, b_len
);
1784 for(; height
--; y
++)
1787 maskLine
+= maskStride
;
1792 if(y
>= image
->height
) break;
1796 if(tx
>= image
->width
) break;
1799 if(tx
< 0) continue;
1802 XPutPixel (image
, tx
, y
, color
);
1807 pixel
= XGetPixel (image
, tx
, y
);
1809 r
= GetField(pixel
, r_shift
, r_len
);
1810 r
= ((BYTE
)~m
* (WORD
)r
+ (BYTE
)m
* (WORD
)src_r
) >> 8;
1811 g
= GetField(pixel
, g_shift
, g_len
);
1812 g
= ((BYTE
)~m
* (WORD
)g
+ (BYTE
)m
* (WORD
)src_g
) >> 8;
1813 b
= GetField(pixel
, b_shift
, b_len
);
1814 b
= ((BYTE
)~m
* (WORD
)b
+ (BYTE
)m
* (WORD
)src_b
) >> 8;
1816 pixel
= (PutField (r
, r_shift
, r_len
) |
1817 PutField (g
, g_shift
, g_len
) |
1818 PutField (b
, b_shift
, b_len
));
1819 XPutPixel (image
, tx
, y
, pixel
);
1825 /*************************************************************
1828 * Returns an appropriate Picture for tiling the text colour.
1829 * Call and use result within the xrender_cs
1831 static Picture
get_tile_pict( enum wxr_format wxr_format
, const XRenderColor
*color
)
1837 XRenderColor current_color
;
1838 } tiles
[WXR_NB_FORMATS
], *tile
;
1840 tile
= &tiles
[wxr_format
];
1844 XRenderPictureAttributes pa
;
1845 XRenderPictFormat
*pict_format
= pict_formats
[wxr_format
];
1848 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_format
->depth
);
1850 pa
.repeat
= RepeatNormal
;
1851 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_format
, CPRepeat
, &pa
);
1852 wine_tsx11_unlock();
1854 /* init current_color to something different from text_pixel */
1855 tile
->current_color
= *color
;
1856 tile
->current_color
.red
^= 0xffff;
1858 if (wxr_format
== WXR_FORMAT_MONO
)
1860 /* for a 1bpp bitmap we always need a 1 in the tile */
1862 col
.red
= col
.green
= col
.blue
= 0;
1865 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1866 wine_tsx11_unlock();
1870 if (memcmp( color
, &tile
->current_color
, sizeof(*color
) ) && wxr_format
!= WXR_FORMAT_MONO
)
1873 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, color
, 0, 0, 1, 1);
1874 wine_tsx11_unlock();
1875 tile
->current_color
= *color
;
1880 /*************************************************************
1883 * Returns an appropriate Picture for masking with the specified alpha.
1884 * Call and use result within the xrender_cs
1886 static Picture
get_mask_pict( int alpha
)
1888 static Pixmap pixmap
;
1889 static Picture pict
;
1890 static int current_alpha
;
1892 if (alpha
== 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1896 XRenderPictureAttributes pa
;
1899 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
1900 pa
.repeat
= RepeatNormal
;
1901 pict
= pXRenderCreatePicture( gdi_display
, pixmap
,
1902 pict_formats
[WXR_FORMAT_A8R8G8B8
], CPRepeat
, &pa
);
1903 wine_tsx11_unlock();
1907 if (alpha
!= current_alpha
)
1910 col
.red
= col
.green
= col
.blue
= 0;
1911 col
.alpha
= current_alpha
= alpha
;
1913 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
1914 wine_tsx11_unlock();
1919 static int XRenderErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
1924 /********************************************************************
1925 * is_dib_with_colortable
1927 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1929 static inline BOOL
is_dib_with_colortable( X11DRV_PDEVICE
*physDev
)
1933 if( physDev
->bitmap
&& GetObjectW( physDev
->bitmap
->hbitmap
, sizeof(dib
), &dib
) == sizeof(dib
) &&
1934 dib
.dsBmih
.biBitCount
<= 8 )
1940 /***********************************************************************
1941 * xrenderdrv_ExtTextOut
1943 BOOL
xrenderdrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
,
1944 const RECT
*lprect
, LPCWSTR wstr
, UINT count
, const INT
*lpDx
)
1946 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1948 gsCacheEntry
*entry
;
1949 gsCacheEntryFormat
*formatEntry
;
1951 int textPixel
, backgroundPixel
;
1952 RGNDATA
*saved_region
= NULL
;
1953 BOOL disable_antialias
= FALSE
;
1954 AA_Type aa_type
= AA_None
;
1956 Picture tile_pict
= 0;
1958 if (!physdev
->x11dev
->has_gdi_font
)
1960 dev
= GET_NEXT_PHYSDEV( dev
, pExtTextOut
);
1961 return dev
->funcs
->pExtTextOut( dev
, x
, y
, flags
, lprect
, wstr
, count
, lpDx
);
1964 if(is_dib_with_colortable( physdev
->x11dev
))
1966 TRACE("Disabling antialiasing\n");
1967 disable_antialias
= TRUE
;
1970 xgcval
.function
= GXcopy
;
1971 xgcval
.background
= physdev
->x11dev
->backgroundPixel
;
1972 xgcval
.fill_style
= FillSolid
;
1974 XChangeGC( gdi_display
, physdev
->x11dev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1975 wine_tsx11_unlock();
1977 X11DRV_LockDIBSection( physdev
->x11dev
, DIB_Status_GdiMod
);
1979 if(physdev
->x11dev
->depth
== 1) {
1980 if((physdev
->x11dev
->textPixel
& 0xffffff) == 0) {
1982 backgroundPixel
= 1;
1985 backgroundPixel
= 0;
1988 textPixel
= physdev
->x11dev
->textPixel
;
1989 backgroundPixel
= physdev
->x11dev
->backgroundPixel
;
1992 if(flags
& ETO_OPAQUE
)
1995 XSetForeground( gdi_display
, physdev
->x11dev
->gc
, backgroundPixel
);
1996 XFillRectangle( gdi_display
, physdev
->x11dev
->drawable
, physdev
->x11dev
->gc
,
1997 physdev
->x11dev
->dc_rect
.left
+ lprect
->left
, physdev
->x11dev
->dc_rect
.top
+ lprect
->top
,
1998 lprect
->right
- lprect
->left
, lprect
->bottom
- lprect
->top
);
1999 wine_tsx11_unlock();
2008 EnterCriticalSection(&xrender_cs
);
2010 entry
= glyphsetCache
+ physdev
->cache_index
;
2011 if( disable_antialias
== FALSE
)
2012 aa_type
= entry
->aa_default
;
2013 formatEntry
= entry
->format
[aa_type
];
2015 for(idx
= 0; idx
< count
; idx
++) {
2016 if( !formatEntry
) {
2017 UploadGlyph(physdev
, wstr
[idx
], aa_type
);
2018 /* re-evaluate antialias since aa_default may have changed */
2019 if( disable_antialias
== FALSE
)
2020 aa_type
= entry
->aa_default
;
2021 formatEntry
= entry
->format
[aa_type
];
2022 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
2023 UploadGlyph(physdev
, wstr
[idx
], aa_type
);
2028 WARN("could not upload requested glyphs\n");
2029 LeaveCriticalSection(&xrender_cs
);
2033 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
2034 physdev
->x11dev
->dc_rect
.left
+ x
, physdev
->x11dev
->dc_rect
.top
+ y
);
2036 if(X11DRV_XRender_Installed
)
2038 XGlyphElt16
*elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
2039 POINT offset
= {0, 0};
2040 POINT desired
, current
;
2041 int render_op
= PictOpOver
;
2042 Picture pict
= get_xrender_picture( physdev
, 0, (flags
& ETO_CLIPPED
) ? lprect
: NULL
);
2045 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
2046 So we pass zeros to the function and move to our starting position using the first
2047 element of the elts array. */
2049 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
;
2050 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
;
2051 current
.x
= current
.y
= 0;
2053 get_xrender_color(physdev
->pict_format
, physdev
->x11dev
->textPixel
, &col
);
2054 tile_pict
= get_tile_pict(physdev
->format
, &col
);
2056 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
2058 if((physdev
->format
== WXR_FORMAT_MONO
) && (textPixel
== 0))
2059 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
2061 for(idx
= 0; idx
< count
; idx
++)
2063 elts
[idx
].glyphset
= formatEntry
->glyphset
;
2064 elts
[idx
].chars
= wstr
+ idx
;
2065 elts
[idx
].nchars
= 1;
2066 elts
[idx
].xOff
= desired
.x
- current
.x
;
2067 elts
[idx
].yOff
= desired
.y
- current
.y
;
2069 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
2070 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
2074 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
2075 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
2081 offset
.x
+= lpDx
[idx
* 2];
2082 offset
.y
+= lpDx
[idx
* 2 + 1];
2085 offset
.x
+= lpDx
[idx
];
2086 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
+ offset
.x
;
2087 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
+ offset
.y
;
2092 /* Make sure we don't have any transforms set from a previous call */
2093 set_xrender_transformation(pict
, 1, 1, 0, 0);
2094 pXRenderCompositeText16(gdi_display
, render_op
,
2097 formatEntry
->font_format
,
2098 0, 0, 0, 0, elts
, count
);
2099 wine_tsx11_unlock();
2100 HeapFree(GetProcessHeap(), 0, elts
);
2102 POINT offset
= {0, 0};
2104 if (flags
& ETO_CLIPPED
)
2106 HRGN clip_region
= CreateRectRgnIndirect( lprect
);
2107 saved_region
= add_extra_clipping_region( physdev
->x11dev
, clip_region
);
2108 DeleteObject( clip_region
);
2112 XSetForeground( gdi_display
, physdev
->x11dev
->gc
, textPixel
);
2114 if(aa_type
== AA_None
|| physdev
->x11dev
->depth
== 1)
2116 void (* sharp_glyph_fn
)(struct xrender_physdev
*, INT
, INT
, void *, XGlyphInfo
*);
2118 if(aa_type
== AA_None
)
2119 sharp_glyph_fn
= SharpGlyphMono
;
2121 sharp_glyph_fn
= SharpGlyphGray
;
2123 for(idx
= 0; idx
< count
; idx
++) {
2124 sharp_glyph_fn(physdev
,
2125 physdev
->x11dev
->dc_rect
.left
+ x
+ offset
.x
,
2126 physdev
->x11dev
->dc_rect
.top
+ y
+ offset
.y
,
2127 formatEntry
->bitmaps
[wstr
[idx
]],
2128 &formatEntry
->gis
[wstr
[idx
]]);
2133 offset
.x
+= lpDx
[idx
* 2];
2134 offset
.y
+= lpDx
[idx
* 2 + 1];
2137 offset
.x
+= lpDx
[idx
];
2141 offset
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
2142 offset
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
2147 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
2148 RECT extents
= {0, 0, 0, 0};
2150 int w
= physdev
->x11dev
->drawable_rect
.right
- physdev
->x11dev
->drawable_rect
.left
;
2151 int h
= physdev
->x11dev
->drawable_rect
.bottom
- physdev
->x11dev
->drawable_rect
.top
;
2153 TRACE("drawable %dx%d\n", w
, h
);
2155 for(idx
= 0; idx
< count
; idx
++) {
2156 if(extents
.left
> cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
)
2157 extents
.left
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
;
2158 if(extents
.top
> cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
)
2159 extents
.top
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
;
2160 if(extents
.right
< cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
)
2161 extents
.right
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
;
2162 if(extents
.bottom
< cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
)
2163 extents
.bottom
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
;
2169 cur
.x
+= lpDx
[idx
* 2];
2170 cur
.y
+= lpDx
[idx
* 2 + 1];
2177 cur
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
2178 cur
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
2181 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents
.left
, extents
.top
,
2182 extents
.right
, extents
.bottom
, physdev
->x11dev
->dc_rect
.left
+ x
, physdev
->x11dev
->dc_rect
.top
+ y
);
2184 if(physdev
->x11dev
->dc_rect
.left
+ x
+ extents
.left
>= 0) {
2185 image_x
= physdev
->x11dev
->dc_rect
.left
+ x
+ extents
.left
;
2189 image_off_x
= physdev
->x11dev
->dc_rect
.left
+ x
+ extents
.left
;
2191 if(physdev
->x11dev
->dc_rect
.top
+ y
+ extents
.top
>= 0) {
2192 image_y
= physdev
->x11dev
->dc_rect
.top
+ y
+ extents
.top
;
2196 image_off_y
= physdev
->x11dev
->dc_rect
.top
+ y
+ extents
.top
;
2198 if(physdev
->x11dev
->dc_rect
.left
+ x
+ extents
.right
< w
)
2199 image_w
= physdev
->x11dev
->dc_rect
.left
+ x
+ extents
.right
- image_x
;
2201 image_w
= w
- image_x
;
2202 if(physdev
->x11dev
->dc_rect
.top
+ y
+ extents
.bottom
< h
)
2203 image_h
= physdev
->x11dev
->dc_rect
.top
+ y
+ extents
.bottom
- image_y
;
2205 image_h
= h
- image_y
;
2207 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
2209 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
2210 image
= XGetImage(gdi_display
, physdev
->x11dev
->drawable
,
2211 image_x
, image_y
, image_w
, image_h
,
2212 AllPlanes
, ZPixmap
);
2213 X11DRV_check_error();
2215 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2216 gdi_display
, (int)physdev
->x11dev
->drawable
, image_x
, image_y
,
2217 image_w
, image_h
, AllPlanes
, ZPixmap
,
2218 physdev
->x11dev
->depth
, image
);
2220 Pixmap xpm
= XCreatePixmap(gdi_display
, root_window
, image_w
, image_h
,
2221 physdev
->x11dev
->depth
);
2225 gcv
.graphics_exposures
= False
;
2226 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
2227 XCopyArea(gdi_display
, physdev
->x11dev
->drawable
, xpm
, gc
, image_x
, image_y
,
2228 image_w
, image_h
, 0, 0);
2229 XFreeGC(gdi_display
, gc
);
2230 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
2231 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
2233 X11DRV_check_error();
2234 XFreePixmap(gdi_display
, xpm
);
2236 if(!image
) goto no_image
;
2238 image
->red_mask
= visual
->red_mask
;
2239 image
->green_mask
= visual
->green_mask
;
2240 image
->blue_mask
= visual
->blue_mask
;
2242 for(idx
= 0; idx
< count
; idx
++) {
2243 SmoothGlyphGray(image
,
2244 offset
.x
+ image_off_x
- extents
.left
,
2245 offset
.y
+ image_off_y
- extents
.top
,
2246 formatEntry
->bitmaps
[wstr
[idx
]],
2247 &formatEntry
->gis
[wstr
[idx
]],
2248 physdev
->x11dev
->textPixel
);
2253 offset
.x
+= lpDx
[idx
* 2];
2254 offset
.y
+= lpDx
[idx
* 2 + 1];
2257 offset
.x
+= lpDx
[idx
];
2261 offset
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
2262 offset
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
2265 XPutImage(gdi_display
, physdev
->x11dev
->drawable
, physdev
->x11dev
->gc
, image
, 0, 0,
2266 image_x
, image_y
, image_w
, image_h
);
2267 XDestroyImage(image
);
2270 wine_tsx11_unlock();
2271 restore_clipping_region( physdev
->x11dev
, saved_region
);
2273 LeaveCriticalSection(&xrender_cs
);
2277 X11DRV_UnlockDIBSection( physdev
->x11dev
, TRUE
);
2281 /* Helper function for (stretched) blitting using xrender */
2282 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
2283 int x_src
, int y_src
, int x_dst
, int y_dst
,
2284 double xscale
, double yscale
, int width
, int height
)
2286 int x_offset
, y_offset
;
2288 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2289 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2290 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2292 if(xscale
!= 1.0 || yscale
!= 1.0)
2294 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2295 * in the wrong quadrant of the x-y plane.
2297 x_offset
= (xscale
< 0) ? -width
: 0;
2298 y_offset
= (yscale
< 0) ? -height
: 0;
2299 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
2305 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
2307 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
2308 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width
, height
);
2309 wine_tsx11_unlock();
2312 /* Helper function for (stretched) mono->color blitting using xrender */
2313 static void xrender_mono_blit( Picture src_pict
, Picture dst_pict
,
2314 enum wxr_format dst_format
, XRenderColor
*fg
, XRenderColor
*bg
,
2315 int x_src
, int y_src
, int x_dst
, int y_dst
,
2316 double xscale
, double yscale
, int width
, int height
)
2319 int x_offset
, y_offset
;
2321 /* When doing a mono->color blit, the source data is used as mask, and the source picture
2322 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
2325 EnterCriticalSection( &xrender_cs
);
2326 tile_pict
= get_tile_pict( dst_format
, bg
);
2329 pXRenderFillRectangle( gdi_display
, PictOpSrc
, dst_pict
, fg
, x_dst
, y_dst
, width
, height
);
2331 if (xscale
!= 1.0 || yscale
!= 1.0)
2333 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2334 * in the wrong quadrant of the x-y plane.
2336 x_offset
= (xscale
< 0) ? -width
: 0;
2337 y_offset
= (yscale
< 0) ? -height
: 0;
2338 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
2344 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
2346 pXRenderComposite(gdi_display
, PictOpOver
, tile_pict
, src_pict
, dst_pict
,
2347 0, 0, x_offset
, y_offset
, x_dst
, y_dst
, width
, height
);
2348 wine_tsx11_unlock();
2349 LeaveCriticalSection( &xrender_cs
);
2352 static void get_colors( struct xrender_physdev
*physdev_src
, struct xrender_physdev
*physdev_dst
,
2353 XRenderColor
*fg
, XRenderColor
*bg
)
2355 if (physdev_src
->format
== WXR_FORMAT_MONO
)
2360 if (GetDIBColorTable( physdev_src
->dev
.hdc
, 0, 2, rgb
) == 2)
2362 pixel
= X11DRV_PALETTE_ToPhysical( physdev_dst
->x11dev
,
2363 RGB( rgb
[0].rgbRed
, rgb
[0].rgbGreen
, rgb
[0].rgbBlue
));
2364 get_xrender_color( physdev_dst
->pict_format
, pixel
, fg
);
2365 pixel
= X11DRV_PALETTE_ToPhysical( physdev_dst
->x11dev
,
2366 RGB( rgb
[1].rgbRed
, rgb
[1].rgbGreen
, rgb
[1].rgbBlue
));
2367 get_xrender_color( physdev_dst
->pict_format
, pixel
, bg
);
2371 get_xrender_color( physdev_dst
->pict_format
, physdev_dst
->x11dev
->textPixel
, fg
);
2372 get_xrender_color( physdev_dst
->pict_format
, physdev_dst
->x11dev
->backgroundPixel
, bg
);
2375 /* create a pixmap and render picture for an image */
2376 static DWORD
create_image_pixmap( BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
2377 struct bitblt_coords
*src
, enum wxr_format format
,
2378 Pixmap
*pixmap
, Picture
*pict
, BOOL
*use_repeat
)
2381 int width
= src
->visrect
.right
- src
->visrect
.left
;
2382 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
2383 int depth
= pict_formats
[format
]->depth
;
2384 struct gdi_image_bits dst_bits
;
2385 XRenderPictureAttributes pa
;
2389 image
= XCreateImage( gdi_display
, visual
, depth
, ZPixmap
, 0, NULL
,
2390 info
->bmiHeader
.biWidth
, height
, 32, 0 );
2391 wine_tsx11_unlock();
2392 if (!image
) return ERROR_OUTOFMEMORY
;
2394 ret
= copy_image_bits( info
, (format
== WXR_FORMAT_R8G8B8
), image
, bits
, &dst_bits
, src
, NULL
, ~0u );
2395 if (ret
) return ret
;
2397 image
->data
= dst_bits
.ptr
;
2398 /* hack: make sure the bits are readable if we are reading from a DIB section */
2399 /* to be removed once we get rid of DIB access protections */
2400 if (!dst_bits
.is_copy
) IsBadReadPtr( dst_bits
.ptr
, image
->height
* image
->bytes_per_line
);
2402 *use_repeat
= (width
== 1 && height
== 1);
2403 pa
.repeat
= *use_repeat
? RepeatNormal
: RepeatNone
;
2406 *pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, depth
);
2407 XPutImage( gdi_display
, *pixmap
, get_bitmap_gc( depth
), image
,
2408 src
->visrect
.left
, 0, 0, 0, width
, height
);
2409 *pict
= pXRenderCreatePicture( gdi_display
, *pixmap
, pict_formats
[format
], CPRepeat
, &pa
);
2410 wine_tsx11_unlock();
2412 /* make coordinates relative to the pixmap */
2413 src
->x
-= src
->visrect
.left
;
2414 src
->y
-= src
->visrect
.top
;
2415 OffsetRect( &src
->visrect
, -src
->visrect
.left
, -src
->visrect
.top
);
2419 XDestroyImage( image
);
2420 wine_tsx11_unlock();
2421 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
2425 static void xrender_stretch_blit( struct xrender_physdev
*physdev_src
, struct xrender_physdev
*physdev_dst
,
2426 Drawable drawable
, const struct bitblt_coords
*src
,
2427 const struct bitblt_coords
*dst
)
2429 int width
= abs( dst
->width
);
2430 int height
= abs( dst
->height
);
2431 int x_src
= physdev_src
->x11dev
->dc_rect
.left
+ src
->x
;
2432 int y_src
= physdev_src
->x11dev
->dc_rect
.top
+ src
->y
;
2434 Picture src_pict
= 0, dst_pict
, mask_pict
= 0;
2436 double xscale
, yscale
;
2438 use_repeat
= use_source_repeat( physdev_src
);
2441 xscale
= src
->width
/ (double)dst
->width
;
2442 yscale
= src
->height
/ (double)dst
->height
;
2444 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2446 if (drawable
) /* using an intermediate pixmap */
2448 XRenderPictureAttributes pa
;
2452 pa
.repeat
= RepeatNone
;
2454 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, physdev_dst
->pict_format
, CPRepeat
, &pa
);
2455 wine_tsx11_unlock();
2459 x_dst
= physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
;
2460 y_dst
= physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
;
2461 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
2464 if (src
->width
< 0) x_src
+= src
->width
+ 1;
2465 if (src
->height
< 0) y_src
+= src
->height
+ 1;
2466 if (dst
->width
< 0) x_dst
+= dst
->width
+ 1;
2467 if (dst
->height
< 0) y_dst
+= dst
->height
+ 1;
2469 src_pict
= get_xrender_picture_source( physdev_src
, use_repeat
);
2472 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
2474 XRenderColor fg
, bg
;
2476 get_colors( physdev_src
, physdev_dst
, &fg
, &bg
);
2477 fg
.alpha
= bg
.alpha
= 0;
2479 xrender_mono_blit( src_pict
, dst_pict
, physdev_dst
->format
, &fg
, &bg
,
2480 x_src
, y_src
, x_dst
, y_dst
, xscale
, yscale
, width
, height
);
2482 else /* color -> color (can be at different depths) or mono -> mono */
2484 if (physdev_dst
->x11dev
->depth
== 32 && physdev_src
->x11dev
->depth
< 32)
2485 mask_pict
= get_no_alpha_mask();
2487 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
2488 x_src
, y_src
, x_dst
, y_dst
, xscale
, yscale
, width
, height
);
2494 pXRenderFreePicture( gdi_display
, dst_pict
);
2495 wine_tsx11_unlock();
2500 static void xrender_put_image( Pixmap src_pixmap
, Picture src_pict
, HRGN clip
,
2501 XRenderPictFormat
*dst_format
, struct xrender_physdev
*physdev
,
2502 Drawable drawable
, struct bitblt_coords
*src
,
2503 struct bitblt_coords
*dst
, BOOL use_repeat
)
2505 int x_src
, y_src
, x_dst
, y_dst
;
2507 XRenderPictureAttributes pa
;
2508 double xscale
, yscale
;
2510 if (drawable
) /* using an intermediate pixmap */
2512 RGNDATA
*clip_data
= NULL
;
2514 if (clip
) clip_data
= X11DRV_GetRegionData( clip
, 0 );
2517 pa
.repeat
= RepeatNone
;
2519 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, dst_format
, CPRepeat
, &pa
);
2521 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
, 0, 0,
2522 (XRectangle
*)clip_data
->Buffer
, clip_data
->rdh
.nCount
);
2523 wine_tsx11_unlock();
2524 HeapFree( GetProcessHeap(), 0, clip_data
);
2528 x_dst
= physdev
->x11dev
->dc_rect
.left
+ dst
->x
;
2529 y_dst
= physdev
->x11dev
->dc_rect
.top
+ dst
->y
;
2530 dst_pict
= get_xrender_picture( physdev
, clip
, &dst
->visrect
);
2535 xscale
= src
->width
/ (double)dst
->width
;
2536 yscale
= src
->height
/ (double)dst
->height
;
2538 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2542 if (src
->width
< 0) x_src
+= src
->width
+ 1;
2543 if (src
->height
< 0) y_src
+= src
->height
+ 1;
2544 if (dst
->width
< 0) x_dst
+= dst
->width
+ 1;
2545 if (dst
->height
< 0) y_dst
+= dst
->height
+ 1;
2547 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
, x_src
, y_src
, x_dst
, y_dst
,
2548 xscale
, yscale
, abs( dst
->width
), abs( dst
->height
));
2553 pXRenderFreePicture( gdi_display
, dst_pict
);
2554 wine_tsx11_unlock();
2559 /***********************************************************************
2560 * xrenderdrv_StretchBlt
2562 static BOOL
xrenderdrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
2563 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
2565 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
2566 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
2568 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
2570 if (src_dev
->funcs
!= dst_dev
->funcs
)
2572 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pStretchBlt
);
2573 return dst_dev
->funcs
->pStretchBlt( dst_dev
, dst
, src_dev
, src
, rop
);
2576 if (!X11DRV_XRender_Installed
) goto x11drv_fallback
;
2578 /* XRender is of no use for color -> mono */
2579 if (physdev_dst
->format
== WXR_FORMAT_MONO
&& physdev_src
->format
!= WXR_FORMAT_MONO
)
2580 goto x11drv_fallback
;
2582 /* if not stretching, we only need to handle format conversion */
2583 if (!stretch
&& physdev_dst
->format
== physdev_src
->format
) goto x11drv_fallback
;
2585 sSrc
= sDst
= X11DRV_LockDIBSection( physdev_dst
->x11dev
, DIB_Status_None
);
2586 if (physdev_dst
!= physdev_src
) sSrc
= X11DRV_LockDIBSection( physdev_src
->x11dev
, DIB_Status_None
);
2588 /* try client-side DIB copy */
2589 if (!stretch
&& sSrc
== DIB_Status_AppMod
)
2591 if (physdev_dst
!= physdev_src
) X11DRV_UnlockDIBSection( physdev_src
->x11dev
, FALSE
);
2592 X11DRV_UnlockDIBSection( physdev_dst
->x11dev
, TRUE
);
2593 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pStretchBlt
);
2594 return dst_dev
->funcs
->pStretchBlt( dst_dev
, dst
, src_dev
, src
, rop
);
2597 X11DRV_CoerceDIBSection( physdev_dst
->x11dev
, DIB_Status_GdiMod
);
2598 if (physdev_dst
!= physdev_src
) X11DRV_CoerceDIBSection( physdev_src
->x11dev
, DIB_Status_GdiMod
);
2604 struct bitblt_coords tmp
;
2606 /* make coordinates relative to tmp pixmap */
2608 tmp
.x
-= tmp
.visrect
.left
;
2609 tmp
.y
-= tmp
.visrect
.top
;
2610 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
2613 tmpGC
= XCreateGC( gdi_display
, physdev_dst
->x11dev
->drawable
, 0, NULL
);
2614 XSetSubwindowMode( gdi_display
, tmpGC
, IncludeInferiors
);
2615 XSetGraphicsExposures( gdi_display
, tmpGC
, False
);
2616 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, tmp
.visrect
.right
- tmp
.visrect
.left
,
2617 tmp
.visrect
.bottom
- tmp
.visrect
.top
, physdev_dst
->x11dev
->depth
);
2618 wine_tsx11_unlock();
2620 xrender_stretch_blit( physdev_src
, physdev_dst
, tmp_pixmap
, src
, &tmp
);
2621 execute_rop( physdev_dst
->x11dev
, tmp_pixmap
, tmpGC
, &dst
->visrect
, rop
);
2624 XFreePixmap( gdi_display
, tmp_pixmap
);
2625 XFreeGC( gdi_display
, tmpGC
);
2626 wine_tsx11_unlock();
2628 else xrender_stretch_blit( physdev_src
, physdev_dst
, 0, src
, dst
);
2630 if (physdev_dst
!= physdev_src
) X11DRV_UnlockDIBSection( physdev_src
->x11dev
, FALSE
);
2631 X11DRV_UnlockDIBSection( physdev_dst
->x11dev
, TRUE
);
2635 return X11DRV_StretchBlt( &physdev_dst
->x11dev
->dev
, dst
, &physdev_src
->x11dev
->dev
, src
, rop
);
2639 /***********************************************************************
2640 * xrenderdrv_PutImage
2642 static DWORD
xrenderdrv_PutImage( PHYSDEV dev
, HBITMAP hbitmap
, HRGN clip
, BITMAPINFO
*info
,
2643 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
2644 struct bitblt_coords
*dst
, DWORD rop
)
2646 struct xrender_physdev
*physdev
;
2647 X_PHYSBITMAP
*bitmap
;
2651 enum wxr_format src_format
, dst_format
;
2652 XRenderPictFormat
*pict_format
;
2657 if (!X11DRV_XRender_Installed
) goto x11drv_fallback
;
2661 if (!(bitmap
= X11DRV_get_phys_bitmap( hbitmap
))) return ERROR_INVALID_HANDLE
;
2663 dst_format
= get_xrender_format_from_color_shifts( bitmap
->pixmap_depth
,
2664 &bitmap
->pixmap_color_shifts
);
2668 physdev
= get_xrender_dev( dev
);
2670 dst_format
= physdev
->format
;
2673 src_format
= get_xrender_format_from_bitmapinfo( info
, TRUE
);
2674 if (!(pict_format
= pict_formats
[src_format
])) goto update_format
;
2676 /* make sure we can create an image with the same bpp */
2677 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
2680 /* mono <-> color conversions not supported */
2681 if ((src_format
!= dst_format
) && (src_format
== WXR_FORMAT_MONO
|| dst_format
== WXR_FORMAT_MONO
))
2682 goto x11drv_fallback
;
2684 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
2686 ret
= create_image_pixmap( info
, bits
, src
, src_format
, &src_pixmap
, &src_pict
, &use_repeat
);
2689 struct bitblt_coords tmp
;
2693 HRGN rgn
= CreateRectRgnIndirect( &dst
->visrect
);
2694 if (clip
) CombineRgn( rgn
, rgn
, clip
, RGN_AND
);
2696 X11DRV_DIB_Lock( bitmap
, DIB_Status_GdiMod
);
2698 xrender_put_image( src_pixmap
, src_pict
, rgn
, pict_formats
[dst_format
],
2699 NULL
, bitmap
->pixmap
, src
, dst
, use_repeat
);
2701 X11DRV_DIB_Unlock( bitmap
, TRUE
);
2702 DeleteObject( rgn
);
2706 X11DRV_LockDIBSection( physdev
->x11dev
, DIB_Status_GdiMod
);
2710 RGNDATA
*clip_data
= NULL
;
2712 /* make coordinates relative to tmp pixmap */
2714 tmp
.x
-= tmp
.visrect
.left
;
2715 tmp
.y
-= tmp
.visrect
.top
;
2716 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
2718 if (clip
) clip_data
= add_extra_clipping_region( physdev
->x11dev
, clip
);
2721 gc
= XCreateGC( gdi_display
, physdev
->x11dev
->drawable
, 0, NULL
);
2722 XSetSubwindowMode( gdi_display
, gc
, IncludeInferiors
);
2723 XSetGraphicsExposures( gdi_display
, gc
, False
);
2724 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, tmp
.visrect
.right
- tmp
.visrect
.left
,
2725 tmp
.visrect
.bottom
- tmp
.visrect
.top
, physdev
->x11dev
->depth
);
2726 wine_tsx11_unlock();
2728 xrender_put_image( src_pixmap
, src_pict
, NULL
, physdev
->pict_format
,
2729 NULL
, tmp_pixmap
, src
, &tmp
, use_repeat
);
2730 execute_rop( physdev
->x11dev
, tmp_pixmap
, gc
, &dst
->visrect
, rop
);
2733 XFreePixmap( gdi_display
, tmp_pixmap
);
2734 XFreeGC( gdi_display
, gc
);
2735 wine_tsx11_unlock();
2737 restore_clipping_region( physdev
->x11dev
, clip_data
);
2739 else xrender_put_image( src_pixmap
, src_pict
, clip
,
2740 physdev
->pict_format
, physdev
, 0, src
, dst
, use_repeat
);
2742 X11DRV_UnlockDIBSection( physdev
->x11dev
, TRUE
);
2746 pXRenderFreePicture( gdi_display
, src_pict
);
2747 XFreePixmap( gdi_display
, src_pixmap
);
2748 wine_tsx11_unlock();
2753 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
2754 set_color_info( pict_formats
[dst_format
], info
);
2755 return ERROR_BAD_FORMAT
;
2758 if (hbitmap
) return X11DRV_PutImage( dev
, hbitmap
, clip
, info
, bits
, src
, dst
, rop
);
2759 dev
= GET_NEXT_PHYSDEV( dev
, pPutImage
);
2760 return dev
->funcs
->pPutImage( dev
, hbitmap
, clip
, info
, bits
, src
, dst
, rop
);
2764 /***********************************************************************
2765 * xrenderdrv_BlendImage
2767 static DWORD
xrenderdrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
2768 struct bitblt_coords
*src
, struct bitblt_coords
*dst
,
2769 BLENDFUNCTION func
)
2771 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2773 enum wxr_format format
;
2774 XRenderPictFormat
*pict_format
;
2775 Picture dst_pict
, src_pict
, mask_pict
;
2779 if (!X11DRV_XRender_Installed
)
2781 dev
= GET_NEXT_PHYSDEV( dev
, pBlendImage
);
2782 return dev
->funcs
->pBlendImage( dev
, info
, bits
, src
, dst
, func
);
2785 format
= get_xrender_format_from_bitmapinfo( info
, func
.AlphaFormat
& AC_SRC_ALPHA
);
2786 if (!(pict_format
= pict_formats
[format
])) goto update_format
;
2788 /* make sure we can create an image with the same bpp */
2789 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
2792 if (format
== WXR_FORMAT_MONO
&& physdev
->format
!= WXR_FORMAT_MONO
)
2795 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
2797 ret
= create_image_pixmap( info
, bits
, src
, format
, &src_pixmap
, &src_pict
, &use_repeat
);
2800 double xscale
, yscale
;
2802 X11DRV_LockDIBSection( physdev
->x11dev
, DIB_Status_GdiMod
);
2806 xscale
= src
->width
/ (double)dst
->width
;
2807 yscale
= src
->height
/ (double)dst
->height
;
2809 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2811 dst_pict
= get_xrender_picture( physdev
, 0, &dst
->visrect
);
2813 EnterCriticalSection( &xrender_cs
);
2814 mask_pict
= get_mask_pict( func
.SourceConstantAlpha
* 257 );
2816 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
, src
->x
, src
->y
,
2817 physdev
->x11dev
->dc_rect
.left
+ dst
->x
,
2818 physdev
->x11dev
->dc_rect
.top
+ dst
->y
,
2819 xscale
, yscale
, dst
->width
, dst
->height
);
2822 pXRenderFreePicture( gdi_display
, src_pict
);
2823 XFreePixmap( gdi_display
, src_pixmap
);
2824 wine_tsx11_unlock();
2826 LeaveCriticalSection( &xrender_cs
);
2828 X11DRV_UnlockDIBSection( physdev
->x11dev
, TRUE
);
2833 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
2834 set_color_info( physdev
->pict_format
, info
);
2835 return ERROR_BAD_FORMAT
;
2839 /***********************************************************************
2840 * xrenderdrv_AlphaBlend
2842 static BOOL
xrenderdrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
2843 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
2845 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
2846 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
2847 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
2848 XRenderPictureAttributes pa
;
2849 Pixmap tmp_pixmap
= 0;
2850 double xscale
, yscale
;
2853 if (!X11DRV_XRender_Installed
|| src_dev
->funcs
!= dst_dev
->funcs
)
2855 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pAlphaBlend
);
2856 return dst_dev
->funcs
->pAlphaBlend( dst_dev
, dst
, src_dev
, src
, blendfn
);
2859 if (physdev_dst
!= physdev_src
)
2861 int status
= X11DRV_LockDIBSection( physdev_src
->x11dev
, DIB_Status_None
);
2862 if (status
== DIB_Status_AppMod
|| status
== DIB_Status_InSync
)
2864 X11DRV_UnlockDIBSection( physdev_src
->x11dev
, FALSE
);
2865 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pAlphaBlend
);
2866 return dst_dev
->funcs
->pAlphaBlend( dst_dev
, dst
, src_dev
, src
, blendfn
);
2868 X11DRV_CoerceDIBSection( physdev_src
->x11dev
, DIB_Status_GdiMod
);
2870 X11DRV_LockDIBSection( physdev_dst
->x11dev
, DIB_Status_GdiMod
);
2872 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
2874 use_repeat
= use_source_repeat( physdev_src
);
2877 xscale
= src
->width
/ (double)dst
->width
;
2878 yscale
= src
->height
/ (double)dst
->height
;
2880 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2882 src_pict
= get_xrender_picture_source( physdev_src
, use_repeat
);
2884 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
2886 /* mono -> color blending needs an intermediate color pixmap */
2887 XRenderColor fg
, bg
;
2888 int width
= src
->visrect
.right
- src
->visrect
.left
;
2889 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
2891 /* blending doesn't use the destination DC colors */
2892 fg
.red
= fg
.green
= fg
.blue
= 0;
2893 bg
.red
= bg
.green
= bg
.blue
= 0xffff;
2894 fg
.alpha
= bg
.alpha
= 0xffff;
2897 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
,
2898 physdev_dst
->pict_format
->depth
);
2899 pa
.repeat
= use_repeat
? RepeatNormal
: RepeatNone
;
2900 tmp_pict
= pXRenderCreatePicture( gdi_display
, tmp_pixmap
, physdev_dst
->pict_format
,
2902 wine_tsx11_unlock();
2904 xrender_mono_blit( src_pict
, tmp_pict
, physdev_dst
->format
, &fg
, &bg
,
2905 src
->visrect
.left
, src
->visrect
.top
, 0, 0, 1, 1, width
, height
);
2907 else if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->pict_format
)
2909 /* we need a source picture with no alpha */
2910 enum wxr_format format
= get_format_without_alpha( physdev_src
->format
);
2911 if (format
!= physdev_src
->format
)
2914 pa
.subwindow_mode
= IncludeInferiors
;
2915 pa
.repeat
= use_repeat
? RepeatNormal
: RepeatNone
;
2916 tmp_pict
= pXRenderCreatePicture( gdi_display
, physdev_src
->x11dev
->drawable
,
2917 pict_formats
[format
], CPSubwindowMode
|CPRepeat
, &pa
);
2918 wine_tsx11_unlock();
2922 if (tmp_pict
) src_pict
= tmp_pict
;
2924 EnterCriticalSection( &xrender_cs
);
2925 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
2927 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2928 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
2929 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
2930 physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
,
2931 physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
,
2932 xscale
, yscale
, dst
->width
, dst
->height
);
2935 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
2936 if (tmp_pixmap
) XFreePixmap( gdi_display
, tmp_pixmap
);
2937 wine_tsx11_unlock();
2939 LeaveCriticalSection( &xrender_cs
);
2940 if (physdev_src
!= physdev_dst
) X11DRV_UnlockDIBSection( physdev_src
->x11dev
, FALSE
);
2941 X11DRV_UnlockDIBSection( physdev_dst
->x11dev
, TRUE
);
2946 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
2948 /* At depths >1, the depth of physBitmap and physDev might not be the same e.g. the physbitmap might be a 16-bit DIB while the physdev uses 24-bit */
2949 int depth
= physBitmap
->pixmap_depth
== 1 ? 1 : physDev
->depth
;
2950 enum wxr_format src_format
= get_xrender_format_from_color_shifts(physBitmap
->pixmap_depth
, &physBitmap
->pixmap_color_shifts
);
2951 enum wxr_format dst_format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
2954 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, depth
);
2956 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2957 if( (physBitmap
->pixmap_depth
== 1) || (!X11DRV_XRender_Installed
&& physDev
->depth
== physBitmap
->pixmap_depth
) ||
2958 (src_format
== dst_format
) )
2960 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
2961 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
2963 else /* We need depth conversion */
2965 Picture src_pict
, dst_pict
;
2966 XRenderPictureAttributes pa
;
2967 pa
.subwindow_mode
= IncludeInferiors
;
2968 pa
.repeat
= RepeatNone
;
2970 src_pict
= pXRenderCreatePicture(gdi_display
, physBitmap
->pixmap
,
2971 pict_formats
[src_format
], CPSubwindowMode
|CPRepeat
, &pa
);
2972 dst_pict
= pXRenderCreatePicture(gdi_display
, physDev
->brush
.pixmap
,
2973 pict_formats
[dst_format
], CPSubwindowMode
|CPRepeat
, &pa
);
2975 xrender_blit(PictOpSrc
, src_pict
, 0, dst_pict
, 0, 0, 0, 0, 1.0, 1.0, width
, height
);
2976 pXRenderFreePicture(gdi_display
, src_pict
);
2977 pXRenderFreePicture(gdi_display
, dst_pict
);
2979 wine_tsx11_unlock();
2982 static const struct gdi_dc_funcs xrender_funcs
=
2984 NULL
, /* pAbortDoc */
2985 NULL
, /* pAbortPath */
2986 xrenderdrv_AlphaBlend
, /* pAlphaBlend */
2987 NULL
, /* pAngleArc */
2990 NULL
, /* pBeginPath */
2991 xrenderdrv_BlendImage
, /* pBlendImage */
2992 NULL
, /* pChoosePixelFormat */
2994 NULL
, /* pCloseFigure */
2995 xrenderdrv_CreateBitmap
, /* pCreateBitmap */
2996 xrenderdrv_CreateCompatibleDC
, /* pCreateCompatibleDC */
2997 xrenderdrv_CreateDC
, /* pCreateDC */
2998 NULL
, /* pCreateDIBSection */
2999 xrenderdrv_DeleteBitmap
, /* pDeleteBitmap */
3000 xrenderdrv_DeleteDC
, /* pDeleteDC */
3001 NULL
, /* pDeleteObject */
3002 NULL
, /* pDescribePixelFormat */
3003 NULL
, /* pDeviceCapabilities */
3004 NULL
, /* pEllipse */
3006 NULL
, /* pEndPage */
3007 NULL
, /* pEndPath */
3008 NULL
, /* pEnumDeviceFonts */
3009 NULL
, /* pEnumICMProfiles */
3010 NULL
, /* pExcludeClipRect */
3011 NULL
, /* pExtDeviceMode */
3012 xrenderdrv_ExtEscape
, /* pExtEscape */
3013 NULL
, /* pExtFloodFill */
3014 NULL
, /* pExtSelectClipRgn */
3015 xrenderdrv_ExtTextOut
, /* pExtTextOut */
3016 NULL
, /* pFillPath */
3017 NULL
, /* pFillRgn */
3018 NULL
, /* pFlattenPath */
3019 NULL
, /* pFrameRgn */
3020 NULL
, /* pGdiComment */
3021 NULL
, /* pGetCharWidth */
3022 NULL
, /* pGetDeviceCaps */
3023 NULL
, /* pGetDeviceGammaRamp */
3024 NULL
, /* pGetICMProfile */
3025 xrenderdrv_GetImage
, /* pGetImage */
3026 NULL
, /* pGetNearestColor */
3027 NULL
, /* pGetPixel */
3028 NULL
, /* pGetPixelFormat */
3029 NULL
, /* pGetSystemPaletteEntries */
3030 NULL
, /* pGetTextExtentExPoint */
3031 NULL
, /* pGetTextMetrics */
3032 NULL
, /* pIntersectClipRect */
3033 NULL
, /* pInvertRgn */
3035 NULL
, /* pModifyWorldTransform */
3037 NULL
, /* pOffsetClipRgn */
3038 NULL
, /* pOffsetViewportOrg */
3039 NULL
, /* pOffsetWindowOrg */
3040 NULL
, /* pPaintRgn */
3043 NULL
, /* pPolyBezier */
3044 NULL
, /* pPolyBezierTo */
3045 NULL
, /* pPolyDraw */
3046 NULL
, /* pPolyPolygon */
3047 NULL
, /* pPolyPolyline */
3048 NULL
, /* pPolygon */
3049 NULL
, /* pPolyline */
3050 NULL
, /* pPolylineTo */
3051 xrenderdrv_PutImage
, /* pPutImage */
3052 NULL
, /* pRealizeDefaultPalette */
3053 NULL
, /* pRealizePalette */
3054 NULL
, /* pRectangle */
3055 NULL
, /* pResetDC */
3056 NULL
, /* pRestoreDC */
3057 NULL
, /* pRoundRect */
3059 NULL
, /* pScaleViewportExt */
3060 NULL
, /* pScaleWindowExt */
3061 xrenderdrv_SelectBitmap
, /* pSelectBitmap */
3062 NULL
, /* pSelectBrush */
3063 NULL
, /* pSelectClipPath */
3064 xrenderdrv_SelectFont
, /* pSelectFont */
3065 NULL
, /* pSelectPalette */
3066 NULL
, /* pSelectPen */
3067 NULL
, /* pSetArcDirection */
3068 NULL
, /* pSetBkColor */
3069 NULL
, /* pSetBkMode */
3070 NULL
, /* pSetDCBrushColor */
3071 NULL
, /* pSetDCPenColor */
3072 NULL
, /* pSetDIBColorTable */
3073 NULL
, /* pSetDIBitsToDevice */
3074 xrenderdrv_SetDeviceClipping
, /* pSetDeviceClipping */
3075 NULL
, /* pSetDeviceGammaRamp */
3076 NULL
, /* pSetLayout */
3077 NULL
, /* pSetMapMode */
3078 NULL
, /* pSetMapperFlags */
3079 NULL
, /* pSetPixel */
3080 NULL
, /* pSetPixelFormat */
3081 NULL
, /* pSetPolyFillMode */
3082 NULL
, /* pSetROP2 */
3083 NULL
, /* pSetRelAbs */
3084 NULL
, /* pSetStretchBltMode */
3085 NULL
, /* pSetTextAlign */
3086 NULL
, /* pSetTextCharacterExtra */
3087 NULL
, /* pSetTextColor */
3088 NULL
, /* pSetTextJustification */
3089 NULL
, /* pSetViewportExt */
3090 NULL
, /* pSetViewportOrg */
3091 NULL
, /* pSetWindowExt */
3092 NULL
, /* pSetWindowOrg */
3093 NULL
, /* pSetWorldTransform */
3094 NULL
, /* pStartDoc */
3095 NULL
, /* pStartPage */
3096 xrenderdrv_StretchBlt
, /* pStretchBlt */
3097 NULL
, /* pStretchDIBits */
3098 NULL
, /* pStrokeAndFillPath */
3099 NULL
, /* pStrokePath */
3100 NULL
, /* pSwapBuffers */
3101 NULL
, /* pUnrealizePalette */
3102 NULL
, /* pWidenPath */
3103 /* OpenGL not supported */
3106 #else /* SONAME_LIBXRENDER */
3108 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
3110 TRACE("XRender support not compiled in.\n");
3114 void X11DRV_XRender_Finalize(void)
3118 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
3121 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, physBitmap
->pixmap_depth
);
3123 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
3124 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
3125 wine_tsx11_unlock();
3128 BOOL
X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP
*physBitmap
, int bits_pixel
, const DIBSECTION
*dib
)
3133 #endif /* SONAME_LIBXRENDER */