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 );
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 #ifdef SONAME_LIBFONTCONFIG
909 if (fontconfig_installed)
911 FcPattern *match, *pattern = pFcPatternCreate();
913 char family[LF_FACESIZE * 4];
915 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
916 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
917 if (plfsz->lf.lfWeight != FW_DONTCARE)
920 switch (plfsz->lf.lfWeight)
922 case FW_THIN: weight = FC_WEIGHT_THIN; break;
923 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
924 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
925 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
926 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
927 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
928 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
929 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
930 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
931 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
933 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
935 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
936 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
937 pFcDefaultSubstitute( pattern );
938 if ((match = pFcFontMatch( NULL, pattern, &result )))
943 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
945 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
948 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
950 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
951 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
955 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
956 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
957 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
958 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
959 case FC_RGBA_NONE: entry->aa_default = antialias ? AA_Grey : AA_None; break;
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 = antialias ? AA_Grey : AA_None;
993 entry->aa_default = AA_None;
998 static void dec_ref_cache(int index)
1001 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1002 assert(glyphsetCache[index].count > 0);
1003 glyphsetCache[index].count--;
1006 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1008 DWORD hash = 0, *ptr, two_chars;
1012 hash ^= plfsz->devsize.cx;
1013 hash ^= plfsz->devsize.cy;
1014 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1016 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1018 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1020 pwc = (WCHAR *)&two_chars;
1022 *pwc = toupperW(*pwc);
1024 *pwc = toupperW(*pwc);
1032 /***********************************************************************
1033 * X11DRV_XRender_Finalize
1035 void X11DRV_XRender_Finalize(void)
1039 EnterCriticalSection(&xrender_cs);
1040 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1042 LeaveCriticalSection(&xrender_cs);
1046 /***********************************************************************
1047 * X11DRV_XRender_SelectFont
1049 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1052 struct xrender_info *info;
1054 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
1055 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1056 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1057 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1058 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1059 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
1060 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
1061 GetWorldTransform( physDev->hdc, &lfsz.xform );
1062 lfsz_calc_hash(&lfsz);
1064 info = get_xrender_info(physDev);
1065 if (!info) return 0;
1067 EnterCriticalSection(&xrender_cs);
1068 if(info->cache_index != -1)
1069 dec_ref_cache(info->cache_index);
1070 info->cache_index = GetCacheEntry(physDev, &lfsz);
1071 LeaveCriticalSection(&xrender_cs);
1075 /***********************************************************************
1076 * X11DRV_XRender_SetDeviceClipping
1078 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
1080 if (physDev->xrender->pict)
1083 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1084 physDev->dc_rect.left, physDev->dc_rect.top,
1085 (XRectangle *)data->Buffer, data->rdh.nCount );
1086 wine_tsx11_unlock();
1090 /***********************************************************************
1091 * X11DRV_XRender_DeleteDC
1093 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1095 X11DRV_XRender_UpdateDrawable(physDev);
1097 EnterCriticalSection(&xrender_cs);
1098 if(physDev->xrender->cache_index != -1)
1099 dec_ref_cache(physDev->xrender->cache_index);
1100 LeaveCriticalSection(&xrender_cs);
1102 HeapFree(GetProcessHeap(), 0, physDev->xrender);
1103 physDev->xrender = NULL;
1107 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1109 const WineXRenderFormat *fmt;
1112 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1113 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1114 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1115 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1120 X11DRV_PALETTE_ComputeColorShifts(&shifts, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
1121 fmt = get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts);
1123 /* Common formats should be in our picture format table. */
1126 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1127 dib->dsBm.bmBitsPixel, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
1133 int red_mask, green_mask, blue_mask;
1135 /* We are dealing with a DDB */
1139 fmt = get_xrender_format(WXR_FORMAT_R5G6B5);
1142 fmt = get_xrender_format(WXR_FORMAT_R8G8B8);
1145 fmt = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1153 TRACE("Unhandled DDB bits_pixel=%d\n", bits_pixel);
1157 red_mask = fmt->pict_format->direct.redMask << fmt->pict_format->direct.red;
1158 green_mask = fmt->pict_format->direct.greenMask << fmt->pict_format->direct.green;
1159 blue_mask = fmt->pict_format->direct.blueMask << fmt->pict_format->direct.blue;
1160 X11DRV_PALETTE_ComputeColorShifts(&shifts, red_mask, green_mask, blue_mask);
1163 physBitmap->pixmap_depth = fmt->pict_format->depth;
1164 physBitmap->trueColor = TRUE;
1165 physBitmap->pixmap_color_shifts = shifts;
1169 /***********************************************************************
1170 * X11DRV_XRender_UpdateDrawable
1172 * Deletes the pict and tile when the drawable changes.
1174 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1176 struct xrender_info *info = physDev->xrender;
1178 if (info->pict || info->pict_src)
1181 XFlush( gdi_display );
1184 TRACE("freeing pict = %lx dc = %p\n", info->pict, physDev->hdc);
1185 pXRenderFreePicture(gdi_display, info->pict);
1190 TRACE("freeing pict = %lx dc = %p\n", info->pict_src, physDev->hdc);
1191 pXRenderFreePicture(gdi_display, info->pict_src);
1194 wine_tsx11_unlock();
1197 info->format = NULL;
1200 /************************************************************************
1203 * Helper to ExtTextOut. Must be called inside xrender_cs
1205 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
1207 unsigned int buflen;
1212 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
1213 gsCacheEntryFormat *formatEntry;
1214 UINT ggo_format = GGO_GLYPH_INDEX;
1215 WXRFormat wxr_format;
1216 static const char zero[4];
1217 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1221 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1224 ggo_format |= WINE_GGO_HRGB_BITMAP;
1227 ggo_format |= WINE_GGO_HBGR_BITMAP;
1230 ggo_format |= WINE_GGO_VRGB_BITMAP;
1233 ggo_format |= WINE_GGO_VBGR_BITMAP;
1237 ERR("aa = %d - not implemented\n", format);
1239 ggo_format |= GGO_BITMAP;
1243 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1244 if(buflen == GDI_ERROR) {
1245 if(format != AA_None) {
1247 entry->aa_default = AA_None;
1248 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1249 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1251 if(buflen == GDI_ERROR) {
1252 WARN("GetGlyphOutlineW failed\n");
1255 TRACE("Turning off antialiasing for this monochrome font\n");
1258 /* If there is nothing for the current type, we create the entry. */
1259 if( !entry->format[format] ) {
1260 entry->format[format] = HeapAlloc(GetProcessHeap(),
1262 sizeof(gsCacheEntryFormat));
1264 formatEntry = entry->format[format];
1266 if(formatEntry->nrealized <= glyph) {
1267 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1269 if (formatEntry->realized)
1270 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1272 formatEntry->realized,
1273 formatEntry->nrealized * sizeof(BOOL));
1275 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1277 formatEntry->nrealized * sizeof(BOOL));
1279 if(!X11DRV_XRender_Installed) {
1280 if (formatEntry->bitmaps)
1281 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1283 formatEntry->bitmaps,
1284 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1286 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1288 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1290 if (formatEntry->gis)
1291 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1294 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1296 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1298 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1302 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1305 wxr_format = WXR_FORMAT_GRAY;
1312 wxr_format = WXR_FORMAT_A8R8G8B8;
1316 ERR("aa = %d - not implemented\n", format);
1318 wxr_format = WXR_FORMAT_MONO;
1323 formatEntry->font_format = get_xrender_format(wxr_format);
1324 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
1325 wine_tsx11_unlock();
1329 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1330 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1331 formatEntry->realized[glyph] = TRUE;
1333 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1335 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1336 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1338 gi.width = gm.gmBlackBoxX;
1339 gi.height = gm.gmBlackBoxY;
1340 gi.x = -gm.gmptGlyphOrigin.x;
1341 gi.y = gm.gmptGlyphOrigin.y;
1342 gi.xOff = gm.gmCellIncX;
1343 gi.yOff = gm.gmCellIncY;
1345 if(TRACE_ON(xrender)) {
1348 unsigned char *line;
1350 if(format == AA_None) {
1351 pitch = ((gi.width + 31) / 32) * 4;
1352 for(i = 0; i < gi.height; i++) {
1353 line = (unsigned char*) buf + i * pitch;
1355 for(j = 0; j < pitch * 8; j++) {
1356 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1358 TRACE("%s\n", output);
1361 static const char blks[] = " .:;!o*#";
1365 pitch = ((gi.width + 3) / 4) * 4;
1366 for(i = 0; i < gi.height; i++) {
1367 line = (unsigned char*) buf + i * pitch;
1369 for(j = 0; j < pitch; j++) {
1370 str[0] = blks[line[j] >> 5];
1371 strcat(output, str);
1373 TRACE("%s\n", output);
1379 if(formatEntry->glyphset) {
1380 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1381 unsigned char *byte = (unsigned char*) buf, c;
1387 /* magic to flip bit order */
1388 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1389 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1390 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1395 else if ( format != AA_Grey &&
1396 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1398 unsigned int i, *data = (unsigned int *)buf;
1399 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1404 XRenderCompositeText seems to ignore 0x0 glyphs when
1405 AA_None, which means we lose the advance width of glyphs
1406 like the space. We'll pretend that such glyphs are 1x1
1411 gi.width = gi.height = 1;
1414 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1415 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1416 wine_tsx11_unlock();
1417 HeapFree(GetProcessHeap(), 0, buf);
1419 formatEntry->bitmaps[glyph] = buf;
1422 formatEntry->gis[glyph] = gi;
1427 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
1428 void *bitmap, XGlyphInfo *gi)
1430 unsigned char *srcLine = bitmap, *src;
1431 unsigned char bits, bitsMask;
1432 int width = gi->width;
1433 int stride = ((width + 31) & ~31) >> 3;
1434 int height = gi->height;
1438 TRACE("%d, %d\n", x, y);
1447 bitsMask = 0x80; /* FreeType is always MSB first */
1453 if (bits & bitsMask)
1461 bitsMask = bitsMask >> 1;
1467 } while (bits & bitsMask);
1468 XFillRectangle (gdi_display, physDev->drawable,
1469 physDev->gc, xspan, y, lenspan, 1);
1481 bitsMask = bitsMask >> 1;
1487 } while (!(bits & bitsMask));
1494 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
1495 void *bitmap, XGlyphInfo *gi)
1497 unsigned char *srcLine = bitmap, *src, bits;
1498 int width = gi->width;
1499 int stride = ((width + 3) & ~3);
1500 int height = gi->height;
1525 } while (bits >= 0x80);
1526 XFillRectangle (gdi_display, physDev->drawable,
1527 physDev->gc, xspan, y, lenspan, 1);
1540 } while (bits < 0x80);
1548 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1553 while ((mask & 1) == 0)
1559 while ((mask & 1) == 1)
1568 static DWORD GetField (DWORD pixel, int shift, int len)
1570 pixel = pixel & (((1 << (len)) - 1) << shift);
1571 pixel = pixel << (32 - (shift + len)) >> 24;
1574 pixel |= (pixel >> len);
1581 static DWORD PutField (DWORD pixel, int shift, int len)
1583 shift = shift - (8 - len);
1585 pixel &= (((1 << len) - 1) << (8 - len));
1593 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1599 BYTE *maskLine, *mask, m;
1604 BYTE src_r, src_g, src_b;
1609 height = gi->height;
1612 maskStride = (width + 3) & ~3;
1614 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1615 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1616 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1618 src_r = GetField(color, r_shift, r_len);
1619 src_g = GetField(color, g_shift, g_len);
1620 src_b = GetField(color, b_shift, b_len);
1622 for(; height--; y++)
1625 maskLine += maskStride;
1630 if(y >= image->height) break;
1634 if(tx >= image->width) break;
1637 if(tx < 0) continue;
1640 XPutPixel (image, tx, y, color);
1645 pixel = XGetPixel (image, tx, y);
1647 r = GetField(pixel, r_shift, r_len);
1648 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1649 g = GetField(pixel, g_shift, g_len);
1650 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1651 b = GetField(pixel, b_shift, b_len);
1652 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1654 pixel = (PutField (r, r_shift, r_len) |
1655 PutField (g, g_shift, g_len) |
1656 PutField (b, b_shift, b_len));
1657 XPutPixel (image, tx, y, pixel);
1663 /*************************************************************
1666 * Returns an appropriate Picture for tiling the text colour.
1667 * Call and use result within the xrender_cs
1669 static Picture get_tile_pict(const WineXRenderFormat *wxr_format, int text_pixel)
1676 } tiles[WXR_NB_FORMATS], *tile;
1679 tile = &tiles[wxr_format->format];
1683 XRenderPictureAttributes pa;
1686 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1688 pa.repeat = RepeatNormal;
1689 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1690 wine_tsx11_unlock();
1692 /* init current_color to something different from text_pixel */
1693 tile->current_color = ~text_pixel;
1695 if(wxr_format->format == WXR_FORMAT_MONO)
1697 /* for a 1bpp bitmap we always need a 1 in the tile */
1698 col.red = col.green = col.blue = 0;
1701 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1702 wine_tsx11_unlock();
1706 if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1708 get_xrender_color(wxr_format, text_pixel, &col);
1710 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1711 wine_tsx11_unlock();
1712 tile->current_color = text_pixel;
1717 /*************************************************************
1720 * Returns an appropriate Picture for masking with the specified alpha.
1721 * Call and use result within the xrender_cs
1723 static Picture get_mask_pict( int alpha )
1725 static Pixmap pixmap;
1726 static Picture pict;
1727 static int current_alpha;
1729 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1733 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
1734 XRenderPictureAttributes pa;
1737 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1738 pa.repeat = RepeatNormal;
1739 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format, CPRepeat, &pa );
1740 wine_tsx11_unlock();
1744 if (alpha != current_alpha)
1747 col.red = col.green = col.blue = 0;
1748 col.alpha = current_alpha = alpha;
1750 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1751 wine_tsx11_unlock();
1756 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1761 /***********************************************************************
1762 * X11DRV_XRender_ExtTextOut
1764 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1765 const RECT *lprect, LPCWSTR wstr, UINT count,
1769 gsCacheEntry *entry;
1770 gsCacheEntryFormat *formatEntry;
1772 int textPixel, backgroundPixel;
1773 HRGN saved_region = 0;
1774 BOOL disable_antialias = FALSE;
1775 AA_Type aa_type = AA_None;
1778 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
1779 Picture tile_pict = 0;
1781 /* Do we need to disable antialiasing because of palette mode? */
1782 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1783 TRACE("bitmap is not a DIB\n");
1785 else if (bmp.dsBmih.biBitCount <= 8) {
1786 TRACE("Disabling antialiasing\n");
1787 disable_antialias = TRUE;
1790 xgcval.function = GXcopy;
1791 xgcval.background = physDev->backgroundPixel;
1792 xgcval.fill_style = FillSolid;
1794 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1795 wine_tsx11_unlock();
1797 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1799 if(physDev->depth == 1) {
1800 if((physDev->textPixel & 0xffffff) == 0) {
1802 backgroundPixel = 1;
1805 backgroundPixel = 0;
1808 textPixel = physDev->textPixel;
1809 backgroundPixel = physDev->backgroundPixel;
1812 if(flags & ETO_OPAQUE)
1815 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1816 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1817 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1818 lprect->right - lprect->left, lprect->bottom - lprect->top );
1819 wine_tsx11_unlock();
1828 if (flags & ETO_CLIPPED)
1832 clip_region = CreateRectRgnIndirect( lprect );
1833 /* make a copy of the current device region */
1834 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1835 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1836 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1837 DeleteObject( clip_region );
1840 EnterCriticalSection(&xrender_cs);
1842 entry = glyphsetCache + physDev->xrender->cache_index;
1843 if( disable_antialias == FALSE )
1844 aa_type = entry->aa_default;
1845 formatEntry = entry->format[aa_type];
1847 for(idx = 0; idx < count; idx++) {
1848 if( !formatEntry ) {
1849 UploadGlyph(physDev, wstr[idx], aa_type);
1850 /* re-evaluate antialias since aa_default may have changed */
1851 if( disable_antialias == FALSE )
1852 aa_type = entry->aa_default;
1853 formatEntry = entry->format[aa_type];
1854 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1855 UploadGlyph(physDev, wstr[idx], aa_type);
1860 WARN("could not upload requested glyphs\n");
1861 LeaveCriticalSection(&xrender_cs);
1865 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1866 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1868 if(X11DRV_XRender_Installed)
1870 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1871 POINT offset = {0, 0};
1872 POINT desired, current;
1873 int render_op = PictOpOver;
1874 Picture pict = get_xrender_picture(physDev);
1876 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1877 So we pass zeros to the function and move to our starting position using the first
1878 element of the elts array. */
1880 desired.x = physDev->dc_rect.left + x;
1881 desired.y = physDev->dc_rect.top + y;
1882 current.x = current.y = 0;
1884 tile_pict = get_tile_pict(dst_format, physDev->textPixel);
1886 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1888 if((dst_format->format == WXR_FORMAT_MONO) && (textPixel == 0))
1889 render_op = PictOpOutReverse; /* This gives us 'black' text */
1891 for(idx = 0; idx < count; idx++)
1893 elts[idx].glyphset = formatEntry->glyphset;
1894 elts[idx].chars = wstr + idx;
1895 elts[idx].nchars = 1;
1896 elts[idx].xOff = desired.x - current.x;
1897 elts[idx].yOff = desired.y - current.y;
1899 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1900 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1904 desired.x += formatEntry->gis[wstr[idx]].xOff;
1905 desired.y += formatEntry->gis[wstr[idx]].yOff;
1911 offset.x += lpDx[idx * 2];
1912 offset.y += lpDx[idx * 2 + 1];
1915 offset.x += lpDx[idx];
1916 desired.x = physDev->dc_rect.left + x + offset.x;
1917 desired.y = physDev->dc_rect.top + y + offset.y;
1921 /* Make sure we don't have any transforms set from a previous call */
1922 set_xrender_transformation(pict, 1, 1, 0, 0);
1923 pXRenderCompositeText16(gdi_display, render_op,
1926 formatEntry->font_format->pict_format,
1927 0, 0, 0, 0, elts, count);
1928 wine_tsx11_unlock();
1929 HeapFree(GetProcessHeap(), 0, elts);
1931 POINT offset = {0, 0};
1933 XSetForeground( gdi_display, physDev->gc, textPixel );
1935 if(aa_type == AA_None || physDev->depth == 1)
1937 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1939 if(aa_type == AA_None)
1940 sharp_glyph_fn = SharpGlyphMono;
1942 sharp_glyph_fn = SharpGlyphGray;
1944 for(idx = 0; idx < count; idx++) {
1945 sharp_glyph_fn(physDev,
1946 physDev->dc_rect.left + x + offset.x,
1947 physDev->dc_rect.top + y + offset.y,
1948 formatEntry->bitmaps[wstr[idx]],
1949 &formatEntry->gis[wstr[idx]]);
1954 offset.x += lpDx[idx * 2];
1955 offset.y += lpDx[idx * 2 + 1];
1958 offset.x += lpDx[idx];
1962 offset.x += formatEntry->gis[wstr[idx]].xOff;
1963 offset.y += formatEntry->gis[wstr[idx]].yOff;
1968 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1969 RECT extents = {0, 0, 0, 0};
1971 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1972 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1974 TRACE("drawable %dx%d\n", w, h);
1976 for(idx = 0; idx < count; idx++) {
1977 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1978 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1979 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1980 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1981 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1982 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1983 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1984 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1990 cur.x += lpDx[idx * 2];
1991 cur.y += lpDx[idx * 2 + 1];
1998 cur.x += formatEntry->gis[wstr[idx]].xOff;
1999 cur.y += formatEntry->gis[wstr[idx]].yOff;
2002 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2003 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
2005 if(physDev->dc_rect.left + x + extents.left >= 0) {
2006 image_x = physDev->dc_rect.left + x + extents.left;
2010 image_off_x = physDev->dc_rect.left + x + extents.left;
2012 if(physDev->dc_rect.top + y + extents.top >= 0) {
2013 image_y = physDev->dc_rect.top + y + extents.top;
2017 image_off_y = physDev->dc_rect.top + y + extents.top;
2019 if(physDev->dc_rect.left + x + extents.right < w)
2020 image_w = physDev->dc_rect.left + x + extents.right - image_x;
2022 image_w = w - image_x;
2023 if(physDev->dc_rect.top + y + extents.bottom < h)
2024 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
2026 image_h = h - image_y;
2028 if(image_w <= 0 || image_h <= 0) goto no_image;
2030 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2031 image = XGetImage(gdi_display, physDev->drawable,
2032 image_x, image_y, image_w, image_h,
2033 AllPlanes, ZPixmap);
2034 X11DRV_check_error();
2036 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2037 gdi_display, (int)physDev->drawable, image_x, image_y,
2038 image_w, image_h, AllPlanes, ZPixmap,
2039 physDev->depth, image);
2041 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2046 gcv.graphics_exposures = False;
2047 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2048 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
2049 image_w, image_h, 0, 0);
2050 XFreeGC(gdi_display, gc);
2051 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2052 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2054 X11DRV_check_error();
2055 XFreePixmap(gdi_display, xpm);
2057 if(!image) goto no_image;
2059 image->red_mask = visual->red_mask;
2060 image->green_mask = visual->green_mask;
2061 image->blue_mask = visual->blue_mask;
2063 for(idx = 0; idx < count; idx++) {
2064 SmoothGlyphGray(image,
2065 offset.x + image_off_x - extents.left,
2066 offset.y + image_off_y - extents.top,
2067 formatEntry->bitmaps[wstr[idx]],
2068 &formatEntry->gis[wstr[idx]],
2069 physDev->textPixel);
2074 offset.x += lpDx[idx * 2];
2075 offset.y += lpDx[idx * 2 + 1];
2078 offset.x += lpDx[idx];
2082 offset.x += formatEntry->gis[wstr[idx]].xOff;
2083 offset.y += formatEntry->gis[wstr[idx]].yOff;
2086 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
2087 image_x, image_y, image_w, image_h);
2088 XDestroyImage(image);
2091 wine_tsx11_unlock();
2093 LeaveCriticalSection(&xrender_cs);
2095 if (flags & ETO_CLIPPED)
2097 /* restore the device region */
2098 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
2099 DeleteObject( saved_region );
2105 X11DRV_UnlockDIBSection( physDev, TRUE );
2109 /* Helper function for (stretched) blitting using xrender */
2110 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2111 int x_src, int y_src, int x_dst, int y_dst,
2112 double xscale, double yscale, int width, int height )
2114 int x_offset, y_offset;
2116 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2117 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2118 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2119 if(xscale != 1.0 || yscale != 1.0)
2121 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2122 * in the wrong quadrant of the x-y plane.
2124 x_offset = (xscale < 0) ? -width : 0;
2125 y_offset = (yscale < 0) ? -height : 0;
2126 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2132 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2134 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2135 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2138 /* Helper function for (stretched) mono->color blitting using xrender */
2139 static void xrender_mono_blit( Picture src_pict, Picture mask_pict, Picture dst_pict,
2140 int x_src, int y_src, double xscale, double yscale, int width, int height )
2142 int x_offset, y_offset;
2144 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2145 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
2146 * tile data. We need PictOpOver for correct rendering.
2147 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2150 if (xscale != 1.0 || yscale != 1.0)
2152 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2153 * in the wrong quadrant of the x-y plane.
2155 x_offset = (xscale < 0) ? -width : 0;
2156 y_offset = (yscale < 0) ? -height : 0;
2157 set_xrender_transformation(mask_pict, xscale, yscale, x_src, y_src);
2163 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
2165 pXRenderComposite(gdi_display, PictOpOver, src_pict, mask_pict, dst_pict,
2166 0, 0, x_offset, y_offset, 0, 0, width, height);
2169 /******************************************************************************
2172 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2173 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2175 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2176 struct xrender_info *src_info = get_xrender_info( devSrc );
2177 double xscale, yscale;
2180 if(!X11DRV_XRender_Installed) {
2181 FIXME("Unable to AlphaBlend without Xrender\n");
2185 if (devSrc != devDst) X11DRV_LockDIBSection( devSrc, DIB_Status_GdiMod );
2186 X11DRV_LockDIBSection( devDst, DIB_Status_GdiMod );
2188 dst_pict = get_xrender_picture( devDst );
2190 use_repeat = use_source_repeat( devSrc );
2193 xscale = src->width / (double)dst->width;
2194 yscale = src->height / (double)dst->height;
2196 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2198 if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && src_info->format)
2200 /* we need a source picture with no alpha */
2201 WXRFormat format = get_format_without_alpha( src_info->format->format );
2202 if (format != src_info->format->format)
2204 XRenderPictureAttributes pa;
2205 const WineXRenderFormat *fmt = get_xrender_format( format );
2208 pa.subwindow_mode = IncludeInferiors;
2209 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2210 tmp_pict = pXRenderCreatePicture( gdi_display, devSrc->drawable, fmt->pict_format,
2211 CPSubwindowMode|CPRepeat, &pa );
2212 wine_tsx11_unlock();
2213 src_pict = tmp_pict;
2217 if (!src_pict) src_pict = get_xrender_picture_source( devSrc, use_repeat );
2219 EnterCriticalSection( &xrender_cs );
2220 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2223 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2224 devSrc->dc_rect.left + src->visrect.left, devSrc->dc_rect.top + src->visrect.top,
2225 devDst->dc_rect.left + dst->visrect.left, devDst->dc_rect.top + dst->visrect.top,
2227 dst->visrect.right - dst->visrect.left, dst->visrect.bottom - dst->visrect.top );
2228 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2229 wine_tsx11_unlock();
2231 LeaveCriticalSection( &xrender_cs );
2232 if (devSrc != devDst) X11DRV_UnlockDIBSection( devSrc, FALSE );
2233 X11DRV_UnlockDIBSection( devDst, TRUE );
2238 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2240 /* 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 */
2241 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2242 const WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2243 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2246 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2248 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2249 if( (physBitmap->pixmap_depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->pixmap_depth) ||
2250 (src_format->format == dst_format->format) )
2252 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2253 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2255 else /* We need depth conversion */
2257 Picture src_pict, dst_pict;
2258 XRenderPictureAttributes pa;
2259 pa.subwindow_mode = IncludeInferiors;
2260 pa.repeat = RepeatNone;
2262 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2263 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2265 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2266 pXRenderFreePicture(gdi_display, src_pict);
2267 pXRenderFreePicture(gdi_display, dst_pict);
2269 wine_tsx11_unlock();
2272 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2273 Pixmap pixmap, GC gc,
2274 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2276 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2277 int width = dst->visrect.right - dst->visrect.left;
2278 int height = dst->visrect.bottom - dst->visrect.top;
2279 int x_src = physDevSrc->dc_rect.left + src->visrect.left;
2280 int y_src = physDevSrc->dc_rect.top + src->visrect.top;
2281 struct xrender_info *src_info = get_xrender_info(physDevSrc);
2282 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDevDst->depth, physDevDst->color_shifts);
2283 Picture src_pict=0, dst_pict=0, mask_pict=0;
2285 double xscale, yscale;
2287 XRenderPictureAttributes pa;
2288 pa.subwindow_mode = IncludeInferiors;
2289 pa.repeat = RepeatNone;
2291 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2292 physDevSrc->depth, src->width, src->height, x_src, y_src);
2293 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst->depth, dst->width, dst->height);
2295 if(!X11DRV_XRender_Installed)
2297 TRACE("Not using XRender since it is not available or disabled\n");
2301 /* XRender can't handle palettes, so abort */
2302 if(X11DRV_PALETTE_XPixelToPalette)
2305 /* XRender is of no use in this case */
2306 if((physDevDst->depth == 1) && (physDevSrc->depth > 1))
2309 /* Just use traditional X copy when the formats match and we don't need stretching */
2310 if((src_info->format->format == dst_format->format) && !stretch)
2312 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2314 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
2315 wine_tsx11_unlock();
2319 use_repeat = use_source_repeat( physDevSrc );
2322 xscale = src->width / (double)dst->width;
2323 yscale = src->height / (double)dst->height;
2325 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2328 if(physDevSrc->depth == 1 && physDevDst->depth > 1)
2331 get_xrender_color(dst_format, physDevDst->textPixel, &col);
2333 /* We use the source drawable as a mask */
2334 mask_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2336 /* Use backgroundPixel as the foreground color */
2337 EnterCriticalSection( &xrender_cs );
2338 src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
2340 /* Create a destination picture and fill it with textPixel color as the background color */
2342 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2343 pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height);
2345 xrender_mono_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
2347 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2348 wine_tsx11_unlock();
2349 LeaveCriticalSection( &xrender_cs );
2351 else /* color -> color (can be at different depths) or mono -> mono */
2353 if (physDevDst->depth == 32 && physDevSrc->depth < 32) mask_pict = get_no_alpha_mask();
2354 src_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2357 dst_pict = pXRenderCreatePicture(gdi_display,
2358 pixmap, dst_format->pict_format,
2359 CPSubwindowMode|CPRepeat, &pa);
2361 xrender_blit(PictOpSrc, src_pict, mask_pict, dst_pict,
2362 x_src, y_src, 0, 0, xscale, yscale, width, height);
2364 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2365 wine_tsx11_unlock();
2370 #else /* SONAME_LIBXRENDER */
2372 void X11DRV_XRender_Init(void)
2374 TRACE("XRender support not compiled in.\n");
2378 void X11DRV_XRender_Finalize(void)
2382 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
2388 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
2394 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
2400 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
2401 const RECT *lprect, LPCWSTR wstr, UINT count,
2408 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
2414 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2415 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2417 FIXME("not supported - XRENDER headers were missing at compile time\n");
2421 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2424 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
2426 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2427 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2428 wine_tsx11_unlock();
2431 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2436 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2437 Pixmap pixmap, GC gc,
2438 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2442 #endif /* SONAME_LIBXRENDER */