2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
8 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
36 #include "wine/library.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
40 int using_client_side_fonts
= FALSE
;
42 WINE_DEFAULT_DEBUG_CHANNEL(xrender
);
44 #ifdef SONAME_LIBXRENDER
46 static BOOL X11DRV_XRender_Installed
= FALSE
;
49 #include <X11/extensions/Xrender.h>
51 #ifndef RepeatNone /* added in 0.10 */
53 #define RepeatNormal 1
55 #define RepeatReflect 3
58 typedef enum wine_xrformat
75 typedef struct wine_xrender_format_template
80 unsigned int alphaMask
;
84 unsigned int greenMask
;
86 unsigned int blueMask
;
87 } WineXRenderFormatTemplate
;
89 static const WineXRenderFormatTemplate wxr_formats_template
[WXR_NB_FORMATS
] =
91 /* Format depth alpha mask red mask green mask blue mask*/
92 {WXR_FORMAT_MONO
, 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
93 {WXR_FORMAT_GRAY
, 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
94 {WXR_FORMAT_X1R5G5B5
, 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
95 {WXR_FORMAT_X1B5G5R5
, 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
96 {WXR_FORMAT_R5G6B5
, 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
97 {WXR_FORMAT_B5G6R5
, 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
98 {WXR_FORMAT_R8G8B8
, 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
99 {WXR_FORMAT_B8G8R8
, 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
100 {WXR_FORMAT_A8R8G8B8
, 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
101 {WXR_FORMAT_B8G8R8A8
, 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
102 {WXR_FORMAT_X8R8G8B8
, 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
103 {WXR_FORMAT_B8G8R8X8
, 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
106 typedef struct wine_xrender_format
109 XRenderPictFormat
*pict_format
;
112 static WineXRenderFormat wxr_formats
[WXR_NB_FORMATS
];
113 static int WineXRenderFormatsListSize
= 0;
114 static WineXRenderFormat
*default_format
= NULL
;
120 SIZE devsize
; /* size in device coords */
124 #define INITIAL_REALIZED_BUF_SIZE 128
126 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
131 const WineXRenderFormat
*font_format
;
136 } gsCacheEntryFormat
;
142 gsCacheEntryFormat
* format
[AA_MAXVALUE
];
152 const WineXRenderFormat
*format
;
155 static gsCacheEntry
*glyphsetCache
= NULL
;
156 static DWORD glyphsetCacheSize
= 0;
157 static INT lastfree
= -1;
160 #define INIT_CACHE_SIZE 10
162 static int antialias
= 1;
164 static void *xrender_handle
;
166 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
167 MAKE_FUNCPTR(XRenderAddGlyphs
)
168 MAKE_FUNCPTR(XRenderComposite
)
169 MAKE_FUNCPTR(XRenderCompositeString8
)
170 MAKE_FUNCPTR(XRenderCompositeString16
)
171 MAKE_FUNCPTR(XRenderCompositeString32
)
172 MAKE_FUNCPTR(XRenderCompositeText16
)
173 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
174 MAKE_FUNCPTR(XRenderCreatePicture
)
175 MAKE_FUNCPTR(XRenderFillRectangle
)
176 MAKE_FUNCPTR(XRenderFindFormat
)
177 MAKE_FUNCPTR(XRenderFindVisualFormat
)
178 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
179 MAKE_FUNCPTR(XRenderFreePicture
)
180 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
181 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
182 MAKE_FUNCPTR(XRenderSetPictureTransform
)
184 MAKE_FUNCPTR(XRenderQueryExtension
)
186 #ifdef SONAME_LIBFONTCONFIG
187 #include <fontconfig/fontconfig.h>
188 MAKE_FUNCPTR(FcConfigSubstitute
)
189 MAKE_FUNCPTR(FcDefaultSubstitute
)
190 MAKE_FUNCPTR(FcFontMatch
)
192 MAKE_FUNCPTR(FcPatternCreate
)
193 MAKE_FUNCPTR(FcPatternDestroy
)
194 MAKE_FUNCPTR(FcPatternAddInteger
)
195 MAKE_FUNCPTR(FcPatternAddString
)
196 MAKE_FUNCPTR(FcPatternGetInteger
)
197 MAKE_FUNCPTR(FcPatternGetString
)
198 static void *fontconfig_handle
;
199 static BOOL fontconfig_installed
;
204 static CRITICAL_SECTION xrender_cs
;
205 static CRITICAL_SECTION_DEBUG critsect_debug
=
208 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
209 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
211 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
213 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
214 ( ( (ULONG)_x4 << 24 ) | \
215 ( (ULONG)_x3 << 16 ) | \
216 ( (ULONG)_x2 << 8 ) | \
219 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
221 #define GASP_GRIDFIT 0x01
222 #define GASP_DOGRAY 0x02
224 #ifdef WORDS_BIGENDIAN
225 #define get_be_word(x) (x)
226 #define NATIVE_BYTE_ORDER MSBFirst
228 #define get_be_word(x) RtlUshortByteSwap(x)
229 #define NATIVE_BYTE_ORDER LSBFirst
232 static WXRFormat
get_format_without_alpha( WXRFormat format
)
236 case WXR_FORMAT_A8R8G8B8
: return WXR_FORMAT_X8R8G8B8
;
237 case WXR_FORMAT_B8G8R8A8
: return WXR_FORMAT_B8G8R8X8
;
238 default: return format
;
242 static BOOL
get_xrender_template(const WineXRenderFormatTemplate
*fmt
, XRenderPictFormat
*templ
, unsigned long *mask
)
245 templ
->type
= PictTypeDirect
;
246 templ
->depth
= fmt
->depth
;
247 templ
->direct
.alpha
= fmt
->alpha
;
248 templ
->direct
.alphaMask
= fmt
->alphaMask
;
249 templ
->direct
.red
= fmt
->red
;
250 templ
->direct
.redMask
= fmt
->redMask
;
251 templ
->direct
.green
= fmt
->green
;
252 templ
->direct
.greenMask
= fmt
->greenMask
;
253 templ
->direct
.blue
= fmt
->blue
;
254 templ
->direct
.blueMask
= fmt
->blueMask
;
257 *mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
| PictFormatRed
| PictFormatRedMask
| PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
| PictFormatBlueMask
;
262 static BOOL
is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate
*fmt
)
264 if(fmt
->depth
!= screen_depth
)
266 if( (fmt
->redMask
<< fmt
->red
) != visual
->red_mask
)
268 if( (fmt
->greenMask
<< fmt
->green
) != visual
->green_mask
)
270 if( (fmt
->blueMask
<< fmt
->blue
) != visual
->blue_mask
)
273 /* We never select a default ARGB visual */
280 static int load_xrender_formats(void)
283 for(i
= 0; i
< (sizeof(wxr_formats_template
) / sizeof(wxr_formats_template
[0])); i
++)
285 XRenderPictFormat templ
, *pict_format
;
287 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template
[i
]))
290 pict_format
= pXRenderFindVisualFormat(gdi_display
, visual
);
293 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
294 if (visual
->class == DirectColor
)
297 if (XMatchVisualInfo( gdi_display
, DefaultScreen(gdi_display
),
298 screen_depth
, TrueColor
, &info
))
300 pict_format
= pXRenderFindVisualFormat(gdi_display
, info
.visual
);
301 if (pict_format
) visual
= info
.visual
;
309 wxr_formats
[WineXRenderFormatsListSize
].format
= wxr_formats_template
[i
].wxr_format
;
310 wxr_formats
[WineXRenderFormatsListSize
].pict_format
= pict_format
;
311 default_format
= &wxr_formats
[WineXRenderFormatsListSize
];
312 WineXRenderFormatsListSize
++;
313 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format
->id
, wxr_formats_template
[i
].wxr_format
);
318 unsigned long mask
= 0;
319 get_xrender_template(&wxr_formats_template
[i
], &templ
, &mask
);
322 pict_format
= pXRenderFindFormat(gdi_display
, mask
, &templ
, 0);
327 wxr_formats
[WineXRenderFormatsListSize
].format
= wxr_formats_template
[i
].wxr_format
;
328 wxr_formats
[WineXRenderFormatsListSize
].pict_format
= pict_format
;
329 WineXRenderFormatsListSize
++;
330 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format
->id
, wxr_formats_template
[i
].wxr_format
);
334 return WineXRenderFormatsListSize
;
337 /***********************************************************************
338 * X11DRV_XRender_Init
340 * Let's see if our XServer has the extension available
343 void X11DRV_XRender_Init(void)
347 if (client_side_with_render
&&
348 wine_dlopen(SONAME_LIBX11
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
349 wine_dlopen(SONAME_LIBXEXT
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
350 (xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0)))
353 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
354 LOAD_FUNCPTR(XRenderAddGlyphs
)
355 LOAD_FUNCPTR(XRenderComposite
)
356 LOAD_FUNCPTR(XRenderCompositeString8
)
357 LOAD_FUNCPTR(XRenderCompositeString16
)
358 LOAD_FUNCPTR(XRenderCompositeString32
)
359 LOAD_FUNCPTR(XRenderCompositeText16
)
360 LOAD_FUNCPTR(XRenderCreateGlyphSet
)
361 LOAD_FUNCPTR(XRenderCreatePicture
)
362 LOAD_FUNCPTR(XRenderFillRectangle
)
363 LOAD_FUNCPTR(XRenderFindFormat
)
364 LOAD_FUNCPTR(XRenderFindVisualFormat
)
365 LOAD_FUNCPTR(XRenderFreeGlyphSet
)
366 LOAD_FUNCPTR(XRenderFreePicture
)
367 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
)
368 LOAD_FUNCPTR(XRenderQueryExtension
)
370 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
371 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
372 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
)
373 #undef LOAD_OPTIONAL_FUNCPTR
377 X11DRV_XRender_Installed
= pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
);
379 if(X11DRV_XRender_Installed
) {
380 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
381 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
385 "Wine has detected that you probably have a buggy version\n"
386 "of libXrender.so . Because of this client side font rendering\n"
387 "will be disabled. Please upgrade this library.\n");
388 X11DRV_XRender_Installed
= FALSE
;
392 if (!visual
->red_mask
|| !visual
->green_mask
|| !visual
->blue_mask
) {
393 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
394 X11DRV_XRender_Installed
= FALSE
;
399 #ifdef SONAME_LIBFONTCONFIG
400 if ((fontconfig_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0)))
402 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fontconfig_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
403 LOAD_FUNCPTR(FcConfigSubstitute
);
404 LOAD_FUNCPTR(FcDefaultSubstitute
);
405 LOAD_FUNCPTR(FcFontMatch
);
406 LOAD_FUNCPTR(FcInit
);
407 LOAD_FUNCPTR(FcPatternCreate
);
408 LOAD_FUNCPTR(FcPatternDestroy
);
409 LOAD_FUNCPTR(FcPatternAddInteger
);
410 LOAD_FUNCPTR(FcPatternAddString
);
411 LOAD_FUNCPTR(FcPatternGetInteger
);
412 LOAD_FUNCPTR(FcPatternGetString
);
414 fontconfig_installed
= pFcInit();
416 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG
"\n" );
420 if(X11DRV_XRender_Installed
|| client_side_with_core
)
422 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
423 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
425 glyphsetCacheSize
= INIT_CACHE_SIZE
;
427 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
428 glyphsetCache
[i
].next
= i
+ 1;
429 glyphsetCache
[i
].count
= -1;
431 glyphsetCache
[i
-1].next
= -1;
432 using_client_side_fonts
= 1;
434 if(!X11DRV_XRender_Installed
) {
435 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
436 if(screen_depth
<= 8 || !client_side_antialias_with_core
)
439 if(screen_depth
<= 8 || !client_side_antialias_with_render
)
443 else TRACE("Using X11 core fonts\n");
446 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
447 static void get_xrender_color(const WineXRenderFormat
*wxr_format
, int src_color
, XRenderColor
*dst_color
)
449 XRenderPictFormat
*pf
= wxr_format
->pict_format
;
451 if(pf
->direct
.redMask
)
452 dst_color
->red
= ((src_color
>> pf
->direct
.red
) & pf
->direct
.redMask
) * 65535/pf
->direct
.redMask
;
456 if(pf
->direct
.greenMask
)
457 dst_color
->green
= ((src_color
>> pf
->direct
.green
) & pf
->direct
.greenMask
) * 65535/pf
->direct
.greenMask
;
459 dst_color
->green
= 0;
461 if(pf
->direct
.blueMask
)
462 dst_color
->blue
= ((src_color
>> pf
->direct
.blue
) & pf
->direct
.blueMask
) * 65535/pf
->direct
.blueMask
;
466 dst_color
->alpha
= 0xffff;
469 static const WineXRenderFormat
*get_xrender_format(WXRFormat format
)
472 for(i
=0; i
<WineXRenderFormatsListSize
; i
++)
474 if(wxr_formats
[i
].format
== format
)
476 TRACE("Returning wxr_format=%#x\n", format
);
477 return &wxr_formats
[i
];
483 static const WineXRenderFormat
*get_xrender_format_from_color_shifts(int depth
, ColorShifts
*shifts
)
485 int redMask
, greenMask
, blueMask
;
489 return get_xrender_format(WXR_FORMAT_MONO
);
491 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
493 return default_format
;
495 redMask
= shifts
->physicalRed
.max
<< shifts
->physicalRed
.shift
;
496 greenMask
= shifts
->physicalGreen
.max
<< shifts
->physicalGreen
.shift
;
497 blueMask
= shifts
->physicalBlue
.max
<< shifts
->physicalBlue
.shift
;
499 /* Try to locate a format which matches the specification of the dibsection. */
500 for(i
= 0; i
< (sizeof(wxr_formats_template
) / sizeof(wxr_formats_template
[0])); i
++)
502 if( depth
== wxr_formats_template
[i
].depth
&&
503 redMask
== (wxr_formats_template
[i
].redMask
<< wxr_formats_template
[i
].red
) &&
504 greenMask
== (wxr_formats_template
[i
].greenMask
<< wxr_formats_template
[i
].green
) &&
505 blueMask
== (wxr_formats_template
[i
].blueMask
<< wxr_formats_template
[i
].blue
) )
508 /* When we reach this stage the format was found in our template table but this doesn't mean that
509 * the Xserver also supports this format (e.g. its depth might be too low). The call below verifies that.
511 return get_xrender_format(wxr_formats_template
[i
].wxr_format
);
515 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
516 ERR("No XRender format found!\n");
520 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
521 static void set_xrender_transformation(Picture src_pict
, double xscale
, double yscale
, int xoffset
, int yoffset
)
523 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
524 XTransform xform
= {{
525 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(xoffset
) },
526 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(yoffset
) },
527 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
530 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
534 /* check if we can use repeating instead of scaling for the specified source DC */
535 static BOOL
use_source_repeat( X11DRV_PDEVICE
*physDev
)
537 return (physDev
->bitmap
&&
538 physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
== 1 &&
539 physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
== 1);
542 static struct xrender_info
*get_xrender_info(X11DRV_PDEVICE
*physDev
)
544 if(!physDev
->xrender
)
546 physDev
->xrender
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physDev
->xrender
));
548 if(!physDev
->xrender
)
550 ERR("Unable to allocate XRENDERINFO!\n");
553 physDev
->xrender
->cache_index
= -1;
555 if (!physDev
->xrender
->format
)
556 physDev
->xrender
->format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
558 return physDev
->xrender
;
561 static Picture
get_xrender_picture(X11DRV_PDEVICE
*physDev
)
563 struct xrender_info
*info
= get_xrender_info(physDev
);
566 if (!info
->pict
&& info
->format
)
568 XRenderPictureAttributes pa
;
569 RGNDATA
*clip
= X11DRV_GetRegionData( physDev
->region
, 0 );
572 pa
.subwindow_mode
= IncludeInferiors
;
573 info
->pict
= pXRenderCreatePicture(gdi_display
, physDev
->drawable
, info
->format
->pict_format
,
574 CPSubwindowMode
, &pa
);
575 if (info
->pict
&& clip
)
576 pXRenderSetPictureClipRectangles( gdi_display
, info
->pict
,
577 physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
578 (XRectangle
*)clip
->Buffer
, clip
->rdh
.nCount
);
580 TRACE("Allocing pict=%lx dc=%p drawable=%08lx\n", info
->pict
, physDev
->hdc
, physDev
->drawable
);
581 HeapFree( GetProcessHeap(), 0, clip
);
587 static Picture
get_xrender_picture_source(X11DRV_PDEVICE
*physDev
, BOOL repeat
)
589 struct xrender_info
*info
= get_xrender_info(physDev
);
592 if (!info
->pict_src
&& info
->format
)
594 XRenderPictureAttributes pa
;
597 pa
.subwindow_mode
= IncludeInferiors
;
598 pa
.repeat
= repeat
? RepeatNormal
: RepeatNone
;
599 info
->pict_src
= pXRenderCreatePicture(gdi_display
, physDev
->drawable
, info
->format
->pict_format
,
600 CPSubwindowMode
|CPRepeat
, &pa
);
603 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
604 info
->pict_src
, physDev
->hdc
, physDev
->drawable
, pa
.repeat
);
607 return info
->pict_src
;
610 /* return a mask picture used to force alpha to 0 */
611 static Picture
get_no_alpha_mask(void)
613 static Pixmap pixmap
;
619 const WineXRenderFormat
*fmt
= get_xrender_format( WXR_FORMAT_A8R8G8B8
);
620 XRenderPictureAttributes pa
;
623 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
624 pa
.repeat
= RepeatNormal
;
625 pa
.component_alpha
= True
;
626 pict
= pXRenderCreatePicture( gdi_display
, pixmap
, fmt
->pict_format
,
627 CPRepeat
|CPComponentAlpha
, &pa
);
628 col
.red
= col
.green
= col
.blue
= 0xffff;
630 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
636 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
638 if(p1
->hash
!= p2
->hash
) return TRUE
;
639 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
640 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
641 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
642 return strcmpiW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
646 static void walk_cache(void)
650 EnterCriticalSection(&xrender_cs
);
651 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
652 TRACE("item %d\n", i
);
653 LeaveCriticalSection(&xrender_cs
);
657 static int LookupEntry(LFANDSIZE
*plfsz
)
661 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
663 if(glyphsetCache
[i
].count
== -1) { /* reached free list so stop */
668 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
669 glyphsetCache
[i
].count
++;
671 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
672 glyphsetCache
[i
].next
= mru
;
675 TRACE("found font in cache %d\n", i
);
680 TRACE("font not in cache\n");
684 static void FreeEntry(int entry
)
688 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
689 gsCacheEntryFormat
* formatEntry
;
691 if( !glyphsetCache
[entry
].format
[format
] )
694 formatEntry
= glyphsetCache
[entry
].format
[format
];
696 if(formatEntry
->glyphset
) {
698 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
700 formatEntry
->glyphset
= 0;
702 if(formatEntry
->nrealized
) {
703 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
704 formatEntry
->realized
= NULL
;
705 if(formatEntry
->bitmaps
) {
706 for(i
= 0; i
< formatEntry
->nrealized
; i
++)
707 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
[i
]);
708 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
);
709 formatEntry
->bitmaps
= NULL
;
711 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
712 formatEntry
->gis
= NULL
;
713 formatEntry
->nrealized
= 0;
716 HeapFree(GetProcessHeap(), 0, formatEntry
);
717 glyphsetCache
[entry
].format
[format
] = NULL
;
721 static int AllocEntry(void)
723 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
726 assert(glyphsetCache
[lastfree
].count
== -1);
727 glyphsetCache
[lastfree
].count
= 1;
729 lastfree
= glyphsetCache
[lastfree
].next
;
731 glyphsetCache
[best
].next
= mru
;
734 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
738 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
739 if(glyphsetCache
[i
].count
== 0) {
747 TRACE("freeing unused glyphset at cache %d\n", best
);
749 glyphsetCache
[best
].count
= 1;
751 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
752 glyphsetCache
[best
].next
= mru
;
760 TRACE("Growing cache\n");
763 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
765 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
766 * sizeof(*glyphsetCache
));
768 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
769 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
770 * sizeof(*glyphsetCache
));
772 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
774 glyphsetCache
[i
].next
= i
+ 1;
775 glyphsetCache
[i
].count
= -1;
777 glyphsetCache
[i
-1].next
= -1;
778 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
780 lastfree
= glyphsetCache
[best
].next
;
781 glyphsetCache
[best
].count
= 1;
782 glyphsetCache
[best
].next
= mru
;
784 TRACE("new free cache slot at %d\n", mru
);
788 static BOOL
get_gasp_flags(X11DRV_PDEVICE
*physDev
, WORD
*flags
)
798 size
= GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, NULL
, 0);
799 if(size
== GDI_ERROR
)
802 gasp
= buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
803 GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, gasp
, size
);
805 GetTextMetricsW(physDev
->hdc
, &tm
);
806 ppem
= abs(X11DRV_YWStoDS(physDev
, tm
.tmAscent
+ tm
.tmDescent
- tm
.tmInternalLeading
));
809 num_recs
= get_be_word(*gasp
);
813 *flags
= get_be_word(*(gasp
+ 1));
814 if(ppem
<= get_be_word(*gasp
))
818 TRACE("got flags %04x for ppem %d\n", *flags
, ppem
);
820 HeapFree(GetProcessHeap(), 0, buffer
);
824 static AA_Type
get_antialias_type( X11DRV_PDEVICE
*physDev
, BOOL subpixel
, BOOL hinter
)
828 UINT font_smoothing_type
, font_smoothing_orientation
;
830 if (X11DRV_XRender_Installed
&& subpixel
&&
831 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE
, 0, &font_smoothing_type
, 0) &&
832 font_smoothing_type
== FE_FONTSMOOTHINGCLEARTYPE
)
834 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION
, 0,
835 &font_smoothing_orientation
, 0) &&
836 font_smoothing_orientation
== FE_FONTSMOOTHINGORIENTATIONBGR
)
843 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
844 But, Wine's subpixel rendering can support the portrait mode.
847 else if (!hinter
|| !get_gasp_flags(physDev
, &flags
) || flags
& GASP_DOGRAY
)
855 static int GetCacheEntry(X11DRV_PDEVICE
*physDev
, LFANDSIZE
*plfsz
)
860 static int hinter
= -1;
861 static int subpixel
= -1;
864 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
867 entry
= glyphsetCache
+ ret
;
868 entry
->lfsz
= *plfsz
;
869 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
870 assert( !entry
->format
[format
] );
873 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
875 if(hinter
== -1 || subpixel
== -1)
877 RASTERIZER_STATUS status
;
878 GetRasterizerCaps(&status
, sizeof(status
));
879 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
880 subpixel
= status
.wFlags
& WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
883 switch (plfsz
->lf
.lfQuality
)
885 case ANTIALIASED_QUALITY
:
886 entry
->aa_default
= get_antialias_type( physDev
, FALSE
, hinter
);
888 case CLEARTYPE_QUALITY
:
889 case CLEARTYPE_NATURAL_QUALITY
:
890 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
892 case DEFAULT_QUALITY
:
896 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING
, 0, &font_smoothing
, 0) &&
899 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
902 entry
->aa_default
= AA_None
;
906 #ifdef SONAME_LIBFONTCONFIG
907 if (fontconfig_installed
)
909 FcPattern
*match
, *pattern
= pFcPatternCreate();
911 char family
[LF_FACESIZE
* 4];
913 WideCharToMultiByte( CP_UTF8
, 0, plfsz
->lf
.lfFaceName
, -1, family
, sizeof(family
), NULL
, NULL
);
914 pFcPatternAddString( pattern
, FC_FAMILY
, (FcChar8
*)family
);
915 if (plfsz
->lf
.lfWeight
!= FW_DONTCARE
)
918 switch (plfsz
->lf
.lfWeight
)
920 case FW_THIN
: weight
= FC_WEIGHT_THIN
; break;
921 case FW_EXTRALIGHT
: weight
= FC_WEIGHT_EXTRALIGHT
; break;
922 case FW_LIGHT
: weight
= FC_WEIGHT_LIGHT
; break;
923 case FW_NORMAL
: weight
= FC_WEIGHT_NORMAL
; break;
924 case FW_MEDIUM
: weight
= FC_WEIGHT_MEDIUM
; break;
925 case FW_SEMIBOLD
: weight
= FC_WEIGHT_SEMIBOLD
; break;
926 case FW_BOLD
: weight
= FC_WEIGHT_BOLD
; break;
927 case FW_EXTRABOLD
: weight
= FC_WEIGHT_EXTRABOLD
; break;
928 case FW_HEAVY
: weight
= FC_WEIGHT_HEAVY
; break;
929 default: weight
= (plfsz
->lf
.lfWeight
- 80) / 4; break;
931 pFcPatternAddInteger( pattern
, FC_WEIGHT
, weight
);
933 pFcPatternAddInteger( pattern
, FC_SLANT
, plfsz
->lf
.lfItalic
? FC_SLANT_ITALIC
: FC_SLANT_ROMAN
);
934 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
935 pFcDefaultSubstitute( pattern
);
936 if ((match
= pFcFontMatch( NULL
, pattern
, &result
)))
940 if (pFcPatternGetInteger( match
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
943 if (pFcPatternGetString( match
, FC_FILE
, 0, &file
) != FcResultMatch
) file
= NULL
;
945 TRACE( "fontconfig returned rgba %u for font %s file %s\n",
946 rgba
, debugstr_w(plfsz
->lf
.lfFaceName
), debugstr_a((char *)file
) );
950 case FC_RGBA_RGB
: entry
->aa_default
= AA_RGB
; break;
951 case FC_RGBA_BGR
: entry
->aa_default
= AA_BGR
; break;
952 case FC_RGBA_VRGB
: entry
->aa_default
= AA_VRGB
; break;
953 case FC_RGBA_VBGR
: entry
->aa_default
= AA_VBGR
; break;
954 case FC_RGBA_NONE
: entry
->aa_default
= AA_None
; break;
957 pFcPatternDestroy( match
);
959 pFcPatternDestroy( pattern
);
961 #endif /* SONAME_LIBFONTCONFIG */
964 entry
->aa_default
= AA_None
;
969 static void dec_ref_cache(int index
)
972 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
973 assert(glyphsetCache
[index
].count
> 0);
974 glyphsetCache
[index
].count
--;
977 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
979 DWORD hash
= 0, *ptr
, two_chars
;
983 hash
^= plfsz
->devsize
.cx
;
984 hash
^= plfsz
->devsize
.cy
;
985 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
987 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
989 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
991 pwc
= (WCHAR
*)&two_chars
;
993 *pwc
= toupperW(*pwc
);
995 *pwc
= toupperW(*pwc
);
1003 /***********************************************************************
1004 * X11DRV_XRender_Finalize
1006 void X11DRV_XRender_Finalize(void)
1010 EnterCriticalSection(&xrender_cs
);
1011 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
1013 LeaveCriticalSection(&xrender_cs
);
1017 /***********************************************************************
1018 * X11DRV_XRender_SelectFont
1020 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
1023 struct xrender_info
*info
;
1025 GetObjectW(hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
1026 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1027 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
1028 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
1029 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
1030 lfsz
.devsize
.cx
= X11DRV_XWStoDS( physDev
, lfsz
.lf
.lfWidth
);
1031 lfsz
.devsize
.cy
= X11DRV_YWStoDS( physDev
, lfsz
.lf
.lfHeight
);
1032 GetWorldTransform( physDev
->hdc
, &lfsz
.xform
);
1033 lfsz_calc_hash(&lfsz
);
1035 info
= get_xrender_info(physDev
);
1036 if (!info
) return 0;
1038 EnterCriticalSection(&xrender_cs
);
1039 if(info
->cache_index
!= -1)
1040 dec_ref_cache(info
->cache_index
);
1041 info
->cache_index
= GetCacheEntry(physDev
, &lfsz
);
1042 LeaveCriticalSection(&xrender_cs
);
1046 /***********************************************************************
1047 * X11DRV_XRender_SetDeviceClipping
1049 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE
*physDev
, const RGNDATA
*data
)
1051 if (physDev
->xrender
->pict
)
1054 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
1055 physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
1056 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
1057 wine_tsx11_unlock();
1061 /***********************************************************************
1062 * X11DRV_XRender_DeleteDC
1064 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
1066 X11DRV_XRender_UpdateDrawable(physDev
);
1068 EnterCriticalSection(&xrender_cs
);
1069 if(physDev
->xrender
->cache_index
!= -1)
1070 dec_ref_cache(physDev
->xrender
->cache_index
);
1071 LeaveCriticalSection(&xrender_cs
);
1073 HeapFree(GetProcessHeap(), 0, physDev
->xrender
);
1074 physDev
->xrender
= NULL
;
1078 BOOL
X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP
*physBitmap
, int bits_pixel
, const DIBSECTION
*dib
)
1080 const WineXRenderFormat
*fmt
;
1083 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1084 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1085 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1086 if (!X11DRV_XRender_Installed
|| bits_pixel
<= 8)
1091 X11DRV_PALETTE_ComputeColorShifts(&shifts
, dib
->dsBitfields
[0], dib
->dsBitfields
[1], dib
->dsBitfields
[2]);
1092 fmt
= get_xrender_format_from_color_shifts(dib
->dsBm
.bmBitsPixel
, &shifts
);
1094 /* Common formats should be in our picture format table. */
1097 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1098 dib
->dsBm
.bmBitsPixel
, dib
->dsBitfields
[0], dib
->dsBitfields
[1], dib
->dsBitfields
[2]);
1104 int red_mask
, green_mask
, blue_mask
;
1106 /* We are dealing with a DDB */
1110 fmt
= get_xrender_format(WXR_FORMAT_R5G6B5
);
1113 fmt
= get_xrender_format(WXR_FORMAT_R8G8B8
);
1116 fmt
= get_xrender_format(WXR_FORMAT_A8R8G8B8
);
1124 TRACE("Unhandled DDB bits_pixel=%d\n", bits_pixel
);
1128 red_mask
= fmt
->pict_format
->direct
.redMask
<< fmt
->pict_format
->direct
.red
;
1129 green_mask
= fmt
->pict_format
->direct
.greenMask
<< fmt
->pict_format
->direct
.green
;
1130 blue_mask
= fmt
->pict_format
->direct
.blueMask
<< fmt
->pict_format
->direct
.blue
;
1131 X11DRV_PALETTE_ComputeColorShifts(&shifts
, red_mask
, green_mask
, blue_mask
);
1134 physBitmap
->pixmap_depth
= fmt
->pict_format
->depth
;
1135 physBitmap
->trueColor
= TRUE
;
1136 physBitmap
->pixmap_color_shifts
= shifts
;
1140 /***********************************************************************
1141 * X11DRV_XRender_UpdateDrawable
1143 * Deletes the pict and tile when the drawable changes.
1145 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
1147 struct xrender_info
*info
= physDev
->xrender
;
1149 if (info
->pict
|| info
->pict_src
)
1152 XFlush( gdi_display
);
1155 TRACE("freeing pict = %lx dc = %p\n", info
->pict
, physDev
->hdc
);
1156 pXRenderFreePicture(gdi_display
, info
->pict
);
1161 TRACE("freeing pict = %lx dc = %p\n", info
->pict_src
, physDev
->hdc
);
1162 pXRenderFreePicture(gdi_display
, info
->pict_src
);
1165 wine_tsx11_unlock();
1168 info
->format
= NULL
;
1171 /************************************************************************
1174 * Helper to ExtTextOut. Must be called inside xrender_cs
1176 static BOOL
UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
, AA_Type format
)
1178 unsigned int buflen
;
1183 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1184 gsCacheEntryFormat
*formatEntry
;
1185 UINT ggo_format
= GGO_GLYPH_INDEX
;
1186 WXRFormat wxr_format
;
1187 static const char zero
[4];
1188 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
1192 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
1195 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
1198 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
1201 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
1204 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
1208 ERR("aa = %d - not implemented\n", format
);
1210 ggo_format
|= GGO_BITMAP
;
1214 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1215 if(buflen
== GDI_ERROR
) {
1216 if(format
!= AA_None
) {
1218 entry
->aa_default
= AA_None
;
1219 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
1220 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1222 if(buflen
== GDI_ERROR
) {
1223 WARN("GetGlyphOutlineW failed\n");
1226 TRACE("Turning off antialiasing for this monochrome font\n");
1229 /* If there is nothing for the current type, we create the entry. */
1230 if( !entry
->format
[format
] ) {
1231 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
1233 sizeof(gsCacheEntryFormat
));
1235 formatEntry
= entry
->format
[format
];
1237 if(formatEntry
->nrealized
<= glyph
) {
1238 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
1240 if (formatEntry
->realized
)
1241 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
1243 formatEntry
->realized
,
1244 formatEntry
->nrealized
* sizeof(BOOL
));
1246 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
1248 formatEntry
->nrealized
* sizeof(BOOL
));
1250 if(!X11DRV_XRender_Installed
) {
1251 if (formatEntry
->bitmaps
)
1252 formatEntry
->bitmaps
= HeapReAlloc(GetProcessHeap(),
1254 formatEntry
->bitmaps
,
1255 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
1257 formatEntry
->bitmaps
= HeapAlloc(GetProcessHeap(),
1259 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
1261 if (formatEntry
->gis
)
1262 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
1265 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1267 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
1269 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1273 if(formatEntry
->glyphset
== 0 && X11DRV_XRender_Installed
) {
1276 wxr_format
= WXR_FORMAT_GRAY
;
1283 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1287 ERR("aa = %d - not implemented\n", format
);
1289 wxr_format
= WXR_FORMAT_MONO
;
1294 formatEntry
->font_format
= get_xrender_format(wxr_format
);
1295 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
->pict_format
);
1296 wine_tsx11_unlock();
1300 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
1301 GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
1302 formatEntry
->realized
[glyph
] = TRUE
;
1304 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1306 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1307 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1309 gi
.width
= gm
.gmBlackBoxX
;
1310 gi
.height
= gm
.gmBlackBoxY
;
1311 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1312 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1313 gi
.xOff
= gm
.gmCellIncX
;
1314 gi
.yOff
= gm
.gmCellIncY
;
1316 if(TRACE_ON(xrender
)) {
1319 unsigned char *line
;
1321 if(format
== AA_None
) {
1322 pitch
= ((gi
.width
+ 31) / 32) * 4;
1323 for(i
= 0; i
< gi
.height
; i
++) {
1324 line
= (unsigned char*) buf
+ i
* pitch
;
1326 for(j
= 0; j
< pitch
* 8; j
++) {
1327 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1329 TRACE("%s\n", output
);
1332 static const char blks
[] = " .:;!o*#";
1336 pitch
= ((gi
.width
+ 3) / 4) * 4;
1337 for(i
= 0; i
< gi
.height
; i
++) {
1338 line
= (unsigned char*) buf
+ i
* pitch
;
1340 for(j
= 0; j
< pitch
; j
++) {
1341 str
[0] = blks
[line
[j
] >> 5];
1342 strcat(output
, str
);
1344 TRACE("%s\n", output
);
1350 if(formatEntry
->glyphset
) {
1351 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1352 unsigned char *byte
= (unsigned char*) buf
, c
;
1358 /* magic to flip bit order */
1359 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1360 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1361 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1366 else if ( format
!= AA_Grey
&&
1367 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1369 unsigned int i
, *data
= (unsigned int *)buf
;
1370 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1375 XRenderCompositeText seems to ignore 0x0 glyphs when
1376 AA_None, which means we lose the advance width of glyphs
1377 like the space. We'll pretend that such glyphs are 1x1
1382 gi
.width
= gi
.height
= 1;
1385 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1386 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1387 wine_tsx11_unlock();
1388 HeapFree(GetProcessHeap(), 0, buf
);
1390 formatEntry
->bitmaps
[glyph
] = buf
;
1393 formatEntry
->gis
[glyph
] = gi
;
1398 static void SharpGlyphMono(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
1399 void *bitmap
, XGlyphInfo
*gi
)
1401 unsigned char *srcLine
= bitmap
, *src
;
1402 unsigned char bits
, bitsMask
;
1403 int width
= gi
->width
;
1404 int stride
= ((width
+ 31) & ~31) >> 3;
1405 int height
= gi
->height
;
1409 TRACE("%d, %d\n", x
, y
);
1418 bitsMask
= 0x80; /* FreeType is always MSB first */
1424 if (bits
& bitsMask
)
1432 bitsMask
= bitsMask
>> 1;
1438 } while (bits
& bitsMask
);
1439 XFillRectangle (gdi_display
, physDev
->drawable
,
1440 physDev
->gc
, xspan
, y
, lenspan
, 1);
1452 bitsMask
= bitsMask
>> 1;
1458 } while (!(bits
& bitsMask
));
1465 static void SharpGlyphGray(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
1466 void *bitmap
, XGlyphInfo
*gi
)
1468 unsigned char *srcLine
= bitmap
, *src
, bits
;
1469 int width
= gi
->width
;
1470 int stride
= ((width
+ 3) & ~3);
1471 int height
= gi
->height
;
1496 } while (bits
>= 0x80);
1497 XFillRectangle (gdi_display
, physDev
->drawable
,
1498 physDev
->gc
, xspan
, y
, lenspan
, 1);
1511 } while (bits
< 0x80);
1519 static void ExamineBitfield (DWORD mask
, int *shift
, int *len
)
1524 while ((mask
& 1) == 0)
1530 while ((mask
& 1) == 1)
1539 static DWORD
GetField (DWORD pixel
, int shift
, int len
)
1541 pixel
= pixel
& (((1 << (len
)) - 1) << shift
);
1542 pixel
= pixel
<< (32 - (shift
+ len
)) >> 24;
1545 pixel
|= (pixel
>> len
);
1552 static DWORD
PutField (DWORD pixel
, int shift
, int len
)
1554 shift
= shift
- (8 - len
);
1556 pixel
&= (((1 << len
) - 1) << (8 - len
));
1564 static void SmoothGlyphGray(XImage
*image
, int x
, int y
, void *bitmap
, XGlyphInfo
*gi
,
1570 BYTE
*maskLine
, *mask
, m
;
1575 BYTE src_r
, src_g
, src_b
;
1580 height
= gi
->height
;
1583 maskStride
= (width
+ 3) & ~3;
1585 ExamineBitfield (image
->red_mask
, &r_shift
, &r_len
);
1586 ExamineBitfield (image
->green_mask
, &g_shift
, &g_len
);
1587 ExamineBitfield (image
->blue_mask
, &b_shift
, &b_len
);
1589 src_r
= GetField(color
, r_shift
, r_len
);
1590 src_g
= GetField(color
, g_shift
, g_len
);
1591 src_b
= GetField(color
, b_shift
, b_len
);
1593 for(; height
--; y
++)
1596 maskLine
+= maskStride
;
1601 if(y
>= image
->height
) break;
1605 if(tx
>= image
->width
) break;
1608 if(tx
< 0) continue;
1611 XPutPixel (image
, tx
, y
, color
);
1616 pixel
= XGetPixel (image
, tx
, y
);
1618 r
= GetField(pixel
, r_shift
, r_len
);
1619 r
= ((BYTE
)~m
* (WORD
)r
+ (BYTE
)m
* (WORD
)src_r
) >> 8;
1620 g
= GetField(pixel
, g_shift
, g_len
);
1621 g
= ((BYTE
)~m
* (WORD
)g
+ (BYTE
)m
* (WORD
)src_g
) >> 8;
1622 b
= GetField(pixel
, b_shift
, b_len
);
1623 b
= ((BYTE
)~m
* (WORD
)b
+ (BYTE
)m
* (WORD
)src_b
) >> 8;
1625 pixel
= (PutField (r
, r_shift
, r_len
) |
1626 PutField (g
, g_shift
, g_len
) |
1627 PutField (b
, b_shift
, b_len
));
1628 XPutPixel (image
, tx
, y
, pixel
);
1634 /*************************************************************
1637 * Returns an appropriate Picture for tiling the text colour.
1638 * Call and use result within the xrender_cs
1640 static Picture
get_tile_pict(const WineXRenderFormat
*wxr_format
, int text_pixel
)
1647 } tiles
[WXR_NB_FORMATS
], *tile
;
1650 tile
= &tiles
[wxr_format
->format
];
1654 XRenderPictureAttributes pa
;
1657 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, wxr_format
->pict_format
->depth
);
1659 pa
.repeat
= RepeatNormal
;
1660 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, wxr_format
->pict_format
, CPRepeat
, &pa
);
1661 wine_tsx11_unlock();
1663 /* init current_color to something different from text_pixel */
1664 tile
->current_color
= ~text_pixel
;
1666 if(wxr_format
->format
== WXR_FORMAT_MONO
)
1668 /* for a 1bpp bitmap we always need a 1 in the tile */
1669 col
.red
= col
.green
= col
.blue
= 0;
1672 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1673 wine_tsx11_unlock();
1677 if(text_pixel
!= tile
->current_color
&& wxr_format
->format
!= WXR_FORMAT_MONO
)
1679 get_xrender_color(wxr_format
, text_pixel
, &col
);
1681 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1682 wine_tsx11_unlock();
1683 tile
->current_color
= text_pixel
;
1688 /*************************************************************
1691 * Returns an appropriate Picture for masking with the specified alpha.
1692 * Call and use result within the xrender_cs
1694 static Picture
get_mask_pict( int alpha
)
1696 static Pixmap pixmap
;
1697 static Picture pict
;
1698 static int current_alpha
;
1700 if (alpha
== 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1704 const WineXRenderFormat
*fmt
= get_xrender_format( WXR_FORMAT_A8R8G8B8
);
1705 XRenderPictureAttributes pa
;
1708 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
1709 pa
.repeat
= RepeatNormal
;
1710 pict
= pXRenderCreatePicture( gdi_display
, pixmap
, fmt
->pict_format
, CPRepeat
, &pa
);
1711 wine_tsx11_unlock();
1715 if (alpha
!= current_alpha
)
1718 col
.red
= col
.green
= col
.blue
= 0;
1719 col
.alpha
= current_alpha
= alpha
;
1721 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
1722 wine_tsx11_unlock();
1727 static int XRenderErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
1732 /***********************************************************************
1733 * X11DRV_XRender_ExtTextOut
1735 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1736 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1740 gsCacheEntry
*entry
;
1741 gsCacheEntryFormat
*formatEntry
;
1743 int textPixel
, backgroundPixel
;
1744 HRGN saved_region
= 0;
1745 BOOL disable_antialias
= FALSE
;
1746 AA_Type aa_type
= AA_None
;
1749 const WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
1750 Picture tile_pict
= 0;
1752 /* Do we need to disable antialiasing because of palette mode? */
1753 if( !physDev
->bitmap
|| GetObjectW( physDev
->bitmap
->hbitmap
, sizeof(bmp
), &bmp
) != sizeof(bmp
) ) {
1754 TRACE("bitmap is not a DIB\n");
1756 else if (bmp
.dsBmih
.biBitCount
<= 8) {
1757 TRACE("Disabling antialiasing\n");
1758 disable_antialias
= TRUE
;
1761 xgcval
.function
= GXcopy
;
1762 xgcval
.background
= physDev
->backgroundPixel
;
1763 xgcval
.fill_style
= FillSolid
;
1765 XChangeGC( gdi_display
, physDev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1766 wine_tsx11_unlock();
1768 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
);
1770 if(physDev
->depth
== 1) {
1771 if((physDev
->textPixel
& 0xffffff) == 0) {
1773 backgroundPixel
= 1;
1776 backgroundPixel
= 0;
1779 textPixel
= physDev
->textPixel
;
1780 backgroundPixel
= physDev
->backgroundPixel
;
1783 if(flags
& ETO_OPAQUE
)
1786 XSetForeground( gdi_display
, physDev
->gc
, backgroundPixel
);
1787 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1788 physDev
->dc_rect
.left
+ lprect
->left
, physDev
->dc_rect
.top
+ lprect
->top
,
1789 lprect
->right
- lprect
->left
, lprect
->bottom
- lprect
->top
);
1790 wine_tsx11_unlock();
1799 if (flags
& ETO_CLIPPED
)
1803 clip_region
= CreateRectRgnIndirect( lprect
);
1804 /* make a copy of the current device region */
1805 saved_region
= CreateRectRgn( 0, 0, 0, 0 );
1806 CombineRgn( saved_region
, physDev
->region
, 0, RGN_COPY
);
1807 X11DRV_SetDeviceClipping( physDev
, saved_region
, clip_region
);
1808 DeleteObject( clip_region
);
1811 EnterCriticalSection(&xrender_cs
);
1813 entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1814 if( disable_antialias
== FALSE
)
1815 aa_type
= entry
->aa_default
;
1816 formatEntry
= entry
->format
[aa_type
];
1818 for(idx
= 0; idx
< count
; idx
++) {
1819 if( !formatEntry
) {
1820 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1821 /* re-evaluate antialias since aa_default may have changed */
1822 if( disable_antialias
== FALSE
)
1823 aa_type
= entry
->aa_default
;
1824 formatEntry
= entry
->format
[aa_type
];
1825 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1826 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1831 WARN("could not upload requested glyphs\n");
1832 LeaveCriticalSection(&xrender_cs
);
1836 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1837 physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1839 if(X11DRV_XRender_Installed
)
1841 XGlyphElt16
*elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1842 POINT offset
= {0, 0};
1843 POINT desired
, current
;
1844 int render_op
= PictOpOver
;
1845 Picture pict
= get_xrender_picture(physDev
);
1847 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1848 So we pass zeros to the function and move to our starting position using the first
1849 element of the elts array. */
1851 desired
.x
= physDev
->dc_rect
.left
+ x
;
1852 desired
.y
= physDev
->dc_rect
.top
+ y
;
1853 current
.x
= current
.y
= 0;
1855 tile_pict
= get_tile_pict(dst_format
, physDev
->textPixel
);
1857 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1859 if((dst_format
->format
== WXR_FORMAT_MONO
) && (textPixel
== 0))
1860 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1862 for(idx
= 0; idx
< count
; idx
++)
1864 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1865 elts
[idx
].chars
= wstr
+ idx
;
1866 elts
[idx
].nchars
= 1;
1867 elts
[idx
].xOff
= desired
.x
- current
.x
;
1868 elts
[idx
].yOff
= desired
.y
- current
.y
;
1870 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1871 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1875 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1876 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1882 offset
.x
+= lpDx
[idx
* 2];
1883 offset
.y
+= lpDx
[idx
* 2 + 1];
1886 offset
.x
+= lpDx
[idx
];
1887 desired
.x
= physDev
->dc_rect
.left
+ x
+ offset
.x
;
1888 desired
.y
= physDev
->dc_rect
.top
+ y
+ offset
.y
;
1892 /* Make sure we don't have any transforms set from a previous call */
1893 set_xrender_transformation(pict
, 1, 1, 0, 0);
1894 pXRenderCompositeText16(gdi_display
, render_op
,
1897 formatEntry
->font_format
->pict_format
,
1898 0, 0, 0, 0, elts
, count
);
1899 wine_tsx11_unlock();
1900 HeapFree(GetProcessHeap(), 0, elts
);
1902 POINT offset
= {0, 0};
1904 XSetForeground( gdi_display
, physDev
->gc
, textPixel
);
1906 if(aa_type
== AA_None
|| physDev
->depth
== 1)
1908 void (* sharp_glyph_fn
)(X11DRV_PDEVICE
*, INT
, INT
, void *, XGlyphInfo
*);
1910 if(aa_type
== AA_None
)
1911 sharp_glyph_fn
= SharpGlyphMono
;
1913 sharp_glyph_fn
= SharpGlyphGray
;
1915 for(idx
= 0; idx
< count
; idx
++) {
1916 sharp_glyph_fn(physDev
,
1917 physDev
->dc_rect
.left
+ x
+ offset
.x
,
1918 physDev
->dc_rect
.top
+ y
+ offset
.y
,
1919 formatEntry
->bitmaps
[wstr
[idx
]],
1920 &formatEntry
->gis
[wstr
[idx
]]);
1925 offset
.x
+= lpDx
[idx
* 2];
1926 offset
.y
+= lpDx
[idx
* 2 + 1];
1929 offset
.x
+= lpDx
[idx
];
1933 offset
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1934 offset
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1939 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
1940 RECT extents
= {0, 0, 0, 0};
1942 int w
= physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
;
1943 int h
= physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
;
1945 TRACE("drawable %dx%d\n", w
, h
);
1947 for(idx
= 0; idx
< count
; idx
++) {
1948 if(extents
.left
> cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
)
1949 extents
.left
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
;
1950 if(extents
.top
> cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
)
1951 extents
.top
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
;
1952 if(extents
.right
< cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
)
1953 extents
.right
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
;
1954 if(extents
.bottom
< cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
)
1955 extents
.bottom
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
;
1961 cur
.x
+= lpDx
[idx
* 2];
1962 cur
.y
+= lpDx
[idx
* 2 + 1];
1969 cur
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1970 cur
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1973 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents
.left
, extents
.top
,
1974 extents
.right
, extents
.bottom
, physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1976 if(physDev
->dc_rect
.left
+ x
+ extents
.left
>= 0) {
1977 image_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1981 image_off_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1983 if(physDev
->dc_rect
.top
+ y
+ extents
.top
>= 0) {
1984 image_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1988 image_off_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1990 if(physDev
->dc_rect
.left
+ x
+ extents
.right
< w
)
1991 image_w
= physDev
->dc_rect
.left
+ x
+ extents
.right
- image_x
;
1993 image_w
= w
- image_x
;
1994 if(physDev
->dc_rect
.top
+ y
+ extents
.bottom
< h
)
1995 image_h
= physDev
->dc_rect
.top
+ y
+ extents
.bottom
- image_y
;
1997 image_h
= h
- image_y
;
1999 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
2001 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
2002 image
= XGetImage(gdi_display
, physDev
->drawable
,
2003 image_x
, image_y
, image_w
, image_h
,
2004 AllPlanes
, ZPixmap
);
2005 X11DRV_check_error();
2007 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2008 gdi_display
, (int)physDev
->drawable
, image_x
, image_y
,
2009 image_w
, image_h
, AllPlanes
, ZPixmap
,
2010 physDev
->depth
, image
);
2012 Pixmap xpm
= XCreatePixmap(gdi_display
, root_window
, image_w
, image_h
,
2017 gcv
.graphics_exposures
= False
;
2018 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
2019 XCopyArea(gdi_display
, physDev
->drawable
, xpm
, gc
, image_x
, image_y
,
2020 image_w
, image_h
, 0, 0);
2021 XFreeGC(gdi_display
, gc
);
2022 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
2023 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
2025 X11DRV_check_error();
2026 XFreePixmap(gdi_display
, xpm
);
2028 if(!image
) goto no_image
;
2030 image
->red_mask
= visual
->red_mask
;
2031 image
->green_mask
= visual
->green_mask
;
2032 image
->blue_mask
= visual
->blue_mask
;
2034 for(idx
= 0; idx
< count
; idx
++) {
2035 SmoothGlyphGray(image
,
2036 offset
.x
+ image_off_x
- extents
.left
,
2037 offset
.y
+ image_off_y
- extents
.top
,
2038 formatEntry
->bitmaps
[wstr
[idx
]],
2039 &formatEntry
->gis
[wstr
[idx
]],
2040 physDev
->textPixel
);
2045 offset
.x
+= lpDx
[idx
* 2];
2046 offset
.y
+= lpDx
[idx
* 2 + 1];
2049 offset
.x
+= lpDx
[idx
];
2053 offset
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
2054 offset
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
2057 XPutImage(gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
2058 image_x
, image_y
, image_w
, image_h
);
2059 XDestroyImage(image
);
2062 wine_tsx11_unlock();
2064 LeaveCriticalSection(&xrender_cs
);
2066 if (flags
& ETO_CLIPPED
)
2068 /* restore the device region */
2069 X11DRV_SetDeviceClipping( physDev
, saved_region
, 0 );
2070 DeleteObject( saved_region
);
2076 X11DRV_UnlockDIBSection( physDev
, TRUE
);
2080 /* Helper function for (stretched) blitting using xrender */
2081 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
2082 int x_src
, int y_src
, int x_dst
, int y_dst
,
2083 double xscale
, double yscale
, int width
, int height
)
2085 int x_offset
, y_offset
;
2087 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2088 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2089 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2090 if(xscale
!= 1.0 || yscale
!= 1.0)
2092 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2093 * in the wrong quadrant of the x-y plane.
2095 x_offset
= (xscale
< 0) ? -width
: 0;
2096 y_offset
= (yscale
< 0) ? -height
: 0;
2097 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
2103 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
2105 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
2106 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width
, height
);
2109 /* Helper function for (stretched) mono->color blitting using xrender */
2110 static void xrender_mono_blit( Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
2111 int x_src
, int y_src
, double xscale
, double yscale
, int width
, int height
)
2113 int x_offset
, y_offset
;
2115 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2116 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
2117 * tile data. We need PictOpOver for correct rendering.
2118 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2121 if (xscale
!= 1.0 || yscale
!= 1.0)
2123 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2124 * in the wrong quadrant of the x-y plane.
2126 x_offset
= (xscale
< 0) ? -width
: 0;
2127 y_offset
= (yscale
< 0) ? -height
: 0;
2128 set_xrender_transformation(mask_pict
, xscale
, yscale
, x_src
, y_src
);
2134 set_xrender_transformation(mask_pict
, 1, 1, 0, 0);
2136 pXRenderComposite(gdi_display
, PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2137 0, 0, x_offset
, y_offset
, 0, 0, width
, height
);
2140 /******************************************************************************
2143 BOOL
XRender_AlphaBlend( X11DRV_PDEVICE
*devDst
, X11DRV_PDEVICE
*devSrc
,
2144 struct bitblt_coords
*dst
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
2146 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
2147 struct xrender_info
*src_info
= get_xrender_info( devSrc
);
2148 double xscale
, yscale
;
2151 if(!X11DRV_XRender_Installed
) {
2152 FIXME("Unable to AlphaBlend without Xrender\n");
2156 if (devSrc
!= devDst
) X11DRV_LockDIBSection( devSrc
, DIB_Status_GdiMod
);
2157 X11DRV_LockDIBSection( devDst
, DIB_Status_GdiMod
);
2159 dst_pict
= get_xrender_picture( devDst
);
2161 use_repeat
= use_source_repeat( devSrc
);
2164 xscale
= src
->width
/ (double)dst
->width
;
2165 yscale
= src
->height
/ (double)dst
->height
;
2167 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2169 if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && src_info
->format
)
2171 /* we need a source picture with no alpha */
2172 WXRFormat format
= get_format_without_alpha( src_info
->format
->format
);
2173 if (format
!= src_info
->format
->format
)
2175 XRenderPictureAttributes pa
;
2176 const WineXRenderFormat
*fmt
= get_xrender_format( format
);
2179 pa
.subwindow_mode
= IncludeInferiors
;
2180 pa
.repeat
= use_repeat
? RepeatNormal
: RepeatNone
;
2181 tmp_pict
= pXRenderCreatePicture( gdi_display
, devSrc
->drawable
, fmt
->pict_format
,
2182 CPSubwindowMode
|CPRepeat
, &pa
);
2183 wine_tsx11_unlock();
2184 src_pict
= tmp_pict
;
2188 if (!src_pict
) src_pict
= get_xrender_picture_source( devSrc
, use_repeat
);
2190 EnterCriticalSection( &xrender_cs
);
2191 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
2194 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2195 devSrc
->dc_rect
.left
+ src
->visrect
.left
, devSrc
->dc_rect
.top
+ src
->visrect
.top
,
2196 devDst
->dc_rect
.left
+ dst
->visrect
.left
, devDst
->dc_rect
.top
+ dst
->visrect
.top
,
2198 dst
->visrect
.right
- dst
->visrect
.left
, dst
->visrect
.bottom
- dst
->visrect
.top
);
2199 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
2200 wine_tsx11_unlock();
2202 LeaveCriticalSection( &xrender_cs
);
2203 if (devSrc
!= devDst
) X11DRV_UnlockDIBSection( devSrc
, FALSE
);
2204 X11DRV_UnlockDIBSection( devDst
, TRUE
);
2209 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
2211 /* 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 */
2212 int depth
= physBitmap
->pixmap_depth
== 1 ? 1 : physDev
->depth
;
2213 const WineXRenderFormat
*src_format
= get_xrender_format_from_color_shifts(physBitmap
->pixmap_depth
, &physBitmap
->pixmap_color_shifts
);
2214 const WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
2217 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, depth
);
2219 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2220 if( (physBitmap
->pixmap_depth
== 1) || (!X11DRV_XRender_Installed
&& physDev
->depth
== physBitmap
->pixmap_depth
) ||
2221 (src_format
->format
== dst_format
->format
) )
2223 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
2224 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
2226 else /* We need depth conversion */
2228 Picture src_pict
, dst_pict
;
2229 XRenderPictureAttributes pa
;
2230 pa
.subwindow_mode
= IncludeInferiors
;
2231 pa
.repeat
= RepeatNone
;
2233 src_pict
= pXRenderCreatePicture(gdi_display
, physBitmap
->pixmap
, src_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2234 dst_pict
= pXRenderCreatePicture(gdi_display
, physDev
->brush
.pixmap
, dst_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2236 xrender_blit(PictOpSrc
, src_pict
, 0, dst_pict
, 0, 0, 0, 0, 1.0, 1.0, width
, height
);
2237 pXRenderFreePicture(gdi_display
, src_pict
);
2238 pXRenderFreePicture(gdi_display
, dst_pict
);
2240 wine_tsx11_unlock();
2243 BOOL
X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
2244 Pixmap pixmap
, GC gc
,
2245 const struct bitblt_coords
*src
, const struct bitblt_coords
*dst
)
2247 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
2248 int width
= dst
->visrect
.right
- dst
->visrect
.left
;
2249 int height
= dst
->visrect
.bottom
- dst
->visrect
.top
;
2250 int x_src
= physDevSrc
->dc_rect
.left
+ src
->visrect
.left
;
2251 int y_src
= physDevSrc
->dc_rect
.top
+ src
->visrect
.top
;
2252 struct xrender_info
*src_info
= get_xrender_info(physDevSrc
);
2253 const WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDevDst
->depth
, physDevDst
->color_shifts
);
2254 Picture src_pict
=0, dst_pict
=0, mask_pict
=0;
2256 double xscale
, yscale
;
2258 XRenderPictureAttributes pa
;
2259 pa
.subwindow_mode
= IncludeInferiors
;
2260 pa
.repeat
= RepeatNone
;
2262 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2263 physDevSrc
->depth
, src
->width
, src
->height
, x_src
, y_src
);
2264 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst
->depth
, dst
->width
, dst
->height
);
2266 if(!X11DRV_XRender_Installed
)
2268 TRACE("Not using XRender since it is not available or disabled\n");
2272 /* XRender can't handle palettes, so abort */
2273 if(X11DRV_PALETTE_XPixelToPalette
)
2276 /* XRender is of no use in this case */
2277 if((physDevDst
->depth
== 1) && (physDevSrc
->depth
> 1))
2280 /* Just use traditional X copy when the formats match and we don't need stretching */
2281 if((src_info
->format
->format
== dst_format
->format
) && !stretch
)
2283 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2285 XCopyArea( gdi_display
, physDevSrc
->drawable
, pixmap
, gc
, x_src
, y_src
, width
, height
, 0, 0);
2286 wine_tsx11_unlock();
2290 use_repeat
= use_source_repeat( physDevSrc
);
2293 xscale
= src
->width
/ (double)dst
->width
;
2294 yscale
= src
->height
/ (double)dst
->height
;
2296 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2299 if(physDevSrc
->depth
== 1 && physDevDst
->depth
> 1)
2302 get_xrender_color(dst_format
, physDevDst
->textPixel
, &col
);
2304 /* We use the source drawable as a mask */
2305 mask_pict
= get_xrender_picture_source( physDevSrc
, use_repeat
);
2307 /* Use backgroundPixel as the foreground color */
2308 EnterCriticalSection( &xrender_cs
);
2309 src_pict
= get_tile_pict(dst_format
, physDevDst
->backgroundPixel
);
2311 /* Create a destination picture and fill it with textPixel color as the background color */
2313 dst_pict
= pXRenderCreatePicture(gdi_display
, pixmap
, dst_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2314 pXRenderFillRectangle(gdi_display
, PictOpSrc
, dst_pict
, &col
, 0, 0, width
, height
);
2316 xrender_mono_blit(src_pict
, mask_pict
, dst_pict
, x_src
, y_src
, xscale
, yscale
, width
, height
);
2318 if(dst_pict
) pXRenderFreePicture(gdi_display
, dst_pict
);
2319 wine_tsx11_unlock();
2320 LeaveCriticalSection( &xrender_cs
);
2322 else /* color -> color (can be at different depths) or mono -> mono */
2324 if (physDevDst
->depth
== 32 && physDevSrc
->depth
< 32) mask_pict
= get_no_alpha_mask();
2325 src_pict
= get_xrender_picture_source( physDevSrc
, use_repeat
);
2328 dst_pict
= pXRenderCreatePicture(gdi_display
,
2329 pixmap
, dst_format
->pict_format
,
2330 CPSubwindowMode
|CPRepeat
, &pa
);
2332 xrender_blit(PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
2333 x_src
, y_src
, 0, 0, xscale
, yscale
, width
, height
);
2335 if(dst_pict
) pXRenderFreePicture(gdi_display
, dst_pict
);
2336 wine_tsx11_unlock();
2341 #else /* SONAME_LIBXRENDER */
2343 void X11DRV_XRender_Init(void)
2345 TRACE("XRender support not compiled in.\n");
2349 void X11DRV_XRender_Finalize(void)
2353 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
2359 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
2365 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE
*physDev
, const RGNDATA
*data
)
2371 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
2372 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
2379 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
2385 BOOL
XRender_AlphaBlend( X11DRV_PDEVICE
*devDst
, X11DRV_PDEVICE
*devSrc
,
2386 struct bitblt_coords
*dst
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
2388 FIXME("not supported - XRENDER headers were missing at compile time\n");
2392 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
2395 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, physBitmap
->pixmap_depth
);
2397 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
2398 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
2399 wine_tsx11_unlock();
2402 BOOL
X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP
*physBitmap
, int bits_pixel
, const DIBSECTION
*dib
)
2407 BOOL
X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
2408 Pixmap pixmap
, GC gc
,
2409 const struct bitblt_coords
*src
, const struct bitblt_coords
*dst
)
2413 #endif /* SONAME_LIBXRENDER */