2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
8 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
36 #include "wine/library.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
40 int using_client_side_fonts
= FALSE
;
42 WINE_DEFAULT_DEBUG_CHANNEL(xrender
);
44 #ifdef SONAME_LIBXRENDER
46 static BOOL X11DRV_XRender_Installed
= FALSE
;
49 #include <X11/extensions/Xrender.h>
51 #ifndef RepeatNone /* added in 0.10 */
53 #define RepeatNormal 1
55 #define RepeatReflect 3
58 typedef enum wine_xrformat
75 typedef struct wine_xrender_format_template
80 unsigned int alphaMask
;
84 unsigned int greenMask
;
86 unsigned int blueMask
;
87 } WineXRenderFormatTemplate
;
89 static const WineXRenderFormatTemplate wxr_formats_template
[WXR_NB_FORMATS
] =
91 /* Format depth alpha mask red mask green mask blue mask*/
92 {WXR_FORMAT_MONO
, 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
93 {WXR_FORMAT_GRAY
, 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
94 {WXR_FORMAT_X1R5G5B5
, 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
95 {WXR_FORMAT_X1B5G5R5
, 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
96 {WXR_FORMAT_R5G6B5
, 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
97 {WXR_FORMAT_B5G6R5
, 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
98 {WXR_FORMAT_R8G8B8
, 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
99 {WXR_FORMAT_B8G8R8
, 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
100 {WXR_FORMAT_A8R8G8B8
, 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
101 {WXR_FORMAT_B8G8R8A8
, 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
102 {WXR_FORMAT_X8R8G8B8
, 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
103 {WXR_FORMAT_B8G8R8X8
, 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
106 typedef struct wine_xrender_format
109 XRenderPictFormat
*pict_format
;
112 static WineXRenderFormat wxr_formats
[WXR_NB_FORMATS
];
113 static int WineXRenderFormatsListSize
= 0;
114 static WineXRenderFormat
*default_format
= NULL
;
120 SIZE devsize
; /* size in device coords */
124 #define INITIAL_REALIZED_BUF_SIZE 128
126 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
131 const WineXRenderFormat
*font_format
;
136 } gsCacheEntryFormat
;
142 gsCacheEntryFormat
* format
[AA_MAXVALUE
];
152 const WineXRenderFormat
*format
;
155 static gsCacheEntry
*glyphsetCache
= NULL
;
156 static DWORD glyphsetCacheSize
= 0;
157 static INT lastfree
= -1;
160 #define INIT_CACHE_SIZE 10
162 static int antialias
= 1;
164 static void *xrender_handle
;
166 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
167 MAKE_FUNCPTR(XRenderAddGlyphs
)
168 MAKE_FUNCPTR(XRenderComposite
)
169 MAKE_FUNCPTR(XRenderCompositeString8
)
170 MAKE_FUNCPTR(XRenderCompositeString16
)
171 MAKE_FUNCPTR(XRenderCompositeString32
)
172 MAKE_FUNCPTR(XRenderCompositeText16
)
173 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
174 MAKE_FUNCPTR(XRenderCreatePicture
)
175 MAKE_FUNCPTR(XRenderFillRectangle
)
176 MAKE_FUNCPTR(XRenderFindFormat
)
177 MAKE_FUNCPTR(XRenderFindVisualFormat
)
178 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
179 MAKE_FUNCPTR(XRenderFreePicture
)
180 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
181 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
182 MAKE_FUNCPTR(XRenderSetPictureTransform
)
184 MAKE_FUNCPTR(XRenderQueryExtension
)
187 static CRITICAL_SECTION xrender_cs
;
188 static CRITICAL_SECTION_DEBUG critsect_debug
=
191 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
192 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
194 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
196 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
197 ( ( (ULONG)_x4 << 24 ) | \
198 ( (ULONG)_x3 << 16 ) | \
199 ( (ULONG)_x2 << 8 ) | \
202 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
204 #define GASP_GRIDFIT 0x01
205 #define GASP_DOGRAY 0x02
207 #ifdef WORDS_BIGENDIAN
208 #define get_be_word(x) (x)
209 #define NATIVE_BYTE_ORDER MSBFirst
211 #define get_be_word(x) RtlUshortByteSwap(x)
212 #define NATIVE_BYTE_ORDER LSBFirst
215 static WXRFormat
get_format_without_alpha( WXRFormat format
)
219 case WXR_FORMAT_A8R8G8B8
: return WXR_FORMAT_X8R8G8B8
;
220 case WXR_FORMAT_B8G8R8A8
: return WXR_FORMAT_B8G8R8X8
;
221 default: return format
;
225 static BOOL
get_xrender_template(const WineXRenderFormatTemplate
*fmt
, XRenderPictFormat
*templ
, unsigned long *mask
)
228 templ
->type
= PictTypeDirect
;
229 templ
->depth
= fmt
->depth
;
230 templ
->direct
.alpha
= fmt
->alpha
;
231 templ
->direct
.alphaMask
= fmt
->alphaMask
;
232 templ
->direct
.red
= fmt
->red
;
233 templ
->direct
.redMask
= fmt
->redMask
;
234 templ
->direct
.green
= fmt
->green
;
235 templ
->direct
.greenMask
= fmt
->greenMask
;
236 templ
->direct
.blue
= fmt
->blue
;
237 templ
->direct
.blueMask
= fmt
->blueMask
;
240 *mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
| PictFormatRed
| PictFormatRedMask
| PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
| PictFormatBlueMask
;
245 static BOOL
is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate
*fmt
)
247 if(fmt
->depth
!= screen_depth
)
249 if( (fmt
->redMask
<< fmt
->red
) != visual
->red_mask
)
251 if( (fmt
->greenMask
<< fmt
->green
) != visual
->green_mask
)
253 if( (fmt
->blueMask
<< fmt
->blue
) != visual
->blue_mask
)
256 /* We never select a default ARGB visual */
263 static int load_xrender_formats(void)
266 for(i
= 0; i
< (sizeof(wxr_formats_template
) / sizeof(wxr_formats_template
[0])); i
++)
268 XRenderPictFormat templ
, *pict_format
;
270 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template
[i
]))
273 pict_format
= pXRenderFindVisualFormat(gdi_display
, visual
);
276 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
277 if (visual
->class == DirectColor
)
280 if (XMatchVisualInfo( gdi_display
, DefaultScreen(gdi_display
),
281 screen_depth
, TrueColor
, &info
))
283 pict_format
= pXRenderFindVisualFormat(gdi_display
, info
.visual
);
284 if (pict_format
) visual
= info
.visual
;
292 wxr_formats
[WineXRenderFormatsListSize
].format
= wxr_formats_template
[i
].wxr_format
;
293 wxr_formats
[WineXRenderFormatsListSize
].pict_format
= pict_format
;
294 default_format
= &wxr_formats
[WineXRenderFormatsListSize
];
295 WineXRenderFormatsListSize
++;
296 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format
->id
, wxr_formats_template
[i
].wxr_format
);
301 unsigned long mask
= 0;
302 get_xrender_template(&wxr_formats_template
[i
], &templ
, &mask
);
305 pict_format
= pXRenderFindFormat(gdi_display
, mask
, &templ
, 0);
310 wxr_formats
[WineXRenderFormatsListSize
].format
= wxr_formats_template
[i
].wxr_format
;
311 wxr_formats
[WineXRenderFormatsListSize
].pict_format
= pict_format
;
312 WineXRenderFormatsListSize
++;
313 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format
->id
, wxr_formats_template
[i
].wxr_format
);
317 return WineXRenderFormatsListSize
;
320 /***********************************************************************
321 * X11DRV_XRender_Init
323 * Let's see if our XServer has the extension available
326 void X11DRV_XRender_Init(void)
330 if (client_side_with_render
&&
331 wine_dlopen(SONAME_LIBX11
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
332 wine_dlopen(SONAME_LIBXEXT
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
333 (xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0)))
336 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
337 LOAD_FUNCPTR(XRenderAddGlyphs
)
338 LOAD_FUNCPTR(XRenderComposite
)
339 LOAD_FUNCPTR(XRenderCompositeString8
)
340 LOAD_FUNCPTR(XRenderCompositeString16
)
341 LOAD_FUNCPTR(XRenderCompositeString32
)
342 LOAD_FUNCPTR(XRenderCompositeText16
)
343 LOAD_FUNCPTR(XRenderCreateGlyphSet
)
344 LOAD_FUNCPTR(XRenderCreatePicture
)
345 LOAD_FUNCPTR(XRenderFillRectangle
)
346 LOAD_FUNCPTR(XRenderFindFormat
)
347 LOAD_FUNCPTR(XRenderFindVisualFormat
)
348 LOAD_FUNCPTR(XRenderFreeGlyphSet
)
349 LOAD_FUNCPTR(XRenderFreePicture
)
350 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
)
351 LOAD_FUNCPTR(XRenderQueryExtension
)
353 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
354 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
355 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
)
356 #undef LOAD_OPTIONAL_FUNCPTR
360 X11DRV_XRender_Installed
= pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
);
362 if(X11DRV_XRender_Installed
) {
363 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
364 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
368 "Wine has detected that you probably have a buggy version\n"
369 "of libXrender.so . Because of this client side font rendering\n"
370 "will be disabled. Please upgrade this library.\n");
371 X11DRV_XRender_Installed
= FALSE
;
375 if (!visual
->red_mask
|| !visual
->green_mask
|| !visual
->blue_mask
) {
376 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
377 X11DRV_XRender_Installed
= FALSE
;
383 if(X11DRV_XRender_Installed
|| client_side_with_core
)
385 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
386 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
388 glyphsetCacheSize
= INIT_CACHE_SIZE
;
390 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
391 glyphsetCache
[i
].next
= i
+ 1;
392 glyphsetCache
[i
].count
= -1;
394 glyphsetCache
[i
-1].next
= -1;
395 using_client_side_fonts
= 1;
397 if(!X11DRV_XRender_Installed
) {
398 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
399 if(screen_depth
<= 8 || !client_side_antialias_with_core
)
402 if(screen_depth
<= 8 || !client_side_antialias_with_render
)
406 else TRACE("Using X11 core fonts\n");
409 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
410 static void get_xrender_color(const WineXRenderFormat
*wxr_format
, int src_color
, XRenderColor
*dst_color
)
412 XRenderPictFormat
*pf
= wxr_format
->pict_format
;
414 if(pf
->direct
.redMask
)
415 dst_color
->red
= ((src_color
>> pf
->direct
.red
) & pf
->direct
.redMask
) * 65535/pf
->direct
.redMask
;
419 if(pf
->direct
.greenMask
)
420 dst_color
->green
= ((src_color
>> pf
->direct
.green
) & pf
->direct
.greenMask
) * 65535/pf
->direct
.greenMask
;
422 dst_color
->green
= 0;
424 if(pf
->direct
.blueMask
)
425 dst_color
->blue
= ((src_color
>> pf
->direct
.blue
) & pf
->direct
.blueMask
) * 65535/pf
->direct
.blueMask
;
429 dst_color
->alpha
= 0xffff;
432 static const WineXRenderFormat
*get_xrender_format(WXRFormat format
)
435 for(i
=0; i
<WineXRenderFormatsListSize
; i
++)
437 if(wxr_formats
[i
].format
== format
)
439 TRACE("Returning wxr_format=%#x\n", format
);
440 return &wxr_formats
[i
];
446 static const WineXRenderFormat
*get_xrender_format_from_color_shifts(int depth
, ColorShifts
*shifts
)
448 int redMask
, greenMask
, blueMask
;
452 return get_xrender_format(WXR_FORMAT_MONO
);
454 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
456 return default_format
;
458 redMask
= shifts
->physicalRed
.max
<< shifts
->physicalRed
.shift
;
459 greenMask
= shifts
->physicalGreen
.max
<< shifts
->physicalGreen
.shift
;
460 blueMask
= shifts
->physicalBlue
.max
<< shifts
->physicalBlue
.shift
;
462 /* Try to locate a format which matches the specification of the dibsection. */
463 for(i
= 0; i
< (sizeof(wxr_formats_template
) / sizeof(wxr_formats_template
[0])); i
++)
465 if( depth
== wxr_formats_template
[i
].depth
&&
466 redMask
== (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
467 greenMask
== (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
468 blueMask
== (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
) )
471 /* When we reach this stage the format was found in our template table but this doesn't mean that
472 * the Xserver also supports this format (e.g. its depth might be too low). The call below verifies that.
474 return get_xrender_format(wxr_formats_template
[i
].wxr_format
);
478 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
479 ERR("No XRender format found!\n");
483 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
484 static void set_xrender_transformation(Picture src_pict
, double xscale
, double yscale
, int xoffset
, int yoffset
)
486 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
487 XTransform xform
= {{
488 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(xoffset
) },
489 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(yoffset
) },
490 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
493 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
497 /* check if we can use repeating instead of scaling for the specified source DC */
498 static BOOL
use_source_repeat( X11DRV_PDEVICE
*physDev
)
500 return (physDev
->bitmap
&&
501 physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
== 1 &&
502 physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
== 1);
505 static struct xrender_info
*get_xrender_info(X11DRV_PDEVICE
*physDev
)
507 if(!physDev
->xrender
)
509 physDev
->xrender
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physDev
->xrender
));
511 if(!physDev
->xrender
)
513 ERR("Unable to allocate XRENDERINFO!\n");
516 physDev
->xrender
->cache_index
= -1;
518 if (!physDev
->xrender
->format
)
519 physDev
->xrender
->format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
521 return physDev
->xrender
;
524 static Picture
get_xrender_picture(X11DRV_PDEVICE
*physDev
)
526 struct xrender_info
*info
= get_xrender_info(physDev
);
529 if (!info
->pict
&& info
->format
)
531 XRenderPictureAttributes pa
;
532 RGNDATA
*clip
= X11DRV_GetRegionData( physDev
->region
, 0 );
535 pa
.subwindow_mode
= IncludeInferiors
;
536 info
->pict
= pXRenderCreatePicture(gdi_display
, physDev
->drawable
, info
->format
->pict_format
,
537 CPSubwindowMode
, &pa
);
538 if (info
->pict
&& clip
)
539 pXRenderSetPictureClipRectangles( gdi_display
, info
->pict
,
540 physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
541 (XRectangle
*)clip
->Buffer
, clip
->rdh
.nCount
);
543 TRACE("Allocing pict=%lx dc=%p drawable=%08lx\n", info
->pict
, physDev
->hdc
, physDev
->drawable
);
544 HeapFree( GetProcessHeap(), 0, clip
);
550 static Picture
get_xrender_picture_source(X11DRV_PDEVICE
*physDev
, BOOL repeat
)
552 struct xrender_info
*info
= get_xrender_info(physDev
);
555 if (!info
->pict_src
&& info
->format
)
557 XRenderPictureAttributes pa
;
560 pa
.subwindow_mode
= IncludeInferiors
;
561 pa
.repeat
= repeat
? RepeatNormal
: RepeatNone
;
562 info
->pict_src
= pXRenderCreatePicture(gdi_display
, physDev
->drawable
, info
->format
->pict_format
,
563 CPSubwindowMode
|CPRepeat
, &pa
);
566 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
567 info
->pict_src
, physDev
->hdc
, physDev
->drawable
, pa
.repeat
);
570 return info
->pict_src
;
573 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
575 if(p1
->hash
!= p2
->hash
) return TRUE
;
576 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
577 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
578 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
579 return strcmpiW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
583 static void walk_cache(void)
587 EnterCriticalSection(&xrender_cs
);
588 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
589 TRACE("item %d\n", i
);
590 LeaveCriticalSection(&xrender_cs
);
594 static int LookupEntry(LFANDSIZE
*plfsz
)
598 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
600 if(glyphsetCache
[i
].count
== -1) { /* reached free list so stop */
605 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
606 glyphsetCache
[i
].count
++;
608 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
609 glyphsetCache
[i
].next
= mru
;
612 TRACE("found font in cache %d\n", i
);
617 TRACE("font not in cache\n");
621 static void FreeEntry(int entry
)
625 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
626 gsCacheEntryFormat
* formatEntry
;
628 if( !glyphsetCache
[entry
].format
[format
] )
631 formatEntry
= glyphsetCache
[entry
].format
[format
];
633 if(formatEntry
->glyphset
) {
635 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
637 formatEntry
->glyphset
= 0;
639 if(formatEntry
->nrealized
) {
640 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
641 formatEntry
->realized
= NULL
;
642 if(formatEntry
->bitmaps
) {
643 for(i
= 0; i
< formatEntry
->nrealized
; i
++)
644 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
[i
]);
645 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
);
646 formatEntry
->bitmaps
= NULL
;
648 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
649 formatEntry
->gis
= NULL
;
650 formatEntry
->nrealized
= 0;
653 HeapFree(GetProcessHeap(), 0, formatEntry
);
654 glyphsetCache
[entry
].format
[format
] = NULL
;
658 static int AllocEntry(void)
660 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
663 assert(glyphsetCache
[lastfree
].count
== -1);
664 glyphsetCache
[lastfree
].count
= 1;
666 lastfree
= glyphsetCache
[lastfree
].next
;
668 glyphsetCache
[best
].next
= mru
;
671 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
675 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
676 if(glyphsetCache
[i
].count
== 0) {
684 TRACE("freeing unused glyphset at cache %d\n", best
);
686 glyphsetCache
[best
].count
= 1;
688 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
689 glyphsetCache
[best
].next
= mru
;
697 TRACE("Growing cache\n");
700 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
702 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
703 * sizeof(*glyphsetCache
));
705 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
706 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
707 * sizeof(*glyphsetCache
));
709 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
711 glyphsetCache
[i
].next
= i
+ 1;
712 glyphsetCache
[i
].count
= -1;
714 glyphsetCache
[i
-1].next
= -1;
715 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
717 lastfree
= glyphsetCache
[best
].next
;
718 glyphsetCache
[best
].count
= 1;
719 glyphsetCache
[best
].next
= mru
;
721 TRACE("new free cache slot at %d\n", mru
);
725 static BOOL
get_gasp_flags(X11DRV_PDEVICE
*physDev
, WORD
*flags
)
735 size
= GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, NULL
, 0);
736 if(size
== GDI_ERROR
)
739 gasp
= buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
740 GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, gasp
, size
);
742 GetTextMetricsW(physDev
->hdc
, &tm
);
743 ppem
= abs(X11DRV_YWStoDS(physDev
, tm
.tmAscent
+ tm
.tmDescent
- tm
.tmInternalLeading
));
746 num_recs
= get_be_word(*gasp
);
750 *flags
= get_be_word(*(gasp
+ 1));
751 if(ppem
<= get_be_word(*gasp
))
755 TRACE("got flags %04x for ppem %d\n", *flags
, ppem
);
757 HeapFree(GetProcessHeap(), 0, buffer
);
761 static AA_Type
get_antialias_type( X11DRV_PDEVICE
*physDev
, BOOL subpixel
, BOOL hinter
)
765 UINT font_smoothing_type
, font_smoothing_orientation
;
767 if (X11DRV_XRender_Installed
&& subpixel
&&
768 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE
, 0, &font_smoothing_type
, 0) &&
769 font_smoothing_type
== FE_FONTSMOOTHINGCLEARTYPE
)
771 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION
, 0,
772 &font_smoothing_orientation
, 0) &&
773 font_smoothing_orientation
== FE_FONTSMOOTHINGORIENTATIONBGR
)
780 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
781 But, Wine's subpixel rendering can support the portrait mode.
784 else if (!hinter
|| !get_gasp_flags(physDev
, &flags
) || flags
& GASP_DOGRAY
)
792 static int GetCacheEntry(X11DRV_PDEVICE
*physDev
, LFANDSIZE
*plfsz
)
797 static int hinter
= -1;
798 static int subpixel
= -1;
801 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
804 entry
= glyphsetCache
+ ret
;
805 entry
->lfsz
= *plfsz
;
806 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
807 assert( !entry
->format
[format
] );
810 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
812 if(hinter
== -1 || subpixel
== -1)
814 RASTERIZER_STATUS status
;
815 GetRasterizerCaps(&status
, sizeof(status
));
816 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
817 subpixel
= status
.wFlags
& WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
820 switch (plfsz
->lf
.lfQuality
)
822 case ANTIALIASED_QUALITY
:
823 entry
->aa_default
= get_antialias_type( physDev
, FALSE
, hinter
);
825 case CLEARTYPE_QUALITY
:
826 case CLEARTYPE_NATURAL_QUALITY
:
827 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
829 case DEFAULT_QUALITY
:
833 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING
, 0, &font_smoothing
, 0) &&
836 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
839 entry
->aa_default
= AA_None
;
844 entry
->aa_default
= AA_None
;
849 static void dec_ref_cache(int index
)
852 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
853 assert(glyphsetCache
[index
].count
> 0);
854 glyphsetCache
[index
].count
--;
857 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
859 DWORD hash
= 0, *ptr
, two_chars
;
863 hash
^= plfsz
->devsize
.cx
;
864 hash
^= plfsz
->devsize
.cy
;
865 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
867 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
869 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
871 pwc
= (WCHAR
*)&two_chars
;
873 *pwc
= toupperW(*pwc
);
875 *pwc
= toupperW(*pwc
);
883 /***********************************************************************
884 * X11DRV_XRender_Finalize
886 void X11DRV_XRender_Finalize(void)
890 EnterCriticalSection(&xrender_cs
);
891 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
893 LeaveCriticalSection(&xrender_cs
);
897 /***********************************************************************
898 * X11DRV_XRender_SelectFont
900 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
903 struct xrender_info
*info
;
905 GetObjectW(hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
906 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
907 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
908 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
909 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
910 lfsz
.devsize
.cx
= X11DRV_XWStoDS( physDev
, lfsz
.lf
.lfWidth
);
911 lfsz
.devsize
.cy
= X11DRV_YWStoDS( physDev
, lfsz
.lf
.lfHeight
);
912 GetWorldTransform( physDev
->hdc
, &lfsz
.xform
);
913 lfsz_calc_hash(&lfsz
);
915 info
= get_xrender_info(physDev
);
918 EnterCriticalSection(&xrender_cs
);
919 if(info
->cache_index
!= -1)
920 dec_ref_cache(info
->cache_index
);
921 info
->cache_index
= GetCacheEntry(physDev
, &lfsz
);
922 LeaveCriticalSection(&xrender_cs
);
926 /***********************************************************************
927 * X11DRV_XRender_SetDeviceClipping
929 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE
*physDev
, const RGNDATA
*data
)
931 if (physDev
->xrender
->pict
)
934 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
935 physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
936 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
941 /***********************************************************************
942 * X11DRV_XRender_DeleteDC
944 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
946 X11DRV_XRender_UpdateDrawable(physDev
);
948 EnterCriticalSection(&xrender_cs
);
949 if(physDev
->xrender
->cache_index
!= -1)
950 dec_ref_cache(physDev
->xrender
->cache_index
);
951 LeaveCriticalSection(&xrender_cs
);
953 HeapFree(GetProcessHeap(), 0, physDev
->xrender
);
954 physDev
->xrender
= NULL
;
958 BOOL
X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP
*physBitmap
, int bits_pixel
, const DIBSECTION
*dib
)
960 const WineXRenderFormat
*fmt
;
963 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
964 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
965 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
966 if (!X11DRV_XRender_Installed
|| bits_pixel
<= 8)
971 X11DRV_PALETTE_ComputeColorShifts(&shifts
, dib
->dsBitfields
[0], dib
->dsBitfields
[1], dib
->dsBitfields
[2]);
972 fmt
= get_xrender_format_from_color_shifts(dib
->dsBm
.bmBitsPixel
, &shifts
);
974 /* Common formats should be in our picture format table. */
977 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
978 dib
->dsBm
.bmBitsPixel
, dib
->dsBitfields
[0], dib
->dsBitfields
[1], dib
->dsBitfields
[2]);
984 int red_mask
, green_mask
, blue_mask
;
986 /* We are dealing with a DDB */
990 fmt
= get_xrender_format(WXR_FORMAT_R5G6B5
);
993 fmt
= get_xrender_format(WXR_FORMAT_R8G8B8
);
996 fmt
= get_xrender_format(WXR_FORMAT_A8R8G8B8
);
1004 TRACE("Unhandled DDB bits_pixel=%d\n", bits_pixel
);
1008 red_mask
= fmt
->pict_format
->direct
.redMask
<< fmt
->pict_format
->direct
.red
;
1009 green_mask
= fmt
->pict_format
->direct
.greenMask
<< fmt
->pict_format
->direct
.green
;
1010 blue_mask
= fmt
->pict_format
->direct
.blueMask
<< fmt
->pict_format
->direct
.blue
;
1011 X11DRV_PALETTE_ComputeColorShifts(&shifts
, red_mask
, green_mask
, blue_mask
);
1014 physBitmap
->pixmap_depth
= fmt
->pict_format
->depth
;
1015 physBitmap
->trueColor
= TRUE
;
1016 physBitmap
->pixmap_color_shifts
= shifts
;
1020 /***********************************************************************
1021 * X11DRV_XRender_UpdateDrawable
1023 * Deletes the pict and tile when the drawable changes.
1025 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
1027 struct xrender_info
*info
= physDev
->xrender
;
1029 if (info
->pict
|| info
->pict_src
)
1032 XFlush( gdi_display
);
1035 TRACE("freeing pict = %lx dc = %p\n", info
->pict
, physDev
->hdc
);
1036 pXRenderFreePicture(gdi_display
, info
->pict
);
1041 TRACE("freeing pict = %lx dc = %p\n", info
->pict_src
, physDev
->hdc
);
1042 pXRenderFreePicture(gdi_display
, info
->pict_src
);
1045 wine_tsx11_unlock();
1048 info
->format
= NULL
;
1051 /************************************************************************
1054 * Helper to ExtTextOut. Must be called inside xrender_cs
1056 static BOOL
UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
, AA_Type format
)
1058 unsigned int buflen
;
1063 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1064 gsCacheEntryFormat
*formatEntry
;
1065 UINT ggo_format
= GGO_GLYPH_INDEX
;
1066 WXRFormat wxr_format
;
1067 static const char zero
[4];
1068 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
1072 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
1075 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
1078 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
1081 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
1084 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
1088 ERR("aa = %d - not implemented\n", format
);
1090 ggo_format
|= GGO_BITMAP
;
1094 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1095 if(buflen
== GDI_ERROR
) {
1096 if(format
!= AA_None
) {
1098 entry
->aa_default
= AA_None
;
1099 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
1100 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1102 if(buflen
== GDI_ERROR
) {
1103 WARN("GetGlyphOutlineW failed\n");
1106 TRACE("Turning off antialiasing for this monochrome font\n");
1109 /* If there is nothing for the current type, we create the entry. */
1110 if( !entry
->format
[format
] ) {
1111 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
1113 sizeof(gsCacheEntryFormat
));
1115 formatEntry
= entry
->format
[format
];
1117 if(formatEntry
->nrealized
<= glyph
) {
1118 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
1120 if (formatEntry
->realized
)
1121 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
1123 formatEntry
->realized
,
1124 formatEntry
->nrealized
* sizeof(BOOL
));
1126 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
1128 formatEntry
->nrealized
* sizeof(BOOL
));
1130 if(!X11DRV_XRender_Installed
) {
1131 if (formatEntry
->bitmaps
)
1132 formatEntry
->bitmaps
= HeapReAlloc(GetProcessHeap(),
1134 formatEntry
->bitmaps
,
1135 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
1137 formatEntry
->bitmaps
= HeapAlloc(GetProcessHeap(),
1139 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
1141 if (formatEntry
->gis
)
1142 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
1145 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1147 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
1149 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1153 if(formatEntry
->glyphset
== 0 && X11DRV_XRender_Installed
) {
1156 wxr_format
= WXR_FORMAT_GRAY
;
1163 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1167 ERR("aa = %d - not implemented\n", format
);
1169 wxr_format
= WXR_FORMAT_MONO
;
1174 formatEntry
->font_format
= get_xrender_format(wxr_format
);
1175 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
->pict_format
);
1176 wine_tsx11_unlock();
1180 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
1181 GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
1182 formatEntry
->realized
[glyph
] = TRUE
;
1184 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1186 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1187 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1189 gi
.width
= gm
.gmBlackBoxX
;
1190 gi
.height
= gm
.gmBlackBoxY
;
1191 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1192 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1193 gi
.xOff
= gm
.gmCellIncX
;
1194 gi
.yOff
= gm
.gmCellIncY
;
1196 if(TRACE_ON(xrender
)) {
1199 unsigned char *line
;
1201 if(format
== AA_None
) {
1202 pitch
= ((gi
.width
+ 31) / 32) * 4;
1203 for(i
= 0; i
< gi
.height
; i
++) {
1204 line
= (unsigned char*) buf
+ i
* pitch
;
1206 for(j
= 0; j
< pitch
* 8; j
++) {
1207 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1209 TRACE("%s\n", output
);
1212 static const char blks
[] = " .:;!o*#";
1216 pitch
= ((gi
.width
+ 3) / 4) * 4;
1217 for(i
= 0; i
< gi
.height
; i
++) {
1218 line
= (unsigned char*) buf
+ i
* pitch
;
1220 for(j
= 0; j
< pitch
; j
++) {
1221 str
[0] = blks
[line
[j
] >> 5];
1222 strcat(output
, str
);
1224 TRACE("%s\n", output
);
1230 if(formatEntry
->glyphset
) {
1231 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1232 unsigned char *byte
= (unsigned char*) buf
, c
;
1238 /* magic to flip bit order */
1239 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1240 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1241 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1246 else if ( format
!= AA_Grey
&&
1247 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1249 unsigned int i
, *data
= (unsigned int *)buf
;
1250 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1255 XRenderCompositeText seems to ignore 0x0 glyphs when
1256 AA_None, which means we lose the advance width of glyphs
1257 like the space. We'll pretend that such glyphs are 1x1
1262 gi
.width
= gi
.height
= 1;
1265 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1266 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1267 wine_tsx11_unlock();
1268 HeapFree(GetProcessHeap(), 0, buf
);
1270 formatEntry
->bitmaps
[glyph
] = buf
;
1273 formatEntry
->gis
[glyph
] = gi
;
1278 static void SharpGlyphMono(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
1279 void *bitmap
, XGlyphInfo
*gi
)
1281 unsigned char *srcLine
= bitmap
, *src
;
1282 unsigned char bits
, bitsMask
;
1283 int width
= gi
->width
;
1284 int stride
= ((width
+ 31) & ~31) >> 3;
1285 int height
= gi
->height
;
1289 TRACE("%d, %d\n", x
, y
);
1298 bitsMask
= 0x80; /* FreeType is always MSB first */
1304 if (bits
& bitsMask
)
1312 bitsMask
= bitsMask
>> 1;
1318 } while (bits
& bitsMask
);
1319 XFillRectangle (gdi_display
, physDev
->drawable
,
1320 physDev
->gc
, xspan
, y
, lenspan
, 1);
1332 bitsMask
= bitsMask
>> 1;
1338 } while (!(bits
& bitsMask
));
1345 static void SharpGlyphGray(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
1346 void *bitmap
, XGlyphInfo
*gi
)
1348 unsigned char *srcLine
= bitmap
, *src
, bits
;
1349 int width
= gi
->width
;
1350 int stride
= ((width
+ 3) & ~3);
1351 int height
= gi
->height
;
1376 } while (bits
>= 0x80);
1377 XFillRectangle (gdi_display
, physDev
->drawable
,
1378 physDev
->gc
, xspan
, y
, lenspan
, 1);
1391 } while (bits
< 0x80);
1399 static void ExamineBitfield (DWORD mask
, int *shift
, int *len
)
1404 while ((mask
& 1) == 0)
1410 while ((mask
& 1) == 1)
1419 static DWORD
GetField (DWORD pixel
, int shift
, int len
)
1421 pixel
= pixel
& (((1 << (len
)) - 1) << shift
);
1422 pixel
= pixel
<< (32 - (shift
+ len
)) >> 24;
1425 pixel
|= (pixel
>> len
);
1432 static DWORD
PutField (DWORD pixel
, int shift
, int len
)
1434 shift
= shift
- (8 - len
);
1436 pixel
&= (((1 << len
) - 1) << (8 - len
));
1444 static void SmoothGlyphGray(XImage
*image
, int x
, int y
, void *bitmap
, XGlyphInfo
*gi
,
1450 BYTE
*maskLine
, *mask
, m
;
1455 BYTE src_r
, src_g
, src_b
;
1460 height
= gi
->height
;
1463 maskStride
= (width
+ 3) & ~3;
1465 ExamineBitfield (image
->red_mask
, &r_shift
, &r_len
);
1466 ExamineBitfield (image
->green_mask
, &g_shift
, &g_len
);
1467 ExamineBitfield (image
->blue_mask
, &b_shift
, &b_len
);
1469 src_r
= GetField(color
, r_shift
, r_len
);
1470 src_g
= GetField(color
, g_shift
, g_len
);
1471 src_b
= GetField(color
, b_shift
, b_len
);
1473 for(; height
--; y
++)
1476 maskLine
+= maskStride
;
1481 if(y
>= image
->height
) break;
1485 if(tx
>= image
->width
) break;
1488 if(tx
< 0) continue;
1491 XPutPixel (image
, tx
, y
, color
);
1496 pixel
= XGetPixel (image
, tx
, y
);
1498 r
= GetField(pixel
, r_shift
, r_len
);
1499 r
= ((BYTE
)~m
* (WORD
)r
+ (BYTE
)m
* (WORD
)src_r
) >> 8;
1500 g
= GetField(pixel
, g_shift
, g_len
);
1501 g
= ((BYTE
)~m
* (WORD
)g
+ (BYTE
)m
* (WORD
)src_g
) >> 8;
1502 b
= GetField(pixel
, b_shift
, b_len
);
1503 b
= ((BYTE
)~m
* (WORD
)b
+ (BYTE
)m
* (WORD
)src_b
) >> 8;
1505 pixel
= (PutField (r
, r_shift
, r_len
) |
1506 PutField (g
, g_shift
, g_len
) |
1507 PutField (b
, b_shift
, b_len
));
1508 XPutPixel (image
, tx
, y
, pixel
);
1514 /*************************************************************
1517 * Returns an appropriate Picture for tiling the text colour.
1518 * Call and use result within the xrender_cs
1520 static Picture
get_tile_pict(const WineXRenderFormat
*wxr_format
, int text_pixel
)
1527 } tiles
[WXR_NB_FORMATS
], *tile
;
1530 tile
= &tiles
[wxr_format
->format
];
1534 XRenderPictureAttributes pa
;
1537 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, wxr_format
->pict_format
->depth
);
1539 pa
.repeat
= RepeatNormal
;
1540 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, wxr_format
->pict_format
, CPRepeat
, &pa
);
1541 wine_tsx11_unlock();
1543 /* init current_color to something different from text_pixel */
1544 tile
->current_color
= ~text_pixel
;
1546 if(wxr_format
->format
== WXR_FORMAT_MONO
)
1548 /* for a 1bpp bitmap we always need a 1 in the tile */
1549 col
.red
= col
.green
= col
.blue
= 0;
1552 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1553 wine_tsx11_unlock();
1557 if(text_pixel
!= tile
->current_color
&& wxr_format
->format
!= WXR_FORMAT_MONO
)
1559 get_xrender_color(wxr_format
, text_pixel
, &col
);
1561 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1562 wine_tsx11_unlock();
1563 tile
->current_color
= text_pixel
;
1568 /*************************************************************
1571 * Returns an appropriate Picture for masking with the specified alpha.
1572 * Call and use result within the xrender_cs
1574 static Picture
get_mask_pict( int alpha
)
1576 static Pixmap pixmap
;
1577 static Picture pict
;
1578 static int current_alpha
;
1580 if (alpha
== 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1584 const WineXRenderFormat
*fmt
= get_xrender_format( WXR_FORMAT_A8R8G8B8
);
1585 XRenderPictureAttributes pa
;
1588 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
1589 pa
.repeat
= RepeatNormal
;
1590 pict
= pXRenderCreatePicture( gdi_display
, pixmap
, fmt
->pict_format
, CPRepeat
, &pa
);
1591 wine_tsx11_unlock();
1595 if (alpha
!= current_alpha
)
1598 col
.red
= col
.green
= col
.blue
= 0;
1599 col
.alpha
= current_alpha
= alpha
;
1601 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
1602 wine_tsx11_unlock();
1607 static int XRenderErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
1612 /***********************************************************************
1613 * X11DRV_XRender_ExtTextOut
1615 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1616 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1620 gsCacheEntry
*entry
;
1621 gsCacheEntryFormat
*formatEntry
;
1623 int textPixel
, backgroundPixel
;
1624 HRGN saved_region
= 0;
1625 BOOL disable_antialias
= FALSE
;
1626 AA_Type aa_type
= AA_None
;
1629 const WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
1630 Picture tile_pict
= 0;
1632 /* Do we need to disable antialiasing because of palette mode? */
1633 if( !physDev
->bitmap
|| GetObjectW( physDev
->bitmap
->hbitmap
, sizeof(bmp
), &bmp
) != sizeof(bmp
) ) {
1634 TRACE("bitmap is not a DIB\n");
1636 else if (bmp
.dsBmih
.biBitCount
<= 8) {
1637 TRACE("Disabling antialiasing\n");
1638 disable_antialias
= TRUE
;
1641 xgcval
.function
= GXcopy
;
1642 xgcval
.background
= physDev
->backgroundPixel
;
1643 xgcval
.fill_style
= FillSolid
;
1645 XChangeGC( gdi_display
, physDev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1646 wine_tsx11_unlock();
1648 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
);
1650 if(physDev
->depth
== 1) {
1651 if((physDev
->textPixel
& 0xffffff) == 0) {
1653 backgroundPixel
= 1;
1656 backgroundPixel
= 0;
1659 textPixel
= physDev
->textPixel
;
1660 backgroundPixel
= physDev
->backgroundPixel
;
1663 if(flags
& ETO_OPAQUE
)
1666 XSetForeground( gdi_display
, physDev
->gc
, backgroundPixel
);
1667 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1668 physDev
->dc_rect
.left
+ lprect
->left
, physDev
->dc_rect
.top
+ lprect
->top
,
1669 lprect
->right
- lprect
->left
, lprect
->bottom
- lprect
->top
);
1670 wine_tsx11_unlock();
1679 if (flags
& ETO_CLIPPED
)
1683 clip_region
= CreateRectRgnIndirect( lprect
);
1684 /* make a copy of the current device region */
1685 saved_region
= CreateRectRgn( 0, 0, 0, 0 );
1686 CombineRgn( saved_region
, physDev
->region
, 0, RGN_COPY
);
1687 X11DRV_SetDeviceClipping( physDev
, saved_region
, clip_region
);
1688 DeleteObject( clip_region
);
1691 EnterCriticalSection(&xrender_cs
);
1693 entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1694 if( disable_antialias
== FALSE
)
1695 aa_type
= entry
->aa_default
;
1696 formatEntry
= entry
->format
[aa_type
];
1698 for(idx
= 0; idx
< count
; idx
++) {
1699 if( !formatEntry
) {
1700 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1701 /* re-evaluate antialias since aa_default may have changed */
1702 if( disable_antialias
== FALSE
)
1703 aa_type
= entry
->aa_default
;
1704 formatEntry
= entry
->format
[aa_type
];
1705 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1706 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1711 WARN("could not upload requested glyphs\n");
1712 LeaveCriticalSection(&xrender_cs
);
1716 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1717 physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1719 if(X11DRV_XRender_Installed
)
1721 XGlyphElt16
*elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1722 POINT offset
= {0, 0};
1723 POINT desired
, current
;
1724 int render_op
= PictOpOver
;
1725 Picture pict
= get_xrender_picture(physDev
);
1727 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1728 So we pass zeros to the function and move to our starting position using the first
1729 element of the elts array. */
1731 desired
.x
= physDev
->dc_rect
.left
+ x
;
1732 desired
.y
= physDev
->dc_rect
.top
+ y
;
1733 current
.x
= current
.y
= 0;
1735 tile_pict
= get_tile_pict(dst_format
, physDev
->textPixel
);
1737 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1739 if((dst_format
->format
== WXR_FORMAT_MONO
) && (textPixel
== 0))
1740 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1742 for(idx
= 0; idx
< count
; idx
++)
1744 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1745 elts
[idx
].chars
= wstr
+ idx
;
1746 elts
[idx
].nchars
= 1;
1747 elts
[idx
].xOff
= desired
.x
- current
.x
;
1748 elts
[idx
].yOff
= desired
.y
- current
.y
;
1750 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1751 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1755 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1756 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1762 offset
.x
+= lpDx
[idx
* 2];
1763 offset
.y
+= lpDx
[idx
* 2 + 1];
1766 offset
.x
+= lpDx
[idx
];
1767 desired
.x
= physDev
->dc_rect
.left
+ x
+ offset
.x
;
1768 desired
.y
= physDev
->dc_rect
.top
+ y
+ offset
.y
;
1772 /* Make sure we don't have any transforms set from a previous call */
1773 set_xrender_transformation(pict
, 1, 1, 0, 0);
1774 pXRenderCompositeText16(gdi_display
, render_op
,
1777 formatEntry
->font_format
->pict_format
,
1778 0, 0, 0, 0, elts
, count
);
1779 wine_tsx11_unlock();
1780 HeapFree(GetProcessHeap(), 0, elts
);
1782 POINT offset
= {0, 0};
1784 XSetForeground( gdi_display
, physDev
->gc
, textPixel
);
1786 if(aa_type
== AA_None
|| physDev
->depth
== 1)
1788 void (* sharp_glyph_fn
)(X11DRV_PDEVICE
*, INT
, INT
, void *, XGlyphInfo
*);
1790 if(aa_type
== AA_None
)
1791 sharp_glyph_fn
= SharpGlyphMono
;
1793 sharp_glyph_fn
= SharpGlyphGray
;
1795 for(idx
= 0; idx
< count
; idx
++) {
1796 sharp_glyph_fn(physDev
,
1797 physDev
->dc_rect
.left
+ x
+ offset
.x
,
1798 physDev
->dc_rect
.top
+ y
+ offset
.y
,
1799 formatEntry
->bitmaps
[wstr
[idx
]],
1800 &formatEntry
->gis
[wstr
[idx
]]);
1805 offset
.x
+= lpDx
[idx
* 2];
1806 offset
.y
+= lpDx
[idx
* 2 + 1];
1809 offset
.x
+= lpDx
[idx
];
1813 offset
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1814 offset
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1819 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
1820 RECT extents
= {0, 0, 0, 0};
1822 int w
= physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
;
1823 int h
= physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
;
1825 TRACE("drawable %dx%d\n", w
, h
);
1827 for(idx
= 0; idx
< count
; idx
++) {
1828 if(extents
.left
> cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
)
1829 extents
.left
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
;
1830 if(extents
.top
> cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
)
1831 extents
.top
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
;
1832 if(extents
.right
< cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
)
1833 extents
.right
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
;
1834 if(extents
.bottom
< cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
)
1835 extents
.bottom
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
;
1841 cur
.x
+= lpDx
[idx
* 2];
1842 cur
.y
+= lpDx
[idx
* 2 + 1];
1849 cur
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1850 cur
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1853 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents
.left
, extents
.top
,
1854 extents
.right
, extents
.bottom
, physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1856 if(physDev
->dc_rect
.left
+ x
+ extents
.left
>= 0) {
1857 image_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1861 image_off_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1863 if(physDev
->dc_rect
.top
+ y
+ extents
.top
>= 0) {
1864 image_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1868 image_off_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1870 if(physDev
->dc_rect
.left
+ x
+ extents
.right
< w
)
1871 image_w
= physDev
->dc_rect
.left
+ x
+ extents
.right
- image_x
;
1873 image_w
= w
- image_x
;
1874 if(physDev
->dc_rect
.top
+ y
+ extents
.bottom
< h
)
1875 image_h
= physDev
->dc_rect
.top
+ y
+ extents
.bottom
- image_y
;
1877 image_h
= h
- image_y
;
1879 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
1881 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1882 image
= XGetImage(gdi_display
, physDev
->drawable
,
1883 image_x
, image_y
, image_w
, image_h
,
1884 AllPlanes
, ZPixmap
);
1885 X11DRV_check_error();
1887 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1888 gdi_display
, (int)physDev
->drawable
, image_x
, image_y
,
1889 image_w
, image_h
, AllPlanes
, ZPixmap
,
1890 physDev
->depth
, image
);
1892 Pixmap xpm
= XCreatePixmap(gdi_display
, root_window
, image_w
, image_h
,
1897 gcv
.graphics_exposures
= False
;
1898 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1899 XCopyArea(gdi_display
, physDev
->drawable
, xpm
, gc
, image_x
, image_y
,
1900 image_w
, image_h
, 0, 0);
1901 XFreeGC(gdi_display
, gc
);
1902 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1903 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
1905 X11DRV_check_error();
1906 XFreePixmap(gdi_display
, xpm
);
1908 if(!image
) goto no_image
;
1910 image
->red_mask
= visual
->red_mask
;
1911 image
->green_mask
= visual
->green_mask
;
1912 image
->blue_mask
= visual
->blue_mask
;
1914 for(idx
= 0; idx
< count
; idx
++) {
1915 SmoothGlyphGray(image
,
1916 offset
.x
+ image_off_x
- extents
.left
,
1917 offset
.y
+ image_off_y
- extents
.top
,
1918 formatEntry
->bitmaps
[wstr
[idx
]],
1919 &formatEntry
->gis
[wstr
[idx
]],
1920 physDev
->textPixel
);
1925 offset
.x
+= lpDx
[idx
* 2];
1926 offset
.y
+= lpDx
[idx
* 2 + 1];
1929 offset
.x
+= lpDx
[idx
];
1933 offset
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1934 offset
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1937 XPutImage(gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
1938 image_x
, image_y
, image_w
, image_h
);
1939 XDestroyImage(image
);
1942 wine_tsx11_unlock();
1944 LeaveCriticalSection(&xrender_cs
);
1946 if (flags
& ETO_CLIPPED
)
1948 /* restore the device region */
1949 X11DRV_SetDeviceClipping( physDev
, saved_region
, 0 );
1950 DeleteObject( saved_region
);
1956 X11DRV_UnlockDIBSection( physDev
, TRUE
);
1960 /* Helper function for (stretched) blitting using xrender */
1961 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
1962 int x_src
, int y_src
, int x_dst
, int y_dst
,
1963 double xscale
, double yscale
, int width
, int height
)
1965 int x_offset
, y_offset
;
1967 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1968 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1969 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1970 if(xscale
!= 1.0 || yscale
!= 1.0)
1972 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1973 * in the wrong quadrant of the x-y plane.
1975 x_offset
= (xscale
< 0) ? -width
: 0;
1976 y_offset
= (yscale
< 0) ? -height
: 0;
1977 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1983 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1985 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
1986 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width
, height
);
1989 /* Helper function for (stretched) mono->color blitting using xrender */
1990 static void xrender_mono_blit( Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
1991 int x_src
, int y_src
, double xscale
, double yscale
, int width
, int height
)
1993 int x_offset
, y_offset
;
1995 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
1996 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
1997 * tile data. We need PictOpOver for correct rendering.
1998 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2001 if (xscale
!= 1.0 || yscale
!= 1.0)
2003 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2004 * in the wrong quadrant of the x-y plane.
2006 x_offset
= (xscale
< 0) ? -width
: 0;
2007 y_offset
= (yscale
< 0) ? -height
: 0;
2008 set_xrender_transformation(mask_pict
, xscale
, yscale
, x_src
, y_src
);
2014 set_xrender_transformation(mask_pict
, 1, 1, 0, 0);
2016 pXRenderComposite(gdi_display
, PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2017 0, 0, x_offset
, y_offset
, 0, 0, width
, height
);
2020 /******************************************************************************
2023 BOOL
XRender_AlphaBlend( X11DRV_PDEVICE
*devDst
, X11DRV_PDEVICE
*devSrc
,
2024 struct bitblt_coords
*dst
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
2026 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
2027 struct xrender_info
*src_info
= get_xrender_info( devSrc
);
2028 double xscale
, yscale
;
2031 if(!X11DRV_XRender_Installed
) {
2032 FIXME("Unable to AlphaBlend without Xrender\n");
2036 if (devSrc
!= devDst
) X11DRV_LockDIBSection( devSrc
, DIB_Status_GdiMod
);
2037 X11DRV_LockDIBSection( devDst
, DIB_Status_GdiMod
);
2039 dst_pict
= get_xrender_picture( devDst
);
2041 use_repeat
= use_source_repeat( devSrc
);
2044 xscale
= src
->width
/ (double)dst
->width
;
2045 yscale
= src
->height
/ (double)dst
->height
;
2047 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2049 if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && src_info
->format
)
2051 /* we need a source picture with no alpha */
2052 WXRFormat format
= get_format_without_alpha( src_info
->format
->format
);
2053 if (format
!= src_info
->format
->format
)
2055 XRenderPictureAttributes pa
;
2056 const WineXRenderFormat
*fmt
= get_xrender_format( format
);
2059 pa
.subwindow_mode
= IncludeInferiors
;
2060 pa
.repeat
= use_repeat
? RepeatNormal
: RepeatNone
;
2061 tmp_pict
= pXRenderCreatePicture( gdi_display
, devSrc
->drawable
, fmt
->pict_format
,
2062 CPSubwindowMode
|CPRepeat
, &pa
);
2063 wine_tsx11_unlock();
2064 src_pict
= tmp_pict
;
2068 if (!src_pict
) src_pict
= get_xrender_picture_source( devSrc
, use_repeat
);
2070 EnterCriticalSection( &xrender_cs
);
2071 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
2074 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2075 devSrc
->dc_rect
.left
+ src
->visrect
.left
, devSrc
->dc_rect
.top
+ src
->visrect
.top
,
2076 devDst
->dc_rect
.left
+ dst
->visrect
.left
, devDst
->dc_rect
.top
+ dst
->visrect
.top
,
2078 dst
->visrect
.right
- dst
->visrect
.left
, dst
->visrect
.bottom
- dst
->visrect
.top
);
2079 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
2080 wine_tsx11_unlock();
2082 LeaveCriticalSection( &xrender_cs
);
2083 if (devSrc
!= devDst
) X11DRV_UnlockDIBSection( devSrc
, FALSE
);
2084 X11DRV_UnlockDIBSection( devDst
, TRUE
);
2089 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
2091 /* 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 */
2092 int depth
= physBitmap
->pixmap_depth
== 1 ? 1 : physDev
->depth
;
2093 const WineXRenderFormat
*src_format
= get_xrender_format_from_color_shifts(physBitmap
->pixmap_depth
, &physBitmap
->pixmap_color_shifts
);
2094 const WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
2097 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, depth
);
2099 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2100 if( (physBitmap
->pixmap_depth
== 1) || (!X11DRV_XRender_Installed
&& physDev
->depth
== physBitmap
->pixmap_depth
) ||
2101 (src_format
->format
== dst_format
->format
) )
2103 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
2104 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
2106 else /* We need depth conversion */
2108 Picture src_pict
, dst_pict
;
2109 XRenderPictureAttributes pa
;
2110 pa
.subwindow_mode
= IncludeInferiors
;
2111 pa
.repeat
= RepeatNone
;
2113 src_pict
= pXRenderCreatePicture(gdi_display
, physBitmap
->pixmap
, src_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2114 dst_pict
= pXRenderCreatePicture(gdi_display
, physDev
->brush
.pixmap
, dst_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2116 xrender_blit(PictOpSrc
, src_pict
, 0, dst_pict
, 0, 0, 0, 0, 1.0, 1.0, width
, height
);
2117 pXRenderFreePicture(gdi_display
, src_pict
);
2118 pXRenderFreePicture(gdi_display
, dst_pict
);
2120 wine_tsx11_unlock();
2123 BOOL
X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
2124 Pixmap pixmap
, GC gc
,
2125 const struct bitblt_coords
*src
, const struct bitblt_coords
*dst
)
2127 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
2128 int width
= dst
->visrect
.right
- dst
->visrect
.left
;
2129 int height
= dst
->visrect
.bottom
- dst
->visrect
.top
;
2130 int x_src
= physDevSrc
->dc_rect
.left
+ src
->visrect
.left
;
2131 int y_src
= physDevSrc
->dc_rect
.top
+ src
->visrect
.top
;
2132 struct xrender_info
*src_info
= get_xrender_info(physDevSrc
);
2133 const WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDevDst
->depth
, physDevDst
->color_shifts
);
2134 Picture src_pict
=0, dst_pict
=0, mask_pict
=0;
2136 double xscale
, yscale
;
2138 XRenderPictureAttributes pa
;
2139 pa
.subwindow_mode
= IncludeInferiors
;
2140 pa
.repeat
= RepeatNone
;
2142 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2143 physDevSrc
->depth
, src
->width
, src
->height
, x_src
, y_src
);
2144 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst
->depth
, dst
->width
, dst
->height
);
2146 if(!X11DRV_XRender_Installed
)
2148 TRACE("Not using XRender since it is not available or disabled\n");
2152 /* XRender can't handle palettes, so abort */
2153 if(X11DRV_PALETTE_XPixelToPalette
)
2156 /* XRender is of no use in this case */
2157 if((physDevDst
->depth
== 1) && (physDevSrc
->depth
> 1))
2160 /* Just use traditional X copy when the formats match and we don't need stretching */
2161 if((src_info
->format
->format
== dst_format
->format
) && !stretch
)
2163 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2165 XCopyArea( gdi_display
, physDevSrc
->drawable
, pixmap
, gc
, x_src
, y_src
, width
, height
, 0, 0);
2166 wine_tsx11_unlock();
2170 use_repeat
= use_source_repeat( physDevSrc
);
2173 xscale
= src
->width
/ (double)dst
->width
;
2174 yscale
= src
->height
/ (double)dst
->height
;
2176 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2179 if(physDevSrc
->depth
== 1 && physDevDst
->depth
> 1)
2182 get_xrender_color(dst_format
, physDevDst
->textPixel
, &col
);
2184 /* We use the source drawable as a mask */
2185 mask_pict
= get_xrender_picture_source( physDevSrc
, use_repeat
);
2187 /* Use backgroundPixel as the foreground color */
2188 EnterCriticalSection( &xrender_cs
);
2189 src_pict
= get_tile_pict(dst_format
, physDevDst
->backgroundPixel
);
2191 /* Create a destination picture and fill it with textPixel color as the background color */
2193 dst_pict
= pXRenderCreatePicture(gdi_display
, pixmap
, dst_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2194 pXRenderFillRectangle(gdi_display
, PictOpSrc
, dst_pict
, &col
, 0, 0, width
, height
);
2196 xrender_mono_blit(src_pict
, mask_pict
, dst_pict
, x_src
, y_src
, xscale
, yscale
, width
, height
);
2198 if(dst_pict
) pXRenderFreePicture(gdi_display
, dst_pict
);
2199 wine_tsx11_unlock();
2200 LeaveCriticalSection( &xrender_cs
);
2202 else /* color -> color (can be at different depths) or mono -> mono */
2204 src_pict
= get_xrender_picture_source( physDevSrc
, use_repeat
);
2207 dst_pict
= pXRenderCreatePicture(gdi_display
,
2208 pixmap
, dst_format
->pict_format
,
2209 CPSubwindowMode
|CPRepeat
, &pa
);
2211 xrender_blit(PictOpSrc
, src_pict
, 0, dst_pict
, x_src
, y_src
, 0, 0, xscale
, yscale
, width
, height
);
2213 if(dst_pict
) pXRenderFreePicture(gdi_display
, dst_pict
);
2214 wine_tsx11_unlock();
2219 #else /* SONAME_LIBXRENDER */
2221 void X11DRV_XRender_Init(void)
2223 TRACE("XRender support not compiled in.\n");
2227 void X11DRV_XRender_Finalize(void)
2231 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
2237 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
2243 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE
*physDev
, const RGNDATA
*data
)
2249 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
2250 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
2257 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
2263 BOOL
XRender_AlphaBlend( X11DRV_PDEVICE
*devDst
, X11DRV_PDEVICE
*devSrc
,
2264 struct bitblt_coords
*dst
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
2266 FIXME("not supported - XRENDER headers were missing at compile time\n");
2270 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
2273 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, physBitmap
->pixmap_depth
);
2275 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
2276 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
2277 wine_tsx11_unlock();
2280 BOOL
X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP
*physBitmap
, int bits_pixel
, const DIBSECTION
*dib
)
2285 BOOL
X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
2286 Pixmap pixmap
, GC gc
,
2287 const struct bitblt_coords
*src
, const struct bitblt_coords
*dst
)
2291 #endif /* SONAME_LIBXRENDER */