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
)
1871 clip_region
= CreateRectRgnIndirect( lprect
);
1872 /* make a copy of the current device region */
1873 saved_region
= CreateRectRgn( 0, 0, 0, 0 );
1874 CombineRgn( saved_region
, physDev
->region
, 0, RGN_COPY
);
1875 X11DRV_SetDeviceClipping( &physDev
->dev
, saved_region
, clip_region
);
1876 DeleteObject( clip_region
);
1879 EnterCriticalSection(&xrender_cs
);
1881 entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1882 if( disable_antialias
== FALSE
)
1883 aa_type
= entry
->aa_default
;
1884 formatEntry
= entry
->format
[aa_type
];
1886 for(idx
= 0; idx
< count
; idx
++) {
1887 if( !formatEntry
) {
1888 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1889 /* re-evaluate antialias since aa_default may have changed */
1890 if( disable_antialias
== FALSE
)
1891 aa_type
= entry
->aa_default
;
1892 formatEntry
= entry
->format
[aa_type
];
1893 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1894 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1899 WARN("could not upload requested glyphs\n");
1900 LeaveCriticalSection(&xrender_cs
);
1904 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1905 physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1907 if(X11DRV_XRender_Installed
)
1909 XGlyphElt16
*elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1910 POINT offset
= {0, 0};
1911 POINT desired
, current
;
1912 int render_op
= PictOpOver
;
1913 Picture pict
= get_xrender_picture(physDev
);
1915 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1916 So we pass zeros to the function and move to our starting position using the first
1917 element of the elts array. */
1919 desired
.x
= physDev
->dc_rect
.left
+ x
;
1920 desired
.y
= physDev
->dc_rect
.top
+ y
;
1921 current
.x
= current
.y
= 0;
1923 tile_pict
= get_tile_pict(dst_format
, physDev
->textPixel
);
1925 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1927 if((dst_format
->format
== WXR_FORMAT_MONO
) && (textPixel
== 0))
1928 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1930 for(idx
= 0; idx
< count
; idx
++)
1932 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1933 elts
[idx
].chars
= wstr
+ idx
;
1934 elts
[idx
].nchars
= 1;
1935 elts
[idx
].xOff
= desired
.x
- current
.x
;
1936 elts
[idx
].yOff
= desired
.y
- current
.y
;
1938 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1939 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1943 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1944 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1950 offset
.x
+= lpDx
[idx
* 2];
1951 offset
.y
+= lpDx
[idx
* 2 + 1];
1954 offset
.x
+= lpDx
[idx
];
1955 desired
.x
= physDev
->dc_rect
.left
+ x
+ offset
.x
;
1956 desired
.y
= physDev
->dc_rect
.top
+ y
+ offset
.y
;
1960 /* Make sure we don't have any transforms set from a previous call */
1961 set_xrender_transformation(pict
, 1, 1, 0, 0);
1962 pXRenderCompositeText16(gdi_display
, render_op
,
1965 formatEntry
->font_format
->pict_format
,
1966 0, 0, 0, 0, elts
, count
);
1967 wine_tsx11_unlock();
1968 HeapFree(GetProcessHeap(), 0, elts
);
1970 POINT offset
= {0, 0};
1972 XSetForeground( gdi_display
, physDev
->gc
, textPixel
);
1974 if(aa_type
== AA_None
|| physDev
->depth
== 1)
1976 void (* sharp_glyph_fn
)(X11DRV_PDEVICE
*, INT
, INT
, void *, XGlyphInfo
*);
1978 if(aa_type
== AA_None
)
1979 sharp_glyph_fn
= SharpGlyphMono
;
1981 sharp_glyph_fn
= SharpGlyphGray
;
1983 for(idx
= 0; idx
< count
; idx
++) {
1984 sharp_glyph_fn(physDev
,
1985 physDev
->dc_rect
.left
+ x
+ offset
.x
,
1986 physDev
->dc_rect
.top
+ y
+ offset
.y
,
1987 formatEntry
->bitmaps
[wstr
[idx
]],
1988 &formatEntry
->gis
[wstr
[idx
]]);
1993 offset
.x
+= lpDx
[idx
* 2];
1994 offset
.y
+= lpDx
[idx
* 2 + 1];
1997 offset
.x
+= lpDx
[idx
];
2001 offset
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
2002 offset
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
2007 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
2008 RECT extents
= {0, 0, 0, 0};
2010 int w
= physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
;
2011 int h
= physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
;
2013 TRACE("drawable %dx%d\n", w
, h
);
2015 for(idx
= 0; idx
< count
; idx
++) {
2016 if(extents
.left
> cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
)
2017 extents
.left
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
;
2018 if(extents
.top
> cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
)
2019 extents
.top
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
;
2020 if(extents
.right
< cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
)
2021 extents
.right
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
;
2022 if(extents
.bottom
< cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
)
2023 extents
.bottom
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
;
2029 cur
.x
+= lpDx
[idx
* 2];
2030 cur
.y
+= lpDx
[idx
* 2 + 1];
2037 cur
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
2038 cur
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
2041 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents
.left
, extents
.top
,
2042 extents
.right
, extents
.bottom
, physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
2044 if(physDev
->dc_rect
.left
+ x
+ extents
.left
>= 0) {
2045 image_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
2049 image_off_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
2051 if(physDev
->dc_rect
.top
+ y
+ extents
.top
>= 0) {
2052 image_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
2056 image_off_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
2058 if(physDev
->dc_rect
.left
+ x
+ extents
.right
< w
)
2059 image_w
= physDev
->dc_rect
.left
+ x
+ extents
.right
- image_x
;
2061 image_w
= w
- image_x
;
2062 if(physDev
->dc_rect
.top
+ y
+ extents
.bottom
< h
)
2063 image_h
= physDev
->dc_rect
.top
+ y
+ extents
.bottom
- image_y
;
2065 image_h
= h
- image_y
;
2067 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
2069 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
2070 image
= XGetImage(gdi_display
, physDev
->drawable
,
2071 image_x
, image_y
, image_w
, image_h
,
2072 AllPlanes
, ZPixmap
);
2073 X11DRV_check_error();
2075 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2076 gdi_display
, (int)physDev
->drawable
, image_x
, image_y
,
2077 image_w
, image_h
, AllPlanes
, ZPixmap
,
2078 physDev
->depth
, image
);
2080 Pixmap xpm
= XCreatePixmap(gdi_display
, root_window
, image_w
, image_h
,
2085 gcv
.graphics_exposures
= False
;
2086 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
2087 XCopyArea(gdi_display
, physDev
->drawable
, xpm
, gc
, image_x
, image_y
,
2088 image_w
, image_h
, 0, 0);
2089 XFreeGC(gdi_display
, gc
);
2090 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
2091 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
2093 X11DRV_check_error();
2094 XFreePixmap(gdi_display
, xpm
);
2096 if(!image
) goto no_image
;
2098 image
->red_mask
= visual
->red_mask
;
2099 image
->green_mask
= visual
->green_mask
;
2100 image
->blue_mask
= visual
->blue_mask
;
2102 for(idx
= 0; idx
< count
; idx
++) {
2103 SmoothGlyphGray(image
,
2104 offset
.x
+ image_off_x
- extents
.left
,
2105 offset
.y
+ image_off_y
- extents
.top
,
2106 formatEntry
->bitmaps
[wstr
[idx
]],
2107 &formatEntry
->gis
[wstr
[idx
]],
2108 physDev
->textPixel
);
2113 offset
.x
+= lpDx
[idx
* 2];
2114 offset
.y
+= lpDx
[idx
* 2 + 1];
2117 offset
.x
+= lpDx
[idx
];
2121 offset
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
2122 offset
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
2125 XPutImage(gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
2126 image_x
, image_y
, image_w
, image_h
);
2127 XDestroyImage(image
);
2130 wine_tsx11_unlock();
2132 LeaveCriticalSection(&xrender_cs
);
2134 if (flags
& ETO_CLIPPED
)
2136 /* restore the device region */
2137 X11DRV_SetDeviceClipping( &physDev
->dev
, saved_region
, 0 );
2138 DeleteObject( saved_region
);
2144 X11DRV_UnlockDIBSection( physDev
, TRUE
);
2148 /* Helper function for (stretched) blitting using xrender */
2149 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
2150 int x_src
, int y_src
, int x_dst
, int y_dst
,
2151 double xscale
, double yscale
, int width
, int height
)
2153 int x_offset
, y_offset
;
2155 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2156 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2157 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2158 if(xscale
!= 1.0 || yscale
!= 1.0)
2160 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2161 * in the wrong quadrant of the x-y plane.
2163 x_offset
= (xscale
< 0) ? -width
: 0;
2164 y_offset
= (yscale
< 0) ? -height
: 0;
2165 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
2171 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
2173 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
2174 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width
, height
);
2177 /* Helper function for (stretched) mono->color blitting using xrender */
2178 static void xrender_mono_blit( Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
2179 int x_src
, int y_src
, double xscale
, double yscale
, int width
, int height
)
2181 int x_offset
, y_offset
;
2183 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2184 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
2185 * tile data. We need PictOpOver for correct rendering.
2186 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2189 if (xscale
!= 1.0 || yscale
!= 1.0)
2191 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2192 * in the wrong quadrant of the x-y plane.
2194 x_offset
= (xscale
< 0) ? -width
: 0;
2195 y_offset
= (yscale
< 0) ? -height
: 0;
2196 set_xrender_transformation(mask_pict
, xscale
, yscale
, x_src
, y_src
);
2202 set_xrender_transformation(mask_pict
, 1, 1, 0, 0);
2204 pXRenderComposite(gdi_display
, PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2205 0, 0, x_offset
, y_offset
, 0, 0, width
, height
);
2208 /******************************************************************************
2211 BOOL
XRender_AlphaBlend( X11DRV_PDEVICE
*devDst
, struct bitblt_coords
*dst
,
2212 X11DRV_PDEVICE
*devSrc
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
2214 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
2215 struct xrender_info
*src_info
= get_xrender_info( devSrc
);
2216 double xscale
, yscale
;
2219 if(!X11DRV_XRender_Installed
) {
2220 FIXME("Unable to AlphaBlend without Xrender\n");
2224 if (devSrc
!= devDst
) X11DRV_LockDIBSection( devSrc
, DIB_Status_GdiMod
);
2225 X11DRV_LockDIBSection( devDst
, DIB_Status_GdiMod
);
2227 dst_pict
= get_xrender_picture( devDst
);
2229 use_repeat
= use_source_repeat( devSrc
);
2232 xscale
= src
->width
/ (double)dst
->width
;
2233 yscale
= src
->height
/ (double)dst
->height
;
2235 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2237 if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && src_info
->format
)
2239 /* we need a source picture with no alpha */
2240 WXRFormat format
= get_format_without_alpha( src_info
->format
->format
);
2241 if (format
!= src_info
->format
->format
)
2243 XRenderPictureAttributes pa
;
2244 const WineXRenderFormat
*fmt
= get_xrender_format( format
);
2247 pa
.subwindow_mode
= IncludeInferiors
;
2248 pa
.repeat
= use_repeat
? RepeatNormal
: RepeatNone
;
2249 tmp_pict
= pXRenderCreatePicture( gdi_display
, devSrc
->drawable
, fmt
->pict_format
,
2250 CPSubwindowMode
|CPRepeat
, &pa
);
2251 wine_tsx11_unlock();
2252 src_pict
= tmp_pict
;
2256 if (!src_pict
) src_pict
= get_xrender_picture_source( devSrc
, use_repeat
);
2258 EnterCriticalSection( &xrender_cs
);
2259 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
2262 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2263 devSrc
->dc_rect
.left
+ src
->visrect
.left
, devSrc
->dc_rect
.top
+ src
->visrect
.top
,
2264 devDst
->dc_rect
.left
+ dst
->visrect
.left
, devDst
->dc_rect
.top
+ dst
->visrect
.top
,
2266 dst
->visrect
.right
- dst
->visrect
.left
, dst
->visrect
.bottom
- dst
->visrect
.top
);
2267 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
2268 wine_tsx11_unlock();
2270 LeaveCriticalSection( &xrender_cs
);
2271 if (devSrc
!= devDst
) X11DRV_UnlockDIBSection( devSrc
, FALSE
);
2272 X11DRV_UnlockDIBSection( devDst
, TRUE
);
2277 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
2279 /* 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 */
2280 int depth
= physBitmap
->pixmap_depth
== 1 ? 1 : physDev
->depth
;
2281 const WineXRenderFormat
*src_format
= get_xrender_format_from_color_shifts(physBitmap
->pixmap_depth
, &physBitmap
->pixmap_color_shifts
);
2282 const WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDev
->depth
, physDev
->color_shifts
);
2285 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, depth
);
2287 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2288 if( (physBitmap
->pixmap_depth
== 1) || (!X11DRV_XRender_Installed
&& physDev
->depth
== physBitmap
->pixmap_depth
) ||
2289 (src_format
->format
== dst_format
->format
) )
2291 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
2292 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
2294 else /* We need depth conversion */
2296 Picture src_pict
, dst_pict
;
2297 XRenderPictureAttributes pa
;
2298 pa
.subwindow_mode
= IncludeInferiors
;
2299 pa
.repeat
= RepeatNone
;
2301 src_pict
= pXRenderCreatePicture(gdi_display
, physBitmap
->pixmap
, src_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2302 dst_pict
= pXRenderCreatePicture(gdi_display
, physDev
->brush
.pixmap
, dst_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2304 xrender_blit(PictOpSrc
, src_pict
, 0, dst_pict
, 0, 0, 0, 0, 1.0, 1.0, width
, height
);
2305 pXRenderFreePicture(gdi_display
, src_pict
);
2306 pXRenderFreePicture(gdi_display
, dst_pict
);
2308 wine_tsx11_unlock();
2311 BOOL
X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
2312 Pixmap pixmap
, GC gc
,
2313 const struct bitblt_coords
*src
, const struct bitblt_coords
*dst
)
2315 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
2316 int width
= dst
->visrect
.right
- dst
->visrect
.left
;
2317 int height
= dst
->visrect
.bottom
- dst
->visrect
.top
;
2318 int x_src
= physDevSrc
->dc_rect
.left
+ src
->visrect
.left
;
2319 int y_src
= physDevSrc
->dc_rect
.top
+ src
->visrect
.top
;
2320 struct xrender_info
*src_info
= get_xrender_info(physDevSrc
);
2321 const WineXRenderFormat
*dst_format
= get_xrender_format_from_color_shifts(physDevDst
->depth
, physDevDst
->color_shifts
);
2322 Picture src_pict
=0, dst_pict
=0, mask_pict
=0;
2324 double xscale
, yscale
;
2326 XRenderPictureAttributes pa
;
2327 pa
.subwindow_mode
= IncludeInferiors
;
2328 pa
.repeat
= RepeatNone
;
2330 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2331 physDevSrc
->depth
, src
->width
, src
->height
, x_src
, y_src
);
2332 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst
->depth
, dst
->width
, dst
->height
);
2334 if(!X11DRV_XRender_Installed
)
2336 TRACE("Not using XRender since it is not available or disabled\n");
2340 /* XRender can't handle palettes, so abort */
2341 if(X11DRV_PALETTE_XPixelToPalette
)
2344 /* XRender is of no use in this case */
2345 if((physDevDst
->depth
== 1) && (physDevSrc
->depth
> 1))
2348 /* Just use traditional X copy when the formats match and we don't need stretching */
2349 if((src_info
->format
->format
== dst_format
->format
) && !stretch
)
2351 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2353 XCopyArea( gdi_display
, physDevSrc
->drawable
, pixmap
, gc
, x_src
, y_src
, width
, height
, 0, 0);
2354 wine_tsx11_unlock();
2358 use_repeat
= use_source_repeat( physDevSrc
);
2361 xscale
= src
->width
/ (double)dst
->width
;
2362 yscale
= src
->height
/ (double)dst
->height
;
2364 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2367 if(physDevSrc
->depth
== 1 && physDevDst
->depth
> 1)
2370 get_xrender_color(dst_format
, physDevDst
->textPixel
, &col
);
2372 /* We use the source drawable as a mask */
2373 mask_pict
= get_xrender_picture_source( physDevSrc
, use_repeat
);
2375 /* Use backgroundPixel as the foreground color */
2376 EnterCriticalSection( &xrender_cs
);
2377 src_pict
= get_tile_pict(dst_format
, physDevDst
->backgroundPixel
);
2379 /* Create a destination picture and fill it with textPixel color as the background color */
2381 dst_pict
= pXRenderCreatePicture(gdi_display
, pixmap
, dst_format
->pict_format
, CPSubwindowMode
|CPRepeat
, &pa
);
2382 pXRenderFillRectangle(gdi_display
, PictOpSrc
, dst_pict
, &col
, 0, 0, width
, height
);
2384 xrender_mono_blit(src_pict
, mask_pict
, dst_pict
, x_src
, y_src
, xscale
, yscale
, width
, height
);
2386 if(dst_pict
) pXRenderFreePicture(gdi_display
, dst_pict
);
2387 wine_tsx11_unlock();
2388 LeaveCriticalSection( &xrender_cs
);
2390 else /* color -> color (can be at different depths) or mono -> mono */
2392 if (physDevDst
->depth
== 32 && physDevSrc
->depth
< 32) mask_pict
= get_no_alpha_mask();
2393 src_pict
= get_xrender_picture_source( physDevSrc
, use_repeat
);
2396 dst_pict
= pXRenderCreatePicture(gdi_display
,
2397 pixmap
, dst_format
->pict_format
,
2398 CPSubwindowMode
|CPRepeat
, &pa
);
2400 xrender_blit(PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
2401 x_src
, y_src
, 0, 0, xscale
, yscale
, width
, height
);
2403 if(dst_pict
) pXRenderFreePicture(gdi_display
, dst_pict
);
2404 wine_tsx11_unlock();
2409 #else /* SONAME_LIBXRENDER */
2411 void X11DRV_XRender_Init(void)
2413 TRACE("XRender support not compiled in.\n");
2417 void X11DRV_XRender_Finalize(void)
2421 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
2427 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
2433 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE
*physDev
, const RGNDATA
*data
)
2439 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
2440 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
2447 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
2453 BOOL
XRender_AlphaBlend( X11DRV_PDEVICE
*devDst
, X11DRV_PDEVICE
*devSrc
,
2454 struct bitblt_coords
*dst
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
2456 FIXME("not supported - XRENDER headers were missing at compile time\n");
2460 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE
*physDev
, X_PHYSBITMAP
*physBitmap
, int width
, int height
)
2463 physDev
->brush
.pixmap
= XCreatePixmap(gdi_display
, root_window
, width
, height
, physBitmap
->pixmap_depth
);
2465 XCopyArea( gdi_display
, physBitmap
->pixmap
, physDev
->brush
.pixmap
,
2466 get_bitmap_gc(physBitmap
->pixmap_depth
), 0, 0, width
, height
, 0, 0 );
2467 wine_tsx11_unlock();
2470 BOOL
X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP
*physBitmap
, int bits_pixel
, const DIBSECTION
*dib
)
2475 BOOL
X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE
*physDevSrc
, X11DRV_PDEVICE
*physDevDst
,
2476 Pixmap pixmap
, GC gc
,
2477 const struct bitblt_coords
*src
, const struct bitblt_coords
*dst
)
2481 #endif /* SONAME_LIBXRENDER */