2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
7 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
35 #include "wine/library.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 int using_client_side_fonts
= FALSE
;
41 WINE_DEFAULT_DEBUG_CHANNEL(xrender
);
43 #ifdef SONAME_LIBXRENDER
45 static BOOL X11DRV_XRender_Installed
= FALSE
;
48 #include <X11/extensions/Xrender.h>
50 #ifndef RepeatNone /* added in 0.10 */
52 #define RepeatNormal 1
54 #define RepeatReflect 3
57 #define MAX_FORMATS 10
58 typedef enum wine_xrformat
72 typedef struct wine_xrender_format_template
77 unsigned int alphaMask
;
81 unsigned int greenMask
;
83 unsigned int blueMask
;
84 } WineXRenderFormatTemplate
;
86 static const WineXRenderFormatTemplate wxr_formats_template
[] =
88 /* Format depth alpha mask red mask green mask blue mask*/
89 {WXR_FORMAT_MONO
, 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
90 {WXR_FORMAT_GRAY
, 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
91 {WXR_FORMAT_X1R5G5B5
, 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
92 {WXR_FORMAT_X1B5G5R5
, 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
93 {WXR_FORMAT_R5G6B5
, 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
94 {WXR_FORMAT_B5G6R5
, 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
95 {WXR_FORMAT_R8G8B8
, 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
96 {WXR_FORMAT_B8G8R8
, 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
97 {WXR_FORMAT_A8R8G8B8
, 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
98 {WXR_FORMAT_X8R8G8B8
, 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff }
101 typedef struct wine_xrender_format
104 XRenderPictFormat
*pict_format
;
107 static WineXRenderFormat wxr_formats
[MAX_FORMATS
];
108 static int WineXRenderFormatsListSize
= 0;
109 static WineXRenderFormat
*default_format
= NULL
;
115 SIZE devsize
; /* size in device coords */
119 #define INITIAL_REALIZED_BUF_SIZE 128
121 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
126 WineXRenderFormat
*font_format
;
131 } gsCacheEntryFormat
;
137 gsCacheEntryFormat
* format
[AA_MAXVALUE
];
142 struct tagXRENDERINFO
149 static gsCacheEntry
*glyphsetCache
= NULL
;
150 static DWORD glyphsetCacheSize
= 0;
151 static INT lastfree
= -1;
154 #define INIT_CACHE_SIZE 10
156 static int antialias
= 1;
158 static void *xrender_handle
;
160 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
161 MAKE_FUNCPTR(XRenderAddGlyphs
)
162 MAKE_FUNCPTR(XRenderComposite
)
163 MAKE_FUNCPTR(XRenderCompositeString8
)
164 MAKE_FUNCPTR(XRenderCompositeString16
)
165 MAKE_FUNCPTR(XRenderCompositeString32
)
166 MAKE_FUNCPTR(XRenderCompositeText16
)
167 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
168 MAKE_FUNCPTR(XRenderCreatePicture
)
169 MAKE_FUNCPTR(XRenderFillRectangle
)
170 MAKE_FUNCPTR(XRenderFindFormat
)
171 MAKE_FUNCPTR(XRenderFindVisualFormat
)
172 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
173 MAKE_FUNCPTR(XRenderFreePicture
)
174 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
175 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
176 MAKE_FUNCPTR(XRenderSetPictureTransform
)
178 MAKE_FUNCPTR(XRenderQueryExtension
)
181 static CRITICAL_SECTION xrender_cs
;
182 static CRITICAL_SECTION_DEBUG critsect_debug
=
185 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
186 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
188 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
190 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
191 ( ( (ULONG)_x4 << 24 ) | \
192 ( (ULONG)_x3 << 16 ) | \
193 ( (ULONG)_x2 << 8 ) | \
196 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
198 #define GASP_GRIDFIT 0x01
199 #define GASP_DOGRAY 0x02
201 #ifdef WORDS_BIGENDIAN
202 #define get_be_word(x) (x)
203 #define NATIVE_BYTE_ORDER MSBFirst
205 #define get_be_word(x) RtlUshortByteSwap(x)
206 #define NATIVE_BYTE_ORDER LSBFirst
209 static BOOL
get_xrender_template(const WineXRenderFormatTemplate
*fmt
, XRenderPictFormat
*templ
, unsigned long *mask
)
212 templ
->type
= PictTypeDirect
;
213 templ
->depth
= fmt
->depth
;
214 templ
->direct
.alpha
= fmt
->alpha
;
215 templ
->direct
.alphaMask
= fmt
->alphaMask
;
216 templ
->direct
.red
= fmt
->red
;
217 templ
->direct
.redMask
= fmt
->redMask
;
218 templ
->direct
.green
= fmt
->green
;
219 templ
->direct
.greenMask
= fmt
->greenMask
;
220 templ
->direct
.blue
= fmt
->blue
;
221 templ
->direct
.blueMask
= fmt
->blueMask
;
224 *mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
| PictFormatRed
| PictFormatRedMask
| PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
| PictFormatBlueMask
;
229 static BOOL
is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate
*fmt
)
231 if(fmt
->depth
!= screen_depth
)
233 if( (fmt
->redMask
<< fmt
->red
) != visual
->red_mask
)
235 if( (fmt
->greenMask
<< fmt
->green
) != visual
->green_mask
)
237 if( (fmt
->blueMask
<< fmt
->blue
) != visual
->blue_mask
)
240 /* We never select a default ARGB visual */
247 static int load_xrender_formats(void)
250 for(i
= 0; i
< (sizeof(wxr_formats_template
) / sizeof(wxr_formats_template
[0])); i
++)
252 XRenderPictFormat templ
, *pict_format
;
254 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template
[i
]))
257 pict_format
= pXRenderFindVisualFormat(gdi_display
, visual
);
260 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
261 if (visual
->class == DirectColor
)
264 if (XMatchVisualInfo( gdi_display
, DefaultScreen(gdi_display
),
265 screen_depth
, TrueColor
, &info
))
267 pict_format
= pXRenderFindVisualFormat(gdi_display
, info
.visual
);
268 if (pict_format
) visual
= info
.visual
;
276 wxr_formats
[WineXRenderFormatsListSize
].format
= wxr_formats_template
[i
].wxr_format
;
277 wxr_formats
[WineXRenderFormatsListSize
].pict_format
= pict_format
;
278 default_format
= &wxr_formats
[WineXRenderFormatsListSize
];
279 WineXRenderFormatsListSize
++;
280 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format
->id
, wxr_formats_template
[i
].wxr_format
);
285 unsigned long mask
= 0;
286 get_xrender_template(&wxr_formats_template
[i
], &templ
, &mask
);
289 pict_format
= pXRenderFindFormat(gdi_display
, mask
, &templ
, 0);
294 wxr_formats
[WineXRenderFormatsListSize
].format
= wxr_formats_template
[i
].wxr_format
;
295 wxr_formats
[WineXRenderFormatsListSize
].pict_format
= pict_format
;
296 WineXRenderFormatsListSize
++;
297 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format
->id
, wxr_formats_template
[i
].wxr_format
);
301 return WineXRenderFormatsListSize
;
304 /***********************************************************************
305 * X11DRV_XRender_Init
307 * Let's see if our XServer has the extension available
310 void X11DRV_XRender_Init(void)
314 if (client_side_with_render
&&
315 wine_dlopen(SONAME_LIBX11
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
316 wine_dlopen(SONAME_LIBXEXT
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
317 (xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0)))
320 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
321 LOAD_FUNCPTR(XRenderAddGlyphs
)
322 LOAD_FUNCPTR(XRenderComposite
)
323 LOAD_FUNCPTR(XRenderCompositeString8
)
324 LOAD_FUNCPTR(XRenderCompositeString16
)
325 LOAD_FUNCPTR(XRenderCompositeString32
)
326 LOAD_FUNCPTR(XRenderCompositeText16
)
327 LOAD_FUNCPTR(XRenderCreateGlyphSet
)
328 LOAD_FUNCPTR(XRenderCreatePicture
)
329 LOAD_FUNCPTR(XRenderFillRectangle
)
330 LOAD_FUNCPTR(XRenderFindFormat
)
331 LOAD_FUNCPTR(XRenderFindVisualFormat
)
332 LOAD_FUNCPTR(XRenderFreeGlyphSet
)
333 LOAD_FUNCPTR(XRenderFreePicture
)
334 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
)
335 LOAD_FUNCPTR(XRenderQueryExtension
)
337 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
338 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
339 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
)
340 #undef LOAD_OPTIONAL_FUNCPTR
344 X11DRV_XRender_Installed
= pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
);
346 if(X11DRV_XRender_Installed
) {
347 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
348 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
352 "Wine has detected that you probably have a buggy version\n"
353 "of libXrender.so . Because of this client side font rendering\n"
354 "will be disabled. Please upgrade this library.\n");
355 X11DRV_XRender_Installed
= FALSE
;
359 if (!visual
->red_mask
|| !visual
->green_mask
|| !visual
->blue_mask
) {
360 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
361 X11DRV_XRender_Installed
= FALSE
;
367 if(X11DRV_XRender_Installed
|| client_side_with_core
)
369 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
370 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
372 glyphsetCacheSize
= INIT_CACHE_SIZE
;
374 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
375 glyphsetCache
[i
].next
= i
+ 1;
376 glyphsetCache
[i
].count
= -1;
378 glyphsetCache
[i
-1].next
= -1;
379 using_client_side_fonts
= 1;
381 if(!X11DRV_XRender_Installed
) {
382 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
383 if(screen_depth
<= 8 || !client_side_antialias_with_core
)
386 if(screen_depth
<= 8 || !client_side_antialias_with_render
)
390 else TRACE("Using X11 core fonts\n");
393 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
394 static void get_xrender_color(WineXRenderFormat
*wxr_format
, int src_color
, XRenderColor
*dst_color
)
396 XRenderPictFormat
*pf
= wxr_format
->pict_format
;
398 if(pf
->direct
.redMask
)
399 dst_color
->red
= ((src_color
>> pf
->direct
.red
) & pf
->direct
.redMask
) * 65535/pf
->direct
.redMask
;
403 if(pf
->direct
.greenMask
)
404 dst_color
->green
= ((src_color
>> pf
->direct
.green
) & pf
->direct
.greenMask
) * 65535/pf
->direct
.greenMask
;
406 dst_color
->green
= 0;
408 if(pf
->direct
.blueMask
)
409 dst_color
->blue
= ((src_color
>> pf
->direct
.blue
) & pf
->direct
.blueMask
) * 65535/pf
->direct
.blueMask
;
413 dst_color
->alpha
= 0xffff;
416 static WineXRenderFormat
*get_xrender_format(WXRFormat format
)
419 for(i
=0; i
<WineXRenderFormatsListSize
; i
++)
421 if(wxr_formats
[i
].format
== format
)
423 TRACE("Returning wxr_format=%#x\n", format
);
424 return &wxr_formats
[i
];
430 static WineXRenderFormat
*get_xrender_format_from_color_shifts(int depth
, ColorShifts
*shifts
)
432 int redMask
, greenMask
, blueMask
;
436 return get_xrender_format(WXR_FORMAT_MONO
);
438 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
440 return default_format
;
442 redMask
= shifts
->physicalRed
.max
<< shifts
->physicalRed
.shift
;
443 greenMask
= shifts
->physicalGreen
.max
<< shifts
->physicalGreen
.shift
;
444 blueMask
= shifts
->physicalBlue
.max
<< shifts
->physicalBlue
.shift
;
446 /* Try to locate a format which matches the specification of the dibsection. */
447 for(i
= 0; i
< (sizeof(wxr_formats_template
) / sizeof(wxr_formats_template
[0])); i
++)
449 if( depth
== wxr_formats_template
[i
].depth
&&
450 redMask
== (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
451 greenMask
== (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
452 blueMask
== (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
) )
455 /* When we reach this stage the format was found in our template table but this doesn't mean that
456 * the Xserver also supports this format (e.g. its depth might be too low). The call below verifies that.
458 return get_xrender_format(wxr_formats_template
[i
].wxr_format
);
462 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
463 ERR("No XRender format found!\n");
467 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
469 if(p1
->hash
!= p2
->hash
) return TRUE
;
470 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
471 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
472 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
473 return strcmpiW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
477 static void walk_cache(void)
481 EnterCriticalSection(&xrender_cs
);
482 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
483 TRACE("item %d\n", i
);
484 LeaveCriticalSection(&xrender_cs
);
488 static int LookupEntry(LFANDSIZE
*plfsz
)
492 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
494 if(glyphsetCache
[i
].count
== -1) { /* reached free list so stop */
499 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
500 glyphsetCache
[i
].count
++;
502 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
503 glyphsetCache
[i
].next
= mru
;
506 TRACE("found font in cache %d\n", i
);
511 TRACE("font not in cache\n");
515 static void FreeEntry(int entry
)
519 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
520 gsCacheEntryFormat
* formatEntry
;
522 if( !glyphsetCache
[entry
].format
[format
] )
525 formatEntry
= glyphsetCache
[entry
].format
[format
];
527 if(formatEntry
->glyphset
) {
529 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
531 formatEntry
->glyphset
= 0;
533 if(formatEntry
->nrealized
) {
534 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
535 formatEntry
->realized
= NULL
;
536 if(formatEntry
->bitmaps
) {
537 for(i
= 0; i
< formatEntry
->nrealized
; i
++)
538 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
[i
]);
539 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
);
540 formatEntry
->bitmaps
= NULL
;
542 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
543 formatEntry
->gis
= NULL
;
544 formatEntry
->nrealized
= 0;
547 HeapFree(GetProcessHeap(), 0, formatEntry
);
548 glyphsetCache
[entry
].format
[format
] = NULL
;
552 static int AllocEntry(void)
554 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
557 assert(glyphsetCache
[lastfree
].count
== -1);
558 glyphsetCache
[lastfree
].count
= 1;
560 lastfree
= glyphsetCache
[lastfree
].next
;
562 glyphsetCache
[best
].next
= mru
;
565 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
569 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
570 if(glyphsetCache
[i
].count
== 0) {
578 TRACE("freeing unused glyphset at cache %d\n", best
);
580 glyphsetCache
[best
].count
= 1;
582 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
583 glyphsetCache
[best
].next
= mru
;
591 TRACE("Growing cache\n");
594 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
596 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
597 * sizeof(*glyphsetCache
));
599 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
600 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
601 * sizeof(*glyphsetCache
));
603 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
605 glyphsetCache
[i
].next
= i
+ 1;
606 glyphsetCache
[i
].count
= -1;
608 glyphsetCache
[i
-1].next
= -1;
609 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
611 lastfree
= glyphsetCache
[best
].next
;
612 glyphsetCache
[best
].count
= 1;
613 glyphsetCache
[best
].next
= mru
;
615 TRACE("new free cache slot at %d\n", mru
);
619 static BOOL
get_gasp_flags(X11DRV_PDEVICE
*physDev
, WORD
*flags
)
629 size
= GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, NULL
, 0);
630 if(size
== GDI_ERROR
)
633 gasp
= buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
634 GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, gasp
, size
);
636 GetTextMetricsW(physDev
->hdc
, &tm
);
637 ppem
= abs(X11DRV_YWStoDS(physDev
, tm
.tmAscent
+ tm
.tmDescent
- tm
.tmInternalLeading
));
640 num_recs
= get_be_word(*gasp
);
644 *flags
= get_be_word(*(gasp
+ 1));
645 if(ppem
<= get_be_word(*gasp
))
649 TRACE("got flags %04x for ppem %d\n", *flags
, ppem
);
651 HeapFree(GetProcessHeap(), 0, buffer
);
655 static AA_Type
get_antialias_type( X11DRV_PDEVICE
*physDev
, BOOL subpixel
, BOOL hinter
)
659 UINT font_smoothing_type
, font_smoothing_orientation
;
661 if (X11DRV_XRender_Installed
&& subpixel
&&
662 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE
, 0, &font_smoothing_type
, 0) &&
663 font_smoothing_type
== FE_FONTSMOOTHINGCLEARTYPE
)
665 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION
, 0,
666 &font_smoothing_orientation
, 0) &&
667 font_smoothing_orientation
== FE_FONTSMOOTHINGORIENTATIONBGR
)
674 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
675 But, Wine's subpixel rendering can support the portrait mode.
678 else if (!hinter
|| !get_gasp_flags(physDev
, &flags
) || flags
& GASP_DOGRAY
)
686 static int GetCacheEntry(X11DRV_PDEVICE
*physDev
, LFANDSIZE
*plfsz
)
691 static int hinter
= -1;
692 static int subpixel
= -1;
695 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
698 entry
= glyphsetCache
+ ret
;
699 entry
->lfsz
= *plfsz
;
700 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
701 assert( !entry
->format
[format
] );
704 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
706 if(hinter
== -1 || subpixel
== -1)
708 RASTERIZER_STATUS status
;
709 GetRasterizerCaps(&status
, sizeof(status
));
710 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
711 subpixel
= status
.wFlags
& WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
714 switch (plfsz
->lf
.lfQuality
)
716 case ANTIALIASED_QUALITY
:
717 entry
->aa_default
= get_antialias_type( physDev
, FALSE
, hinter
);
719 case CLEARTYPE_QUALITY
:
720 case CLEARTYPE_NATURAL_QUALITY
:
721 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
723 case DEFAULT_QUALITY
:
727 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING
, 0, &font_smoothing
, 0) &&
730 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
733 entry
->aa_default
= AA_None
;
738 entry
->aa_default
= AA_None
;
743 static void dec_ref_cache(int index
)
746 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
747 assert(glyphsetCache
[index
].count
> 0);
748 glyphsetCache
[index
].count
--;
751 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
753 DWORD hash
= 0, *ptr
, two_chars
;
757 hash
^= plfsz
->devsize
.cx
;
758 hash
^= plfsz
->devsize
.cy
;
759 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
761 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
763 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
765 pwc
= (WCHAR
*)&two_chars
;
767 *pwc
= toupperW(*pwc
);
769 *pwc
= toupperW(*pwc
);
777 /***********************************************************************
778 * X11DRV_XRender_Finalize
780 void X11DRV_XRender_Finalize(void)
784 EnterCriticalSection(&xrender_cs
);
785 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
787 LeaveCriticalSection(&xrender_cs
);
791 /***********************************************************************
792 * X11DRV_XRender_SelectFont
794 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
798 GetObjectW(hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
799 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
800 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
801 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
802 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
803 lfsz
.devsize
.cx
= X11DRV_XWStoDS( physDev
, lfsz
.lf
.lfWidth
);
804 lfsz
.devsize
.cy
= X11DRV_YWStoDS( physDev
, lfsz
.lf
.lfHeight
);
805 GetWorldTransform( physDev
->hdc
, &lfsz
.xform
);
806 lfsz_calc_hash(&lfsz
);
808 EnterCriticalSection(&xrender_cs
);
809 if(!physDev
->xrender
) {
810 physDev
->xrender
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
811 sizeof(*physDev
->xrender
));
812 physDev
->xrender
->cache_index
= -1;
814 else if(physDev
->xrender
->cache_index
!= -1)
815 dec_ref_cache(physDev
->xrender
->cache_index
);
816 physDev
->xrender
->cache_index
= GetCacheEntry(physDev
, &lfsz
);
817 LeaveCriticalSection(&xrender_cs
);
821 /***********************************************************************
822 * X11DRV_XRender_DeleteDC
824 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
826 X11DRV_XRender_UpdateDrawable(physDev
);
828 EnterCriticalSection(&xrender_cs
);
829 if(physDev
->xrender
->cache_index
!= -1)
830 dec_ref_cache(physDev
->xrender
->cache_index
);
831 LeaveCriticalSection(&xrender_cs
);
833 HeapFree(GetProcessHeap(), 0, physDev
->xrender
);
834 physDev
->xrender
= NULL
;
838 /***********************************************************************
839 * X11DRV_XRender_UpdateDrawable
841 * Deletes the pict and tile when the drawable changes.
843 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
847 if(physDev
->xrender
->pict
)
849 TRACE("freeing pict = %lx dc = %p\n", physDev
->xrender
->pict
, physDev
->hdc
);
851 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
852 physDev
->xrender
->pict
= 0;
859 /************************************************************************
862 * Helper to ExtTextOut. Must be called inside xrender_cs
864 static BOOL
UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
, AA_Type format
)
871 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
872 gsCacheEntryFormat
*formatEntry
;
873 UINT ggo_format
= GGO_GLYPH_INDEX
;
874 WXRFormat wxr_format
;
875 static const char zero
[4];
876 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
880 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
883 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
886 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
889 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
892 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
896 ERR("aa = %d - not implemented\n", format
);
898 ggo_format
|= GGO_BITMAP
;
902 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
903 if(buflen
== GDI_ERROR
) {
904 if(format
!= AA_None
) {
906 entry
->aa_default
= AA_None
;
907 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
908 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
910 if(buflen
== GDI_ERROR
) {
911 WARN("GetGlyphOutlineW failed\n");
914 TRACE("Turning off antialiasing for this monochrome font\n");
917 /* If there is nothing for the current type, we create the entry. */
918 if( !entry
->format
[format
] ) {
919 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
921 sizeof(gsCacheEntryFormat
));
923 formatEntry
= entry
->format
[format
];
925 if(formatEntry
->nrealized
<= glyph
) {
926 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
928 if (formatEntry
->realized
)
929 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
931 formatEntry
->realized
,
932 formatEntry
->nrealized
* sizeof(BOOL
));
934 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
936 formatEntry
->nrealized
* sizeof(BOOL
));
938 if(!X11DRV_XRender_Installed
) {
939 if (formatEntry
->bitmaps
)
940 formatEntry
->bitmaps
= HeapReAlloc(GetProcessHeap(),
942 formatEntry
->bitmaps
,
943 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
945 formatEntry
->bitmaps
= HeapAlloc(GetProcessHeap(),
947 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
949 if (formatEntry
->gis
)
950 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
953 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
955 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
957 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
961 if(formatEntry
->glyphset
== 0 && X11DRV_XRender_Installed
) {
964 wxr_format
= WXR_FORMAT_GRAY
;
971 wxr_format
= WXR_FORMAT_A8R8G8B8
;
975 ERR("aa = %d - not implemented\n", format
);
977 wxr_format
= WXR_FORMAT_MONO
;
982 formatEntry
->font_format
= get_xrender_format(wxr_format
);
983 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
->pict_format
);
988 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
989 GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
990 formatEntry
->realized
[glyph
] = TRUE
;
992 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
994 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
995 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
997 gi
.width
= gm
.gmBlackBoxX
;
998 gi
.height
= gm
.gmBlackBoxY
;
999 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1000 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1001 gi
.xOff
= gm
.gmCellIncX
;
1002 gi
.yOff
= gm
.gmCellIncY
;
1004 if(TRACE_ON(xrender
)) {
1007 unsigned char *line
;
1009 if(format
== AA_None
) {
1010 pitch
= ((gi
.width
+ 31) / 32) * 4;
1011 for(i
= 0; i
< gi
.height
; i
++) {
1012 line
= (unsigned char*) buf
+ i
* pitch
;
1014 for(j
= 0; j
< pitch
* 8; j
++) {
1015 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1017 TRACE("%s\n", output
);
1020 static const char blks
[] = " .:;!o*#";
1024 pitch
= ((gi
.width
+ 3) / 4) * 4;
1025 for(i
= 0; i
< gi
.height
; i
++) {
1026 line
= (unsigned char*) buf
+ i
* pitch
;
1028 for(j
= 0; j
< pitch
; j
++) {
1029 str
[0] = blks
[line
[j
] >> 5];
1030 strcat(output
, str
);
1032 TRACE("%s\n", output
);
1038 if(formatEntry
->glyphset
) {
1039 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1040 unsigned char *byte
= (unsigned char*) buf
, c
;
1046 /* magic to flip bit order */
1047 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1048 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1049 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1054 else if ( format
!= AA_Grey
&&
1055 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1057 unsigned int i
, *data
= (unsigned int *)buf
;
1058 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1063 XRenderCompositeText seems to ignore 0x0 glyphs when
1064 AA_None, which means we lose the advance width of glyphs
1065 like the space. We'll pretend that such glyphs are 1x1
1070 gi
.width
= gi
.height
= 1;
1073 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1074 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1075 wine_tsx11_unlock();
1076 HeapFree(GetProcessHeap(), 0, buf
);
1078 formatEntry
->bitmaps
[glyph
] = buf
;
1081 formatEntry
->gis
[glyph
] = gi
;
1086 static void SharpGlyphMono(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
1087 void *bitmap
, XGlyphInfo
*gi
)
1089 unsigned char *srcLine
= bitmap
, *src
;
1090 unsigned char bits
, bitsMask
;
1091 int width
= gi
->width
;
1092 int stride
= ((width
+ 31) & ~31) >> 3;
1093 int height
= gi
->height
;
1097 TRACE("%d, %d\n", x
, y
);
1106 bitsMask
= 0x80; /* FreeType is always MSB first */
1112 if (bits
& bitsMask
)
1120 bitsMask
= bitsMask
>> 1;
1126 } while (bits
& bitsMask
);
1127 XFillRectangle (gdi_display
, physDev
->drawable
,
1128 physDev
->gc
, xspan
, y
, lenspan
, 1);
1140 bitsMask
= bitsMask
>> 1;
1146 } while (!(bits
& bitsMask
));
1153 static void SharpGlyphGray(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
1154 void *bitmap
, XGlyphInfo
*gi
)
1156 unsigned char *srcLine
= bitmap
, *src
, bits
;
1157 int width
= gi
->width
;
1158 int stride
= ((width
+ 3) & ~3);
1159 int height
= gi
->height
;
1184 } while (bits
>= 0x80);
1185 XFillRectangle (gdi_display
, physDev
->drawable
,
1186 physDev
->gc
, xspan
, y
, lenspan
, 1);
1199 } while (bits
< 0x80);
1207 static void ExamineBitfield (DWORD mask
, int *shift
, int *len
)
1212 while ((mask
& 1) == 0)
1218 while ((mask
& 1) == 1)
1227 static DWORD
GetField (DWORD pixel
, int shift
, int len
)
1229 pixel
= pixel
& (((1 << (len
)) - 1) << shift
);
1230 pixel
= pixel
<< (32 - (shift
+ len
)) >> 24;
1233 pixel
|= (pixel
>> len
);
1240 static DWORD
PutField (DWORD pixel
, int shift
, int len
)
1242 shift
= shift
- (8 - len
);
1244 pixel
&= (((1 << len
) - 1) << (8 - len
));
1252 static void SmoothGlyphGray(XImage
*image
, int x
, int y
, void *bitmap
, XGlyphInfo
*gi
,
1258 BYTE
*maskLine
, *mask
, m
;
1263 BYTE src_r
, src_g
, src_b
;
1268 height
= gi
->height
;
1271 maskStride
= (width
+ 3) & ~3;
1273 ExamineBitfield (image
->red_mask
, &r_shift
, &r_len
);
1274 ExamineBitfield (image
->green_mask
, &g_shift
, &g_len
);
1275 ExamineBitfield (image
->blue_mask
, &b_shift
, &b_len
);
1277 src_r
= GetField(color
, r_shift
, r_len
);
1278 src_g
= GetField(color
, g_shift
, g_len
);
1279 src_b
= GetField(color
, b_shift
, b_len
);
1281 for(; height
--; y
++)
1284 maskLine
+= maskStride
;
1289 if(y
>= image
->height
) break;
1293 if(tx
>= image
->width
) break;
1296 if(tx
< 0) continue;
1299 XPutPixel (image
, tx
, y
, color
);
1304 pixel
= XGetPixel (image
, tx
, y
);
1306 r
= GetField(pixel
, r_shift
, r_len
);
1307 r
= ((BYTE
)~m
* (WORD
)r
+ (BYTE
)m
* (WORD
)src_r
) >> 8;
1308 g
= GetField(pixel
, g_shift
, g_len
);
1309 g
= ((BYTE
)~m
* (WORD
)g
+ (BYTE
)m
* (WORD
)src_g
) >> 8;
1310 b
= GetField(pixel
, b_shift
, b_len
);
1311 b
= ((BYTE
)~m
* (WORD
)b
+ (BYTE
)m
* (WORD
)src_b
) >> 8;
1313 pixel
= (PutField (r
, r_shift
, r_len
) |
1314 PutField (g
, g_shift
, g_len
) |
1315 PutField (b
, b_shift
, b_len
));
1316 XPutPixel (image
, tx
, y
, pixel
);
1322 /*************************************************************
1325 * Returns an appropriate Picture for tiling the text colour.
1326 * Call and use result within the xrender_cs
1328 static Picture
get_tile_pict(WineXRenderFormat
*wxr_format
, int text_pixel
)
1335 } tiles
[MAX_FORMATS
], *tile
;
1338 tile
= &tiles
[wxr_format
->format
];
1342 XRenderPictureAttributes pa
;
1345 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, wxr_format
->pict_format
->depth
);
1347 pa
.repeat
= RepeatNormal
;
1348 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, wxr_format
->pict_format
, CPRepeat
, &pa
);
1349 wine_tsx11_unlock();
1351 /* init current_color to something different from text_pixel */
1352 tile
->current_color
= ~text_pixel
;
1354 if(wxr_format
->format
== WXR_FORMAT_MONO
)
1356 /* for a 1bpp bitmap we always need a 1 in the tile */
1357 col
.red
= col
.green
= col
.blue
= 0;
1360 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1361 wine_tsx11_unlock();
1365 if(text_pixel
!= tile
->current_color
&& wxr_format
->format
!= WXR_FORMAT_MONO
)
1367 get_xrender_color(wxr_format
, text_pixel
, &col
);
1369 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1370 wine_tsx11_unlock();
1371 tile
->current_color
= text_pixel
;
1376 static int XRenderErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
1381 /***********************************************************************
1382 * X11DRV_XRender_ExtTextOut
1384 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1385 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1390 gsCacheEntry
*entry
;
1391 gsCacheEntryFormat
*formatEntry
;
1393 HDC hdc
= physDev
->hdc
;
1394 int textPixel
, backgroundPixel
;
1395 HRGN saved_region
= 0;
1396 BOOL disable_antialias
= FALSE
;
1397 AA_Type aa_type
= AA_None
;
1400 double cosEsc
, sinEsc
;
1402 WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
1403 Picture tile_pict
= 0;
1405 /* Do we need to disable antialiasing because of palette mode? */
1406 if( !physDev
->bitmap
|| GetObjectW( physDev
->bitmap
->hbitmap
, sizeof(bmp
), &bmp
) != sizeof(bmp
) ) {
1407 TRACE("bitmap is not a DIB\n");
1409 else if (bmp
.dsBmih
.biBitCount
<= 8) {
1410 TRACE("Disabling antialiasing\n");
1411 disable_antialias
= TRUE
;
1414 xgcval
.function
= GXcopy
;
1415 xgcval
.background
= physDev
->backgroundPixel
;
1416 xgcval
.fill_style
= FillSolid
;
1418 XChangeGC( gdi_display
, physDev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1419 wine_tsx11_unlock();
1421 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
);
1423 if(physDev
->depth
== 1) {
1424 if((physDev
->textPixel
& 0xffffff) == 0) {
1426 backgroundPixel
= 1;
1429 backgroundPixel
= 0;
1432 textPixel
= physDev
->textPixel
;
1433 backgroundPixel
= physDev
->backgroundPixel
;
1436 if(flags
& ETO_OPAQUE
)
1439 XSetForeground( gdi_display
, physDev
->gc
, backgroundPixel
);
1440 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1441 physDev
->dc_rect
.left
+ lprect
->left
, physDev
->dc_rect
.top
+ lprect
->top
,
1442 lprect
->right
- lprect
->left
, lprect
->bottom
- lprect
->top
);
1443 wine_tsx11_unlock();
1453 GetObjectW(GetCurrentObject(physDev
->hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
1454 if(lf
.lfEscapement
!= 0) {
1455 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
1456 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
1462 if (flags
& ETO_CLIPPED
)
1466 clip_region
= CreateRectRgnIndirect( lprect
);
1467 /* make a copy of the current device region */
1468 saved_region
= CreateRectRgn( 0, 0, 0, 0 );
1469 CombineRgn( saved_region
, physDev
->region
, 0, RGN_COPY
);
1470 X11DRV_SetDeviceClipping( physDev
, saved_region
, clip_region
);
1471 DeleteObject( clip_region
);
1474 if(X11DRV_XRender_Installed
) {
1475 if(!physDev
->xrender
->pict
) {
1476 XRenderPictureAttributes pa
;
1477 pa
.subwindow_mode
= IncludeInferiors
;
1480 physDev
->xrender
->pict
= pXRenderCreatePicture(gdi_display
,
1481 physDev
->drawable
, dst_format
->pict_format
,
1482 CPSubwindowMode
, &pa
);
1483 wine_tsx11_unlock();
1485 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1486 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1488 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1489 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1492 if ((data
= X11DRV_GetRegionData( physDev
->region
, 0 )))
1495 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
1496 physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
1497 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
1498 wine_tsx11_unlock();
1499 HeapFree( GetProcessHeap(), 0, data
);
1503 EnterCriticalSection(&xrender_cs
);
1505 entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1506 if( disable_antialias
== FALSE
)
1507 aa_type
= entry
->aa_default
;
1508 formatEntry
= entry
->format
[aa_type
];
1510 for(idx
= 0; idx
< count
; idx
++) {
1511 if( !formatEntry
) {
1512 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1513 /* re-evaluate antialias since aa_default may have changed */
1514 if( disable_antialias
== FALSE
)
1515 aa_type
= entry
->aa_default
;
1516 formatEntry
= entry
->format
[aa_type
];
1517 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1518 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1523 WARN("could not upload requested glyphs\n");
1524 LeaveCriticalSection(&xrender_cs
);
1528 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1529 physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1531 if(X11DRV_XRender_Installed
)
1533 XGlyphElt16
*elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1535 POINT desired
, current
;
1536 int render_op
= PictOpOver
;
1538 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1539 So we pass zeros to the function and move to our starting position using the first
1540 element of the elts array. */
1542 desired
.x
= physDev
->dc_rect
.left
+ x
;
1543 desired
.y
= physDev
->dc_rect
.top
+ y
;
1544 current
.x
= current
.y
= 0;
1546 tile_pict
= get_tile_pict(dst_format
, physDev
->textPixel
);
1548 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1550 if((dst_format
->format
== WXR_FORMAT_MONO
) && (textPixel
== 0))
1551 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1553 for(idx
= 0; idx
< count
; idx
++)
1555 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1556 elts
[idx
].chars
= wstr
+ idx
;
1557 elts
[idx
].nchars
= 1;
1558 elts
[idx
].xOff
= desired
.x
- current
.x
;
1559 elts
[idx
].yOff
= desired
.y
- current
.y
;
1561 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1562 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1566 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1567 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1571 offset
+= lpDx
[idx
];
1572 desired
.x
= physDev
->dc_rect
.left
+ x
+ offset
* cosEsc
;
1573 desired
.y
= physDev
->dc_rect
.top
+ y
- offset
* sinEsc
;
1577 pXRenderCompositeText16(gdi_display
, render_op
,
1579 physDev
->xrender
->pict
,
1580 formatEntry
->font_format
->pict_format
,
1581 0, 0, 0, 0, elts
, count
);
1582 wine_tsx11_unlock();
1583 HeapFree(GetProcessHeap(), 0, elts
);
1585 INT offset
= 0, xoff
= 0, yoff
= 0;
1587 XSetForeground( gdi_display
, physDev
->gc
, textPixel
);
1589 if(aa_type
== AA_None
|| physDev
->depth
== 1)
1591 void (* sharp_glyph_fn
)(X11DRV_PDEVICE
*, INT
, INT
, void *, XGlyphInfo
*);
1593 if(aa_type
== AA_None
)
1594 sharp_glyph_fn
= SharpGlyphMono
;
1596 sharp_glyph_fn
= SharpGlyphGray
;
1598 for(idx
= 0; idx
< count
; idx
++) {
1599 sharp_glyph_fn(physDev
, physDev
->dc_rect
.left
+ x
+ xoff
,
1600 physDev
->dc_rect
.top
+ y
+ yoff
,
1601 formatEntry
->bitmaps
[wstr
[idx
]],
1602 &formatEntry
->gis
[wstr
[idx
]]);
1604 offset
+= lpDx
[idx
];
1605 xoff
= offset
* cosEsc
;
1606 yoff
= offset
* -sinEsc
;
1608 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1609 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1614 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
1615 RECT extents
= {0, 0, 0, 0};
1617 int w
= physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
;
1618 int h
= physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
;
1620 TRACE("drawable %dx%d\n", w
, h
);
1622 for(idx
= 0; idx
< count
; idx
++) {
1623 if(extents
.left
> cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
)
1624 extents
.left
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
;
1625 if(extents
.top
> cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
)
1626 extents
.top
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
;
1627 if(extents
.right
< cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
)
1628 extents
.right
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
;
1629 if(extents
.bottom
< cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
)
1630 extents
.bottom
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
;
1632 offset
+= lpDx
[idx
];
1633 cur
.x
= offset
* cosEsc
;
1634 cur
.y
= offset
* -sinEsc
;
1636 cur
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1637 cur
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1640 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents
.left
, extents
.top
,
1641 extents
.right
, extents
.bottom
, physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1643 if(physDev
->dc_rect
.left
+ x
+ extents
.left
>= 0) {
1644 image_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1648 image_off_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1650 if(physDev
->dc_rect
.top
+ y
+ extents
.top
>= 0) {
1651 image_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1655 image_off_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1657 if(physDev
->dc_rect
.left
+ x
+ extents
.right
< w
)
1658 image_w
= physDev
->dc_rect
.left
+ x
+ extents
.right
- image_x
;
1660 image_w
= w
- image_x
;
1661 if(physDev
->dc_rect
.top
+ y
+ extents
.bottom
< h
)
1662 image_h
= physDev
->dc_rect
.top
+ y
+ extents
.bottom
- image_y
;
1664 image_h
= h
- image_y
;
1666 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
1668 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1669 image
= XGetImage(gdi_display
, physDev
->drawable
,
1670 image_x
, image_y
, image_w
, image_h
,
1671 AllPlanes
, ZPixmap
);
1672 X11DRV_check_error();
1674 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1675 gdi_display
, (int)physDev
->drawable
, image_x
, image_y
,
1676 image_w
, image_h
, AllPlanes
, ZPixmap
,
1677 physDev
->depth
, image
);
1679 Pixmap xpm
= XCreatePixmap(gdi_display
, root_window
, image_w
, image_h
,
1684 gcv
.graphics_exposures
= False
;
1685 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1686 XCopyArea(gdi_display
, physDev
->drawable
, xpm
, gc
, image_x
, image_y
,
1687 image_w
, image_h
, 0, 0);
1688 XFreeGC(gdi_display
, gc
);
1689 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1690 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
1692 X11DRV_check_error();
1693 XFreePixmap(gdi_display
, xpm
);
1695 if(!image
) goto no_image
;
1697 image
->red_mask
= visual
->red_mask
;
1698 image
->green_mask
= visual
->green_mask
;
1699 image
->blue_mask
= visual
->blue_mask
;
1701 offset
= xoff
= yoff
= 0;
1702 for(idx
= 0; idx
< count
; idx
++) {
1703 SmoothGlyphGray(image
, xoff
+ image_off_x
- extents
.left
,
1704 yoff
+ image_off_y
- extents
.top
,
1705 formatEntry
->bitmaps
[wstr
[idx
]],
1706 &formatEntry
->gis
[wstr
[idx
]],
1707 physDev
->textPixel
);
1709 offset
+= lpDx
[idx
];
1710 xoff
= offset
* cosEsc
;
1711 yoff
= offset
* -sinEsc
;
1713 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1714 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1717 XPutImage(gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
1718 image_x
, image_y
, image_w
, image_h
);
1719 XDestroyImage(image
);
1722 wine_tsx11_unlock();
1724 LeaveCriticalSection(&xrender_cs
);
1726 if (flags
& ETO_CLIPPED
)
1728 /* restore the device region */
1729 X11DRV_SetDeviceClipping( physDev
, saved_region
, 0 );
1730 DeleteObject( saved_region
);
1736 X11DRV_UnlockDIBSection( physDev
, TRUE
);
1740 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
1741 static void set_xrender_transformation(Picture src_pict
, float xscale
, float yscale
, int xoffset
, int yoffset
)
1743 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1744 XTransform xform
= {{
1745 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(xoffset
) },
1746 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(yoffset
) },
1747 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1750 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
1754 /* Helper function for (stretched) blitting using xrender */
1755 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
)
1757 /* Further down a transformation matrix is used for stretching and mirroring the source data.
1758 * xscale/yscale contain the scaling factors for the width and height. In case of mirroring
1759 * we also need a x- and y-offset because without the pixels will be in the wrong quadrant of the x-y plane.
1761 int x_offset
= (xscale
<0) ? width
: 0;
1762 int y_offset
= (yscale
<0) ? height
: 0;
1764 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1765 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1766 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1767 if(xscale
!= 1.0 || yscale
!= 1.0)
1769 /* When we are using a mask, 'src_pict' contains a 1x1 picture for tiling, the actual source data is in mask_pict */
1771 set_xrender_transformation(mask_pict
, xscale
, yscale
, x_offset
, y_offset
);
1773 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
+ x_offset
, y_src
+ y_offset
);
1775 pXRenderComposite(gdi_display
, PictOpSrc
, src_pict
, mask_pict
, dst_pict
, 0, 0, 0, 0, 0, 0, width
, height
);
1779 /* When we are using a mask, 'src_pict' contains a 1x1 picture for tiling, the actual source data is in mask_pict */
1781 set_xrender_transformation(mask_pict
, 1, 1, 0, 0);
1783 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1785 pXRenderComposite(gdi_display
, PictOpSrc
, src_pict
, mask_pict
, dst_pict
, x_src
, y_src
, 0, 0, 0, 0, width
, height
);
1789 /******************************************************************************
1790 * AlphaBlend (x11drv.@)
1792 BOOL CDECL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1793 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1794 BLENDFUNCTION blendfn
)
1796 XRenderPictureAttributes pa
;
1797 Picture dst_pict
, src_pict
;
1803 DWORD
*dstbits
, *data
;
1806 BOOL top_down
= FALSE
;
1808 WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(devDst
->depth
, devDst
->color_shifts
);
1809 WineXRenderFormat
*src_format
;
1812 if(!X11DRV_XRender_Installed
) {
1813 FIXME("Unable to AlphaBlend without Xrender\n");
1818 pts
[1].x
= xDst
+ widthDst
;
1819 pts
[1].y
= yDst
+ heightDst
;
1820 LPtoDP(devDst
->hdc
, pts
, 2);
1823 widthDst
= pts
[1].x
- pts
[0].x
;
1824 heightDst
= pts
[1].y
- pts
[0].y
;
1828 pts
[1].x
= xSrc
+ widthSrc
;
1829 pts
[1].y
= ySrc
+ heightSrc
;
1830 LPtoDP(devSrc
->hdc
, pts
, 2);
1833 widthSrc
= pts
[1].x
- pts
[0].x
;
1834 heightSrc
= pts
[1].y
- pts
[0].y
;
1835 if (!widthDst
|| !heightDst
|| !widthSrc
|| !heightSrc
) return TRUE
;
1837 /* If the source is a 1x1 bitmap, tiling is equivalent to stretching, but
1838 tiling is much faster. Therefore, we do no stretching in this case. */
1839 repeat_src
= widthSrc
== 1 && heightSrc
== 1;
1841 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1842 if((widthDst
!= widthSrc
|| heightDst
!= heightSrc
) && !repeat_src
)
1844 if(!pXRenderSetPictureTransform
&& !repeat_src
)
1847 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1851 if (!devSrc
->bitmap
|| GetObjectW( devSrc
->bitmap
->hbitmap
, sizeof(dib
), &dib
) != sizeof(dib
))
1853 static BOOL out
= FALSE
;
1856 FIXME("not a dibsection\n");
1862 if (xSrc
< 0 || ySrc
< 0 || widthSrc
< 0 || heightSrc
< 0 || xSrc
+ widthSrc
> dib
.dsBmih
.biWidth
1863 || ySrc
+ heightSrc
> abs(dib
.dsBmih
.biHeight
))
1865 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc
, ySrc
, widthSrc
, heightSrc
);
1866 SetLastError(ERROR_INVALID_PARAMETER
);
1870 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && blendfn
.SourceConstantAlpha
!= 0xff)
1871 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn
.SourceConstantAlpha
);
1873 if(dib
.dsBm
.bmBitsPixel
!= 32) {
1874 FIXME("not a 32 bpp dibsection\n");
1877 dstbits
= data
= HeapAlloc(GetProcessHeap(), 0, heightSrc
* widthSrc
* 4);
1879 if(dib
.dsBmih
.biHeight
< 0) { /* top-down dib */
1881 dstbits
+= widthSrc
* (heightSrc
- 1);
1883 y
= y2
+ heightSrc
- 1;
1887 y
= dib
.dsBmih
.biHeight
- ySrc
- 1;
1888 y2
= y
- heightSrc
+ 1;
1891 if (blendfn
.AlphaFormat
& AC_SRC_ALPHA
)
1895 memcpy(dstbits
, (char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
+ xSrc
* 4,
1897 dstbits
+= (top_down
? -1 : 1) * widthSrc
;
1902 DWORD source_alpha
= (DWORD
)blendfn
.SourceConstantAlpha
<< 24;
1907 DWORD
*srcbits
= (DWORD
*)((char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
) + xSrc
;
1908 for (x
= 0; x
< widthSrc
; x
++)
1910 DWORD argb
= *srcbits
++;
1911 argb
= (argb
& 0xffffff) | source_alpha
;
1914 if (top_down
) /* we traversed the row forward so we should go back by two rows */
1915 dstbits
-= 2 * widthSrc
;
1920 rgndata
= X11DRV_GetRegionData( devDst
->region
, 0 );
1923 image
= XCreateImage(gdi_display
, visual
, 32, ZPixmap
, 0,
1924 (char*) data
, widthSrc
, heightSrc
, 32, widthSrc
* 4);
1926 src_format
= get_xrender_format(WXR_FORMAT_A8R8G8B8
);
1927 TRACE("src_format %p\n", src_format
);
1930 WARN("Unable to find a picture format supporting alpha, make sure X is running at 24-bit\n");
1934 pa
.subwindow_mode
= IncludeInferiors
;
1935 pa
.repeat
= repeat_src
? RepeatNormal
: RepeatNone
;
1937 /* FIXME use devDst->xrender->pict ? */
1938 dst_pict
= pXRenderCreatePicture(gdi_display
,
1940 dst_format
->pict_format
,
1941 CPSubwindowMode
, &pa
);
1942 TRACE("dst_pict %08lx\n", dst_pict
);
1943 TRACE("src_drawable = %08lx\n", devSrc
->drawable
);
1944 xpm
= XCreatePixmap(gdi_display
,
1946 widthSrc
, heightSrc
, 32);
1947 gcv
.graphics_exposures
= False
;
1948 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1949 TRACE("xpm = %08lx\n", xpm
);
1950 XPutImage(gdi_display
, xpm
, gc
, image
, 0, 0, 0, 0, widthSrc
, heightSrc
);
1952 src_pict
= pXRenderCreatePicture(gdi_display
,
1953 xpm
, src_format
->pict_format
,
1954 CPSubwindowMode
|CPRepeat
, &pa
);
1955 TRACE("src_pict %08lx\n", src_pict
);
1959 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
,
1960 devDst
->dc_rect
.left
, devDst
->dc_rect
.top
,
1961 (XRectangle
*)rgndata
->Buffer
,
1962 rgndata
->rdh
.nCount
);
1963 HeapFree( GetProcessHeap(), 0, rgndata
);
1966 /* Make sure we ALWAYS set the transformation matrix even if we don't need to scale. The reason is
1967 * that later on we want to reuse pictures (it can bring a lot of extra performance) and each time
1968 * a different transformation matrix might have been used. */
1969 set_xrender_transformation(src_pict
, widthSrc
/(double)widthDst
, heightSrc
/(double)heightDst
, 0, 0);
1970 pXRenderComposite(gdi_display
, PictOpOver
, src_pict
, 0, dst_pict
,
1972 xDst
+ devDst
->dc_rect
.left
, yDst
+ devDst
->dc_rect
.top
, widthDst
, heightDst
);
1975 pXRenderFreePicture(gdi_display
, src_pict
);
1976 XFreePixmap(gdi_display
, xpm
);
1977 XFreeGC(gdi_display
, gc
);
1978 pXRenderFreePicture(gdi_display
, dst_pict
);
1980 XDestroyImage(image
);
1982 wine_tsx11_unlock();
1983 HeapFree(GetProcessHeap(), 0, data
);
1987 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
1989 /* 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 */
1990 int depth
= physBitmap
->pixmap_depth
== 1 ? 1 : physDev
->depth
;
1993 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, depth
);
1995 /* Use XCopyArea when the physBitmap and brush.pixmap have the same depth. */
1996 if(physBitmap
->pixmap_depth
== 1 || physDev
->depth
== physBitmap
->pixmap_depth
)
1998 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
1999 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
2001 else /* We meed depth conversion */
2003 WineXRenderFormat
*src_format
= get_xrender_format_from_color_shifts(physBitmap
->pixmap_depth
, &physBitmap
->pixmap_color_shifts
);
2004 WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
2006 Picture src_pict
, dst_pict
;
2007 XRenderPictureAttributes pa
;
2008 pa
.subwindow_mode
= IncludeInferiors
;
2009 pa
.repeat
= RepeatNone
;
2011 src_pict
= pXRenderCreatePicture(gdi_display
, physBitmap
->pixmap
, src_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2012 dst_pict
= pXRenderCreatePicture(gdi_display
, physDev
->brush
.pixmap
, dst_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2014 xrender_blit(src_pict
, 0, dst_pict
, 0, 0, 1.0, 1.0, width
, height
);
2015 pXRenderFreePicture(gdi_display
, src_pict
);
2016 pXRenderFreePicture(gdi_display
, dst_pict
);
2018 wine_tsx11_unlock();
2021 BOOL
X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
2022 Pixmap pixmap
, GC gc
,
2023 INT widthSrc
, INT heightSrc
,
2024 INT widthDst
, INT heightDst
,
2025 RECT
*visRectSrc
, RECT
*visRectDst
)
2027 BOOL stretch
= (widthSrc
!= widthDst
) || (heightSrc
!= heightDst
);
2028 int width
= visRectDst
->right
- visRectDst
->left
;
2029 int height
= visRectDst
->bottom
- visRectDst
->top
;
2030 int x_src
= physDevSrc
->dc_rect
.left
+ visRectSrc
->left
;
2031 int y_src
= physDevSrc
->dc_rect
.top
+ visRectSrc
->top
;
2032 WineXRenderFormat
*src_format
= get_xrender_format_from_color_shifts(physDevSrc
->depth
, physDevSrc
->color_shifts
);
2033 WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDevDst
->depth
, physDevDst
->color_shifts
);
2034 Picture src_pict
=0, dst_pict
=0, mask_pict
=0;
2036 double xscale
= widthSrc
/(double)widthDst
;
2037 double yscale
= heightSrc
/(double)heightDst
;
2039 XRenderPictureAttributes pa
;
2040 pa
.subwindow_mode
= IncludeInferiors
;
2041 pa
.repeat
= RepeatNone
;
2043 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n", physDevSrc
->depth
, widthSrc
, heightSrc
, x_src
, y_src
);
2044 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst
->depth
, widthDst
, heightDst
);
2046 if(!X11DRV_XRender_Installed
)
2048 TRACE("Not using XRender since it is not available or disabled\n");
2052 /* XRender can't handle palettes, so abort */
2053 if(X11DRV_PALETTE_XPixelToPalette
)
2056 /* XRender is of no use in this case */
2057 if((physDevDst
->depth
== 1) && (physDevSrc
->depth
> 1))
2060 /* Just use traditional X copy when the depths match and we don't need stretching */
2061 if((physDevSrc
->depth
== physDevDst
->depth
) && !stretch
)
2063 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2065 XCopyArea( gdi_display
, physDevSrc
->drawable
, pixmap
, gc
, x_src
, y_src
, width
, height
, 0, 0);
2066 wine_tsx11_unlock();
2071 if(physDevSrc
->depth
== 1)
2074 get_xrender_color(dst_format
, physDevDst
->textPixel
, &col
);
2076 /* We use the source drawable as a mask */
2078 mask_pict
= pXRenderCreatePicture(gdi_display
, physDevSrc
->drawable
, src_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2080 /* Use backgroundPixel as the foreground color */
2081 src_pict
= get_tile_pict(dst_format
, physDevDst
->backgroundPixel
);
2083 /* Create a destination picture and fill it with textPixel color as the background color */
2084 dst_pict
= pXRenderCreatePicture(gdi_display
, pixmap
, dst_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2085 pXRenderFillRectangle(gdi_display
, PictOpSrc
, dst_pict
, &col
, 0, 0, width
, height
);
2087 xrender_blit(src_pict
, mask_pict
, dst_pict
, x_src
, y_src
, xscale
, yscale
, width
, height
);
2089 if(dst_pict
) pXRenderFreePicture(gdi_display
, dst_pict
);
2090 if(mask_pict
) pXRenderFreePicture(gdi_display
, mask_pict
);
2091 wine_tsx11_unlock();
2093 else /* color -> color but with different depths */
2096 src_pict
= pXRenderCreatePicture(gdi_display
,
2097 physDevSrc
->drawable
, src_format
->pict_format
,
2098 CPSubwindowMode
|CPRepeat
, &pa
);
2100 dst_pict
= pXRenderCreatePicture(gdi_display
,
2101 pixmap
, dst_format
->pict_format
,
2102 CPSubwindowMode
|CPRepeat
, &pa
);
2104 xrender_blit(src_pict
, 0, dst_pict
, x_src
, y_src
, xscale
, yscale
, width
, height
);
2106 if(src_pict
) pXRenderFreePicture(gdi_display
, src_pict
);
2107 if(dst_pict
) pXRenderFreePicture(gdi_display
, dst_pict
);
2108 wine_tsx11_unlock();
2113 #else /* SONAME_LIBXRENDER */
2115 void X11DRV_XRender_Init(void)
2117 TRACE("XRender support not compiled in.\n");
2121 void X11DRV_XRender_Finalize(void)
2125 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
2131 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
2137 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
2138 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
2145 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
2151 /******************************************************************************
2152 * AlphaBlend (x11drv.@)
2154 BOOL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
2155 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
2156 BLENDFUNCTION blendfn
)
2158 FIXME("not supported - XRENDER headers were missing at compile time\n");
2162 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
2165 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, physBitmap
->pixmap_depth
);
2167 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
2168 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
2169 wine_tsx11_unlock();
2172 BOOL
X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
2173 Pixmap pixmap
, GC gc
,
2174 INT widthSrc
, INT heightSrc
,
2175 INT widthDst
, INT heightDst
,
2176 RECT
*visRectSrc
, RECT
*visRectDst
)
2180 #endif /* SONAME_LIBXRENDER */