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 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
350 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
351 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
354 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
355 LOAD_FUNCPTR(XRenderAddGlyphs)
356 LOAD_FUNCPTR(XRenderComposite)
357 LOAD_FUNCPTR(XRenderCompositeString8)
358 LOAD_FUNCPTR(XRenderCompositeString16)
359 LOAD_FUNCPTR(XRenderCompositeString32)
360 LOAD_FUNCPTR(XRenderCompositeText16)
361 LOAD_FUNCPTR(XRenderCreateGlyphSet)
362 LOAD_FUNCPTR(XRenderCreatePicture)
363 LOAD_FUNCPTR(XRenderFillRectangle)
364 LOAD_FUNCPTR(XRenderFindFormat)
365 LOAD_FUNCPTR(XRenderFindVisualFormat)
366 LOAD_FUNCPTR(XRenderFreeGlyphSet)
367 LOAD_FUNCPTR(XRenderFreePicture)
368 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
369 LOAD_FUNCPTR(XRenderQueryExtension)
371 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
372 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
373 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
374 #undef LOAD_OPTIONAL_FUNCPTR
378 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
380 if(X11DRV_XRender_Installed) {
381 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
382 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
386 "Wine has detected that you probably have a buggy version\n"
387 "of libXrender.so . Because of this client side font rendering\n"
388 "will be disabled. Please upgrade this library.\n");
389 X11DRV_XRender_Installed = FALSE;
393 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
394 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
395 X11DRV_XRender_Installed = FALSE;
400 #ifdef SONAME_LIBFONTCONFIG
401 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
403 #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;}
404 LOAD_FUNCPTR(FcConfigSubstitute);
405 LOAD_FUNCPTR(FcDefaultSubstitute);
406 LOAD_FUNCPTR(FcFontMatch);
407 LOAD_FUNCPTR(FcInit);
408 LOAD_FUNCPTR(FcPatternCreate);
409 LOAD_FUNCPTR(FcPatternDestroy);
410 LOAD_FUNCPTR(FcPatternAddInteger);
411 LOAD_FUNCPTR(FcPatternAddString);
412 LOAD_FUNCPTR(FcPatternGetBool);
413 LOAD_FUNCPTR(FcPatternGetInteger);
414 LOAD_FUNCPTR(FcPatternGetString);
416 fontconfig_installed = pFcInit();
418 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
422 if(X11DRV_XRender_Installed || client_side_with_core)
424 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
425 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
427 glyphsetCacheSize = INIT_CACHE_SIZE;
429 for(i = 0; i < INIT_CACHE_SIZE; i++) {
430 glyphsetCache[i].next = i + 1;
431 glyphsetCache[i].count = -1;
433 glyphsetCache[i-1].next = -1;
434 using_client_side_fonts = 1;
436 if(!X11DRV_XRender_Installed) {
437 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
438 if(screen_depth <= 8 || !client_side_antialias_with_core)
441 if(screen_depth <= 8 || !client_side_antialias_with_render)
445 else TRACE("Using X11 core fonts\n");
448 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
449 static void get_xrender_color(const WineXRenderFormat *wxr_format, int src_color, XRenderColor *dst_color)
451 XRenderPictFormat *pf = wxr_format->pict_format;
453 if(pf->direct.redMask)
454 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
458 if(pf->direct.greenMask)
459 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
461 dst_color->green = 0;
463 if(pf->direct.blueMask)
464 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
468 dst_color->alpha = 0xffff;
471 static const WineXRenderFormat *get_xrender_format(WXRFormat format)
474 for(i=0; i<WineXRenderFormatsListSize; i++)
476 if(wxr_formats[i].format == format)
478 TRACE("Returning wxr_format=%#x\n", format);
479 return &wxr_formats[i];
485 static const WineXRenderFormat *get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
487 int redMask, greenMask, blueMask;
491 return get_xrender_format(WXR_FORMAT_MONO);
493 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
495 return default_format;
497 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
498 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
499 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
501 /* Try to locate a format which matches the specification of the dibsection. */
502 for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
504 if( depth == wxr_formats_template[i].depth &&
505 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
506 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
507 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
510 /* When we reach this stage the format was found in our template table but this doesn't mean that
511 * the Xserver also supports this format (e.g. its depth might be too low). The call below verifies that.
513 return get_xrender_format(wxr_formats_template[i].wxr_format);
517 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
518 ERR("No XRender format found!\n");
522 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
523 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
525 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
526 XTransform xform = {{
527 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
528 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
529 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
532 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
536 /* check if we can use repeating instead of scaling for the specified source DC */
537 static BOOL use_source_repeat( X11DRV_PDEVICE *physDev )
539 return (physDev->bitmap &&
540 physDev->drawable_rect.right - physDev->drawable_rect.left == 1 &&
541 physDev->drawable_rect.bottom - physDev->drawable_rect.top == 1);
544 static struct xrender_info *get_xrender_info(X11DRV_PDEVICE *physDev)
546 if(!physDev->xrender)
548 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physDev->xrender));
550 if(!physDev->xrender)
552 ERR("Unable to allocate XRENDERINFO!\n");
555 physDev->xrender->cache_index = -1;
557 if (!physDev->xrender->format)
558 physDev->xrender->format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
560 return physDev->xrender;
563 static Picture get_xrender_picture(X11DRV_PDEVICE *physDev)
565 struct xrender_info *info = get_xrender_info(physDev);
568 if (!info->pict && info->format)
570 XRenderPictureAttributes pa;
571 RGNDATA *clip = X11DRV_GetRegionData( physDev->region, 0 );
574 pa.subwindow_mode = IncludeInferiors;
575 info->pict = pXRenderCreatePicture(gdi_display, physDev->drawable, info->format->pict_format,
576 CPSubwindowMode, &pa);
577 if (info->pict && clip)
578 pXRenderSetPictureClipRectangles( gdi_display, info->pict,
579 physDev->dc_rect.left, physDev->dc_rect.top,
580 (XRectangle *)clip->Buffer, clip->rdh.nCount );
582 TRACE("Allocing pict=%lx dc=%p drawable=%08lx\n", info->pict, physDev->hdc, physDev->drawable);
583 HeapFree( GetProcessHeap(), 0, clip );
589 static Picture get_xrender_picture_source(X11DRV_PDEVICE *physDev, BOOL repeat)
591 struct xrender_info *info = get_xrender_info(physDev);
594 if (!info->pict_src && info->format)
596 XRenderPictureAttributes pa;
599 pa.subwindow_mode = IncludeInferiors;
600 pa.repeat = repeat ? RepeatNormal : RepeatNone;
601 info->pict_src = pXRenderCreatePicture(gdi_display, physDev->drawable, info->format->pict_format,
602 CPSubwindowMode|CPRepeat, &pa);
605 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
606 info->pict_src, physDev->hdc, physDev->drawable, pa.repeat);
609 return info->pict_src;
612 /* return a mask picture used to force alpha to 0 */
613 static Picture get_no_alpha_mask(void)
615 static Pixmap pixmap;
621 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
622 XRenderPictureAttributes pa;
625 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
626 pa.repeat = RepeatNormal;
627 pa.component_alpha = True;
628 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format,
629 CPRepeat|CPComponentAlpha, &pa );
630 col.red = col.green = col.blue = 0xffff;
632 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
638 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
640 if(p1->hash != p2->hash) return TRUE;
641 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
642 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
643 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
644 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
648 static void walk_cache(void)
652 EnterCriticalSection(&xrender_cs);
653 for(i=mru; i >= 0; i = glyphsetCache[i].next)
654 TRACE("item %d\n", i);
655 LeaveCriticalSection(&xrender_cs);
659 static int LookupEntry(LFANDSIZE *plfsz)
663 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
665 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
670 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
671 glyphsetCache[i].count++;
673 glyphsetCache[prev_i].next = glyphsetCache[i].next;
674 glyphsetCache[i].next = mru;
677 TRACE("found font in cache %d\n", i);
682 TRACE("font not in cache\n");
686 static void FreeEntry(int entry)
690 for(format = 0; format < AA_MAXVALUE; format++) {
691 gsCacheEntryFormat * formatEntry;
693 if( !glyphsetCache[entry].format[format] )
696 formatEntry = glyphsetCache[entry].format[format];
698 if(formatEntry->glyphset) {
700 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
702 formatEntry->glyphset = 0;
704 if(formatEntry->nrealized) {
705 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
706 formatEntry->realized = NULL;
707 if(formatEntry->bitmaps) {
708 for(i = 0; i < formatEntry->nrealized; i++)
709 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
710 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
711 formatEntry->bitmaps = NULL;
713 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
714 formatEntry->gis = NULL;
715 formatEntry->nrealized = 0;
718 HeapFree(GetProcessHeap(), 0, formatEntry);
719 glyphsetCache[entry].format[format] = NULL;
723 static int AllocEntry(void)
725 int best = -1, prev_best = -1, i, prev_i = -1;
728 assert(glyphsetCache[lastfree].count == -1);
729 glyphsetCache[lastfree].count = 1;
731 lastfree = glyphsetCache[lastfree].next;
733 glyphsetCache[best].next = mru;
736 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
740 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
741 if(glyphsetCache[i].count == 0) {
749 TRACE("freeing unused glyphset at cache %d\n", best);
751 glyphsetCache[best].count = 1;
753 glyphsetCache[prev_best].next = glyphsetCache[best].next;
754 glyphsetCache[best].next = mru;
762 TRACE("Growing cache\n");
765 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
767 (glyphsetCacheSize + INIT_CACHE_SIZE)
768 * sizeof(*glyphsetCache));
770 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
771 (glyphsetCacheSize + INIT_CACHE_SIZE)
772 * sizeof(*glyphsetCache));
774 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
776 glyphsetCache[i].next = i + 1;
777 glyphsetCache[i].count = -1;
779 glyphsetCache[i-1].next = -1;
780 glyphsetCacheSize += INIT_CACHE_SIZE;
782 lastfree = glyphsetCache[best].next;
783 glyphsetCache[best].count = 1;
784 glyphsetCache[best].next = mru;
786 TRACE("new free cache slot at %d\n", mru);
790 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
800 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
801 if(size == GDI_ERROR)
804 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
805 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
807 GetTextMetricsW(physDev->hdc, &tm);
808 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
811 num_recs = get_be_word(*gasp);
815 *flags = get_be_word(*(gasp + 1));
816 if(ppem <= get_be_word(*gasp))
820 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
822 HeapFree(GetProcessHeap(), 0, buffer);
826 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
830 UINT font_smoothing_type, font_smoothing_orientation;
832 if (X11DRV_XRender_Installed && subpixel &&
833 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
834 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
836 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
837 &font_smoothing_orientation, 0) &&
838 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
845 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
846 But, Wine's subpixel rendering can support the portrait mode.
849 else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
857 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
862 static int hinter = -1;
863 static int subpixel = -1;
866 if((ret = LookupEntry(plfsz)) != -1) return ret;
869 entry = glyphsetCache + ret;
870 entry->lfsz = *plfsz;
871 for( format = 0; format < AA_MAXVALUE; format++ ) {
872 assert( !entry->format[format] );
875 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
877 if(hinter == -1 || subpixel == -1)
879 RASTERIZER_STATUS status;
880 GetRasterizerCaps(&status, sizeof(status));
881 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
882 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
885 switch (plfsz->lf.lfQuality)
887 case ANTIALIASED_QUALITY:
888 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
889 return ret; /* ignore further configuration */
890 case CLEARTYPE_QUALITY:
891 case CLEARTYPE_NATURAL_QUALITY:
892 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
894 case DEFAULT_QUALITY:
898 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
901 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
904 entry->aa_default = AA_None;
908 font_smoothing = TRUE; /* default to enabled */
909 #ifdef SONAME_LIBFONTCONFIG
910 if (fontconfig_installed)
912 FcPattern *match, *pattern = pFcPatternCreate();
914 char family[LF_FACESIZE * 4];
916 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
917 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
918 if (plfsz->lf.lfWeight != FW_DONTCARE)
921 switch (plfsz->lf.lfWeight)
923 case FW_THIN: weight = FC_WEIGHT_THIN; break;
924 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
925 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
926 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
927 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
928 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
929 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
930 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
931 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
932 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
934 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
936 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
937 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
938 pFcDefaultSubstitute( pattern );
939 if ((match = pFcFontMatch( NULL, pattern, &result )))
944 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
946 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
949 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
951 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
952 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
956 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
957 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
958 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
959 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
960 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
963 if (!antialias) font_smoothing = FALSE;
964 pFcPatternDestroy( match );
966 pFcPatternDestroy( pattern );
968 #endif /* SONAME_LIBFONTCONFIG */
970 /* now check Xft resources */
973 BOOL antialias = TRUE;
976 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
978 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
979 value[0] == '0' || !strcasecmp( value, "off" ))
982 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
984 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
985 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
986 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
987 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
988 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
989 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
992 if (!antialias) font_smoothing = FALSE;
995 if (!font_smoothing) entry->aa_default = AA_None;
997 /* we can't support subpixel without xrender */
998 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1001 entry->aa_default = AA_None;
1006 static void dec_ref_cache(int index)
1009 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1010 assert(glyphsetCache[index].count > 0);
1011 glyphsetCache[index].count--;
1014 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1016 DWORD hash = 0, *ptr, two_chars;
1020 hash ^= plfsz->devsize.cx;
1021 hash ^= plfsz->devsize.cy;
1022 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1024 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1026 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1028 pwc = (WCHAR *)&two_chars;
1030 *pwc = toupperW(*pwc);
1032 *pwc = toupperW(*pwc);
1040 /***********************************************************************
1041 * X11DRV_XRender_Finalize
1043 void X11DRV_XRender_Finalize(void)
1047 EnterCriticalSection(&xrender_cs);
1048 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1050 LeaveCriticalSection(&xrender_cs);
1054 /***********************************************************************
1055 * X11DRV_XRender_SelectFont
1057 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1060 struct xrender_info *info;
1062 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
1063 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1064 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1065 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1066 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1067 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
1068 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
1069 GetWorldTransform( physDev->hdc, &lfsz.xform );
1070 /* Not used fields, would break hashing */
1071 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1073 lfsz_calc_hash(&lfsz);
1075 info = get_xrender_info(physDev);
1076 if (!info) return 0;
1078 EnterCriticalSection(&xrender_cs);
1079 if(info->cache_index != -1)
1080 dec_ref_cache(info->cache_index);
1081 info->cache_index = GetCacheEntry(physDev, &lfsz);
1082 LeaveCriticalSection(&xrender_cs);
1086 /***********************************************************************
1087 * X11DRV_XRender_SetDeviceClipping
1089 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
1091 if (physDev->xrender->pict)
1094 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1095 physDev->dc_rect.left, physDev->dc_rect.top,
1096 (XRectangle *)data->Buffer, data->rdh.nCount );
1097 wine_tsx11_unlock();
1101 /***********************************************************************
1102 * X11DRV_XRender_DeleteDC
1104 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1106 X11DRV_XRender_UpdateDrawable(physDev);
1108 EnterCriticalSection(&xrender_cs);
1109 if(physDev->xrender->cache_index != -1)
1110 dec_ref_cache(physDev->xrender->cache_index);
1111 LeaveCriticalSection(&xrender_cs);
1113 HeapFree(GetProcessHeap(), 0, physDev->xrender);
1114 physDev->xrender = NULL;
1118 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1120 const WineXRenderFormat *fmt;
1123 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1124 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1125 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1126 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1131 X11DRV_PALETTE_ComputeColorShifts(&shifts, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
1132 fmt = get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts);
1134 /* Common formats should be in our picture format table. */
1137 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1138 dib->dsBm.bmBitsPixel, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
1144 int red_mask, green_mask, blue_mask;
1146 /* We are dealing with a DDB */
1150 fmt = get_xrender_format(WXR_FORMAT_R5G6B5);
1153 fmt = get_xrender_format(WXR_FORMAT_R8G8B8);
1156 fmt = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1164 TRACE("Unhandled DDB bits_pixel=%d\n", bits_pixel);
1168 red_mask = fmt->pict_format->direct.redMask << fmt->pict_format->direct.red;
1169 green_mask = fmt->pict_format->direct.greenMask << fmt->pict_format->direct.green;
1170 blue_mask = fmt->pict_format->direct.blueMask << fmt->pict_format->direct.blue;
1171 X11DRV_PALETTE_ComputeColorShifts(&shifts, red_mask, green_mask, blue_mask);
1174 physBitmap->pixmap_depth = fmt->pict_format->depth;
1175 physBitmap->trueColor = TRUE;
1176 physBitmap->pixmap_color_shifts = shifts;
1180 /***********************************************************************
1181 * X11DRV_XRender_UpdateDrawable
1183 * Deletes the pict and tile when the drawable changes.
1185 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1187 struct xrender_info *info = physDev->xrender;
1189 if (info->pict || info->pict_src)
1192 XFlush( gdi_display );
1195 TRACE("freeing pict = %lx dc = %p\n", info->pict, physDev->hdc);
1196 pXRenderFreePicture(gdi_display, info->pict);
1201 TRACE("freeing pict = %lx dc = %p\n", info->pict_src, physDev->hdc);
1202 pXRenderFreePicture(gdi_display, info->pict_src);
1205 wine_tsx11_unlock();
1208 info->format = NULL;
1211 /************************************************************************
1214 * Helper to ExtTextOut. Must be called inside xrender_cs
1216 static void UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
1218 unsigned int buflen;
1223 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
1224 gsCacheEntryFormat *formatEntry;
1225 UINT ggo_format = GGO_GLYPH_INDEX;
1226 WXRFormat wxr_format;
1227 static const char zero[4];
1228 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1232 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1235 ggo_format |= WINE_GGO_HRGB_BITMAP;
1238 ggo_format |= WINE_GGO_HBGR_BITMAP;
1241 ggo_format |= WINE_GGO_VRGB_BITMAP;
1244 ggo_format |= WINE_GGO_VBGR_BITMAP;
1248 ERR("aa = %d - not implemented\n", format);
1250 ggo_format |= GGO_BITMAP;
1254 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1255 if(buflen == GDI_ERROR) {
1256 if(format != AA_None) {
1258 entry->aa_default = AA_None;
1259 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1260 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1262 if(buflen == GDI_ERROR) {
1263 WARN("GetGlyphOutlineW failed using default glyph\n");
1264 buflen = GetGlyphOutlineW(physDev->hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1265 if(buflen == GDI_ERROR) {
1266 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1267 buflen = GetGlyphOutlineW(physDev->hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1268 if(buflen == GDI_ERROR) {
1269 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1274 TRACE("Turning off antialiasing for this monochrome font\n");
1277 /* If there is nothing for the current type, we create the entry. */
1278 if( !entry->format[format] ) {
1279 entry->format[format] = HeapAlloc(GetProcessHeap(),
1281 sizeof(gsCacheEntryFormat));
1283 formatEntry = entry->format[format];
1285 if(formatEntry->nrealized <= glyph) {
1286 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1288 if (formatEntry->realized)
1289 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1291 formatEntry->realized,
1292 formatEntry->nrealized * sizeof(BOOL));
1294 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1296 formatEntry->nrealized * sizeof(BOOL));
1298 if(!X11DRV_XRender_Installed) {
1299 if (formatEntry->bitmaps)
1300 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1302 formatEntry->bitmaps,
1303 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1305 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1307 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1309 if (formatEntry->gis)
1310 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1313 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1315 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1317 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1321 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1324 wxr_format = WXR_FORMAT_GRAY;
1331 wxr_format = WXR_FORMAT_A8R8G8B8;
1335 ERR("aa = %d - not implemented\n", format);
1337 wxr_format = WXR_FORMAT_MONO;
1342 formatEntry->font_format = get_xrender_format(wxr_format);
1343 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
1344 wine_tsx11_unlock();
1348 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1349 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1350 formatEntry->realized[glyph] = TRUE;
1352 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1354 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1355 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1357 gi.width = gm.gmBlackBoxX;
1358 gi.height = gm.gmBlackBoxY;
1359 gi.x = -gm.gmptGlyphOrigin.x;
1360 gi.y = gm.gmptGlyphOrigin.y;
1361 gi.xOff = gm.gmCellIncX;
1362 gi.yOff = gm.gmCellIncY;
1364 if(TRACE_ON(xrender)) {
1367 unsigned char *line;
1369 if(format == AA_None) {
1370 pitch = ((gi.width + 31) / 32) * 4;
1371 for(i = 0; i < gi.height; i++) {
1372 line = (unsigned char*) buf + i * pitch;
1374 for(j = 0; j < pitch * 8; j++) {
1375 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1377 TRACE("%s\n", output);
1380 static const char blks[] = " .:;!o*#";
1384 pitch = ((gi.width + 3) / 4) * 4;
1385 for(i = 0; i < gi.height; i++) {
1386 line = (unsigned char*) buf + i * pitch;
1388 for(j = 0; j < pitch; j++) {
1389 str[0] = blks[line[j] >> 5];
1390 strcat(output, str);
1392 TRACE("%s\n", output);
1398 if(formatEntry->glyphset) {
1399 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1400 unsigned char *byte = (unsigned char*) buf, c;
1406 /* magic to flip bit order */
1407 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1408 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1409 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1414 else if ( format != AA_Grey &&
1415 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1417 unsigned int i, *data = (unsigned int *)buf;
1418 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1423 XRenderCompositeText seems to ignore 0x0 glyphs when
1424 AA_None, which means we lose the advance width of glyphs
1425 like the space. We'll pretend that such glyphs are 1x1
1430 gi.width = gi.height = 1;
1433 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1434 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1435 wine_tsx11_unlock();
1436 HeapFree(GetProcessHeap(), 0, buf);
1438 formatEntry->bitmaps[glyph] = buf;
1441 formatEntry->gis[glyph] = gi;
1444 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
1445 void *bitmap, XGlyphInfo *gi)
1447 unsigned char *srcLine = bitmap, *src;
1448 unsigned char bits, bitsMask;
1449 int width = gi->width;
1450 int stride = ((width + 31) & ~31) >> 3;
1451 int height = gi->height;
1455 TRACE("%d, %d\n", x, y);
1464 bitsMask = 0x80; /* FreeType is always MSB first */
1470 if (bits & bitsMask)
1478 bitsMask = bitsMask >> 1;
1484 } while (bits & bitsMask);
1485 XFillRectangle (gdi_display, physDev->drawable,
1486 physDev->gc, xspan, y, lenspan, 1);
1498 bitsMask = bitsMask >> 1;
1504 } while (!(bits & bitsMask));
1511 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
1512 void *bitmap, XGlyphInfo *gi)
1514 unsigned char *srcLine = bitmap, *src, bits;
1515 int width = gi->width;
1516 int stride = ((width + 3) & ~3);
1517 int height = gi->height;
1542 } while (bits >= 0x80);
1543 XFillRectangle (gdi_display, physDev->drawable,
1544 physDev->gc, xspan, y, lenspan, 1);
1557 } while (bits < 0x80);
1565 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1570 while ((mask & 1) == 0)
1576 while ((mask & 1) == 1)
1585 static DWORD GetField (DWORD pixel, int shift, int len)
1587 pixel = pixel & (((1 << (len)) - 1) << shift);
1588 pixel = pixel << (32 - (shift + len)) >> 24;
1591 pixel |= (pixel >> len);
1598 static DWORD PutField (DWORD pixel, int shift, int len)
1600 shift = shift - (8 - len);
1602 pixel &= (((1 << len) - 1) << (8 - len));
1610 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1616 BYTE *maskLine, *mask, m;
1621 BYTE src_r, src_g, src_b;
1626 height = gi->height;
1629 maskStride = (width + 3) & ~3;
1631 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1632 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1633 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1635 src_r = GetField(color, r_shift, r_len);
1636 src_g = GetField(color, g_shift, g_len);
1637 src_b = GetField(color, b_shift, b_len);
1639 for(; height--; y++)
1642 maskLine += maskStride;
1647 if(y >= image->height) break;
1651 if(tx >= image->width) break;
1654 if(tx < 0) continue;
1657 XPutPixel (image, tx, y, color);
1662 pixel = XGetPixel (image, tx, y);
1664 r = GetField(pixel, r_shift, r_len);
1665 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1666 g = GetField(pixel, g_shift, g_len);
1667 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1668 b = GetField(pixel, b_shift, b_len);
1669 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1671 pixel = (PutField (r, r_shift, r_len) |
1672 PutField (g, g_shift, g_len) |
1673 PutField (b, b_shift, b_len));
1674 XPutPixel (image, tx, y, pixel);
1680 /*************************************************************
1683 * Returns an appropriate Picture for tiling the text colour.
1684 * Call and use result within the xrender_cs
1686 static Picture get_tile_pict(const WineXRenderFormat *wxr_format, int text_pixel)
1693 } tiles[WXR_NB_FORMATS], *tile;
1696 tile = &tiles[wxr_format->format];
1700 XRenderPictureAttributes pa;
1703 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1705 pa.repeat = RepeatNormal;
1706 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1707 wine_tsx11_unlock();
1709 /* init current_color to something different from text_pixel */
1710 tile->current_color = ~text_pixel;
1712 if(wxr_format->format == WXR_FORMAT_MONO)
1714 /* for a 1bpp bitmap we always need a 1 in the tile */
1715 col.red = col.green = col.blue = 0;
1718 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1719 wine_tsx11_unlock();
1723 if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1725 get_xrender_color(wxr_format, text_pixel, &col);
1727 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1728 wine_tsx11_unlock();
1729 tile->current_color = text_pixel;
1734 /*************************************************************
1737 * Returns an appropriate Picture for masking with the specified alpha.
1738 * Call and use result within the xrender_cs
1740 static Picture get_mask_pict( int alpha )
1742 static Pixmap pixmap;
1743 static Picture pict;
1744 static int current_alpha;
1746 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1750 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
1751 XRenderPictureAttributes pa;
1754 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1755 pa.repeat = RepeatNormal;
1756 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format, CPRepeat, &pa );
1757 wine_tsx11_unlock();
1761 if (alpha != current_alpha)
1764 col.red = col.green = col.blue = 0;
1765 col.alpha = current_alpha = alpha;
1767 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1768 wine_tsx11_unlock();
1773 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1778 /***********************************************************************
1779 * X11DRV_XRender_ExtTextOut
1781 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1782 const RECT *lprect, LPCWSTR wstr, UINT count,
1786 gsCacheEntry *entry;
1787 gsCacheEntryFormat *formatEntry;
1789 int textPixel, backgroundPixel;
1790 HRGN saved_region = 0;
1791 BOOL disable_antialias = FALSE;
1792 AA_Type aa_type = AA_None;
1795 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
1796 Picture tile_pict = 0;
1798 /* Do we need to disable antialiasing because of palette mode? */
1799 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1800 TRACE("bitmap is not a DIB\n");
1802 else if (bmp.dsBmih.biBitCount <= 8) {
1803 TRACE("Disabling antialiasing\n");
1804 disable_antialias = TRUE;
1807 xgcval.function = GXcopy;
1808 xgcval.background = physDev->backgroundPixel;
1809 xgcval.fill_style = FillSolid;
1811 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1812 wine_tsx11_unlock();
1814 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1816 if(physDev->depth == 1) {
1817 if((physDev->textPixel & 0xffffff) == 0) {
1819 backgroundPixel = 1;
1822 backgroundPixel = 0;
1825 textPixel = physDev->textPixel;
1826 backgroundPixel = physDev->backgroundPixel;
1829 if(flags & ETO_OPAQUE)
1832 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1833 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1834 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1835 lprect->right - lprect->left, lprect->bottom - lprect->top );
1836 wine_tsx11_unlock();
1845 if (flags & ETO_CLIPPED)
1849 clip_region = CreateRectRgnIndirect( lprect );
1850 /* make a copy of the current device region */
1851 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1852 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1853 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1854 DeleteObject( clip_region );
1857 EnterCriticalSection(&xrender_cs);
1859 entry = glyphsetCache + physDev->xrender->cache_index;
1860 if( disable_antialias == FALSE )
1861 aa_type = entry->aa_default;
1862 formatEntry = entry->format[aa_type];
1864 for(idx = 0; idx < count; idx++) {
1865 if( !formatEntry ) {
1866 UploadGlyph(physDev, wstr[idx], aa_type);
1867 /* re-evaluate antialias since aa_default may have changed */
1868 if( disable_antialias == FALSE )
1869 aa_type = entry->aa_default;
1870 formatEntry = entry->format[aa_type];
1871 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1872 UploadGlyph(physDev, wstr[idx], aa_type);
1877 WARN("could not upload requested glyphs\n");
1878 LeaveCriticalSection(&xrender_cs);
1882 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1883 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1885 if(X11DRV_XRender_Installed)
1887 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1888 POINT offset = {0, 0};
1889 POINT desired, current;
1890 int render_op = PictOpOver;
1891 Picture pict = get_xrender_picture(physDev);
1893 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1894 So we pass zeros to the function and move to our starting position using the first
1895 element of the elts array. */
1897 desired.x = physDev->dc_rect.left + x;
1898 desired.y = physDev->dc_rect.top + y;
1899 current.x = current.y = 0;
1901 tile_pict = get_tile_pict(dst_format, physDev->textPixel);
1903 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1905 if((dst_format->format == WXR_FORMAT_MONO) && (textPixel == 0))
1906 render_op = PictOpOutReverse; /* This gives us 'black' text */
1908 for(idx = 0; idx < count; idx++)
1910 elts[idx].glyphset = formatEntry->glyphset;
1911 elts[idx].chars = wstr + idx;
1912 elts[idx].nchars = 1;
1913 elts[idx].xOff = desired.x - current.x;
1914 elts[idx].yOff = desired.y - current.y;
1916 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1917 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1921 desired.x += formatEntry->gis[wstr[idx]].xOff;
1922 desired.y += formatEntry->gis[wstr[idx]].yOff;
1928 offset.x += lpDx[idx * 2];
1929 offset.y += lpDx[idx * 2 + 1];
1932 offset.x += lpDx[idx];
1933 desired.x = physDev->dc_rect.left + x + offset.x;
1934 desired.y = physDev->dc_rect.top + y + offset.y;
1938 /* Make sure we don't have any transforms set from a previous call */
1939 set_xrender_transformation(pict, 1, 1, 0, 0);
1940 pXRenderCompositeText16(gdi_display, render_op,
1943 formatEntry->font_format->pict_format,
1944 0, 0, 0, 0, elts, count);
1945 wine_tsx11_unlock();
1946 HeapFree(GetProcessHeap(), 0, elts);
1948 POINT offset = {0, 0};
1950 XSetForeground( gdi_display, physDev->gc, textPixel );
1952 if(aa_type == AA_None || physDev->depth == 1)
1954 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1956 if(aa_type == AA_None)
1957 sharp_glyph_fn = SharpGlyphMono;
1959 sharp_glyph_fn = SharpGlyphGray;
1961 for(idx = 0; idx < count; idx++) {
1962 sharp_glyph_fn(physDev,
1963 physDev->dc_rect.left + x + offset.x,
1964 physDev->dc_rect.top + y + offset.y,
1965 formatEntry->bitmaps[wstr[idx]],
1966 &formatEntry->gis[wstr[idx]]);
1971 offset.x += lpDx[idx * 2];
1972 offset.y += lpDx[idx * 2 + 1];
1975 offset.x += lpDx[idx];
1979 offset.x += formatEntry->gis[wstr[idx]].xOff;
1980 offset.y += formatEntry->gis[wstr[idx]].yOff;
1985 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1986 RECT extents = {0, 0, 0, 0};
1988 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1989 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1991 TRACE("drawable %dx%d\n", w, h);
1993 for(idx = 0; idx < count; idx++) {
1994 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1995 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1996 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1997 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1998 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1999 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2000 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2001 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2007 cur.x += lpDx[idx * 2];
2008 cur.y += lpDx[idx * 2 + 1];
2015 cur.x += formatEntry->gis[wstr[idx]].xOff;
2016 cur.y += formatEntry->gis[wstr[idx]].yOff;
2019 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2020 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
2022 if(physDev->dc_rect.left + x + extents.left >= 0) {
2023 image_x = physDev->dc_rect.left + x + extents.left;
2027 image_off_x = physDev->dc_rect.left + x + extents.left;
2029 if(physDev->dc_rect.top + y + extents.top >= 0) {
2030 image_y = physDev->dc_rect.top + y + extents.top;
2034 image_off_y = physDev->dc_rect.top + y + extents.top;
2036 if(physDev->dc_rect.left + x + extents.right < w)
2037 image_w = physDev->dc_rect.left + x + extents.right - image_x;
2039 image_w = w - image_x;
2040 if(physDev->dc_rect.top + y + extents.bottom < h)
2041 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
2043 image_h = h - image_y;
2045 if(image_w <= 0 || image_h <= 0) goto no_image;
2047 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2048 image = XGetImage(gdi_display, physDev->drawable,
2049 image_x, image_y, image_w, image_h,
2050 AllPlanes, ZPixmap);
2051 X11DRV_check_error();
2053 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2054 gdi_display, (int)physDev->drawable, image_x, image_y,
2055 image_w, image_h, AllPlanes, ZPixmap,
2056 physDev->depth, image);
2058 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2063 gcv.graphics_exposures = False;
2064 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2065 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
2066 image_w, image_h, 0, 0);
2067 XFreeGC(gdi_display, gc);
2068 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2069 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2071 X11DRV_check_error();
2072 XFreePixmap(gdi_display, xpm);
2074 if(!image) goto no_image;
2076 image->red_mask = visual->red_mask;
2077 image->green_mask = visual->green_mask;
2078 image->blue_mask = visual->blue_mask;
2080 for(idx = 0; idx < count; idx++) {
2081 SmoothGlyphGray(image,
2082 offset.x + image_off_x - extents.left,
2083 offset.y + image_off_y - extents.top,
2084 formatEntry->bitmaps[wstr[idx]],
2085 &formatEntry->gis[wstr[idx]],
2086 physDev->textPixel);
2091 offset.x += lpDx[idx * 2];
2092 offset.y += lpDx[idx * 2 + 1];
2095 offset.x += lpDx[idx];
2099 offset.x += formatEntry->gis[wstr[idx]].xOff;
2100 offset.y += formatEntry->gis[wstr[idx]].yOff;
2103 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
2104 image_x, image_y, image_w, image_h);
2105 XDestroyImage(image);
2108 wine_tsx11_unlock();
2110 LeaveCriticalSection(&xrender_cs);
2112 if (flags & ETO_CLIPPED)
2114 /* restore the device region */
2115 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
2116 DeleteObject( saved_region );
2122 X11DRV_UnlockDIBSection( physDev, TRUE );
2126 /* Helper function for (stretched) blitting using xrender */
2127 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2128 int x_src, int y_src, int x_dst, int y_dst,
2129 double xscale, double yscale, int width, int height )
2131 int x_offset, y_offset;
2133 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2134 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2135 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2136 if(xscale != 1.0 || yscale != 1.0)
2138 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2139 * in the wrong quadrant of the x-y plane.
2141 x_offset = (xscale < 0) ? -width : 0;
2142 y_offset = (yscale < 0) ? -height : 0;
2143 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2149 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2151 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2152 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2155 /* Helper function for (stretched) mono->color blitting using xrender */
2156 static void xrender_mono_blit( Picture src_pict, Picture mask_pict, Picture dst_pict,
2157 int x_src, int y_src, double xscale, double yscale, int width, int height )
2159 int x_offset, y_offset;
2161 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2162 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
2163 * tile data. We need PictOpOver for correct rendering.
2164 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2167 if (xscale != 1.0 || yscale != 1.0)
2169 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2170 * in the wrong quadrant of the x-y plane.
2172 x_offset = (xscale < 0) ? -width : 0;
2173 y_offset = (yscale < 0) ? -height : 0;
2174 set_xrender_transformation(mask_pict, xscale, yscale, x_src, y_src);
2180 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
2182 pXRenderComposite(gdi_display, PictOpOver, src_pict, mask_pict, dst_pict,
2183 0, 0, x_offset, y_offset, 0, 0, width, height);
2186 /******************************************************************************
2189 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2190 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2192 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2193 struct xrender_info *src_info = get_xrender_info( devSrc );
2194 double xscale, yscale;
2197 if(!X11DRV_XRender_Installed) {
2198 FIXME("Unable to AlphaBlend without Xrender\n");
2202 if (devSrc != devDst) X11DRV_LockDIBSection( devSrc, DIB_Status_GdiMod );
2203 X11DRV_LockDIBSection( devDst, DIB_Status_GdiMod );
2205 dst_pict = get_xrender_picture( devDst );
2207 use_repeat = use_source_repeat( devSrc );
2210 xscale = src->width / (double)dst->width;
2211 yscale = src->height / (double)dst->height;
2213 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2215 if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && src_info->format)
2217 /* we need a source picture with no alpha */
2218 WXRFormat format = get_format_without_alpha( src_info->format->format );
2219 if (format != src_info->format->format)
2221 XRenderPictureAttributes pa;
2222 const WineXRenderFormat *fmt = get_xrender_format( format );
2225 pa.subwindow_mode = IncludeInferiors;
2226 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2227 tmp_pict = pXRenderCreatePicture( gdi_display, devSrc->drawable, fmt->pict_format,
2228 CPSubwindowMode|CPRepeat, &pa );
2229 wine_tsx11_unlock();
2230 src_pict = tmp_pict;
2234 if (!src_pict) src_pict = get_xrender_picture_source( devSrc, use_repeat );
2236 EnterCriticalSection( &xrender_cs );
2237 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2240 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2241 devSrc->dc_rect.left + src->visrect.left, devSrc->dc_rect.top + src->visrect.top,
2242 devDst->dc_rect.left + dst->visrect.left, devDst->dc_rect.top + dst->visrect.top,
2244 dst->visrect.right - dst->visrect.left, dst->visrect.bottom - dst->visrect.top );
2245 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2246 wine_tsx11_unlock();
2248 LeaveCriticalSection( &xrender_cs );
2249 if (devSrc != devDst) X11DRV_UnlockDIBSection( devSrc, FALSE );
2250 X11DRV_UnlockDIBSection( devDst, TRUE );
2255 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2257 /* 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 */
2258 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2259 const WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2260 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2263 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2265 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2266 if( (physBitmap->pixmap_depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->pixmap_depth) ||
2267 (src_format->format == dst_format->format) )
2269 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2270 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2272 else /* We need depth conversion */
2274 Picture src_pict, dst_pict;
2275 XRenderPictureAttributes pa;
2276 pa.subwindow_mode = IncludeInferiors;
2277 pa.repeat = RepeatNone;
2279 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2280 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2282 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2283 pXRenderFreePicture(gdi_display, src_pict);
2284 pXRenderFreePicture(gdi_display, dst_pict);
2286 wine_tsx11_unlock();
2289 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2290 Pixmap pixmap, GC gc,
2291 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2293 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2294 int width = dst->visrect.right - dst->visrect.left;
2295 int height = dst->visrect.bottom - dst->visrect.top;
2296 int x_src = physDevSrc->dc_rect.left + src->visrect.left;
2297 int y_src = physDevSrc->dc_rect.top + src->visrect.top;
2298 struct xrender_info *src_info = get_xrender_info(physDevSrc);
2299 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDevDst->depth, physDevDst->color_shifts);
2300 Picture src_pict=0, dst_pict=0, mask_pict=0;
2302 double xscale, yscale;
2304 XRenderPictureAttributes pa;
2305 pa.subwindow_mode = IncludeInferiors;
2306 pa.repeat = RepeatNone;
2308 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2309 physDevSrc->depth, src->width, src->height, x_src, y_src);
2310 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst->depth, dst->width, dst->height);
2312 if(!X11DRV_XRender_Installed)
2314 TRACE("Not using XRender since it is not available or disabled\n");
2318 /* XRender can't handle palettes, so abort */
2319 if(X11DRV_PALETTE_XPixelToPalette)
2322 /* XRender is of no use in this case */
2323 if((physDevDst->depth == 1) && (physDevSrc->depth > 1))
2326 /* Just use traditional X copy when the formats match and we don't need stretching */
2327 if((src_info->format->format == dst_format->format) && !stretch)
2329 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2331 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
2332 wine_tsx11_unlock();
2336 use_repeat = use_source_repeat( physDevSrc );
2339 xscale = src->width / (double)dst->width;
2340 yscale = src->height / (double)dst->height;
2342 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2345 if(physDevSrc->depth == 1 && physDevDst->depth > 1)
2348 get_xrender_color(dst_format, physDevDst->textPixel, &col);
2350 /* We use the source drawable as a mask */
2351 mask_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2353 /* Use backgroundPixel as the foreground color */
2354 EnterCriticalSection( &xrender_cs );
2355 src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
2357 /* Create a destination picture and fill it with textPixel color as the background color */
2359 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2360 pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height);
2362 xrender_mono_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
2364 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2365 wine_tsx11_unlock();
2366 LeaveCriticalSection( &xrender_cs );
2368 else /* color -> color (can be at different depths) or mono -> mono */
2370 if (physDevDst->depth == 32 && physDevSrc->depth < 32) mask_pict = get_no_alpha_mask();
2371 src_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2374 dst_pict = pXRenderCreatePicture(gdi_display,
2375 pixmap, dst_format->pict_format,
2376 CPSubwindowMode|CPRepeat, &pa);
2378 xrender_blit(PictOpSrc, src_pict, mask_pict, dst_pict,
2379 x_src, y_src, 0, 0, xscale, yscale, width, height);
2381 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2382 wine_tsx11_unlock();
2387 #else /* SONAME_LIBXRENDER */
2389 void X11DRV_XRender_Init(void)
2391 TRACE("XRender support not compiled in.\n");
2395 void X11DRV_XRender_Finalize(void)
2399 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
2405 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
2411 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
2417 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
2418 const RECT *lprect, LPCWSTR wstr, UINT count,
2425 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
2431 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2432 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2434 FIXME("not supported - XRENDER headers were missing at compile time\n");
2438 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2441 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
2443 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2444 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2445 wine_tsx11_unlock();
2448 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2453 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2454 Pixmap pixmap, GC gc,
2455 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2459 #endif /* SONAME_LIBXRENDER */