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 #define MAX_FORMATS 10
59 typedef enum wine_xrformat
73 typedef struct wine_xrender_format_template
78 unsigned int alphaMask
;
82 unsigned int greenMask
;
84 unsigned int blueMask
;
85 } WineXRenderFormatTemplate
;
87 static const WineXRenderFormatTemplate wxr_formats_template
[] =
89 /* Format depth alpha mask red mask green mask blue mask*/
90 {WXR_FORMAT_MONO
, 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
91 {WXR_FORMAT_GRAY
, 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
92 {WXR_FORMAT_X1R5G5B5
, 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
93 {WXR_FORMAT_X1B5G5R5
, 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
94 {WXR_FORMAT_R5G6B5
, 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
95 {WXR_FORMAT_B5G6R5
, 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
96 {WXR_FORMAT_R8G8B8
, 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
97 {WXR_FORMAT_B8G8R8
, 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
98 {WXR_FORMAT_A8R8G8B8
, 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
99 {WXR_FORMAT_X8R8G8B8
, 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff }
102 typedef struct wine_xrender_format
105 XRenderPictFormat
*pict_format
;
108 static WineXRenderFormat wxr_formats
[MAX_FORMATS
];
109 static int WineXRenderFormatsListSize
= 0;
110 static WineXRenderFormat
*default_format
= NULL
;
116 SIZE devsize
; /* size in device coords */
120 #define INITIAL_REALIZED_BUF_SIZE 128
122 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
127 WineXRenderFormat
*font_format
;
132 } gsCacheEntryFormat
;
138 gsCacheEntryFormat
* format
[AA_MAXVALUE
];
143 struct tagXRENDERINFO
150 static gsCacheEntry
*glyphsetCache
= NULL
;
151 static DWORD glyphsetCacheSize
= 0;
152 static INT lastfree
= -1;
155 #define INIT_CACHE_SIZE 10
157 static int antialias
= 1;
159 static void *xrender_handle
;
161 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
162 MAKE_FUNCPTR(XRenderAddGlyphs
)
163 MAKE_FUNCPTR(XRenderComposite
)
164 MAKE_FUNCPTR(XRenderCompositeString8
)
165 MAKE_FUNCPTR(XRenderCompositeString16
)
166 MAKE_FUNCPTR(XRenderCompositeString32
)
167 MAKE_FUNCPTR(XRenderCompositeText16
)
168 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
169 MAKE_FUNCPTR(XRenderCreatePicture
)
170 MAKE_FUNCPTR(XRenderFillRectangle
)
171 MAKE_FUNCPTR(XRenderFindFormat
)
172 MAKE_FUNCPTR(XRenderFindVisualFormat
)
173 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
174 MAKE_FUNCPTR(XRenderFreePicture
)
175 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
176 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
177 MAKE_FUNCPTR(XRenderSetPictureTransform
)
179 MAKE_FUNCPTR(XRenderQueryExtension
)
182 static CRITICAL_SECTION xrender_cs
;
183 static CRITICAL_SECTION_DEBUG critsect_debug
=
186 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
187 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
189 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
191 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
192 ( ( (ULONG)_x4 << 24 ) | \
193 ( (ULONG)_x3 << 16 ) | \
194 ( (ULONG)_x2 << 8 ) | \
197 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
199 #define GASP_GRIDFIT 0x01
200 #define GASP_DOGRAY 0x02
202 #ifdef WORDS_BIGENDIAN
203 #define get_be_word(x) (x)
204 #define NATIVE_BYTE_ORDER MSBFirst
206 #define get_be_word(x) RtlUshortByteSwap(x)
207 #define NATIVE_BYTE_ORDER LSBFirst
210 static BOOL
get_xrender_template(const WineXRenderFormatTemplate
*fmt
, XRenderPictFormat
*templ
, unsigned long *mask
)
213 templ
->type
= PictTypeDirect
;
214 templ
->depth
= fmt
->depth
;
215 templ
->direct
.alpha
= fmt
->alpha
;
216 templ
->direct
.alphaMask
= fmt
->alphaMask
;
217 templ
->direct
.red
= fmt
->red
;
218 templ
->direct
.redMask
= fmt
->redMask
;
219 templ
->direct
.green
= fmt
->green
;
220 templ
->direct
.greenMask
= fmt
->greenMask
;
221 templ
->direct
.blue
= fmt
->blue
;
222 templ
->direct
.blueMask
= fmt
->blueMask
;
225 *mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
| PictFormatRed
| PictFormatRedMask
| PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
| PictFormatBlueMask
;
230 static BOOL
is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate
*fmt
)
232 if(fmt
->depth
!= screen_depth
)
234 if( (fmt
->redMask
<< fmt
->red
) != visual
->red_mask
)
236 if( (fmt
->greenMask
<< fmt
->green
) != visual
->green_mask
)
238 if( (fmt
->blueMask
<< fmt
->blue
) != visual
->blue_mask
)
241 /* We never select a default ARGB visual */
248 static int load_xrender_formats(void)
251 for(i
= 0; i
< (sizeof(wxr_formats_template
) / sizeof(wxr_formats_template
[0])); i
++)
253 XRenderPictFormat templ
, *pict_format
;
255 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template
[i
]))
258 pict_format
= pXRenderFindVisualFormat(gdi_display
, visual
);
261 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
262 if (visual
->class == DirectColor
)
265 if (XMatchVisualInfo( gdi_display
, DefaultScreen(gdi_display
),
266 screen_depth
, TrueColor
, &info
))
268 pict_format
= pXRenderFindVisualFormat(gdi_display
, info
.visual
);
269 if (pict_format
) visual
= info
.visual
;
277 wxr_formats
[WineXRenderFormatsListSize
].format
= wxr_formats_template
[i
].wxr_format
;
278 wxr_formats
[WineXRenderFormatsListSize
].pict_format
= pict_format
;
279 default_format
= &wxr_formats
[WineXRenderFormatsListSize
];
280 WineXRenderFormatsListSize
++;
281 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format
->id
, wxr_formats_template
[i
].wxr_format
);
286 unsigned long mask
= 0;
287 get_xrender_template(&wxr_formats_template
[i
], &templ
, &mask
);
290 pict_format
= pXRenderFindFormat(gdi_display
, mask
, &templ
, 0);
295 wxr_formats
[WineXRenderFormatsListSize
].format
= wxr_formats_template
[i
].wxr_format
;
296 wxr_formats
[WineXRenderFormatsListSize
].pict_format
= pict_format
;
297 WineXRenderFormatsListSize
++;
298 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format
->id
, wxr_formats_template
[i
].wxr_format
);
302 return WineXRenderFormatsListSize
;
305 /***********************************************************************
306 * X11DRV_XRender_Init
308 * Let's see if our XServer has the extension available
311 void X11DRV_XRender_Init(void)
315 if (client_side_with_render
&&
316 wine_dlopen(SONAME_LIBX11
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
317 wine_dlopen(SONAME_LIBXEXT
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
318 (xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0)))
321 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
322 LOAD_FUNCPTR(XRenderAddGlyphs
)
323 LOAD_FUNCPTR(XRenderComposite
)
324 LOAD_FUNCPTR(XRenderCompositeString8
)
325 LOAD_FUNCPTR(XRenderCompositeString16
)
326 LOAD_FUNCPTR(XRenderCompositeString32
)
327 LOAD_FUNCPTR(XRenderCompositeText16
)
328 LOAD_FUNCPTR(XRenderCreateGlyphSet
)
329 LOAD_FUNCPTR(XRenderCreatePicture
)
330 LOAD_FUNCPTR(XRenderFillRectangle
)
331 LOAD_FUNCPTR(XRenderFindFormat
)
332 LOAD_FUNCPTR(XRenderFindVisualFormat
)
333 LOAD_FUNCPTR(XRenderFreeGlyphSet
)
334 LOAD_FUNCPTR(XRenderFreePicture
)
335 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
)
336 LOAD_FUNCPTR(XRenderQueryExtension
)
338 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
339 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
340 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
)
341 #undef LOAD_OPTIONAL_FUNCPTR
345 X11DRV_XRender_Installed
= pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
);
347 if(X11DRV_XRender_Installed
) {
348 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
349 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
353 "Wine has detected that you probably have a buggy version\n"
354 "of libXrender.so . Because of this client side font rendering\n"
355 "will be disabled. Please upgrade this library.\n");
356 X11DRV_XRender_Installed
= FALSE
;
360 if (!visual
->red_mask
|| !visual
->green_mask
|| !visual
->blue_mask
) {
361 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
362 X11DRV_XRender_Installed
= FALSE
;
368 if(X11DRV_XRender_Installed
|| client_side_with_core
)
370 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
371 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
373 glyphsetCacheSize
= INIT_CACHE_SIZE
;
375 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
376 glyphsetCache
[i
].next
= i
+ 1;
377 glyphsetCache
[i
].count
= -1;
379 glyphsetCache
[i
-1].next
= -1;
380 using_client_side_fonts
= 1;
382 if(!X11DRV_XRender_Installed
) {
383 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
384 if(screen_depth
<= 8 || !client_side_antialias_with_core
)
387 if(screen_depth
<= 8 || !client_side_antialias_with_render
)
391 else TRACE("Using X11 core fonts\n");
394 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
395 static void get_xrender_color(WineXRenderFormat
*wxr_format
, int src_color
, XRenderColor
*dst_color
)
397 XRenderPictFormat
*pf
= wxr_format
->pict_format
;
399 if(pf
->direct
.redMask
)
400 dst_color
->red
= ((src_color
>> pf
->direct
.red
) & pf
->direct
.redMask
) * 65535/pf
->direct
.redMask
;
404 if(pf
->direct
.greenMask
)
405 dst_color
->green
= ((src_color
>> pf
->direct
.green
) & pf
->direct
.greenMask
) * 65535/pf
->direct
.greenMask
;
407 dst_color
->green
= 0;
409 if(pf
->direct
.blueMask
)
410 dst_color
->blue
= ((src_color
>> pf
->direct
.blue
) & pf
->direct
.blueMask
) * 65535/pf
->direct
.blueMask
;
414 dst_color
->alpha
= 0xffff;
417 static WineXRenderFormat
*get_xrender_format(WXRFormat format
)
420 for(i
=0; i
<WineXRenderFormatsListSize
; i
++)
422 if(wxr_formats
[i
].format
== format
)
424 TRACE("Returning wxr_format=%#x\n", format
);
425 return &wxr_formats
[i
];
431 static WineXRenderFormat
*get_xrender_format_from_color_shifts(int depth
, ColorShifts
*shifts
)
433 int redMask
, greenMask
, blueMask
;
437 return get_xrender_format(WXR_FORMAT_MONO
);
439 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
441 return default_format
;
443 redMask
= shifts
->physicalRed
.max
<< shifts
->physicalRed
.shift
;
444 greenMask
= shifts
->physicalGreen
.max
<< shifts
->physicalGreen
.shift
;
445 blueMask
= shifts
->physicalBlue
.max
<< shifts
->physicalBlue
.shift
;
447 /* Try to locate a format which matches the specification of the dibsection. */
448 for(i
= 0; i
< (sizeof(wxr_formats_template
) / sizeof(wxr_formats_template
[0])); i
++)
450 if( depth
== wxr_formats_template
[i
].depth
&&
451 redMask
== (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
452 greenMask
== (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
453 blueMask
== (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
) )
456 /* When we reach this stage the format was found in our template table but this doesn't mean that
457 * the Xserver also supports this format (e.g. its depth might be too low). The call below verifies that.
459 return get_xrender_format(wxr_formats_template
[i
].wxr_format
);
463 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
464 ERR("No XRender format found!\n");
468 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
470 if(p1
->hash
!= p2
->hash
) return TRUE
;
471 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
472 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
473 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
474 return strcmpiW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
478 static void walk_cache(void)
482 EnterCriticalSection(&xrender_cs
);
483 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
484 TRACE("item %d\n", i
);
485 LeaveCriticalSection(&xrender_cs
);
489 static int LookupEntry(LFANDSIZE
*plfsz
)
493 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
495 if(glyphsetCache
[i
].count
== -1) { /* reached free list so stop */
500 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
501 glyphsetCache
[i
].count
++;
503 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
504 glyphsetCache
[i
].next
= mru
;
507 TRACE("found font in cache %d\n", i
);
512 TRACE("font not in cache\n");
516 static void FreeEntry(int entry
)
520 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
521 gsCacheEntryFormat
* formatEntry
;
523 if( !glyphsetCache
[entry
].format
[format
] )
526 formatEntry
= glyphsetCache
[entry
].format
[format
];
528 if(formatEntry
->glyphset
) {
530 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
532 formatEntry
->glyphset
= 0;
534 if(formatEntry
->nrealized
) {
535 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
536 formatEntry
->realized
= NULL
;
537 if(formatEntry
->bitmaps
) {
538 for(i
= 0; i
< formatEntry
->nrealized
; i
++)
539 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
[i
]);
540 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
);
541 formatEntry
->bitmaps
= NULL
;
543 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
544 formatEntry
->gis
= NULL
;
545 formatEntry
->nrealized
= 0;
548 HeapFree(GetProcessHeap(), 0, formatEntry
);
549 glyphsetCache
[entry
].format
[format
] = NULL
;
553 static int AllocEntry(void)
555 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
558 assert(glyphsetCache
[lastfree
].count
== -1);
559 glyphsetCache
[lastfree
].count
= 1;
561 lastfree
= glyphsetCache
[lastfree
].next
;
563 glyphsetCache
[best
].next
= mru
;
566 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
570 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
571 if(glyphsetCache
[i
].count
== 0) {
579 TRACE("freeing unused glyphset at cache %d\n", best
);
581 glyphsetCache
[best
].count
= 1;
583 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
584 glyphsetCache
[best
].next
= mru
;
592 TRACE("Growing cache\n");
595 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
597 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
598 * sizeof(*glyphsetCache
));
600 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
601 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
602 * sizeof(*glyphsetCache
));
604 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
606 glyphsetCache
[i
].next
= i
+ 1;
607 glyphsetCache
[i
].count
= -1;
609 glyphsetCache
[i
-1].next
= -1;
610 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
612 lastfree
= glyphsetCache
[best
].next
;
613 glyphsetCache
[best
].count
= 1;
614 glyphsetCache
[best
].next
= mru
;
616 TRACE("new free cache slot at %d\n", mru
);
620 static BOOL
get_gasp_flags(X11DRV_PDEVICE
*physDev
, WORD
*flags
)
630 size
= GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, NULL
, 0);
631 if(size
== GDI_ERROR
)
634 gasp
= buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
635 GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, gasp
, size
);
637 GetTextMetricsW(physDev
->hdc
, &tm
);
638 ppem
= abs(X11DRV_YWStoDS(physDev
, tm
.tmAscent
+ tm
.tmDescent
- tm
.tmInternalLeading
));
641 num_recs
= get_be_word(*gasp
);
645 *flags
= get_be_word(*(gasp
+ 1));
646 if(ppem
<= get_be_word(*gasp
))
650 TRACE("got flags %04x for ppem %d\n", *flags
, ppem
);
652 HeapFree(GetProcessHeap(), 0, buffer
);
656 static AA_Type
get_antialias_type( X11DRV_PDEVICE
*physDev
, BOOL subpixel
, BOOL hinter
)
660 UINT font_smoothing_type
, font_smoothing_orientation
;
662 if (X11DRV_XRender_Installed
&& subpixel
&&
663 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE
, 0, &font_smoothing_type
, 0) &&
664 font_smoothing_type
== FE_FONTSMOOTHINGCLEARTYPE
)
666 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION
, 0,
667 &font_smoothing_orientation
, 0) &&
668 font_smoothing_orientation
== FE_FONTSMOOTHINGORIENTATIONBGR
)
675 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
676 But, Wine's subpixel rendering can support the portrait mode.
679 else if (!hinter
|| !get_gasp_flags(physDev
, &flags
) || flags
& GASP_DOGRAY
)
687 static int GetCacheEntry(X11DRV_PDEVICE
*physDev
, LFANDSIZE
*plfsz
)
692 static int hinter
= -1;
693 static int subpixel
= -1;
696 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
699 entry
= glyphsetCache
+ ret
;
700 entry
->lfsz
= *plfsz
;
701 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
702 assert( !entry
->format
[format
] );
705 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
707 if(hinter
== -1 || subpixel
== -1)
709 RASTERIZER_STATUS status
;
710 GetRasterizerCaps(&status
, sizeof(status
));
711 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
712 subpixel
= status
.wFlags
& WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
715 switch (plfsz
->lf
.lfQuality
)
717 case ANTIALIASED_QUALITY
:
718 entry
->aa_default
= get_antialias_type( physDev
, FALSE
, hinter
);
720 case CLEARTYPE_QUALITY
:
721 case CLEARTYPE_NATURAL_QUALITY
:
722 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
724 case DEFAULT_QUALITY
:
728 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING
, 0, &font_smoothing
, 0) &&
731 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
734 entry
->aa_default
= AA_None
;
739 entry
->aa_default
= AA_None
;
744 static void dec_ref_cache(int index
)
747 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
748 assert(glyphsetCache
[index
].count
> 0);
749 glyphsetCache
[index
].count
--;
752 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
754 DWORD hash
= 0, *ptr
, two_chars
;
758 hash
^= plfsz
->devsize
.cx
;
759 hash
^= plfsz
->devsize
.cy
;
760 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
762 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
764 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
766 pwc
= (WCHAR
*)&two_chars
;
768 *pwc
= toupperW(*pwc
);
770 *pwc
= toupperW(*pwc
);
778 /***********************************************************************
779 * X11DRV_XRender_Finalize
781 void X11DRV_XRender_Finalize(void)
785 EnterCriticalSection(&xrender_cs
);
786 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
788 LeaveCriticalSection(&xrender_cs
);
792 /***********************************************************************
793 * X11DRV_XRender_SelectFont
795 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
799 GetObjectW(hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
800 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
801 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
802 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
803 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
804 lfsz
.devsize
.cx
= X11DRV_XWStoDS( physDev
, lfsz
.lf
.lfWidth
);
805 lfsz
.devsize
.cy
= X11DRV_YWStoDS( physDev
, lfsz
.lf
.lfHeight
);
806 GetWorldTransform( physDev
->hdc
, &lfsz
.xform
);
807 lfsz_calc_hash(&lfsz
);
809 EnterCriticalSection(&xrender_cs
);
810 if(!physDev
->xrender
) {
811 physDev
->xrender
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
812 sizeof(*physDev
->xrender
));
813 physDev
->xrender
->cache_index
= -1;
815 else if(physDev
->xrender
->cache_index
!= -1)
816 dec_ref_cache(physDev
->xrender
->cache_index
);
817 physDev
->xrender
->cache_index
= GetCacheEntry(physDev
, &lfsz
);
818 LeaveCriticalSection(&xrender_cs
);
822 /***********************************************************************
823 * X11DRV_XRender_DeleteDC
825 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
827 X11DRV_XRender_UpdateDrawable(physDev
);
829 EnterCriticalSection(&xrender_cs
);
830 if(physDev
->xrender
->cache_index
!= -1)
831 dec_ref_cache(physDev
->xrender
->cache_index
);
832 LeaveCriticalSection(&xrender_cs
);
834 HeapFree(GetProcessHeap(), 0, physDev
->xrender
);
835 physDev
->xrender
= NULL
;
839 BOOL
X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP
*physBitmap
, const DIBSECTION
*dib
)
841 WineXRenderFormat
*fmt
;
844 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
845 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
846 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
847 if(!X11DRV_XRender_Installed
|| dib
->dsBm
.bmBitsPixel
<= 8)
850 X11DRV_PALETTE_ComputeColorShifts(&shifts
, dib
->dsBitfields
[0], dib
->dsBitfields
[1], dib
->dsBitfields
[2]);
852 /* Common formats should be in our picture format table. */
853 fmt
= get_xrender_format_from_color_shifts(dib
->dsBm
.bmBitsPixel
, &shifts
);
856 physBitmap
->pixmap_depth
= fmt
->pict_format
->depth
;
857 physBitmap
->trueColor
= TRUE
;
858 physBitmap
->pixmap_color_shifts
= shifts
;
861 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
862 dib
->dsBm
.bmBitsPixel
, dib
->dsBitfields
[0], dib
->dsBitfields
[1], dib
->dsBitfields
[2]);
866 /***********************************************************************
867 * X11DRV_XRender_UpdateDrawable
869 * Deletes the pict and tile when the drawable changes.
871 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
875 if(physDev
->xrender
->pict
)
877 TRACE("freeing pict = %lx dc = %p\n", physDev
->xrender
->pict
, physDev
->hdc
);
879 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
880 physDev
->xrender
->pict
= 0;
887 /************************************************************************
890 * Helper to ExtTextOut. Must be called inside xrender_cs
892 static BOOL
UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
, AA_Type format
)
899 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
900 gsCacheEntryFormat
*formatEntry
;
901 UINT ggo_format
= GGO_GLYPH_INDEX
;
902 WXRFormat wxr_format
;
903 static const char zero
[4];
904 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
908 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
911 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
914 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
917 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
920 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
924 ERR("aa = %d - not implemented\n", format
);
926 ggo_format
|= GGO_BITMAP
;
930 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
931 if(buflen
== GDI_ERROR
) {
932 if(format
!= AA_None
) {
934 entry
->aa_default
= AA_None
;
935 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
936 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
938 if(buflen
== GDI_ERROR
) {
939 WARN("GetGlyphOutlineW failed\n");
942 TRACE("Turning off antialiasing for this monochrome font\n");
945 /* If there is nothing for the current type, we create the entry. */
946 if( !entry
->format
[format
] ) {
947 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
949 sizeof(gsCacheEntryFormat
));
951 formatEntry
= entry
->format
[format
];
953 if(formatEntry
->nrealized
<= glyph
) {
954 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
956 if (formatEntry
->realized
)
957 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
959 formatEntry
->realized
,
960 formatEntry
->nrealized
* sizeof(BOOL
));
962 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
964 formatEntry
->nrealized
* sizeof(BOOL
));
966 if(!X11DRV_XRender_Installed
) {
967 if (formatEntry
->bitmaps
)
968 formatEntry
->bitmaps
= HeapReAlloc(GetProcessHeap(),
970 formatEntry
->bitmaps
,
971 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
973 formatEntry
->bitmaps
= HeapAlloc(GetProcessHeap(),
975 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
977 if (formatEntry
->gis
)
978 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
981 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
983 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
985 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
989 if(formatEntry
->glyphset
== 0 && X11DRV_XRender_Installed
) {
992 wxr_format
= WXR_FORMAT_GRAY
;
999 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1003 ERR("aa = %d - not implemented\n", format
);
1005 wxr_format
= WXR_FORMAT_MONO
;
1010 formatEntry
->font_format
= get_xrender_format(wxr_format
);
1011 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
->pict_format
);
1012 wine_tsx11_unlock();
1016 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
1017 GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
1018 formatEntry
->realized
[glyph
] = TRUE
;
1020 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1022 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1023 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1025 gi
.width
= gm
.gmBlackBoxX
;
1026 gi
.height
= gm
.gmBlackBoxY
;
1027 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1028 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1029 gi
.xOff
= gm
.gmCellIncX
;
1030 gi
.yOff
= gm
.gmCellIncY
;
1032 if(TRACE_ON(xrender
)) {
1035 unsigned char *line
;
1037 if(format
== AA_None
) {
1038 pitch
= ((gi
.width
+ 31) / 32) * 4;
1039 for(i
= 0; i
< gi
.height
; i
++) {
1040 line
= (unsigned char*) buf
+ i
* pitch
;
1042 for(j
= 0; j
< pitch
* 8; j
++) {
1043 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1045 TRACE("%s\n", output
);
1048 static const char blks
[] = " .:;!o*#";
1052 pitch
= ((gi
.width
+ 3) / 4) * 4;
1053 for(i
= 0; i
< gi
.height
; i
++) {
1054 line
= (unsigned char*) buf
+ i
* pitch
;
1056 for(j
= 0; j
< pitch
; j
++) {
1057 str
[0] = blks
[line
[j
] >> 5];
1058 strcat(output
, str
);
1060 TRACE("%s\n", output
);
1066 if(formatEntry
->glyphset
) {
1067 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1068 unsigned char *byte
= (unsigned char*) buf
, c
;
1074 /* magic to flip bit order */
1075 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1076 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1077 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1082 else if ( format
!= AA_Grey
&&
1083 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1085 unsigned int i
, *data
= (unsigned int *)buf
;
1086 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1091 XRenderCompositeText seems to ignore 0x0 glyphs when
1092 AA_None, which means we lose the advance width of glyphs
1093 like the space. We'll pretend that such glyphs are 1x1
1098 gi
.width
= gi
.height
= 1;
1101 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1102 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1103 wine_tsx11_unlock();
1104 HeapFree(GetProcessHeap(), 0, buf
);
1106 formatEntry
->bitmaps
[glyph
] = buf
;
1109 formatEntry
->gis
[glyph
] = gi
;
1114 static void SharpGlyphMono(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
1115 void *bitmap
, XGlyphInfo
*gi
)
1117 unsigned char *srcLine
= bitmap
, *src
;
1118 unsigned char bits
, bitsMask
;
1119 int width
= gi
->width
;
1120 int stride
= ((width
+ 31) & ~31) >> 3;
1121 int height
= gi
->height
;
1125 TRACE("%d, %d\n", x
, y
);
1134 bitsMask
= 0x80; /* FreeType is always MSB first */
1140 if (bits
& bitsMask
)
1148 bitsMask
= bitsMask
>> 1;
1154 } while (bits
& bitsMask
);
1155 XFillRectangle (gdi_display
, physDev
->drawable
,
1156 physDev
->gc
, xspan
, y
, lenspan
, 1);
1168 bitsMask
= bitsMask
>> 1;
1174 } while (!(bits
& bitsMask
));
1181 static void SharpGlyphGray(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
1182 void *bitmap
, XGlyphInfo
*gi
)
1184 unsigned char *srcLine
= bitmap
, *src
, bits
;
1185 int width
= gi
->width
;
1186 int stride
= ((width
+ 3) & ~3);
1187 int height
= gi
->height
;
1212 } while (bits
>= 0x80);
1213 XFillRectangle (gdi_display
, physDev
->drawable
,
1214 physDev
->gc
, xspan
, y
, lenspan
, 1);
1227 } while (bits
< 0x80);
1235 static void ExamineBitfield (DWORD mask
, int *shift
, int *len
)
1240 while ((mask
& 1) == 0)
1246 while ((mask
& 1) == 1)
1255 static DWORD
GetField (DWORD pixel
, int shift
, int len
)
1257 pixel
= pixel
& (((1 << (len
)) - 1) << shift
);
1258 pixel
= pixel
<< (32 - (shift
+ len
)) >> 24;
1261 pixel
|= (pixel
>> len
);
1268 static DWORD
PutField (DWORD pixel
, int shift
, int len
)
1270 shift
= shift
- (8 - len
);
1272 pixel
&= (((1 << len
) - 1) << (8 - len
));
1280 static void SmoothGlyphGray(XImage
*image
, int x
, int y
, void *bitmap
, XGlyphInfo
*gi
,
1286 BYTE
*maskLine
, *mask
, m
;
1291 BYTE src_r
, src_g
, src_b
;
1296 height
= gi
->height
;
1299 maskStride
= (width
+ 3) & ~3;
1301 ExamineBitfield (image
->red_mask
, &r_shift
, &r_len
);
1302 ExamineBitfield (image
->green_mask
, &g_shift
, &g_len
);
1303 ExamineBitfield (image
->blue_mask
, &b_shift
, &b_len
);
1305 src_r
= GetField(color
, r_shift
, r_len
);
1306 src_g
= GetField(color
, g_shift
, g_len
);
1307 src_b
= GetField(color
, b_shift
, b_len
);
1309 for(; height
--; y
++)
1312 maskLine
+= maskStride
;
1317 if(y
>= image
->height
) break;
1321 if(tx
>= image
->width
) break;
1324 if(tx
< 0) continue;
1327 XPutPixel (image
, tx
, y
, color
);
1332 pixel
= XGetPixel (image
, tx
, y
);
1334 r
= GetField(pixel
, r_shift
, r_len
);
1335 r
= ((BYTE
)~m
* (WORD
)r
+ (BYTE
)m
* (WORD
)src_r
) >> 8;
1336 g
= GetField(pixel
, g_shift
, g_len
);
1337 g
= ((BYTE
)~m
* (WORD
)g
+ (BYTE
)m
* (WORD
)src_g
) >> 8;
1338 b
= GetField(pixel
, b_shift
, b_len
);
1339 b
= ((BYTE
)~m
* (WORD
)b
+ (BYTE
)m
* (WORD
)src_b
) >> 8;
1341 pixel
= (PutField (r
, r_shift
, r_len
) |
1342 PutField (g
, g_shift
, g_len
) |
1343 PutField (b
, b_shift
, b_len
));
1344 XPutPixel (image
, tx
, y
, pixel
);
1350 /*************************************************************
1353 * Returns an appropriate Picture for tiling the text colour.
1354 * Call and use result within the xrender_cs
1356 static Picture
get_tile_pict(WineXRenderFormat
*wxr_format
, int text_pixel
)
1363 } tiles
[MAX_FORMATS
], *tile
;
1366 tile
= &tiles
[wxr_format
->format
];
1370 XRenderPictureAttributes pa
;
1373 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, wxr_format
->pict_format
->depth
);
1375 pa
.repeat
= RepeatNormal
;
1376 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, wxr_format
->pict_format
, CPRepeat
, &pa
);
1377 wine_tsx11_unlock();
1379 /* init current_color to something different from text_pixel */
1380 tile
->current_color
= ~text_pixel
;
1382 if(wxr_format
->format
== WXR_FORMAT_MONO
)
1384 /* for a 1bpp bitmap we always need a 1 in the tile */
1385 col
.red
= col
.green
= col
.blue
= 0;
1388 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1389 wine_tsx11_unlock();
1393 if(text_pixel
!= tile
->current_color
&& wxr_format
->format
!= WXR_FORMAT_MONO
)
1395 get_xrender_color(wxr_format
, text_pixel
, &col
);
1397 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1398 wine_tsx11_unlock();
1399 tile
->current_color
= text_pixel
;
1404 static int XRenderErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
1409 /***********************************************************************
1410 * X11DRV_XRender_ExtTextOut
1412 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1413 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1418 gsCacheEntry
*entry
;
1419 gsCacheEntryFormat
*formatEntry
;
1421 HDC hdc
= physDev
->hdc
;
1422 int textPixel
, backgroundPixel
;
1423 HRGN saved_region
= 0;
1424 BOOL disable_antialias
= FALSE
;
1425 AA_Type aa_type
= AA_None
;
1428 double cosEsc
, sinEsc
;
1430 WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
1431 Picture tile_pict
= 0;
1433 /* Do we need to disable antialiasing because of palette mode? */
1434 if( !physDev
->bitmap
|| GetObjectW( physDev
->bitmap
->hbitmap
, sizeof(bmp
), &bmp
) != sizeof(bmp
) ) {
1435 TRACE("bitmap is not a DIB\n");
1437 else if (bmp
.dsBmih
.biBitCount
<= 8) {
1438 TRACE("Disabling antialiasing\n");
1439 disable_antialias
= TRUE
;
1442 xgcval
.function
= GXcopy
;
1443 xgcval
.background
= physDev
->backgroundPixel
;
1444 xgcval
.fill_style
= FillSolid
;
1446 XChangeGC( gdi_display
, physDev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1447 wine_tsx11_unlock();
1449 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
);
1451 if(physDev
->depth
== 1) {
1452 if((physDev
->textPixel
& 0xffffff) == 0) {
1454 backgroundPixel
= 1;
1457 backgroundPixel
= 0;
1460 textPixel
= physDev
->textPixel
;
1461 backgroundPixel
= physDev
->backgroundPixel
;
1464 if(flags
& ETO_OPAQUE
)
1467 XSetForeground( gdi_display
, physDev
->gc
, backgroundPixel
);
1468 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1469 physDev
->dc_rect
.left
+ lprect
->left
, physDev
->dc_rect
.top
+ lprect
->top
,
1470 lprect
->right
- lprect
->left
, lprect
->bottom
- lprect
->top
);
1471 wine_tsx11_unlock();
1481 GetObjectW(GetCurrentObject(physDev
->hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
1482 if(lf
.lfEscapement
!= 0) {
1483 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
1484 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
1490 if (flags
& ETO_CLIPPED
)
1494 clip_region
= CreateRectRgnIndirect( lprect
);
1495 /* make a copy of the current device region */
1496 saved_region
= CreateRectRgn( 0, 0, 0, 0 );
1497 CombineRgn( saved_region
, physDev
->region
, 0, RGN_COPY
);
1498 X11DRV_SetDeviceClipping( physDev
, saved_region
, clip_region
);
1499 DeleteObject( clip_region
);
1502 if(X11DRV_XRender_Installed
) {
1503 if(!physDev
->xrender
->pict
) {
1504 XRenderPictureAttributes pa
;
1505 pa
.subwindow_mode
= IncludeInferiors
;
1508 physDev
->xrender
->pict
= pXRenderCreatePicture(gdi_display
,
1509 physDev
->drawable
, dst_format
->pict_format
,
1510 CPSubwindowMode
, &pa
);
1511 wine_tsx11_unlock();
1513 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1514 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1516 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1517 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1520 if ((data
= X11DRV_GetRegionData( physDev
->region
, 0 )))
1523 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
1524 physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
1525 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
1526 wine_tsx11_unlock();
1527 HeapFree( GetProcessHeap(), 0, data
);
1531 EnterCriticalSection(&xrender_cs
);
1533 entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1534 if( disable_antialias
== FALSE
)
1535 aa_type
= entry
->aa_default
;
1536 formatEntry
= entry
->format
[aa_type
];
1538 for(idx
= 0; idx
< count
; idx
++) {
1539 if( !formatEntry
) {
1540 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1541 /* re-evaluate antialias since aa_default may have changed */
1542 if( disable_antialias
== FALSE
)
1543 aa_type
= entry
->aa_default
;
1544 formatEntry
= entry
->format
[aa_type
];
1545 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1546 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1551 WARN("could not upload requested glyphs\n");
1552 LeaveCriticalSection(&xrender_cs
);
1556 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1557 physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1559 if(X11DRV_XRender_Installed
)
1561 XGlyphElt16
*elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1563 POINT desired
, current
;
1564 int render_op
= PictOpOver
;
1566 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1567 So we pass zeros to the function and move to our starting position using the first
1568 element of the elts array. */
1570 desired
.x
= physDev
->dc_rect
.left
+ x
;
1571 desired
.y
= physDev
->dc_rect
.top
+ y
;
1572 current
.x
= current
.y
= 0;
1574 tile_pict
= get_tile_pict(dst_format
, physDev
->textPixel
);
1576 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1578 if((dst_format
->format
== WXR_FORMAT_MONO
) && (textPixel
== 0))
1579 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1581 for(idx
= 0; idx
< count
; idx
++)
1583 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1584 elts
[idx
].chars
= wstr
+ idx
;
1585 elts
[idx
].nchars
= 1;
1586 elts
[idx
].xOff
= desired
.x
- current
.x
;
1587 elts
[idx
].yOff
= desired
.y
- current
.y
;
1589 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1590 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1594 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1595 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1599 offset
+= lpDx
[idx
];
1600 desired
.x
= physDev
->dc_rect
.left
+ x
+ offset
* cosEsc
;
1601 desired
.y
= physDev
->dc_rect
.top
+ y
- offset
* sinEsc
;
1605 pXRenderCompositeText16(gdi_display
, render_op
,
1607 physDev
->xrender
->pict
,
1608 formatEntry
->font_format
->pict_format
,
1609 0, 0, 0, 0, elts
, count
);
1610 wine_tsx11_unlock();
1611 HeapFree(GetProcessHeap(), 0, elts
);
1613 INT offset
= 0, xoff
= 0, yoff
= 0;
1615 XSetForeground( gdi_display
, physDev
->gc
, textPixel
);
1617 if(aa_type
== AA_None
|| physDev
->depth
== 1)
1619 void (* sharp_glyph_fn
)(X11DRV_PDEVICE
*, INT
, INT
, void *, XGlyphInfo
*);
1621 if(aa_type
== AA_None
)
1622 sharp_glyph_fn
= SharpGlyphMono
;
1624 sharp_glyph_fn
= SharpGlyphGray
;
1626 for(idx
= 0; idx
< count
; idx
++) {
1627 sharp_glyph_fn(physDev
, physDev
->dc_rect
.left
+ x
+ xoff
,
1628 physDev
->dc_rect
.top
+ y
+ yoff
,
1629 formatEntry
->bitmaps
[wstr
[idx
]],
1630 &formatEntry
->gis
[wstr
[idx
]]);
1632 offset
+= lpDx
[idx
];
1633 xoff
= offset
* cosEsc
;
1634 yoff
= offset
* -sinEsc
;
1636 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1637 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1642 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
1643 RECT extents
= {0, 0, 0, 0};
1645 int w
= physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
;
1646 int h
= physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
;
1648 TRACE("drawable %dx%d\n", w
, h
);
1650 for(idx
= 0; idx
< count
; idx
++) {
1651 if(extents
.left
> cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
)
1652 extents
.left
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
;
1653 if(extents
.top
> cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
)
1654 extents
.top
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
;
1655 if(extents
.right
< cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
)
1656 extents
.right
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
;
1657 if(extents
.bottom
< cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
)
1658 extents
.bottom
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
;
1660 offset
+= lpDx
[idx
];
1661 cur
.x
= offset
* cosEsc
;
1662 cur
.y
= offset
* -sinEsc
;
1664 cur
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1665 cur
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1668 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents
.left
, extents
.top
,
1669 extents
.right
, extents
.bottom
, physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1671 if(physDev
->dc_rect
.left
+ x
+ extents
.left
>= 0) {
1672 image_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1676 image_off_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1678 if(physDev
->dc_rect
.top
+ y
+ extents
.top
>= 0) {
1679 image_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1683 image_off_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1685 if(physDev
->dc_rect
.left
+ x
+ extents
.right
< w
)
1686 image_w
= physDev
->dc_rect
.left
+ x
+ extents
.right
- image_x
;
1688 image_w
= w
- image_x
;
1689 if(physDev
->dc_rect
.top
+ y
+ extents
.bottom
< h
)
1690 image_h
= physDev
->dc_rect
.top
+ y
+ extents
.bottom
- image_y
;
1692 image_h
= h
- image_y
;
1694 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
1696 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1697 image
= XGetImage(gdi_display
, physDev
->drawable
,
1698 image_x
, image_y
, image_w
, image_h
,
1699 AllPlanes
, ZPixmap
);
1700 X11DRV_check_error();
1702 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1703 gdi_display
, (int)physDev
->drawable
, image_x
, image_y
,
1704 image_w
, image_h
, AllPlanes
, ZPixmap
,
1705 physDev
->depth
, image
);
1707 Pixmap xpm
= XCreatePixmap(gdi_display
, root_window
, image_w
, image_h
,
1712 gcv
.graphics_exposures
= False
;
1713 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1714 XCopyArea(gdi_display
, physDev
->drawable
, xpm
, gc
, image_x
, image_y
,
1715 image_w
, image_h
, 0, 0);
1716 XFreeGC(gdi_display
, gc
);
1717 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1718 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
1720 X11DRV_check_error();
1721 XFreePixmap(gdi_display
, xpm
);
1723 if(!image
) goto no_image
;
1725 image
->red_mask
= visual
->red_mask
;
1726 image
->green_mask
= visual
->green_mask
;
1727 image
->blue_mask
= visual
->blue_mask
;
1729 offset
= xoff
= yoff
= 0;
1730 for(idx
= 0; idx
< count
; idx
++) {
1731 SmoothGlyphGray(image
, xoff
+ image_off_x
- extents
.left
,
1732 yoff
+ image_off_y
- extents
.top
,
1733 formatEntry
->bitmaps
[wstr
[idx
]],
1734 &formatEntry
->gis
[wstr
[idx
]],
1735 physDev
->textPixel
);
1737 offset
+= lpDx
[idx
];
1738 xoff
= offset
* cosEsc
;
1739 yoff
= offset
* -sinEsc
;
1741 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1742 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1745 XPutImage(gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
1746 image_x
, image_y
, image_w
, image_h
);
1747 XDestroyImage(image
);
1750 wine_tsx11_unlock();
1752 LeaveCriticalSection(&xrender_cs
);
1754 if (flags
& ETO_CLIPPED
)
1756 /* restore the device region */
1757 X11DRV_SetDeviceClipping( physDev
, saved_region
, 0 );
1758 DeleteObject( saved_region
);
1764 X11DRV_UnlockDIBSection( physDev
, TRUE
);
1768 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
1769 static void set_xrender_transformation(Picture src_pict
, float xscale
, float yscale
, int xoffset
, int yoffset
)
1771 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1772 XTransform xform
= {{
1773 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(xoffset
) },
1774 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(yoffset
) },
1775 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1778 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
1782 /* Helper function for (stretched) blitting using xrender */
1783 static void xrender_blit(Picture src_pict
, Picture mask_pict
, Picture dst_pict
, int x_src
, int y_src
, float xscale
, float yscale
, int width
, int height
)
1785 /* Further down a transformation matrix is used for stretching and mirroring the source data.
1786 * xscale/yscale contain the scaling factors for the width and height. In case of mirroring
1787 * we also need a x- and y-offset because without the pixels will be in the wrong quadrant of the x-y plane.
1789 int x_offset
= (xscale
<0) ? width
: 0;
1790 int y_offset
= (yscale
<0) ? height
: 0;
1792 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1793 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1794 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1795 if(xscale
!= 1.0 || yscale
!= 1.0)
1797 /* When we are using a mask, 'src_pict' contains a 1x1 picture for tiling, the actual source data is in mask_pict */
1799 set_xrender_transformation(mask_pict
, xscale
, yscale
, x_offset
, y_offset
);
1801 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
+ x_offset
, y_src
+ y_offset
);
1803 pXRenderComposite(gdi_display
, PictOpSrc
, src_pict
, mask_pict
, dst_pict
, 0, 0, 0, 0, 0, 0, width
, height
);
1807 /* When we are using a mask, 'src_pict' contains a 1x1 picture for tiling, the actual source data is in mask_pict */
1809 set_xrender_transformation(mask_pict
, 1, 1, 0, 0);
1811 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1813 pXRenderComposite(gdi_display
, PictOpSrc
, src_pict
, mask_pict
, dst_pict
, x_src
, y_src
, 0, 0, 0, 0, width
, height
);
1817 /******************************************************************************
1818 * AlphaBlend (x11drv.@)
1820 BOOL CDECL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1821 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1822 BLENDFUNCTION blendfn
)
1824 XRenderPictureAttributes pa
;
1825 Picture dst_pict
, src_pict
;
1831 DWORD
*dstbits
, *data
;
1834 BOOL top_down
= FALSE
;
1836 WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(devDst
->depth
, devDst
->color_shifts
);
1837 WineXRenderFormat
*src_format
;
1840 if(!X11DRV_XRender_Installed
) {
1841 FIXME("Unable to AlphaBlend without Xrender\n");
1846 pts
[1].x
= xDst
+ widthDst
;
1847 pts
[1].y
= yDst
+ heightDst
;
1848 LPtoDP(devDst
->hdc
, pts
, 2);
1851 widthDst
= pts
[1].x
- pts
[0].x
;
1852 heightDst
= pts
[1].y
- pts
[0].y
;
1856 pts
[1].x
= xSrc
+ widthSrc
;
1857 pts
[1].y
= ySrc
+ heightSrc
;
1858 LPtoDP(devSrc
->hdc
, pts
, 2);
1861 widthSrc
= pts
[1].x
- pts
[0].x
;
1862 heightSrc
= pts
[1].y
- pts
[0].y
;
1863 if (!widthDst
|| !heightDst
|| !widthSrc
|| !heightSrc
) return TRUE
;
1865 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1866 if(widthDst
!= widthSrc
|| heightDst
!= heightSrc
)
1868 if(!pXRenderSetPictureTransform
)
1871 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1875 if (!devSrc
->bitmap
|| GetObjectW( devSrc
->bitmap
->hbitmap
, sizeof(dib
), &dib
) != sizeof(dib
))
1877 static BOOL out
= FALSE
;
1880 FIXME("not a dibsection\n");
1886 /* If the source is a 1x1 bitmap, tiling is equivalent to stretching, but
1887 tiling is much faster. Therefore, we do no stretching in this case. */
1888 repeat_src
= dib
.dsBmih
.biWidth
== 1 && abs(dib
.dsBmih
.biHeight
) == 1;
1890 if (xSrc
< 0 || ySrc
< 0 || widthSrc
< 0 || heightSrc
< 0 || xSrc
+ widthSrc
> dib
.dsBmih
.biWidth
1891 || ySrc
+ heightSrc
> abs(dib
.dsBmih
.biHeight
))
1893 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc
, ySrc
, widthSrc
, heightSrc
);
1894 SetLastError(ERROR_INVALID_PARAMETER
);
1898 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && blendfn
.SourceConstantAlpha
!= 0xff)
1899 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn
.SourceConstantAlpha
);
1901 if(dib
.dsBm
.bmBitsPixel
!= 32) {
1902 FIXME("not a 32 bpp dibsection\n");
1905 dstbits
= data
= HeapAlloc(GetProcessHeap(), 0, heightSrc
* widthSrc
* 4);
1907 if(dib
.dsBmih
.biHeight
< 0) { /* top-down dib */
1909 dstbits
+= widthSrc
* (heightSrc
- 1);
1911 y
= y2
+ heightSrc
- 1;
1915 y
= dib
.dsBmih
.biHeight
- ySrc
- 1;
1916 y2
= y
- heightSrc
+ 1;
1919 if (blendfn
.AlphaFormat
& AC_SRC_ALPHA
)
1923 memcpy(dstbits
, (char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
+ xSrc
* 4,
1925 dstbits
+= (top_down
? -1 : 1) * widthSrc
;
1930 DWORD source_alpha
= (DWORD
)blendfn
.SourceConstantAlpha
<< 24;
1935 DWORD
*srcbits
= (DWORD
*)((char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
) + xSrc
;
1936 for (x
= 0; x
< widthSrc
; x
++)
1938 DWORD argb
= *srcbits
++;
1939 argb
= (argb
& 0xffffff) | source_alpha
;
1942 if (top_down
) /* we traversed the row forward so we should go back by two rows */
1943 dstbits
-= 2 * widthSrc
;
1948 rgndata
= X11DRV_GetRegionData( devDst
->region
, 0 );
1951 image
= XCreateImage(gdi_display
, visual
, 32, ZPixmap
, 0,
1952 (char*) data
, widthSrc
, heightSrc
, 32, widthSrc
* 4);
1954 src_format
= get_xrender_format(WXR_FORMAT_A8R8G8B8
);
1955 TRACE("src_format %p\n", src_format
);
1958 WARN("Unable to find a picture format supporting alpha, make sure X is running at 24-bit\n");
1962 pa
.subwindow_mode
= IncludeInferiors
;
1963 pa
.repeat
= repeat_src
? RepeatNormal
: RepeatNone
;
1965 /* FIXME use devDst->xrender->pict ? */
1966 dst_pict
= pXRenderCreatePicture(gdi_display
,
1968 dst_format
->pict_format
,
1969 CPSubwindowMode
, &pa
);
1970 TRACE("dst_pict %08lx\n", dst_pict
);
1971 TRACE("src_drawable = %08lx\n", devSrc
->drawable
);
1972 xpm
= XCreatePixmap(gdi_display
,
1974 widthSrc
, heightSrc
, 32);
1975 gcv
.graphics_exposures
= False
;
1976 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1977 TRACE("xpm = %08lx\n", xpm
);
1978 XPutImage(gdi_display
, xpm
, gc
, image
, 0, 0, 0, 0, widthSrc
, heightSrc
);
1980 src_pict
= pXRenderCreatePicture(gdi_display
,
1981 xpm
, src_format
->pict_format
,
1982 CPSubwindowMode
|CPRepeat
, &pa
);
1983 TRACE("src_pict %08lx\n", src_pict
);
1987 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
,
1988 devDst
->dc_rect
.left
, devDst
->dc_rect
.top
,
1989 (XRectangle
*)rgndata
->Buffer
,
1990 rgndata
->rdh
.nCount
);
1991 HeapFree( GetProcessHeap(), 0, rgndata
);
1994 /* Make sure we ALWAYS set the transformation matrix even if we don't need to scale. The reason is
1995 * that later on we want to reuse pictures (it can bring a lot of extra performance) and each time
1996 * a different transformation matrix might have been used. */
1998 set_xrender_transformation(src_pict
, 1.0, 1.0, 0, 0);
2000 set_xrender_transformation(src_pict
, widthSrc
/(double)widthDst
, heightSrc
/(double)heightDst
, 0, 0);
2001 pXRenderComposite(gdi_display
, PictOpOver
, src_pict
, 0, dst_pict
,
2003 xDst
+ devDst
->dc_rect
.left
, yDst
+ devDst
->dc_rect
.top
, widthDst
, heightDst
);
2006 pXRenderFreePicture(gdi_display
, src_pict
);
2007 XFreePixmap(gdi_display
, xpm
);
2008 XFreeGC(gdi_display
, gc
);
2009 pXRenderFreePicture(gdi_display
, dst_pict
);
2011 XDestroyImage(image
);
2013 wine_tsx11_unlock();
2014 HeapFree(GetProcessHeap(), 0, data
);
2018 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
2020 /* 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 */
2021 int depth
= physBitmap
->pixmap_depth
== 1 ? 1 : physDev
->depth
;
2024 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, depth
);
2026 /* Use XCopyArea when the physBitmap and brush.pixmap have the same depth. */
2027 if(physBitmap
->pixmap_depth
== 1 || physDev
->depth
== physBitmap
->pixmap_depth
)
2029 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
2030 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
2032 else /* We meed depth conversion */
2034 WineXRenderFormat
*src_format
= get_xrender_format_from_color_shifts(physBitmap
->pixmap_depth
, &physBitmap
->pixmap_color_shifts
);
2035 WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
2037 Picture src_pict
, dst_pict
;
2038 XRenderPictureAttributes pa
;
2039 pa
.subwindow_mode
= IncludeInferiors
;
2040 pa
.repeat
= RepeatNone
;
2042 src_pict
= pXRenderCreatePicture(gdi_display
, physBitmap
->pixmap
, src_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2043 dst_pict
= pXRenderCreatePicture(gdi_display
, physDev
->brush
.pixmap
, dst_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2045 xrender_blit(src_pict
, 0, dst_pict
, 0, 0, 1.0, 1.0, width
, height
);
2046 pXRenderFreePicture(gdi_display
, src_pict
);
2047 pXRenderFreePicture(gdi_display
, dst_pict
);
2049 wine_tsx11_unlock();
2052 BOOL
X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
2053 Pixmap pixmap
, GC gc
,
2054 INT widthSrc
, INT heightSrc
,
2055 INT widthDst
, INT heightDst
,
2056 RECT
*visRectSrc
, RECT
*visRectDst
)
2058 BOOL stretch
= (widthSrc
!= widthDst
) || (heightSrc
!= heightDst
);
2059 int width
= visRectDst
->right
- visRectDst
->left
;
2060 int height
= visRectDst
->bottom
- visRectDst
->top
;
2061 int x_src
= physDevSrc
->dc_rect
.left
+ visRectSrc
->left
;
2062 int y_src
= physDevSrc
->dc_rect
.top
+ visRectSrc
->top
;
2063 WineXRenderFormat
*src_format
= get_xrender_format_from_color_shifts(physDevSrc
->depth
, physDevSrc
->color_shifts
);
2064 WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDevDst
->depth
, physDevDst
->color_shifts
);
2065 Picture src_pict
=0, dst_pict
=0, mask_pict
=0;
2067 double xscale
= widthSrc
/(double)widthDst
;
2068 double yscale
= heightSrc
/(double)heightDst
;
2070 XRenderPictureAttributes pa
;
2071 pa
.subwindow_mode
= IncludeInferiors
;
2072 pa
.repeat
= RepeatNone
;
2074 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n", physDevSrc
->depth
, widthSrc
, heightSrc
, x_src
, y_src
);
2075 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst
->depth
, widthDst
, heightDst
);
2077 if(!X11DRV_XRender_Installed
)
2079 TRACE("Not using XRender since it is not available or disabled\n");
2083 /* XRender can't handle palettes, so abort */
2084 if(X11DRV_PALETTE_XPixelToPalette
)
2087 /* XRender is of no use in this case */
2088 if((physDevDst
->depth
== 1) && (physDevSrc
->depth
> 1))
2091 /* Just use traditional X copy when the depths match and we don't need stretching */
2092 if((physDevSrc
->depth
== physDevDst
->depth
) && !stretch
)
2094 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2096 XCopyArea( gdi_display
, physDevSrc
->drawable
, pixmap
, gc
, x_src
, y_src
, width
, height
, 0, 0);
2097 wine_tsx11_unlock();
2102 if(physDevSrc
->depth
== 1)
2105 get_xrender_color(dst_format
, physDevDst
->textPixel
, &col
);
2107 /* We use the source drawable as a mask */
2109 mask_pict
= pXRenderCreatePicture(gdi_display
, physDevSrc
->drawable
, src_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2111 /* Use backgroundPixel as the foreground color */
2112 src_pict
= get_tile_pict(dst_format
, physDevDst
->backgroundPixel
);
2114 /* Create a destination picture and fill it with textPixel color as the background color */
2115 dst_pict
= pXRenderCreatePicture(gdi_display
, pixmap
, dst_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2116 pXRenderFillRectangle(gdi_display
, PictOpSrc
, dst_pict
, &col
, 0, 0, width
, height
);
2118 xrender_blit(src_pict
, mask_pict
, dst_pict
, x_src
, y_src
, xscale
, yscale
, width
, height
);
2120 if(dst_pict
) pXRenderFreePicture(gdi_display
, dst_pict
);
2121 if(mask_pict
) pXRenderFreePicture(gdi_display
, mask_pict
);
2122 wine_tsx11_unlock();
2124 else /* color -> color but with different depths */
2127 src_pict
= pXRenderCreatePicture(gdi_display
,
2128 physDevSrc
->drawable
, src_format
->pict_format
,
2129 CPSubwindowMode
|CPRepeat
, &pa
);
2131 dst_pict
= pXRenderCreatePicture(gdi_display
,
2132 pixmap
, dst_format
->pict_format
,
2133 CPSubwindowMode
|CPRepeat
, &pa
);
2135 xrender_blit(src_pict
, 0, dst_pict
, x_src
, y_src
, xscale
, yscale
, width
, height
);
2137 if(src_pict
) pXRenderFreePicture(gdi_display
, src_pict
);
2138 if(dst_pict
) pXRenderFreePicture(gdi_display
, dst_pict
);
2139 wine_tsx11_unlock();
2144 #else /* SONAME_LIBXRENDER */
2146 void X11DRV_XRender_Init(void)
2148 TRACE("XRender support not compiled in.\n");
2152 void X11DRV_XRender_Finalize(void)
2156 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
2162 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
2168 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
2169 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
2176 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
2182 /******************************************************************************
2183 * AlphaBlend (x11drv.@)
2185 BOOL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
2186 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
2187 BLENDFUNCTION blendfn
)
2189 FIXME("not supported - XRENDER headers were missing at compile time\n");
2193 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
2196 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, physBitmap
->pixmap_depth
);
2198 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
2199 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
2200 wine_tsx11_unlock();
2203 BOOL
X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP
*physBitmap
, const DIBSECTION
*dib
)
2208 BOOL
X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
2209 Pixmap pixmap
, GC gc
,
2210 INT widthSrc
, INT heightSrc
,
2211 INT widthDst
, INT heightDst
,
2212 RECT
*visRectSrc
, RECT
*visRectDst
)
2216 #endif /* SONAME_LIBXRENDER */