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->hdc, physDev->drawable);
581 HeapFree( GetProcessHeap(), 0, clip );
587 static Picture get_xrender_picture_source(X11DRV_PDEVICE *physDev, BOOL repeat)
589 struct xrender_info *info = get_xrender_info(physDev);
592 if (!info->pict_src && info->format)
594 XRenderPictureAttributes pa;
597 pa.subwindow_mode = IncludeInferiors;
598 pa.repeat = repeat ? RepeatNormal : RepeatNone;
599 info->pict_src = pXRenderCreatePicture(gdi_display, physDev->drawable, info->format->pict_format,
600 CPSubwindowMode|CPRepeat, &pa);
603 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
604 info->pict_src, physDev->hdc, physDev->drawable, pa.repeat);
607 return info->pict_src;
610 /* return a mask picture used to force alpha to 0 */
611 static Picture get_no_alpha_mask(void)
613 static Pixmap pixmap;
619 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
620 XRenderPictureAttributes pa;
623 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
624 pa.repeat = RepeatNormal;
625 pa.component_alpha = True;
626 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format,
627 CPRepeat|CPComponentAlpha, &pa );
628 col.red = col.green = col.blue = 0xffff;
630 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
636 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
638 if(p1->hash != p2->hash) return TRUE;
639 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
640 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
641 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
642 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
646 static void walk_cache(void)
650 EnterCriticalSection(&xrender_cs);
651 for(i=mru; i >= 0; i = glyphsetCache[i].next)
652 TRACE("item %d\n", i);
653 LeaveCriticalSection(&xrender_cs);
657 static int LookupEntry(LFANDSIZE *plfsz)
661 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
663 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
668 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
669 glyphsetCache[i].count++;
671 glyphsetCache[prev_i].next = glyphsetCache[i].next;
672 glyphsetCache[i].next = mru;
675 TRACE("found font in cache %d\n", i);
680 TRACE("font not in cache\n");
684 static void FreeEntry(int entry)
688 for(format = 0; format < AA_MAXVALUE; format++) {
689 gsCacheEntryFormat * formatEntry;
691 if( !glyphsetCache[entry].format[format] )
694 formatEntry = glyphsetCache[entry].format[format];
696 if(formatEntry->glyphset) {
698 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
700 formatEntry->glyphset = 0;
702 if(formatEntry->nrealized) {
703 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
704 formatEntry->realized = NULL;
705 if(formatEntry->bitmaps) {
706 for(i = 0; i < formatEntry->nrealized; i++)
707 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
708 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
709 formatEntry->bitmaps = NULL;
711 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
712 formatEntry->gis = NULL;
713 formatEntry->nrealized = 0;
716 HeapFree(GetProcessHeap(), 0, formatEntry);
717 glyphsetCache[entry].format[format] = NULL;
721 static int AllocEntry(void)
723 int best = -1, prev_best = -1, i, prev_i = -1;
726 assert(glyphsetCache[lastfree].count == -1);
727 glyphsetCache[lastfree].count = 1;
729 lastfree = glyphsetCache[lastfree].next;
731 glyphsetCache[best].next = mru;
734 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
738 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
739 if(glyphsetCache[i].count == 0) {
747 TRACE("freeing unused glyphset at cache %d\n", best);
749 glyphsetCache[best].count = 1;
751 glyphsetCache[prev_best].next = glyphsetCache[best].next;
752 glyphsetCache[best].next = mru;
760 TRACE("Growing cache\n");
763 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
765 (glyphsetCacheSize + INIT_CACHE_SIZE)
766 * sizeof(*glyphsetCache));
768 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
769 (glyphsetCacheSize + INIT_CACHE_SIZE)
770 * sizeof(*glyphsetCache));
772 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
774 glyphsetCache[i].next = i + 1;
775 glyphsetCache[i].count = -1;
777 glyphsetCache[i-1].next = -1;
778 glyphsetCacheSize += INIT_CACHE_SIZE;
780 lastfree = glyphsetCache[best].next;
781 glyphsetCache[best].count = 1;
782 glyphsetCache[best].next = mru;
784 TRACE("new free cache slot at %d\n", mru);
788 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
798 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
799 if(size == GDI_ERROR)
802 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
803 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
805 GetTextMetricsW(physDev->hdc, &tm);
806 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
809 num_recs = get_be_word(*gasp);
813 *flags = get_be_word(*(gasp + 1));
814 if(ppem <= get_be_word(*gasp))
818 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
820 HeapFree(GetProcessHeap(), 0, buffer);
824 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
828 UINT font_smoothing_type, font_smoothing_orientation;
830 if (X11DRV_XRender_Installed && subpixel &&
831 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
832 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
834 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
835 &font_smoothing_orientation, 0) &&
836 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
843 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
844 But, Wine's subpixel rendering can support the portrait mode.
847 else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
855 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
860 static int hinter = -1;
861 static int subpixel = -1;
864 if((ret = LookupEntry(plfsz)) != -1) return ret;
867 entry = glyphsetCache + ret;
868 entry->lfsz = *plfsz;
869 for( format = 0; format < AA_MAXVALUE; format++ ) {
870 assert( !entry->format[format] );
873 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
875 if(hinter == -1 || subpixel == -1)
877 RASTERIZER_STATUS status;
878 GetRasterizerCaps(&status, sizeof(status));
879 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
880 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
883 switch (plfsz->lf.lfQuality)
885 case ANTIALIASED_QUALITY:
886 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
887 return ret; /* ignore further configuration */
888 case CLEARTYPE_QUALITY:
889 case CLEARTYPE_NATURAL_QUALITY:
890 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
892 case DEFAULT_QUALITY:
896 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
899 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
902 entry->aa_default = AA_None;
906 font_smoothing = TRUE; /* default to enabled */
907 #ifdef SONAME_LIBFONTCONFIG
908 if (fontconfig_installed)
910 FcPattern *match, *pattern = pFcPatternCreate();
912 char family[LF_FACESIZE * 4];
914 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
915 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
916 if (plfsz->lf.lfWeight != FW_DONTCARE)
919 switch (plfsz->lf.lfWeight)
921 case FW_THIN: weight = FC_WEIGHT_THIN; break;
922 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
923 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
924 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
925 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
926 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
927 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
928 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
929 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
930 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
932 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
934 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
935 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
936 pFcDefaultSubstitute( pattern );
937 if ((match = pFcFontMatch( NULL, pattern, &result )))
942 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
944 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
947 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
949 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
950 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
954 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
955 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
956 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
957 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
958 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
961 if (!antialias) font_smoothing = FALSE;
962 pFcPatternDestroy( match );
964 pFcPatternDestroy( pattern );
966 #endif /* SONAME_LIBFONTCONFIG */
968 /* now check Xft resources */
971 BOOL antialias = TRUE;
974 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
976 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
977 value[0] == '0' || !strcasecmp( value, "off" ))
980 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
982 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
983 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
984 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
985 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
986 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
987 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
990 if (!antialias) font_smoothing = FALSE;
993 if (!font_smoothing) entry->aa_default = AA_None;
995 /* we can't support subpixel without xrender */
996 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
999 entry->aa_default = AA_None;
1004 static void dec_ref_cache(int index)
1007 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1008 assert(glyphsetCache[index].count > 0);
1009 glyphsetCache[index].count--;
1012 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1014 DWORD hash = 0, *ptr, two_chars;
1018 hash ^= plfsz->devsize.cx;
1019 hash ^= plfsz->devsize.cy;
1020 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1022 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1024 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1026 pwc = (WCHAR *)&two_chars;
1028 *pwc = toupperW(*pwc);
1030 *pwc = toupperW(*pwc);
1038 /***********************************************************************
1039 * X11DRV_XRender_Finalize
1041 void X11DRV_XRender_Finalize(void)
1045 EnterCriticalSection(&xrender_cs);
1046 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1048 LeaveCriticalSection(&xrender_cs);
1052 /***********************************************************************
1053 * X11DRV_XRender_SelectFont
1055 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1058 struct xrender_info *info;
1060 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
1061 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1062 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1063 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1064 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1065 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
1066 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
1068 GetTransform( physDev->hdc, 0x204, &lfsz.xform );
1069 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1070 lfsz.xform.eM21, lfsz.xform.eM22);
1072 /* Not used fields, would break hashing */
1073 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1075 lfsz_calc_hash(&lfsz);
1077 info = get_xrender_info(physDev);
1078 if (!info) return 0;
1080 EnterCriticalSection(&xrender_cs);
1081 if(info->cache_index != -1)
1082 dec_ref_cache(info->cache_index);
1083 info->cache_index = GetCacheEntry(physDev, &lfsz);
1084 LeaveCriticalSection(&xrender_cs);
1088 /***********************************************************************
1089 * X11DRV_XRender_SetDeviceClipping
1091 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
1093 if (physDev->xrender->pict)
1096 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1097 physDev->dc_rect.left, physDev->dc_rect.top,
1098 (XRectangle *)data->Buffer, data->rdh.nCount );
1099 wine_tsx11_unlock();
1103 /***********************************************************************
1104 * X11DRV_XRender_DeleteDC
1106 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1108 X11DRV_XRender_UpdateDrawable(physDev);
1110 EnterCriticalSection(&xrender_cs);
1111 if(physDev->xrender->cache_index != -1)
1112 dec_ref_cache(physDev->xrender->cache_index);
1113 LeaveCriticalSection(&xrender_cs);
1115 HeapFree(GetProcessHeap(), 0, physDev->xrender);
1116 physDev->xrender = NULL;
1120 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1122 const WineXRenderFormat *fmt;
1125 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1126 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1127 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1128 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1133 const DWORD *bitfields;
1134 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1135 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1137 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1138 bitfields = dib->dsBitfields;
1139 else if(bits_pixel == 24 || bits_pixel == 32)
1140 bitfields = bitfields_32;
1142 bitfields = bitfields_16;
1144 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1145 fmt = get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts);
1147 /* Common formats should be in our picture format table. */
1150 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1151 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1157 int red_mask, green_mask, blue_mask;
1159 /* We are dealing with a DDB */
1163 fmt = get_xrender_format(WXR_FORMAT_R5G6B5);
1166 fmt = get_xrender_format(WXR_FORMAT_R8G8B8);
1169 fmt = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1177 TRACE("Unhandled DDB bits_pixel=%d\n", bits_pixel);
1181 red_mask = fmt->pict_format->direct.redMask << fmt->pict_format->direct.red;
1182 green_mask = fmt->pict_format->direct.greenMask << fmt->pict_format->direct.green;
1183 blue_mask = fmt->pict_format->direct.blueMask << fmt->pict_format->direct.blue;
1184 X11DRV_PALETTE_ComputeColorShifts(&shifts, red_mask, green_mask, blue_mask);
1187 physBitmap->pixmap_depth = fmt->pict_format->depth;
1188 physBitmap->trueColor = TRUE;
1189 physBitmap->pixmap_color_shifts = shifts;
1193 /***********************************************************************
1194 * X11DRV_XRender_UpdateDrawable
1196 * Deletes the pict and tile when the drawable changes.
1198 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1200 struct xrender_info *info = physDev->xrender;
1202 if (info->pict || info->pict_src)
1205 XFlush( gdi_display );
1208 TRACE("freeing pict = %lx dc = %p\n", info->pict, physDev->hdc);
1209 pXRenderFreePicture(gdi_display, info->pict);
1214 TRACE("freeing pict = %lx dc = %p\n", info->pict_src, physDev->hdc);
1215 pXRenderFreePicture(gdi_display, info->pict_src);
1218 wine_tsx11_unlock();
1221 info->format = NULL;
1224 /************************************************************************
1227 * Helper to ExtTextOut. Must be called inside xrender_cs
1229 static void UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
1231 unsigned int buflen;
1236 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
1237 gsCacheEntryFormat *formatEntry;
1238 UINT ggo_format = GGO_GLYPH_INDEX;
1239 WXRFormat wxr_format;
1240 static const char zero[4];
1241 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1245 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1248 ggo_format |= WINE_GGO_HRGB_BITMAP;
1251 ggo_format |= WINE_GGO_HBGR_BITMAP;
1254 ggo_format |= WINE_GGO_VRGB_BITMAP;
1257 ggo_format |= WINE_GGO_VBGR_BITMAP;
1261 ERR("aa = %d - not implemented\n", format);
1263 ggo_format |= GGO_BITMAP;
1267 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1268 if(buflen == GDI_ERROR) {
1269 if(format != AA_None) {
1271 entry->aa_default = AA_None;
1272 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1273 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1275 if(buflen == GDI_ERROR) {
1276 WARN("GetGlyphOutlineW failed using default glyph\n");
1277 buflen = GetGlyphOutlineW(physDev->hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1278 if(buflen == GDI_ERROR) {
1279 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1280 buflen = GetGlyphOutlineW(physDev->hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1281 if(buflen == GDI_ERROR) {
1282 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1287 TRACE("Turning off antialiasing for this monochrome font\n");
1290 /* If there is nothing for the current type, we create the entry. */
1291 if( !entry->format[format] ) {
1292 entry->format[format] = HeapAlloc(GetProcessHeap(),
1294 sizeof(gsCacheEntryFormat));
1296 formatEntry = entry->format[format];
1298 if(formatEntry->nrealized <= glyph) {
1299 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1301 if (formatEntry->realized)
1302 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1304 formatEntry->realized,
1305 formatEntry->nrealized * sizeof(BOOL));
1307 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1309 formatEntry->nrealized * sizeof(BOOL));
1311 if(!X11DRV_XRender_Installed) {
1312 if (formatEntry->bitmaps)
1313 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1315 formatEntry->bitmaps,
1316 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1318 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1320 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1322 if (formatEntry->gis)
1323 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1326 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1328 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1330 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1334 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1337 wxr_format = WXR_FORMAT_GRAY;
1344 wxr_format = WXR_FORMAT_A8R8G8B8;
1348 ERR("aa = %d - not implemented\n", format);
1350 wxr_format = WXR_FORMAT_MONO;
1355 formatEntry->font_format = get_xrender_format(wxr_format);
1356 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
1357 wine_tsx11_unlock();
1361 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1362 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1363 formatEntry->realized[glyph] = TRUE;
1365 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1367 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1368 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1370 gi.width = gm.gmBlackBoxX;
1371 gi.height = gm.gmBlackBoxY;
1372 gi.x = -gm.gmptGlyphOrigin.x;
1373 gi.y = gm.gmptGlyphOrigin.y;
1374 gi.xOff = gm.gmCellIncX;
1375 gi.yOff = gm.gmCellIncY;
1377 if(TRACE_ON(xrender)) {
1380 unsigned char *line;
1382 if(format == AA_None) {
1383 pitch = ((gi.width + 31) / 32) * 4;
1384 for(i = 0; i < gi.height; i++) {
1385 line = (unsigned char*) buf + i * pitch;
1387 for(j = 0; j < pitch * 8; j++) {
1388 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1390 TRACE("%s\n", output);
1393 static const char blks[] = " .:;!o*#";
1397 pitch = ((gi.width + 3) / 4) * 4;
1398 for(i = 0; i < gi.height; i++) {
1399 line = (unsigned char*) buf + i * pitch;
1401 for(j = 0; j < pitch; j++) {
1402 str[0] = blks[line[j] >> 5];
1403 strcat(output, str);
1405 TRACE("%s\n", output);
1411 if(formatEntry->glyphset) {
1412 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1413 unsigned char *byte = (unsigned char*) buf, c;
1419 /* magic to flip bit order */
1420 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1421 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1422 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1427 else if ( format != AA_Grey &&
1428 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1430 unsigned int i, *data = (unsigned int *)buf;
1431 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1436 XRenderCompositeText seems to ignore 0x0 glyphs when
1437 AA_None, which means we lose the advance width of glyphs
1438 like the space. We'll pretend that such glyphs are 1x1
1443 gi.width = gi.height = 1;
1446 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1447 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1448 wine_tsx11_unlock();
1449 HeapFree(GetProcessHeap(), 0, buf);
1451 formatEntry->bitmaps[glyph] = buf;
1454 formatEntry->gis[glyph] = gi;
1457 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
1458 void *bitmap, XGlyphInfo *gi)
1460 unsigned char *srcLine = bitmap, *src;
1461 unsigned char bits, bitsMask;
1462 int width = gi->width;
1463 int stride = ((width + 31) & ~31) >> 3;
1464 int height = gi->height;
1468 TRACE("%d, %d\n", x, y);
1477 bitsMask = 0x80; /* FreeType is always MSB first */
1483 if (bits & bitsMask)
1491 bitsMask = bitsMask >> 1;
1497 } while (bits & bitsMask);
1498 XFillRectangle (gdi_display, physDev->drawable,
1499 physDev->gc, xspan, y, lenspan, 1);
1511 bitsMask = bitsMask >> 1;
1517 } while (!(bits & bitsMask));
1524 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
1525 void *bitmap, XGlyphInfo *gi)
1527 unsigned char *srcLine = bitmap, *src, bits;
1528 int width = gi->width;
1529 int stride = ((width + 3) & ~3);
1530 int height = gi->height;
1555 } while (bits >= 0x80);
1556 XFillRectangle (gdi_display, physDev->drawable,
1557 physDev->gc, xspan, y, lenspan, 1);
1570 } while (bits < 0x80);
1578 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1583 while ((mask & 1) == 0)
1589 while ((mask & 1) == 1)
1598 static DWORD GetField (DWORD pixel, int shift, int len)
1600 pixel = pixel & (((1 << (len)) - 1) << shift);
1601 pixel = pixel << (32 - (shift + len)) >> 24;
1604 pixel |= (pixel >> len);
1611 static DWORD PutField (DWORD pixel, int shift, int len)
1613 shift = shift - (8 - len);
1615 pixel &= (((1 << len) - 1) << (8 - len));
1623 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1629 BYTE *maskLine, *mask, m;
1634 BYTE src_r, src_g, src_b;
1639 height = gi->height;
1642 maskStride = (width + 3) & ~3;
1644 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1645 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1646 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1648 src_r = GetField(color, r_shift, r_len);
1649 src_g = GetField(color, g_shift, g_len);
1650 src_b = GetField(color, b_shift, b_len);
1652 for(; height--; y++)
1655 maskLine += maskStride;
1660 if(y >= image->height) break;
1664 if(tx >= image->width) break;
1667 if(tx < 0) continue;
1670 XPutPixel (image, tx, y, color);
1675 pixel = XGetPixel (image, tx, y);
1677 r = GetField(pixel, r_shift, r_len);
1678 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1679 g = GetField(pixel, g_shift, g_len);
1680 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1681 b = GetField(pixel, b_shift, b_len);
1682 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1684 pixel = (PutField (r, r_shift, r_len) |
1685 PutField (g, g_shift, g_len) |
1686 PutField (b, b_shift, b_len));
1687 XPutPixel (image, tx, y, pixel);
1693 /*************************************************************
1696 * Returns an appropriate Picture for tiling the text colour.
1697 * Call and use result within the xrender_cs
1699 static Picture get_tile_pict(const WineXRenderFormat *wxr_format, int text_pixel)
1706 } tiles[WXR_NB_FORMATS], *tile;
1709 tile = &tiles[wxr_format->format];
1713 XRenderPictureAttributes pa;
1716 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1718 pa.repeat = RepeatNormal;
1719 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1720 wine_tsx11_unlock();
1722 /* init current_color to something different from text_pixel */
1723 tile->current_color = ~text_pixel;
1725 if(wxr_format->format == WXR_FORMAT_MONO)
1727 /* for a 1bpp bitmap we always need a 1 in the tile */
1728 col.red = col.green = col.blue = 0;
1731 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1732 wine_tsx11_unlock();
1736 if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1738 get_xrender_color(wxr_format, text_pixel, &col);
1740 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1741 wine_tsx11_unlock();
1742 tile->current_color = text_pixel;
1747 /*************************************************************
1750 * Returns an appropriate Picture for masking with the specified alpha.
1751 * Call and use result within the xrender_cs
1753 static Picture get_mask_pict( int alpha )
1755 static Pixmap pixmap;
1756 static Picture pict;
1757 static int current_alpha;
1759 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1763 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
1764 XRenderPictureAttributes pa;
1767 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1768 pa.repeat = RepeatNormal;
1769 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format, CPRepeat, &pa );
1770 wine_tsx11_unlock();
1774 if (alpha != current_alpha)
1777 col.red = col.green = col.blue = 0;
1778 col.alpha = current_alpha = alpha;
1780 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1781 wine_tsx11_unlock();
1786 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1791 /********************************************************************
1792 * is_dib_with_colortable
1794 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1796 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1800 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1801 dib.dsBmih.biBitCount <= 8 )
1807 /***********************************************************************
1808 * X11DRV_XRender_ExtTextOut
1810 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1811 const RECT *lprect, LPCWSTR wstr, UINT count,
1815 gsCacheEntry *entry;
1816 gsCacheEntryFormat *formatEntry;
1818 int textPixel, backgroundPixel;
1819 HRGN saved_region = 0;
1820 BOOL disable_antialias = FALSE;
1821 AA_Type aa_type = AA_None;
1823 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
1824 Picture tile_pict = 0;
1826 if(is_dib_with_colortable( physDev ))
1828 TRACE("Disabling antialiasing\n");
1829 disable_antialias = TRUE;
1832 xgcval.function = GXcopy;
1833 xgcval.background = physDev->backgroundPixel;
1834 xgcval.fill_style = FillSolid;
1836 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1837 wine_tsx11_unlock();
1839 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1841 if(physDev->depth == 1) {
1842 if((physDev->textPixel & 0xffffff) == 0) {
1844 backgroundPixel = 1;
1847 backgroundPixel = 0;
1850 textPixel = physDev->textPixel;
1851 backgroundPixel = physDev->backgroundPixel;
1854 if(flags & ETO_OPAQUE)
1857 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1858 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1859 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1860 lprect->right - lprect->left, lprect->bottom - lprect->top );
1861 wine_tsx11_unlock();
1870 if (flags & ETO_CLIPPED)
1874 clip_region = CreateRectRgnIndirect( lprect );
1875 /* make a copy of the current device region */
1876 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1877 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1878 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1879 DeleteObject( clip_region );
1882 EnterCriticalSection(&xrender_cs);
1884 entry = glyphsetCache + physDev->xrender->cache_index;
1885 if( disable_antialias == FALSE )
1886 aa_type = entry->aa_default;
1887 formatEntry = entry->format[aa_type];
1889 for(idx = 0; idx < count; idx++) {
1890 if( !formatEntry ) {
1891 UploadGlyph(physDev, wstr[idx], aa_type);
1892 /* re-evaluate antialias since aa_default may have changed */
1893 if( disable_antialias == FALSE )
1894 aa_type = entry->aa_default;
1895 formatEntry = entry->format[aa_type];
1896 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1897 UploadGlyph(physDev, wstr[idx], aa_type);
1902 WARN("could not upload requested glyphs\n");
1903 LeaveCriticalSection(&xrender_cs);
1907 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1908 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1910 if(X11DRV_XRender_Installed)
1912 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1913 POINT offset = {0, 0};
1914 POINT desired, current;
1915 int render_op = PictOpOver;
1916 Picture pict = get_xrender_picture(physDev);
1918 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1919 So we pass zeros to the function and move to our starting position using the first
1920 element of the elts array. */
1922 desired.x = physDev->dc_rect.left + x;
1923 desired.y = physDev->dc_rect.top + y;
1924 current.x = current.y = 0;
1926 tile_pict = get_tile_pict(dst_format, physDev->textPixel);
1928 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1930 if((dst_format->format == WXR_FORMAT_MONO) && (textPixel == 0))
1931 render_op = PictOpOutReverse; /* This gives us 'black' text */
1933 for(idx = 0; idx < count; idx++)
1935 elts[idx].glyphset = formatEntry->glyphset;
1936 elts[idx].chars = wstr + idx;
1937 elts[idx].nchars = 1;
1938 elts[idx].xOff = desired.x - current.x;
1939 elts[idx].yOff = desired.y - current.y;
1941 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1942 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1946 desired.x += formatEntry->gis[wstr[idx]].xOff;
1947 desired.y += formatEntry->gis[wstr[idx]].yOff;
1953 offset.x += lpDx[idx * 2];
1954 offset.y += lpDx[idx * 2 + 1];
1957 offset.x += lpDx[idx];
1958 desired.x = physDev->dc_rect.left + x + offset.x;
1959 desired.y = physDev->dc_rect.top + y + offset.y;
1963 /* Make sure we don't have any transforms set from a previous call */
1964 set_xrender_transformation(pict, 1, 1, 0, 0);
1965 pXRenderCompositeText16(gdi_display, render_op,
1968 formatEntry->font_format->pict_format,
1969 0, 0, 0, 0, elts, count);
1970 wine_tsx11_unlock();
1971 HeapFree(GetProcessHeap(), 0, elts);
1973 POINT offset = {0, 0};
1975 XSetForeground( gdi_display, physDev->gc, textPixel );
1977 if(aa_type == AA_None || physDev->depth == 1)
1979 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1981 if(aa_type == AA_None)
1982 sharp_glyph_fn = SharpGlyphMono;
1984 sharp_glyph_fn = SharpGlyphGray;
1986 for(idx = 0; idx < count; idx++) {
1987 sharp_glyph_fn(physDev,
1988 physDev->dc_rect.left + x + offset.x,
1989 physDev->dc_rect.top + y + offset.y,
1990 formatEntry->bitmaps[wstr[idx]],
1991 &formatEntry->gis[wstr[idx]]);
1996 offset.x += lpDx[idx * 2];
1997 offset.y += lpDx[idx * 2 + 1];
2000 offset.x += lpDx[idx];
2004 offset.x += formatEntry->gis[wstr[idx]].xOff;
2005 offset.y += formatEntry->gis[wstr[idx]].yOff;
2010 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2011 RECT extents = {0, 0, 0, 0};
2013 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
2014 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
2016 TRACE("drawable %dx%d\n", w, h);
2018 for(idx = 0; idx < count; idx++) {
2019 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2020 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2021 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2022 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2023 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2024 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2025 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2026 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2032 cur.x += lpDx[idx * 2];
2033 cur.y += lpDx[idx * 2 + 1];
2040 cur.x += formatEntry->gis[wstr[idx]].xOff;
2041 cur.y += formatEntry->gis[wstr[idx]].yOff;
2044 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2045 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
2047 if(physDev->dc_rect.left + x + extents.left >= 0) {
2048 image_x = physDev->dc_rect.left + x + extents.left;
2052 image_off_x = physDev->dc_rect.left + x + extents.left;
2054 if(physDev->dc_rect.top + y + extents.top >= 0) {
2055 image_y = physDev->dc_rect.top + y + extents.top;
2059 image_off_y = physDev->dc_rect.top + y + extents.top;
2061 if(physDev->dc_rect.left + x + extents.right < w)
2062 image_w = physDev->dc_rect.left + x + extents.right - image_x;
2064 image_w = w - image_x;
2065 if(physDev->dc_rect.top + y + extents.bottom < h)
2066 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
2068 image_h = h - image_y;
2070 if(image_w <= 0 || image_h <= 0) goto no_image;
2072 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2073 image = XGetImage(gdi_display, physDev->drawable,
2074 image_x, image_y, image_w, image_h,
2075 AllPlanes, ZPixmap);
2076 X11DRV_check_error();
2078 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2079 gdi_display, (int)physDev->drawable, image_x, image_y,
2080 image_w, image_h, AllPlanes, ZPixmap,
2081 physDev->depth, image);
2083 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2088 gcv.graphics_exposures = False;
2089 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2090 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
2091 image_w, image_h, 0, 0);
2092 XFreeGC(gdi_display, gc);
2093 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2094 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2096 X11DRV_check_error();
2097 XFreePixmap(gdi_display, xpm);
2099 if(!image) goto no_image;
2101 image->red_mask = visual->red_mask;
2102 image->green_mask = visual->green_mask;
2103 image->blue_mask = visual->blue_mask;
2105 for(idx = 0; idx < count; idx++) {
2106 SmoothGlyphGray(image,
2107 offset.x + image_off_x - extents.left,
2108 offset.y + image_off_y - extents.top,
2109 formatEntry->bitmaps[wstr[idx]],
2110 &formatEntry->gis[wstr[idx]],
2111 physDev->textPixel);
2116 offset.x += lpDx[idx * 2];
2117 offset.y += lpDx[idx * 2 + 1];
2120 offset.x += lpDx[idx];
2124 offset.x += formatEntry->gis[wstr[idx]].xOff;
2125 offset.y += formatEntry->gis[wstr[idx]].yOff;
2128 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
2129 image_x, image_y, image_w, image_h);
2130 XDestroyImage(image);
2133 wine_tsx11_unlock();
2135 LeaveCriticalSection(&xrender_cs);
2137 if (flags & ETO_CLIPPED)
2139 /* restore the device region */
2140 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
2141 DeleteObject( saved_region );
2147 X11DRV_UnlockDIBSection( physDev, TRUE );
2151 /* Helper function for (stretched) blitting using xrender */
2152 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2153 int x_src, int y_src, int x_dst, int y_dst,
2154 double xscale, double yscale, int width, int height )
2156 int x_offset, y_offset;
2158 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2159 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2160 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2161 if(xscale != 1.0 || yscale != 1.0)
2163 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2164 * in the wrong quadrant of the x-y plane.
2166 x_offset = (xscale < 0) ? -width : 0;
2167 y_offset = (yscale < 0) ? -height : 0;
2168 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2174 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2176 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2177 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2180 /* Helper function for (stretched) mono->color blitting using xrender */
2181 static void xrender_mono_blit( Picture src_pict, Picture mask_pict, Picture dst_pict,
2182 int x_src, int y_src, double xscale, double yscale, int width, int height )
2184 int x_offset, y_offset;
2186 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2187 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
2188 * tile data. We need PictOpOver for correct rendering.
2189 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2192 if (xscale != 1.0 || yscale != 1.0)
2194 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2195 * in the wrong quadrant of the x-y plane.
2197 x_offset = (xscale < 0) ? -width : 0;
2198 y_offset = (yscale < 0) ? -height : 0;
2199 set_xrender_transformation(mask_pict, xscale, yscale, x_src, y_src);
2205 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
2207 pXRenderComposite(gdi_display, PictOpOver, src_pict, mask_pict, dst_pict,
2208 0, 0, x_offset, y_offset, 0, 0, width, height);
2211 /******************************************************************************
2214 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2215 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2217 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2218 struct xrender_info *src_info = get_xrender_info( devSrc );
2219 double xscale, yscale;
2222 if(!X11DRV_XRender_Installed) {
2223 FIXME("Unable to AlphaBlend without Xrender\n");
2227 if (devSrc != devDst) X11DRV_LockDIBSection( devSrc, DIB_Status_GdiMod );
2228 X11DRV_LockDIBSection( devDst, DIB_Status_GdiMod );
2230 dst_pict = get_xrender_picture( devDst );
2232 use_repeat = use_source_repeat( devSrc );
2235 xscale = src->width / (double)dst->width;
2236 yscale = src->height / (double)dst->height;
2238 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2240 if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && src_info->format)
2242 /* we need a source picture with no alpha */
2243 WXRFormat format = get_format_without_alpha( src_info->format->format );
2244 if (format != src_info->format->format)
2246 XRenderPictureAttributes pa;
2247 const WineXRenderFormat *fmt = get_xrender_format( format );
2250 pa.subwindow_mode = IncludeInferiors;
2251 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2252 tmp_pict = pXRenderCreatePicture( gdi_display, devSrc->drawable, fmt->pict_format,
2253 CPSubwindowMode|CPRepeat, &pa );
2254 wine_tsx11_unlock();
2255 src_pict = tmp_pict;
2259 if (!src_pict) src_pict = get_xrender_picture_source( devSrc, use_repeat );
2261 EnterCriticalSection( &xrender_cs );
2262 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2265 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2266 devSrc->dc_rect.left + src->visrect.left, devSrc->dc_rect.top + src->visrect.top,
2267 devDst->dc_rect.left + dst->visrect.left, devDst->dc_rect.top + dst->visrect.top,
2269 dst->visrect.right - dst->visrect.left, dst->visrect.bottom - dst->visrect.top );
2270 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2271 wine_tsx11_unlock();
2273 LeaveCriticalSection( &xrender_cs );
2274 if (devSrc != devDst) X11DRV_UnlockDIBSection( devSrc, FALSE );
2275 X11DRV_UnlockDIBSection( devDst, TRUE );
2280 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2282 /* 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 */
2283 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2284 const WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2285 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2288 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2290 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2291 if( (physBitmap->pixmap_depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->pixmap_depth) ||
2292 (src_format->format == dst_format->format) )
2294 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2295 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2297 else /* We need depth conversion */
2299 Picture src_pict, dst_pict;
2300 XRenderPictureAttributes pa;
2301 pa.subwindow_mode = IncludeInferiors;
2302 pa.repeat = RepeatNone;
2304 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2305 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2307 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2308 pXRenderFreePicture(gdi_display, src_pict);
2309 pXRenderFreePicture(gdi_display, dst_pict);
2311 wine_tsx11_unlock();
2314 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2315 Pixmap pixmap, GC gc,
2316 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2318 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2319 int width = dst->visrect.right - dst->visrect.left;
2320 int height = dst->visrect.bottom - dst->visrect.top;
2321 int x_src = physDevSrc->dc_rect.left + src->visrect.left;
2322 int y_src = physDevSrc->dc_rect.top + src->visrect.top;
2323 struct xrender_info *src_info = get_xrender_info(physDevSrc);
2324 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDevDst->depth, physDevDst->color_shifts);
2325 Picture src_pict=0, dst_pict=0, mask_pict=0;
2327 double xscale, yscale;
2329 XRenderPictureAttributes pa;
2330 pa.subwindow_mode = IncludeInferiors;
2331 pa.repeat = RepeatNone;
2333 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2334 physDevSrc->depth, src->width, src->height, x_src, y_src);
2335 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst->depth, dst->width, dst->height);
2337 if(!X11DRV_XRender_Installed)
2339 TRACE("Not using XRender since it is not available or disabled\n");
2343 /* XRender can't handle palettes, so abort */
2344 if(X11DRV_PALETTE_XPixelToPalette)
2347 /* XRender is of no use in this case */
2348 if((physDevDst->depth == 1) && (physDevSrc->depth > 1))
2351 /* Just use traditional X copy when the formats match and we don't need stretching */
2352 if((src_info->format->format == dst_format->format) && !stretch)
2354 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2356 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
2357 wine_tsx11_unlock();
2361 use_repeat = use_source_repeat( physDevSrc );
2364 xscale = src->width / (double)dst->width;
2365 yscale = src->height / (double)dst->height;
2367 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2370 if(physDevSrc->depth == 1 && physDevDst->depth > 1)
2373 get_xrender_color(dst_format, physDevDst->textPixel, &col);
2375 /* We use the source drawable as a mask */
2376 mask_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2378 /* Use backgroundPixel as the foreground color */
2379 EnterCriticalSection( &xrender_cs );
2380 src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
2382 /* Create a destination picture and fill it with textPixel color as the background color */
2384 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2385 pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height);
2387 xrender_mono_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
2389 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2390 wine_tsx11_unlock();
2391 LeaveCriticalSection( &xrender_cs );
2393 else /* color -> color (can be at different depths) or mono -> mono */
2395 if (physDevDst->depth == 32 && physDevSrc->depth < 32) mask_pict = get_no_alpha_mask();
2396 src_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2399 dst_pict = pXRenderCreatePicture(gdi_display,
2400 pixmap, dst_format->pict_format,
2401 CPSubwindowMode|CPRepeat, &pa);
2403 xrender_blit(PictOpSrc, src_pict, mask_pict, dst_pict,
2404 x_src, y_src, 0, 0, xscale, yscale, width, height);
2406 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2407 wine_tsx11_unlock();
2412 #else /* SONAME_LIBXRENDER */
2414 void X11DRV_XRender_Init(void)
2416 TRACE("XRender support not compiled in.\n");
2420 void X11DRV_XRender_Finalize(void)
2424 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
2430 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
2436 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
2442 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
2443 const RECT *lprect, LPCWSTR wstr, UINT count,
2450 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
2456 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2457 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2459 FIXME("not supported - XRENDER headers were missing at compile time\n");
2463 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2466 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
2468 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2469 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2470 wine_tsx11_unlock();
2473 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2478 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2479 Pixmap pixmap, GC gc,
2480 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2484 #endif /* SONAME_LIBXRENDER */