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(FcPatternGetBool
)
197 MAKE_FUNCPTR(FcPatternGetInteger
)
198 MAKE_FUNCPTR(FcPatternGetString
)
199 static void *fontconfig_handle
;
200 static BOOL fontconfig_installed
;
205 static CRITICAL_SECTION xrender_cs
;
206 static CRITICAL_SECTION_DEBUG critsect_debug
=
209 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
210 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
212 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
214 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
215 ( ( (ULONG)_x4 << 24 ) | \
216 ( (ULONG)_x3 << 16 ) | \
217 ( (ULONG)_x2 << 8 ) | \
220 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
222 #define GASP_GRIDFIT 0x01
223 #define GASP_DOGRAY 0x02
225 #ifdef WORDS_BIGENDIAN
226 #define get_be_word(x) (x)
227 #define NATIVE_BYTE_ORDER MSBFirst
229 #define get_be_word(x) RtlUshortByteSwap(x)
230 #define NATIVE_BYTE_ORDER LSBFirst
233 static WXRFormat
get_format_without_alpha( WXRFormat format
)
237 case WXR_FORMAT_A8R8G8B8
: return WXR_FORMAT_X8R8G8B8
;
238 case WXR_FORMAT_B8G8R8A8
: return WXR_FORMAT_B8G8R8X8
;
239 default: return format
;
243 static BOOL
get_xrender_template(const WineXRenderFormatTemplate
*fmt
, XRenderPictFormat
*templ
, unsigned long *mask
)
246 templ
->type
= PictTypeDirect
;
247 templ
->depth
= fmt
->depth
;
248 templ
->direct
.alpha
= fmt
->alpha
;
249 templ
->direct
.alphaMask
= fmt
->alphaMask
;
250 templ
->direct
.red
= fmt
->red
;
251 templ
->direct
.redMask
= fmt
->redMask
;
252 templ
->direct
.green
= fmt
->green
;
253 templ
->direct
.greenMask
= fmt
->greenMask
;
254 templ
->direct
.blue
= fmt
->blue
;
255 templ
->direct
.blueMask
= fmt
->blueMask
;
258 *mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
| PictFormatRed
| PictFormatRedMask
| PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
| PictFormatBlueMask
;
263 static BOOL
is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate
*fmt
)
265 if(fmt
->depth
!= screen_depth
)
267 if( (fmt
->redMask
<< fmt
->red
) != visual
->red_mask
)
269 if( (fmt
->greenMask
<< fmt
->green
) != visual
->green_mask
)
271 if( (fmt
->blueMask
<< fmt
->blue
) != visual
->blue_mask
)
274 /* We never select a default ARGB visual */
281 static int load_xrender_formats(void)
284 for(i
= 0; i
< (sizeof(wxr_formats_template
) / sizeof(wxr_formats_template
[0])); i
++)
286 XRenderPictFormat templ
, *pict_format
;
288 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template
[i
]))
291 pict_format
= pXRenderFindVisualFormat(gdi_display
, visual
);
294 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
295 if (visual
->class == DirectColor
)
298 if (XMatchVisualInfo( gdi_display
, DefaultScreen(gdi_display
),
299 screen_depth
, TrueColor
, &info
))
301 pict_format
= pXRenderFindVisualFormat(gdi_display
, info
.visual
);
302 if (pict_format
) visual
= info
.visual
;
310 wxr_formats
[WineXRenderFormatsListSize
].format
= wxr_formats_template
[i
].wxr_format
;
311 wxr_formats
[WineXRenderFormatsListSize
].pict_format
= pict_format
;
312 default_format
= &wxr_formats
[WineXRenderFormatsListSize
];
313 WineXRenderFormatsListSize
++;
314 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format
->id
, wxr_formats_template
[i
].wxr_format
);
319 unsigned long mask
= 0;
320 get_xrender_template(&wxr_formats_template
[i
], &templ
, &mask
);
323 pict_format
= pXRenderFindFormat(gdi_display
, mask
, &templ
, 0);
328 wxr_formats
[WineXRenderFormatsListSize
].format
= wxr_formats_template
[i
].wxr_format
;
329 wxr_formats
[WineXRenderFormatsListSize
].pict_format
= pict_format
;
330 WineXRenderFormatsListSize
++;
331 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format
->id
, wxr_formats_template
[i
].wxr_format
);
335 return WineXRenderFormatsListSize
;
338 /***********************************************************************
339 * X11DRV_XRender_Init
341 * Let's see if our XServer has the extension available
344 void X11DRV_XRender_Init(void)
348 if (client_side_with_render
&&
349 (xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0)))
352 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
353 LOAD_FUNCPTR(XRenderAddGlyphs
)
354 LOAD_FUNCPTR(XRenderComposite
)
355 LOAD_FUNCPTR(XRenderCompositeString8
)
356 LOAD_FUNCPTR(XRenderCompositeString16
)
357 LOAD_FUNCPTR(XRenderCompositeString32
)
358 LOAD_FUNCPTR(XRenderCompositeText16
)
359 LOAD_FUNCPTR(XRenderCreateGlyphSet
)
360 LOAD_FUNCPTR(XRenderCreatePicture
)
361 LOAD_FUNCPTR(XRenderFillRectangle
)
362 LOAD_FUNCPTR(XRenderFindFormat
)
363 LOAD_FUNCPTR(XRenderFindVisualFormat
)
364 LOAD_FUNCPTR(XRenderFreeGlyphSet
)
365 LOAD_FUNCPTR(XRenderFreePicture
)
366 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
)
367 LOAD_FUNCPTR(XRenderQueryExtension
)
369 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
370 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
371 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
)
372 #undef LOAD_OPTIONAL_FUNCPTR
376 X11DRV_XRender_Installed
= pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
);
378 if(X11DRV_XRender_Installed
) {
379 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
380 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
384 "Wine has detected that you probably have a buggy version\n"
385 "of libXrender.so . Because of this client side font rendering\n"
386 "will be disabled. Please upgrade this library.\n");
387 X11DRV_XRender_Installed
= FALSE
;
391 if (!visual
->red_mask
|| !visual
->green_mask
|| !visual
->blue_mask
) {
392 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
393 X11DRV_XRender_Installed
= FALSE
;
398 #ifdef SONAME_LIBFONTCONFIG
399 if ((fontconfig_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0)))
401 #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;}
402 LOAD_FUNCPTR(FcConfigSubstitute
);
403 LOAD_FUNCPTR(FcDefaultSubstitute
);
404 LOAD_FUNCPTR(FcFontMatch
);
405 LOAD_FUNCPTR(FcInit
);
406 LOAD_FUNCPTR(FcPatternCreate
);
407 LOAD_FUNCPTR(FcPatternDestroy
);
408 LOAD_FUNCPTR(FcPatternAddInteger
);
409 LOAD_FUNCPTR(FcPatternAddString
);
410 LOAD_FUNCPTR(FcPatternGetBool
);
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
->dev
.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
->dev
.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) break; /* reached free list so stop */
665 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
666 glyphsetCache
[i
].count
++;
668 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
669 glyphsetCache
[i
].next
= mru
;
672 TRACE("found font in cache %d\n", i
);
677 TRACE("font not in cache\n");
681 static void FreeEntry(int entry
)
685 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
686 gsCacheEntryFormat
* formatEntry
;
688 if( !glyphsetCache
[entry
].format
[format
] )
691 formatEntry
= glyphsetCache
[entry
].format
[format
];
693 if(formatEntry
->glyphset
) {
695 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
697 formatEntry
->glyphset
= 0;
699 if(formatEntry
->nrealized
) {
700 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
701 formatEntry
->realized
= NULL
;
702 if(formatEntry
->bitmaps
) {
703 for(i
= 0; i
< formatEntry
->nrealized
; i
++)
704 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
[i
]);
705 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
);
706 formatEntry
->bitmaps
= NULL
;
708 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
709 formatEntry
->gis
= NULL
;
710 formatEntry
->nrealized
= 0;
713 HeapFree(GetProcessHeap(), 0, formatEntry
);
714 glyphsetCache
[entry
].format
[format
] = NULL
;
718 static int AllocEntry(void)
720 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
723 assert(glyphsetCache
[lastfree
].count
== -1);
724 glyphsetCache
[lastfree
].count
= 1;
726 lastfree
= glyphsetCache
[lastfree
].next
;
728 glyphsetCache
[best
].next
= mru
;
731 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
735 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
736 if(glyphsetCache
[i
].count
== 0) {
744 TRACE("freeing unused glyphset at cache %d\n", best
);
746 glyphsetCache
[best
].count
= 1;
748 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
749 glyphsetCache
[best
].next
= mru
;
757 TRACE("Growing cache\n");
760 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
762 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
763 * sizeof(*glyphsetCache
));
765 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
766 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
767 * sizeof(*glyphsetCache
));
769 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
771 glyphsetCache
[i
].next
= i
+ 1;
772 glyphsetCache
[i
].count
= -1;
774 glyphsetCache
[i
-1].next
= -1;
775 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
777 lastfree
= glyphsetCache
[best
].next
;
778 glyphsetCache
[best
].count
= 1;
779 glyphsetCache
[best
].next
= mru
;
781 TRACE("new free cache slot at %d\n", mru
);
785 static BOOL
get_gasp_flags(X11DRV_PDEVICE
*physDev
, WORD
*flags
)
795 size
= GetFontData(physDev
->dev
.hdc
, MS_GASP_TAG
, 0, NULL
, 0);
796 if(size
== GDI_ERROR
)
799 gasp
= buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
800 GetFontData(physDev
->dev
.hdc
, MS_GASP_TAG
, 0, gasp
, size
);
802 GetTextMetricsW(physDev
->dev
.hdc
, &tm
);
803 ppem
= abs(X11DRV_YWStoDS(physDev
, tm
.tmAscent
+ tm
.tmDescent
- tm
.tmInternalLeading
));
806 num_recs
= get_be_word(*gasp
);
810 *flags
= get_be_word(*(gasp
+ 1));
811 if(ppem
<= get_be_word(*gasp
))
815 TRACE("got flags %04x for ppem %d\n", *flags
, ppem
);
817 HeapFree(GetProcessHeap(), 0, buffer
);
821 static AA_Type
get_antialias_type( X11DRV_PDEVICE
*physDev
, BOOL subpixel
, BOOL hinter
)
825 UINT font_smoothing_type
, font_smoothing_orientation
;
827 if (X11DRV_XRender_Installed
&& subpixel
&&
828 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE
, 0, &font_smoothing_type
, 0) &&
829 font_smoothing_type
== FE_FONTSMOOTHINGCLEARTYPE
)
831 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION
, 0,
832 &font_smoothing_orientation
, 0) &&
833 font_smoothing_orientation
== FE_FONTSMOOTHINGORIENTATIONBGR
)
840 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
841 But, Wine's subpixel rendering can support the portrait mode.
844 else if (!hinter
|| !get_gasp_flags(physDev
, &flags
) || flags
& GASP_DOGRAY
)
852 static int GetCacheEntry(X11DRV_PDEVICE
*physDev
, LFANDSIZE
*plfsz
)
857 static int hinter
= -1;
858 static int subpixel
= -1;
861 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
864 entry
= glyphsetCache
+ ret
;
865 entry
->lfsz
= *plfsz
;
866 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
867 assert( !entry
->format
[format
] );
870 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
872 if(hinter
== -1 || subpixel
== -1)
874 RASTERIZER_STATUS status
;
875 GetRasterizerCaps(&status
, sizeof(status
));
876 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
877 subpixel
= status
.wFlags
& WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
880 switch (plfsz
->lf
.lfQuality
)
882 case ANTIALIASED_QUALITY
:
883 entry
->aa_default
= get_antialias_type( physDev
, FALSE
, hinter
);
884 return ret
; /* ignore further configuration */
885 case CLEARTYPE_QUALITY
:
886 case CLEARTYPE_NATURAL_QUALITY
:
887 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
889 case DEFAULT_QUALITY
:
893 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING
, 0, &font_smoothing
, 0) &&
896 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
899 entry
->aa_default
= AA_None
;
903 font_smoothing
= TRUE
; /* default to enabled */
904 #ifdef SONAME_LIBFONTCONFIG
905 if (fontconfig_installed
)
907 FcPattern
*match
, *pattern
= pFcPatternCreate();
909 char family
[LF_FACESIZE
* 4];
911 WideCharToMultiByte( CP_UTF8
, 0, plfsz
->lf
.lfFaceName
, -1, family
, sizeof(family
), NULL
, NULL
);
912 pFcPatternAddString( pattern
, FC_FAMILY
, (FcChar8
*)family
);
913 if (plfsz
->lf
.lfWeight
!= FW_DONTCARE
)
916 switch (plfsz
->lf
.lfWeight
)
918 case FW_THIN
: weight
= FC_WEIGHT_THIN
; break;
919 case FW_EXTRALIGHT
: weight
= FC_WEIGHT_EXTRALIGHT
; break;
920 case FW_LIGHT
: weight
= FC_WEIGHT_LIGHT
; break;
921 case FW_NORMAL
: weight
= FC_WEIGHT_NORMAL
; break;
922 case FW_MEDIUM
: weight
= FC_WEIGHT_MEDIUM
; break;
923 case FW_SEMIBOLD
: weight
= FC_WEIGHT_SEMIBOLD
; break;
924 case FW_BOLD
: weight
= FC_WEIGHT_BOLD
; break;
925 case FW_EXTRABOLD
: weight
= FC_WEIGHT_EXTRABOLD
; break;
926 case FW_HEAVY
: weight
= FC_WEIGHT_HEAVY
; break;
927 default: weight
= (plfsz
->lf
.lfWeight
- 80) / 4; break;
929 pFcPatternAddInteger( pattern
, FC_WEIGHT
, weight
);
931 pFcPatternAddInteger( pattern
, FC_SLANT
, plfsz
->lf
.lfItalic
? FC_SLANT_ITALIC
: FC_SLANT_ROMAN
);
932 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
933 pFcDefaultSubstitute( pattern
);
934 if ((match
= pFcFontMatch( NULL
, pattern
, &result
)))
939 if (pFcPatternGetBool( match
, FC_ANTIALIAS
, 0, &antialias
) != FcResultMatch
)
941 if (pFcPatternGetInteger( match
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
944 if (pFcPatternGetString( match
, FC_FILE
, 0, &file
) != FcResultMatch
) file
= NULL
;
946 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
947 rgba
, antialias
, debugstr_w(plfsz
->lf
.lfFaceName
), debugstr_a((char *)file
) );
951 case FC_RGBA_RGB
: entry
->aa_default
= AA_RGB
; break;
952 case FC_RGBA_BGR
: entry
->aa_default
= AA_BGR
; break;
953 case FC_RGBA_VRGB
: entry
->aa_default
= AA_VRGB
; break;
954 case FC_RGBA_VBGR
: entry
->aa_default
= AA_VBGR
; break;
955 case FC_RGBA_NONE
: entry
->aa_default
= AA_Grey
; break;
958 if (!antialias
) font_smoothing
= FALSE
;
959 pFcPatternDestroy( match
);
961 pFcPatternDestroy( pattern
);
963 #endif /* SONAME_LIBFONTCONFIG */
965 /* now check Xft resources */
968 BOOL antialias
= TRUE
;
971 if ((value
= XGetDefault( gdi_display
, "Xft", "antialias" )))
973 if (tolower(value
[0]) == 'f' || tolower(value
[0]) == 'n' ||
974 value
[0] == '0' || !strcasecmp( value
, "off" ))
977 if ((value
= XGetDefault( gdi_display
, "Xft", "rgba" )))
979 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value
, antialias
);
980 if (!strcmp( value
, "rgb" )) entry
->aa_default
= AA_RGB
;
981 else if (!strcmp( value
, "bgr" )) entry
->aa_default
= AA_BGR
;
982 else if (!strcmp( value
, "vrgb" )) entry
->aa_default
= AA_VRGB
;
983 else if (!strcmp( value
, "vbgr" )) entry
->aa_default
= AA_VBGR
;
984 else if (!strcmp( value
, "none" )) entry
->aa_default
= AA_Grey
;
987 if (!antialias
) font_smoothing
= FALSE
;
990 if (!font_smoothing
) entry
->aa_default
= AA_None
;
992 /* we can't support subpixel without xrender */
993 if (!X11DRV_XRender_Installed
&& entry
->aa_default
> AA_Grey
) entry
->aa_default
= AA_Grey
;
996 entry
->aa_default
= AA_None
;
1001 static void dec_ref_cache(int index
)
1004 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
1005 assert(glyphsetCache
[index
].count
> 0);
1006 glyphsetCache
[index
].count
--;
1009 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
1011 DWORD hash
= 0, *ptr
, two_chars
;
1015 hash
^= plfsz
->devsize
.cx
;
1016 hash
^= plfsz
->devsize
.cy
;
1017 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
1019 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
1021 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
1023 pwc
= (WCHAR
*)&two_chars
;
1025 *pwc
= toupperW(*pwc
);
1027 *pwc
= toupperW(*pwc
);
1035 /***********************************************************************
1036 * X11DRV_XRender_Finalize
1038 void X11DRV_XRender_Finalize(void)
1042 EnterCriticalSection(&xrender_cs
);
1043 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
1045 LeaveCriticalSection(&xrender_cs
);
1049 /***********************************************************************
1050 * X11DRV_XRender_SelectFont
1052 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
1055 struct xrender_info
*info
;
1057 GetObjectW(hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
1058 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1059 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
1060 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
1061 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
1062 lfsz
.devsize
.cx
= X11DRV_XWStoDS( physDev
, lfsz
.lf
.lfWidth
);
1063 lfsz
.devsize
.cy
= X11DRV_YWStoDS( physDev
, lfsz
.lf
.lfHeight
);
1065 GetTransform( physDev
->dev
.hdc
, 0x204, &lfsz
.xform
);
1066 TRACE("font transform %f %f %f %f\n", lfsz
.xform
.eM11
, lfsz
.xform
.eM12
,
1067 lfsz
.xform
.eM21
, lfsz
.xform
.eM22
);
1069 /* Not used fields, would break hashing */
1070 lfsz
.xform
.eDx
= lfsz
.xform
.eDy
= 0;
1072 lfsz_calc_hash(&lfsz
);
1074 info
= get_xrender_info(physDev
);
1075 if (!info
) return 0;
1077 EnterCriticalSection(&xrender_cs
);
1078 if(info
->cache_index
!= -1)
1079 dec_ref_cache(info
->cache_index
);
1080 info
->cache_index
= GetCacheEntry(physDev
, &lfsz
);
1081 LeaveCriticalSection(&xrender_cs
);
1085 /***********************************************************************
1086 * X11DRV_XRender_SetDeviceClipping
1088 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE
*physDev
, const RGNDATA
*data
)
1090 if (physDev
->xrender
->pict
)
1093 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
1094 physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
1095 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
1096 wine_tsx11_unlock();
1100 /***********************************************************************
1101 * X11DRV_XRender_DeleteDC
1103 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
1105 X11DRV_XRender_UpdateDrawable(physDev
);
1107 EnterCriticalSection(&xrender_cs
);
1108 if(physDev
->xrender
->cache_index
!= -1)
1109 dec_ref_cache(physDev
->xrender
->cache_index
);
1110 LeaveCriticalSection(&xrender_cs
);
1112 HeapFree(GetProcessHeap(), 0, physDev
->xrender
);
1113 physDev
->xrender
= NULL
;
1117 BOOL
X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP
*physBitmap
, int bits_pixel
, const DIBSECTION
*dib
)
1119 const WineXRenderFormat
*fmt
;
1122 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1123 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1124 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1125 if (!X11DRV_XRender_Installed
|| bits_pixel
<= 8)
1130 const DWORD
*bitfields
;
1131 static const DWORD bitfields_32
[3] = {0xff0000, 0x00ff00, 0x0000ff};
1132 static const DWORD bitfields_16
[3] = {0x7c00, 0x03e0, 0x001f};
1134 if(dib
->dsBmih
.biCompression
== BI_BITFIELDS
)
1135 bitfields
= dib
->dsBitfields
;
1136 else if(bits_pixel
== 24 || bits_pixel
== 32)
1137 bitfields
= bitfields_32
;
1139 bitfields
= bitfields_16
;
1141 X11DRV_PALETTE_ComputeColorShifts(&shifts
, bitfields
[0], bitfields
[1], bitfields
[2]);
1142 fmt
= get_xrender_format_from_color_shifts(dib
->dsBm
.bmBitsPixel
, &shifts
);
1144 /* Common formats should be in our picture format table. */
1147 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1148 dib
->dsBm
.bmBitsPixel
, bitfields
[0], bitfields
[1], bitfields
[2]);
1154 int red_mask
, green_mask
, blue_mask
;
1156 /* We are dealing with a DDB */
1160 fmt
= get_xrender_format(WXR_FORMAT_R5G6B5
);
1163 fmt
= get_xrender_format(WXR_FORMAT_R8G8B8
);
1166 fmt
= get_xrender_format(WXR_FORMAT_A8R8G8B8
);
1174 TRACE("Unhandled DDB bits_pixel=%d\n", bits_pixel
);
1178 red_mask
= fmt
->pict_format
->direct
.redMask
<< fmt
->pict_format
->direct
.red
;
1179 green_mask
= fmt
->pict_format
->direct
.greenMask
<< fmt
->pict_format
->direct
.green
;
1180 blue_mask
= fmt
->pict_format
->direct
.blueMask
<< fmt
->pict_format
->direct
.blue
;
1181 X11DRV_PALETTE_ComputeColorShifts(&shifts
, red_mask
, green_mask
, blue_mask
);
1184 physBitmap
->pixmap_depth
= fmt
->pict_format
->depth
;
1185 physBitmap
->trueColor
= TRUE
;
1186 physBitmap
->pixmap_color_shifts
= shifts
;
1190 /***********************************************************************
1191 * X11DRV_XRender_UpdateDrawable
1193 * Deletes the pict and tile when the drawable changes.
1195 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
1197 struct xrender_info
*info
= physDev
->xrender
;
1199 if (info
->pict
|| info
->pict_src
)
1202 XFlush( gdi_display
);
1205 TRACE("freeing pict = %lx dc = %p\n", info
->pict
, physDev
->dev
.hdc
);
1206 pXRenderFreePicture(gdi_display
, info
->pict
);
1211 TRACE("freeing pict = %lx dc = %p\n", info
->pict_src
, physDev
->dev
.hdc
);
1212 pXRenderFreePicture(gdi_display
, info
->pict_src
);
1215 wine_tsx11_unlock();
1218 info
->format
= NULL
;
1221 /************************************************************************
1224 * Helper to ExtTextOut. Must be called inside xrender_cs
1226 static void UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
, AA_Type format
)
1228 unsigned int buflen
;
1233 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1234 gsCacheEntryFormat
*formatEntry
;
1235 UINT ggo_format
= GGO_GLYPH_INDEX
;
1236 WXRFormat wxr_format
;
1237 static const char zero
[4];
1238 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
1242 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
1245 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
1248 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
1251 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
1254 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
1258 ERR("aa = %d - not implemented\n", format
);
1260 ggo_format
|= GGO_BITMAP
;
1264 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1265 if(buflen
== GDI_ERROR
) {
1266 if(format
!= AA_None
) {
1268 entry
->aa_default
= AA_None
;
1269 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
1270 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1272 if(buflen
== GDI_ERROR
) {
1273 WARN("GetGlyphOutlineW failed using default glyph\n");
1274 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0, ggo_format
, &gm
, 0, NULL
, &identity
);
1275 if(buflen
== GDI_ERROR
) {
1276 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1277 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0x20, ggo_format
, &gm
, 0, NULL
, &identity
);
1278 if(buflen
== GDI_ERROR
) {
1279 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1284 TRACE("Turning off antialiasing for this monochrome font\n");
1287 /* If there is nothing for the current type, we create the entry. */
1288 if( !entry
->format
[format
] ) {
1289 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
1291 sizeof(gsCacheEntryFormat
));
1293 formatEntry
= entry
->format
[format
];
1295 if(formatEntry
->nrealized
<= glyph
) {
1296 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
1298 if (formatEntry
->realized
)
1299 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
1301 formatEntry
->realized
,
1302 formatEntry
->nrealized
* sizeof(BOOL
));
1304 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
1306 formatEntry
->nrealized
* sizeof(BOOL
));
1308 if(!X11DRV_XRender_Installed
) {
1309 if (formatEntry
->bitmaps
)
1310 formatEntry
->bitmaps
= HeapReAlloc(GetProcessHeap(),
1312 formatEntry
->bitmaps
,
1313 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
1315 formatEntry
->bitmaps
= HeapAlloc(GetProcessHeap(),
1317 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
1319 if (formatEntry
->gis
)
1320 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
1323 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1325 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
1327 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1331 if(formatEntry
->glyphset
== 0 && X11DRV_XRender_Installed
) {
1334 wxr_format
= WXR_FORMAT_GRAY
;
1341 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1345 ERR("aa = %d - not implemented\n", format
);
1347 wxr_format
= WXR_FORMAT_MONO
;
1352 formatEntry
->font_format
= get_xrender_format(wxr_format
);
1353 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
->pict_format
);
1354 wine_tsx11_unlock();
1358 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
1359 GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
1360 formatEntry
->realized
[glyph
] = TRUE
;
1362 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1364 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1365 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1367 gi
.width
= gm
.gmBlackBoxX
;
1368 gi
.height
= gm
.gmBlackBoxY
;
1369 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1370 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1371 gi
.xOff
= gm
.gmCellIncX
;
1372 gi
.yOff
= gm
.gmCellIncY
;
1374 if(TRACE_ON(xrender
)) {
1377 unsigned char *line
;
1379 if(format
== AA_None
) {
1380 pitch
= ((gi
.width
+ 31) / 32) * 4;
1381 for(i
= 0; i
< gi
.height
; i
++) {
1382 line
= (unsigned char*) buf
+ i
* pitch
;
1384 for(j
= 0; j
< pitch
* 8; j
++) {
1385 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1387 TRACE("%s\n", output
);
1390 static const char blks
[] = " .:;!o*#";
1394 pitch
= ((gi
.width
+ 3) / 4) * 4;
1395 for(i
= 0; i
< gi
.height
; i
++) {
1396 line
= (unsigned char*) buf
+ i
* pitch
;
1398 for(j
= 0; j
< pitch
; j
++) {
1399 str
[0] = blks
[line
[j
] >> 5];
1400 strcat(output
, str
);
1402 TRACE("%s\n", output
);
1408 if(formatEntry
->glyphset
) {
1409 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1410 unsigned char *byte
= (unsigned char*) buf
, c
;
1416 /* magic to flip bit order */
1417 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1418 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1419 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1424 else if ( format
!= AA_Grey
&&
1425 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1427 unsigned int i
, *data
= (unsigned int *)buf
;
1428 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1433 XRenderCompositeText seems to ignore 0x0 glyphs when
1434 AA_None, which means we lose the advance width of glyphs
1435 like the space. We'll pretend that such glyphs are 1x1
1440 gi
.width
= gi
.height
= 1;
1443 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1444 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1445 wine_tsx11_unlock();
1446 HeapFree(GetProcessHeap(), 0, buf
);
1448 formatEntry
->bitmaps
[glyph
] = buf
;
1451 formatEntry
->gis
[glyph
] = gi
;
1454 static void SharpGlyphMono(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
1455 void *bitmap
, XGlyphInfo
*gi
)
1457 unsigned char *srcLine
= bitmap
, *src
;
1458 unsigned char bits
, bitsMask
;
1459 int width
= gi
->width
;
1460 int stride
= ((width
+ 31) & ~31) >> 3;
1461 int height
= gi
->height
;
1465 TRACE("%d, %d\n", x
, y
);
1474 bitsMask
= 0x80; /* FreeType is always MSB first */
1480 if (bits
& bitsMask
)
1488 bitsMask
= bitsMask
>> 1;
1494 } while (bits
& bitsMask
);
1495 XFillRectangle (gdi_display
, physDev
->drawable
,
1496 physDev
->gc
, xspan
, y
, lenspan
, 1);
1508 bitsMask
= bitsMask
>> 1;
1514 } while (!(bits
& bitsMask
));
1521 static void SharpGlyphGray(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
1522 void *bitmap
, XGlyphInfo
*gi
)
1524 unsigned char *srcLine
= bitmap
, *src
, bits
;
1525 int width
= gi
->width
;
1526 int stride
= ((width
+ 3) & ~3);
1527 int height
= gi
->height
;
1552 } while (bits
>= 0x80);
1553 XFillRectangle (gdi_display
, physDev
->drawable
,
1554 physDev
->gc
, xspan
, y
, lenspan
, 1);
1567 } while (bits
< 0x80);
1575 static void ExamineBitfield (DWORD mask
, int *shift
, int *len
)
1580 while ((mask
& 1) == 0)
1586 while ((mask
& 1) == 1)
1595 static DWORD
GetField (DWORD pixel
, int shift
, int len
)
1597 pixel
= pixel
& (((1 << (len
)) - 1) << shift
);
1598 pixel
= pixel
<< (32 - (shift
+ len
)) >> 24;
1601 pixel
|= (pixel
>> len
);
1608 static DWORD
PutField (DWORD pixel
, int shift
, int len
)
1610 shift
= shift
- (8 - len
);
1612 pixel
&= (((1 << len
) - 1) << (8 - len
));
1620 static void SmoothGlyphGray(XImage
*image
, int x
, int y
, void *bitmap
, XGlyphInfo
*gi
,
1626 BYTE
*maskLine
, *mask
, m
;
1631 BYTE src_r
, src_g
, src_b
;
1636 height
= gi
->height
;
1639 maskStride
= (width
+ 3) & ~3;
1641 ExamineBitfield (image
->red_mask
, &r_shift
, &r_len
);
1642 ExamineBitfield (image
->green_mask
, &g_shift
, &g_len
);
1643 ExamineBitfield (image
->blue_mask
, &b_shift
, &b_len
);
1645 src_r
= GetField(color
, r_shift
, r_len
);
1646 src_g
= GetField(color
, g_shift
, g_len
);
1647 src_b
= GetField(color
, b_shift
, b_len
);
1649 for(; height
--; y
++)
1652 maskLine
+= maskStride
;
1657 if(y
>= image
->height
) break;
1661 if(tx
>= image
->width
) break;
1664 if(tx
< 0) continue;
1667 XPutPixel (image
, tx
, y
, color
);
1672 pixel
= XGetPixel (image
, tx
, y
);
1674 r
= GetField(pixel
, r_shift
, r_len
);
1675 r
= ((BYTE
)~m
* (WORD
)r
+ (BYTE
)m
* (WORD
)src_r
) >> 8;
1676 g
= GetField(pixel
, g_shift
, g_len
);
1677 g
= ((BYTE
)~m
* (WORD
)g
+ (BYTE
)m
* (WORD
)src_g
) >> 8;
1678 b
= GetField(pixel
, b_shift
, b_len
);
1679 b
= ((BYTE
)~m
* (WORD
)b
+ (BYTE
)m
* (WORD
)src_b
) >> 8;
1681 pixel
= (PutField (r
, r_shift
, r_len
) |
1682 PutField (g
, g_shift
, g_len
) |
1683 PutField (b
, b_shift
, b_len
));
1684 XPutPixel (image
, tx
, y
, pixel
);
1690 /*************************************************************
1693 * Returns an appropriate Picture for tiling the text colour.
1694 * Call and use result within the xrender_cs
1696 static Picture
get_tile_pict(const WineXRenderFormat
*wxr_format
, int text_pixel
)
1703 } tiles
[WXR_NB_FORMATS
], *tile
;
1706 tile
= &tiles
[wxr_format
->format
];
1710 XRenderPictureAttributes pa
;
1713 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, wxr_format
->pict_format
->depth
);
1715 pa
.repeat
= RepeatNormal
;
1716 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, wxr_format
->pict_format
, CPRepeat
, &pa
);
1717 wine_tsx11_unlock();
1719 /* init current_color to something different from text_pixel */
1720 tile
->current_color
= ~text_pixel
;
1722 if(wxr_format
->format
== WXR_FORMAT_MONO
)
1724 /* for a 1bpp bitmap we always need a 1 in the tile */
1725 col
.red
= col
.green
= col
.blue
= 0;
1728 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1729 wine_tsx11_unlock();
1733 if(text_pixel
!= tile
->current_color
&& wxr_format
->format
!= WXR_FORMAT_MONO
)
1735 get_xrender_color(wxr_format
, text_pixel
, &col
);
1737 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1738 wine_tsx11_unlock();
1739 tile
->current_color
= text_pixel
;
1744 /*************************************************************
1747 * Returns an appropriate Picture for masking with the specified alpha.
1748 * Call and use result within the xrender_cs
1750 static Picture
get_mask_pict( int alpha
)
1752 static Pixmap pixmap
;
1753 static Picture pict
;
1754 static int current_alpha
;
1756 if (alpha
== 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1760 const WineXRenderFormat
*fmt
= get_xrender_format( WXR_FORMAT_A8R8G8B8
);
1761 XRenderPictureAttributes pa
;
1764 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
1765 pa
.repeat
= RepeatNormal
;
1766 pict
= pXRenderCreatePicture( gdi_display
, pixmap
, fmt
->pict_format
, CPRepeat
, &pa
);
1767 wine_tsx11_unlock();
1771 if (alpha
!= current_alpha
)
1774 col
.red
= col
.green
= col
.blue
= 0;
1775 col
.alpha
= current_alpha
= alpha
;
1777 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
1778 wine_tsx11_unlock();
1783 static int XRenderErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
1788 /********************************************************************
1789 * is_dib_with_colortable
1791 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1793 static inline BOOL
is_dib_with_colortable( X11DRV_PDEVICE
*physDev
)
1797 if( physDev
->bitmap
&& GetObjectW( physDev
->bitmap
->hbitmap
, sizeof(dib
), &dib
) == sizeof(dib
) &&
1798 dib
.dsBmih
.biBitCount
<= 8 )
1804 /***********************************************************************
1805 * X11DRV_XRender_ExtTextOut
1807 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1808 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1812 gsCacheEntry
*entry
;
1813 gsCacheEntryFormat
*formatEntry
;
1815 int textPixel
, backgroundPixel
;
1816 HRGN saved_region
= 0;
1817 BOOL disable_antialias
= FALSE
;
1818 AA_Type aa_type
= AA_None
;
1820 const WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
1821 Picture tile_pict
= 0;
1823 if(is_dib_with_colortable( physDev
))
1825 TRACE("Disabling antialiasing\n");
1826 disable_antialias
= TRUE
;
1829 xgcval
.function
= GXcopy
;
1830 xgcval
.background
= physDev
->backgroundPixel
;
1831 xgcval
.fill_style
= FillSolid
;
1833 XChangeGC( gdi_display
, physDev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1834 wine_tsx11_unlock();
1836 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
);
1838 if(physDev
->depth
== 1) {
1839 if((physDev
->textPixel
& 0xffffff) == 0) {
1841 backgroundPixel
= 1;
1844 backgroundPixel
= 0;
1847 textPixel
= physDev
->textPixel
;
1848 backgroundPixel
= physDev
->backgroundPixel
;
1851 if(flags
& ETO_OPAQUE
)
1854 XSetForeground( gdi_display
, physDev
->gc
, backgroundPixel
);
1855 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1856 physDev
->dc_rect
.left
+ lprect
->left
, physDev
->dc_rect
.top
+ lprect
->top
,
1857 lprect
->right
- lprect
->left
, lprect
->bottom
- lprect
->top
);
1858 wine_tsx11_unlock();
1867 if (flags
& ETO_CLIPPED
)
1869 HRGN clip_region
= CreateRectRgnIndirect( lprect
);
1870 saved_region
= add_extra_clipping_region( physDev
, clip_region
);
1871 DeleteObject( clip_region
);
1874 EnterCriticalSection(&xrender_cs
);
1876 entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1877 if( disable_antialias
== FALSE
)
1878 aa_type
= entry
->aa_default
;
1879 formatEntry
= entry
->format
[aa_type
];
1881 for(idx
= 0; idx
< count
; idx
++) {
1882 if( !formatEntry
) {
1883 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1884 /* re-evaluate antialias since aa_default may have changed */
1885 if( disable_antialias
== FALSE
)
1886 aa_type
= entry
->aa_default
;
1887 formatEntry
= entry
->format
[aa_type
];
1888 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1889 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1894 WARN("could not upload requested glyphs\n");
1895 LeaveCriticalSection(&xrender_cs
);
1899 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1900 physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1902 if(X11DRV_XRender_Installed
)
1904 XGlyphElt16
*elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1905 POINT offset
= {0, 0};
1906 POINT desired
, current
;
1907 int render_op
= PictOpOver
;
1908 Picture pict
= get_xrender_picture(physDev
);
1910 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1911 So we pass zeros to the function and move to our starting position using the first
1912 element of the elts array. */
1914 desired
.x
= physDev
->dc_rect
.left
+ x
;
1915 desired
.y
= physDev
->dc_rect
.top
+ y
;
1916 current
.x
= current
.y
= 0;
1918 tile_pict
= get_tile_pict(dst_format
, physDev
->textPixel
);
1920 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1922 if((dst_format
->format
== WXR_FORMAT_MONO
) && (textPixel
== 0))
1923 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1925 for(idx
= 0; idx
< count
; idx
++)
1927 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1928 elts
[idx
].chars
= wstr
+ idx
;
1929 elts
[idx
].nchars
= 1;
1930 elts
[idx
].xOff
= desired
.x
- current
.x
;
1931 elts
[idx
].yOff
= desired
.y
- current
.y
;
1933 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1934 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1938 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1939 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1945 offset
.x
+= lpDx
[idx
* 2];
1946 offset
.y
+= lpDx
[idx
* 2 + 1];
1949 offset
.x
+= lpDx
[idx
];
1950 desired
.x
= physDev
->dc_rect
.left
+ x
+ offset
.x
;
1951 desired
.y
= physDev
->dc_rect
.top
+ y
+ offset
.y
;
1955 /* Make sure we don't have any transforms set from a previous call */
1956 set_xrender_transformation(pict
, 1, 1, 0, 0);
1957 pXRenderCompositeText16(gdi_display
, render_op
,
1960 formatEntry
->font_format
->pict_format
,
1961 0, 0, 0, 0, elts
, count
);
1962 wine_tsx11_unlock();
1963 HeapFree(GetProcessHeap(), 0, elts
);
1965 POINT offset
= {0, 0};
1967 XSetForeground( gdi_display
, physDev
->gc
, textPixel
);
1969 if(aa_type
== AA_None
|| physDev
->depth
== 1)
1971 void (* sharp_glyph_fn
)(X11DRV_PDEVICE
*, INT
, INT
, void *, XGlyphInfo
*);
1973 if(aa_type
== AA_None
)
1974 sharp_glyph_fn
= SharpGlyphMono
;
1976 sharp_glyph_fn
= SharpGlyphGray
;
1978 for(idx
= 0; idx
< count
; idx
++) {
1979 sharp_glyph_fn(physDev
,
1980 physDev
->dc_rect
.left
+ x
+ offset
.x
,
1981 physDev
->dc_rect
.top
+ y
+ offset
.y
,
1982 formatEntry
->bitmaps
[wstr
[idx
]],
1983 &formatEntry
->gis
[wstr
[idx
]]);
1988 offset
.x
+= lpDx
[idx
* 2];
1989 offset
.y
+= lpDx
[idx
* 2 + 1];
1992 offset
.x
+= lpDx
[idx
];
1996 offset
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1997 offset
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
2002 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
2003 RECT extents
= {0, 0, 0, 0};
2005 int w
= physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
;
2006 int h
= physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
;
2008 TRACE("drawable %dx%d\n", w
, h
);
2010 for(idx
= 0; idx
< count
; idx
++) {
2011 if(extents
.left
> cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
)
2012 extents
.left
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
;
2013 if(extents
.top
> cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
)
2014 extents
.top
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
;
2015 if(extents
.right
< cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
)
2016 extents
.right
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
;
2017 if(extents
.bottom
< cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
)
2018 extents
.bottom
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
;
2024 cur
.x
+= lpDx
[idx
* 2];
2025 cur
.y
+= lpDx
[idx
* 2 + 1];
2032 cur
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
2033 cur
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
2036 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents
.left
, extents
.top
,
2037 extents
.right
, extents
.bottom
, physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
2039 if(physDev
->dc_rect
.left
+ x
+ extents
.left
>= 0) {
2040 image_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
2044 image_off_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
2046 if(physDev
->dc_rect
.top
+ y
+ extents
.top
>= 0) {
2047 image_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
2051 image_off_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
2053 if(physDev
->dc_rect
.left
+ x
+ extents
.right
< w
)
2054 image_w
= physDev
->dc_rect
.left
+ x
+ extents
.right
- image_x
;
2056 image_w
= w
- image_x
;
2057 if(physDev
->dc_rect
.top
+ y
+ extents
.bottom
< h
)
2058 image_h
= physDev
->dc_rect
.top
+ y
+ extents
.bottom
- image_y
;
2060 image_h
= h
- image_y
;
2062 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
2064 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
2065 image
= XGetImage(gdi_display
, physDev
->drawable
,
2066 image_x
, image_y
, image_w
, image_h
,
2067 AllPlanes
, ZPixmap
);
2068 X11DRV_check_error();
2070 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2071 gdi_display
, (int)physDev
->drawable
, image_x
, image_y
,
2072 image_w
, image_h
, AllPlanes
, ZPixmap
,
2073 physDev
->depth
, image
);
2075 Pixmap xpm
= XCreatePixmap(gdi_display
, root_window
, image_w
, image_h
,
2080 gcv
.graphics_exposures
= False
;
2081 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
2082 XCopyArea(gdi_display
, physDev
->drawable
, xpm
, gc
, image_x
, image_y
,
2083 image_w
, image_h
, 0, 0);
2084 XFreeGC(gdi_display
, gc
);
2085 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
2086 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
2088 X11DRV_check_error();
2089 XFreePixmap(gdi_display
, xpm
);
2091 if(!image
) goto no_image
;
2093 image
->red_mask
= visual
->red_mask
;
2094 image
->green_mask
= visual
->green_mask
;
2095 image
->blue_mask
= visual
->blue_mask
;
2097 for(idx
= 0; idx
< count
; idx
++) {
2098 SmoothGlyphGray(image
,
2099 offset
.x
+ image_off_x
- extents
.left
,
2100 offset
.y
+ image_off_y
- extents
.top
,
2101 formatEntry
->bitmaps
[wstr
[idx
]],
2102 &formatEntry
->gis
[wstr
[idx
]],
2103 physDev
->textPixel
);
2108 offset
.x
+= lpDx
[idx
* 2];
2109 offset
.y
+= lpDx
[idx
* 2 + 1];
2112 offset
.x
+= lpDx
[idx
];
2116 offset
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
2117 offset
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
2120 XPutImage(gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
2121 image_x
, image_y
, image_w
, image_h
);
2122 XDestroyImage(image
);
2125 wine_tsx11_unlock();
2127 LeaveCriticalSection(&xrender_cs
);
2129 if (saved_region
) restore_clipping_region( physDev
, saved_region
);
2134 X11DRV_UnlockDIBSection( physDev
, TRUE
);
2138 /* Helper function for (stretched) blitting using xrender */
2139 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
2140 int x_src
, int y_src
, int x_dst
, int y_dst
,
2141 double xscale
, double yscale
, int width
, int height
)
2143 int x_offset
, y_offset
;
2145 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2146 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2147 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2148 if(xscale
!= 1.0 || yscale
!= 1.0)
2150 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2151 * in the wrong quadrant of the x-y plane.
2153 x_offset
= (xscale
< 0) ? -width
: 0;
2154 y_offset
= (yscale
< 0) ? -height
: 0;
2155 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
2161 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
2163 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
2164 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width
, height
);
2167 /* Helper function for (stretched) mono->color blitting using xrender */
2168 static void xrender_mono_blit( Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
2169 int x_src
, int y_src
, double xscale
, double yscale
, int width
, int height
)
2171 int x_offset
, y_offset
;
2173 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2174 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
2175 * tile data. We need PictOpOver for correct rendering.
2176 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2179 if (xscale
!= 1.0 || yscale
!= 1.0)
2181 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2182 * in the wrong quadrant of the x-y plane.
2184 x_offset
= (xscale
< 0) ? -width
: 0;
2185 y_offset
= (yscale
< 0) ? -height
: 0;
2186 set_xrender_transformation(mask_pict
, xscale
, yscale
, x_src
, y_src
);
2192 set_xrender_transformation(mask_pict
, 1, 1, 0, 0);
2194 pXRenderComposite(gdi_display
, PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2195 0, 0, x_offset
, y_offset
, 0, 0, width
, height
);
2198 /******************************************************************************
2201 BOOL
XRender_AlphaBlend( X11DRV_PDEVICE
*devDst
, struct bitblt_coords
*dst
,
2202 X11DRV_PDEVICE
*devSrc
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
2204 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
2205 struct xrender_info
*src_info
= get_xrender_info( devSrc
);
2206 double xscale
, yscale
;
2209 if(!X11DRV_XRender_Installed
) {
2210 FIXME("Unable to AlphaBlend without Xrender\n");
2214 if (devSrc
!= devDst
) X11DRV_LockDIBSection( devSrc
, DIB_Status_GdiMod
);
2215 X11DRV_LockDIBSection( devDst
, DIB_Status_GdiMod
);
2217 dst_pict
= get_xrender_picture( devDst
);
2219 use_repeat
= use_source_repeat( devSrc
);
2222 xscale
= src
->width
/ (double)dst
->width
;
2223 yscale
= src
->height
/ (double)dst
->height
;
2225 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2227 if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && src_info
->format
)
2229 /* we need a source picture with no alpha */
2230 WXRFormat format
= get_format_without_alpha( src_info
->format
->format
);
2231 if (format
!= src_info
->format
->format
)
2233 XRenderPictureAttributes pa
;
2234 const WineXRenderFormat
*fmt
= get_xrender_format( format
);
2237 pa
.subwindow_mode
= IncludeInferiors
;
2238 pa
.repeat
= use_repeat
? RepeatNormal
: RepeatNone
;
2239 tmp_pict
= pXRenderCreatePicture( gdi_display
, devSrc
->drawable
, fmt
->pict_format
,
2240 CPSubwindowMode
|CPRepeat
, &pa
);
2241 wine_tsx11_unlock();
2242 src_pict
= tmp_pict
;
2246 if (!src_pict
) src_pict
= get_xrender_picture_source( devSrc
, use_repeat
);
2248 EnterCriticalSection( &xrender_cs
);
2249 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
2252 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2253 devSrc
->dc_rect
.left
+ src
->visrect
.left
, devSrc
->dc_rect
.top
+ src
->visrect
.top
,
2254 devDst
->dc_rect
.left
+ dst
->visrect
.left
, devDst
->dc_rect
.top
+ dst
->visrect
.top
,
2256 dst
->visrect
.right
- dst
->visrect
.left
, dst
->visrect
.bottom
- dst
->visrect
.top
);
2257 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
2258 wine_tsx11_unlock();
2260 LeaveCriticalSection( &xrender_cs
);
2261 if (devSrc
!= devDst
) X11DRV_UnlockDIBSection( devSrc
, FALSE
);
2262 X11DRV_UnlockDIBSection( devDst
, TRUE
);
2267 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
2269 /* 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 */
2270 int depth
= physBitmap
->pixmap_depth
== 1 ? 1 : physDev
->depth
;
2271 const WineXRenderFormat
*src_format
= get_xrender_format_from_color_shifts(physBitmap
->pixmap_depth
, &physBitmap
->pixmap_color_shifts
);
2272 const WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
2275 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, depth
);
2277 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2278 if( (physBitmap
->pixmap_depth
== 1) || (!X11DRV_XRender_Installed
&& physDev
->depth
== physBitmap
->pixmap_depth
) ||
2279 (src_format
->format
== dst_format
->format
) )
2281 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
2282 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
2284 else /* We need depth conversion */
2286 Picture src_pict
, dst_pict
;
2287 XRenderPictureAttributes pa
;
2288 pa
.subwindow_mode
= IncludeInferiors
;
2289 pa
.repeat
= RepeatNone
;
2291 src_pict
= pXRenderCreatePicture(gdi_display
, physBitmap
->pixmap
, src_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2292 dst_pict
= pXRenderCreatePicture(gdi_display
, physDev
->brush
.pixmap
, dst_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2294 xrender_blit(PictOpSrc
, src_pict
, 0, dst_pict
, 0, 0, 0, 0, 1.0, 1.0, width
, height
);
2295 pXRenderFreePicture(gdi_display
, src_pict
);
2296 pXRenderFreePicture(gdi_display
, dst_pict
);
2298 wine_tsx11_unlock();
2301 BOOL
X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
2302 Pixmap pixmap
, GC gc
,
2303 const struct bitblt_coords
*src
, const struct bitblt_coords
*dst
)
2305 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
2306 int width
= dst
->visrect
.right
- dst
->visrect
.left
;
2307 int height
= dst
->visrect
.bottom
- dst
->visrect
.top
;
2308 int x_src
= physDevSrc
->dc_rect
.left
+ src
->visrect
.left
;
2309 int y_src
= physDevSrc
->dc_rect
.top
+ src
->visrect
.top
;
2310 struct xrender_info
*src_info
= get_xrender_info(physDevSrc
);
2311 const WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDevDst
->depth
, physDevDst
->color_shifts
);
2312 Picture src_pict
=0, dst_pict
=0, mask_pict
=0;
2314 double xscale
, yscale
;
2316 XRenderPictureAttributes pa
;
2317 pa
.subwindow_mode
= IncludeInferiors
;
2318 pa
.repeat
= RepeatNone
;
2320 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2321 physDevSrc
->depth
, src
->width
, src
->height
, x_src
, y_src
);
2322 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst
->depth
, dst
->width
, dst
->height
);
2324 if(!X11DRV_XRender_Installed
)
2326 TRACE("Not using XRender since it is not available or disabled\n");
2330 /* XRender can't handle palettes, so abort */
2331 if(X11DRV_PALETTE_XPixelToPalette
)
2334 /* XRender is of no use in this case */
2335 if((physDevDst
->depth
== 1) && (physDevSrc
->depth
> 1))
2338 /* Just use traditional X copy when the formats match and we don't need stretching */
2339 if((src_info
->format
->format
== dst_format
->format
) && !stretch
)
2341 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2343 XCopyArea( gdi_display
, physDevSrc
->drawable
, pixmap
, gc
, x_src
, y_src
, width
, height
, 0, 0);
2344 wine_tsx11_unlock();
2348 use_repeat
= use_source_repeat( physDevSrc
);
2351 xscale
= src
->width
/ (double)dst
->width
;
2352 yscale
= src
->height
/ (double)dst
->height
;
2354 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2357 if(physDevSrc
->depth
== 1 && physDevDst
->depth
> 1)
2360 get_xrender_color(dst_format
, physDevDst
->textPixel
, &col
);
2362 /* We use the source drawable as a mask */
2363 mask_pict
= get_xrender_picture_source( physDevSrc
, use_repeat
);
2365 /* Use backgroundPixel as the foreground color */
2366 EnterCriticalSection( &xrender_cs
);
2367 src_pict
= get_tile_pict(dst_format
, physDevDst
->backgroundPixel
);
2369 /* Create a destination picture and fill it with textPixel color as the background color */
2371 dst_pict
= pXRenderCreatePicture(gdi_display
, pixmap
, dst_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2372 pXRenderFillRectangle(gdi_display
, PictOpSrc
, dst_pict
, &col
, 0, 0, width
, height
);
2374 xrender_mono_blit(src_pict
, mask_pict
, dst_pict
, x_src
, y_src
, xscale
, yscale
, width
, height
);
2376 if(dst_pict
) pXRenderFreePicture(gdi_display
, dst_pict
);
2377 wine_tsx11_unlock();
2378 LeaveCriticalSection( &xrender_cs
);
2380 else /* color -> color (can be at different depths) or mono -> mono */
2382 if (physDevDst
->depth
== 32 && physDevSrc
->depth
< 32) mask_pict
= get_no_alpha_mask();
2383 src_pict
= get_xrender_picture_source( physDevSrc
, use_repeat
);
2386 dst_pict
= pXRenderCreatePicture(gdi_display
,
2387 pixmap
, dst_format
->pict_format
,
2388 CPSubwindowMode
|CPRepeat
, &pa
);
2390 xrender_blit(PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
2391 x_src
, y_src
, 0, 0, xscale
, yscale
, width
, height
);
2393 if(dst_pict
) pXRenderFreePicture(gdi_display
, dst_pict
);
2394 wine_tsx11_unlock();
2399 #else /* SONAME_LIBXRENDER */
2401 void X11DRV_XRender_Init(void)
2403 TRACE("XRender support not compiled in.\n");
2407 void X11DRV_XRender_Finalize(void)
2411 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
2417 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
2423 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE
*physDev
, const RGNDATA
*data
)
2429 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
2430 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
2437 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
2443 BOOL
XRender_AlphaBlend( X11DRV_PDEVICE
*devDst
, X11DRV_PDEVICE
*devSrc
,
2444 struct bitblt_coords
*dst
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
2446 FIXME("not supported - XRENDER headers were missing at compile time\n");
2450 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
2453 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, physBitmap
->pixmap_depth
);
2455 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
2456 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
2457 wine_tsx11_unlock();
2460 BOOL
X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP
*physBitmap
, int bits_pixel
, const DIBSECTION
*dib
)
2465 BOOL
X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
2466 Pixmap pixmap
, GC gc
,
2467 const struct bitblt_coords
*src
, const struct bitblt_coords
*dst
)
2471 #endif /* SONAME_LIBXRENDER */