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
73 WXR_INVALID_FORMAT = WXR_NB_FORMATS
76 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 static enum wxr_format default_format;
107 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
113 SIZE devsize; /* size in device coords */
117 #define INITIAL_REALIZED_BUF_SIZE 128
119 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
124 XRenderPictFormat *font_format;
129 } gsCacheEntryFormat;
135 gsCacheEntryFormat * format[AA_MAXVALUE];
140 struct xrender_physdev
142 struct gdi_physdev dev;
143 X11DRV_PDEVICE *x11dev;
144 enum wxr_format format;
148 XRenderPictFormat *pict_format;
151 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
153 return (struct xrender_physdev *)dev;
156 static const struct gdi_dc_funcs xrender_funcs;
158 static gsCacheEntry *glyphsetCache = NULL;
159 static DWORD glyphsetCacheSize = 0;
160 static INT lastfree = -1;
163 #define INIT_CACHE_SIZE 10
165 static int antialias = 1;
167 static void *xrender_handle;
169 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
170 MAKE_FUNCPTR(XRenderAddGlyphs)
171 MAKE_FUNCPTR(XRenderComposite)
172 MAKE_FUNCPTR(XRenderCompositeString8)
173 MAKE_FUNCPTR(XRenderCompositeString16)
174 MAKE_FUNCPTR(XRenderCompositeString32)
175 MAKE_FUNCPTR(XRenderCompositeText16)
176 MAKE_FUNCPTR(XRenderCreateGlyphSet)
177 MAKE_FUNCPTR(XRenderCreatePicture)
178 MAKE_FUNCPTR(XRenderFillRectangle)
179 MAKE_FUNCPTR(XRenderFindFormat)
180 MAKE_FUNCPTR(XRenderFindVisualFormat)
181 MAKE_FUNCPTR(XRenderFreeGlyphSet)
182 MAKE_FUNCPTR(XRenderFreePicture)
183 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
184 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
185 MAKE_FUNCPTR(XRenderSetPictureTransform)
187 MAKE_FUNCPTR(XRenderQueryExtension)
189 #ifdef SONAME_LIBFONTCONFIG
190 #include <fontconfig/fontconfig.h>
191 MAKE_FUNCPTR(FcConfigSubstitute)
192 MAKE_FUNCPTR(FcDefaultSubstitute)
193 MAKE_FUNCPTR(FcFontMatch)
195 MAKE_FUNCPTR(FcPatternCreate)
196 MAKE_FUNCPTR(FcPatternDestroy)
197 MAKE_FUNCPTR(FcPatternAddInteger)
198 MAKE_FUNCPTR(FcPatternAddString)
199 MAKE_FUNCPTR(FcPatternGetBool)
200 MAKE_FUNCPTR(FcPatternGetInteger)
201 MAKE_FUNCPTR(FcPatternGetString)
202 static void *fontconfig_handle;
203 static BOOL fontconfig_installed;
208 static CRITICAL_SECTION xrender_cs;
209 static CRITICAL_SECTION_DEBUG critsect_debug =
212 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
213 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
215 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
217 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
218 ( ( (ULONG)_x4 << 24 ) | \
219 ( (ULONG)_x3 << 16 ) | \
220 ( (ULONG)_x2 << 8 ) | \
223 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
225 #define GASP_GRIDFIT 0x01
226 #define GASP_DOGRAY 0x02
228 #ifdef WORDS_BIGENDIAN
229 #define get_be_word(x) (x)
230 #define NATIVE_BYTE_ORDER MSBFirst
232 #define get_be_word(x) RtlUshortByteSwap(x)
233 #define NATIVE_BYTE_ORDER LSBFirst
236 static enum wxr_format get_format_without_alpha( enum wxr_format format )
240 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
241 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
242 default: return format;
246 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
249 templ->type = PictTypeDirect;
250 templ->depth = fmt->depth;
251 templ->direct.alpha = fmt->alpha;
252 templ->direct.alphaMask = fmt->alphaMask;
253 templ->direct.red = fmt->red;
254 templ->direct.redMask = fmt->redMask;
255 templ->direct.green = fmt->green;
256 templ->direct.greenMask = fmt->greenMask;
257 templ->direct.blue = fmt->blue;
258 templ->direct.blueMask = fmt->blueMask;
261 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
266 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
268 if(fmt->depth != screen_depth)
270 if( (fmt->redMask << fmt->red) != visual->red_mask)
272 if( (fmt->greenMask << fmt->green) != visual->green_mask)
274 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
277 /* We never select a default ARGB visual */
284 static int load_xrender_formats(void)
289 for (i = 0; i < WXR_NB_FORMATS; i++)
291 XRenderPictFormat templ;
293 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
296 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
297 if (!pict_formats[i])
299 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
300 if (visual->class == DirectColor)
303 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
304 screen_depth, TrueColor, &info ))
306 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
307 if (pict_formats[i]) visual = info.visual;
312 if (pict_formats[i]) default_format = i;
316 unsigned long mask = 0;
317 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
320 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
326 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
332 /***********************************************************************
333 * X11DRV_XRender_Init
335 * Let's see if our XServer has the extension available
338 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
342 if (client_side_with_render &&
343 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
346 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
347 LOAD_FUNCPTR(XRenderAddGlyphs)
348 LOAD_FUNCPTR(XRenderComposite)
349 LOAD_FUNCPTR(XRenderCompositeString8)
350 LOAD_FUNCPTR(XRenderCompositeString16)
351 LOAD_FUNCPTR(XRenderCompositeString32)
352 LOAD_FUNCPTR(XRenderCompositeText16)
353 LOAD_FUNCPTR(XRenderCreateGlyphSet)
354 LOAD_FUNCPTR(XRenderCreatePicture)
355 LOAD_FUNCPTR(XRenderFillRectangle)
356 LOAD_FUNCPTR(XRenderFindFormat)
357 LOAD_FUNCPTR(XRenderFindVisualFormat)
358 LOAD_FUNCPTR(XRenderFreeGlyphSet)
359 LOAD_FUNCPTR(XRenderFreePicture)
360 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
361 LOAD_FUNCPTR(XRenderQueryExtension)
363 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
364 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
365 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
366 #undef LOAD_OPTIONAL_FUNCPTR
370 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
372 if(X11DRV_XRender_Installed) {
373 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
374 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
378 "Wine has detected that you probably have a buggy version\n"
379 "of libXrender.so . Because of this client side font rendering\n"
380 "will be disabled. Please upgrade this library.\n");
381 X11DRV_XRender_Installed = FALSE;
385 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
386 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
387 X11DRV_XRender_Installed = FALSE;
392 #ifdef SONAME_LIBFONTCONFIG
393 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
395 #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;}
396 LOAD_FUNCPTR(FcConfigSubstitute);
397 LOAD_FUNCPTR(FcDefaultSubstitute);
398 LOAD_FUNCPTR(FcFontMatch);
399 LOAD_FUNCPTR(FcInit);
400 LOAD_FUNCPTR(FcPatternCreate);
401 LOAD_FUNCPTR(FcPatternDestroy);
402 LOAD_FUNCPTR(FcPatternAddInteger);
403 LOAD_FUNCPTR(FcPatternAddString);
404 LOAD_FUNCPTR(FcPatternGetBool);
405 LOAD_FUNCPTR(FcPatternGetInteger);
406 LOAD_FUNCPTR(FcPatternGetString);
408 fontconfig_installed = pFcInit();
410 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
414 if(X11DRV_XRender_Installed || client_side_with_core)
416 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
417 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
419 glyphsetCacheSize = INIT_CACHE_SIZE;
421 for(i = 0; i < INIT_CACHE_SIZE; i++) {
422 glyphsetCache[i].next = i + 1;
423 glyphsetCache[i].count = -1;
425 glyphsetCache[i-1].next = -1;
426 using_client_side_fonts = 1;
428 if(!X11DRV_XRender_Installed) {
429 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
430 if(screen_depth <= 8 || !client_side_antialias_with_core)
433 if(screen_depth <= 8 || !client_side_antialias_with_render)
436 return &xrender_funcs;
438 TRACE("Using X11 core fonts\n");
442 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
443 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
445 if(pf->direct.redMask)
446 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
450 if(pf->direct.greenMask)
451 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
453 dst_color->green = 0;
455 if(pf->direct.blueMask)
456 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
460 dst_color->alpha = 0xffff;
463 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
465 int redMask, greenMask, blueMask;
468 if (depth == 1) return WXR_FORMAT_MONO;
470 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
471 if (!shifts) return default_format;
473 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
474 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
475 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
477 /* Try to locate a format which matches the specification of the dibsection. */
478 for(i = 0; i < WXR_NB_FORMATS; i++)
480 if( depth == wxr_formats_template[i].depth &&
481 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
482 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
483 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
487 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
488 ERR("No XRender format found!\n");
489 return WXR_INVALID_FORMAT;
492 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
493 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
495 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
496 XTransform xform = {{
497 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
498 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
499 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
502 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
506 /* check if we can use repeating instead of scaling for the specified source DC */
507 static BOOL use_source_repeat( struct xrender_physdev *dev )
509 return (dev->x11dev->bitmap &&
510 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
511 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
514 static Picture get_xrender_picture( struct xrender_physdev *dev )
516 if (!dev->pict && dev->pict_format)
518 XRenderPictureAttributes pa;
519 RGNDATA *clip = X11DRV_GetRegionData( dev->x11dev->region, 0 );
522 pa.subwindow_mode = IncludeInferiors;
523 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
524 dev->pict_format, CPSubwindowMode, &pa );
525 if (dev->pict && clip)
526 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
527 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
528 (XRectangle *)clip->Buffer, clip->rdh.nCount );
530 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
531 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
532 HeapFree( GetProcessHeap(), 0, clip );
538 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
540 if (!dev->pict_src && dev->pict_format)
542 XRenderPictureAttributes pa;
545 pa.subwindow_mode = IncludeInferiors;
546 pa.repeat = repeat ? RepeatNormal : RepeatNone;
547 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
548 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
551 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
552 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
555 return dev->pict_src;
558 static void free_xrender_picture( struct xrender_physdev *dev )
560 if (dev->pict || dev->pict_src)
563 XFlush( gdi_display );
566 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
567 pXRenderFreePicture(gdi_display, dev->pict);
572 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
573 pXRenderFreePicture(gdi_display, dev->pict_src);
578 dev->pict_format = NULL;
581 static void update_xrender_drawable( struct xrender_physdev *dev )
583 free_xrender_picture( dev );
584 dev->format = get_xrender_format_from_color_shifts( dev->x11dev->depth, dev->x11dev->color_shifts );
585 dev->pict_format = pict_formats[dev->format];
588 /* return a mask picture used to force alpha to 0 */
589 static Picture get_no_alpha_mask(void)
591 static Pixmap pixmap;
597 XRenderPictureAttributes pa;
600 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
601 pa.repeat = RepeatNormal;
602 pa.component_alpha = True;
603 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
604 CPRepeat|CPComponentAlpha, &pa );
605 col.red = col.green = col.blue = 0xffff;
607 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
613 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
615 if(p1->hash != p2->hash) return TRUE;
616 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
617 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
618 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
619 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
623 static void walk_cache(void)
627 EnterCriticalSection(&xrender_cs);
628 for(i=mru; i >= 0; i = glyphsetCache[i].next)
629 TRACE("item %d\n", i);
630 LeaveCriticalSection(&xrender_cs);
634 static int LookupEntry(LFANDSIZE *plfsz)
638 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
640 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
642 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
643 glyphsetCache[i].count++;
645 glyphsetCache[prev_i].next = glyphsetCache[i].next;
646 glyphsetCache[i].next = mru;
649 TRACE("found font in cache %d\n", i);
654 TRACE("font not in cache\n");
658 static void FreeEntry(int entry)
662 for(format = 0; format < AA_MAXVALUE; format++) {
663 gsCacheEntryFormat * formatEntry;
665 if( !glyphsetCache[entry].format[format] )
668 formatEntry = glyphsetCache[entry].format[format];
670 if(formatEntry->glyphset) {
672 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
674 formatEntry->glyphset = 0;
676 if(formatEntry->nrealized) {
677 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
678 formatEntry->realized = NULL;
679 if(formatEntry->bitmaps) {
680 for(i = 0; i < formatEntry->nrealized; i++)
681 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
682 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
683 formatEntry->bitmaps = NULL;
685 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
686 formatEntry->gis = NULL;
687 formatEntry->nrealized = 0;
690 HeapFree(GetProcessHeap(), 0, formatEntry);
691 glyphsetCache[entry].format[format] = NULL;
695 static int AllocEntry(void)
697 int best = -1, prev_best = -1, i, prev_i = -1;
700 assert(glyphsetCache[lastfree].count == -1);
701 glyphsetCache[lastfree].count = 1;
703 lastfree = glyphsetCache[lastfree].next;
705 glyphsetCache[best].next = mru;
708 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
712 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
713 if(glyphsetCache[i].count == 0) {
721 TRACE("freeing unused glyphset at cache %d\n", best);
723 glyphsetCache[best].count = 1;
725 glyphsetCache[prev_best].next = glyphsetCache[best].next;
726 glyphsetCache[best].next = mru;
734 TRACE("Growing cache\n");
737 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
739 (glyphsetCacheSize + INIT_CACHE_SIZE)
740 * sizeof(*glyphsetCache));
742 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
743 (glyphsetCacheSize + INIT_CACHE_SIZE)
744 * sizeof(*glyphsetCache));
746 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
748 glyphsetCache[i].next = i + 1;
749 glyphsetCache[i].count = -1;
751 glyphsetCache[i-1].next = -1;
752 glyphsetCacheSize += INIT_CACHE_SIZE;
754 lastfree = glyphsetCache[best].next;
755 glyphsetCache[best].count = 1;
756 glyphsetCache[best].next = mru;
758 TRACE("new free cache slot at %d\n", mru);
762 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
772 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
773 if(size == GDI_ERROR)
776 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
777 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
779 GetTextMetricsW(hdc, &tm);
780 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
783 num_recs = get_be_word(*gasp);
787 *flags = get_be_word(*(gasp + 1));
788 if(ppem <= get_be_word(*gasp))
792 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
794 HeapFree(GetProcessHeap(), 0, buffer);
798 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
802 UINT font_smoothing_type, font_smoothing_orientation;
804 if (X11DRV_XRender_Installed && subpixel &&
805 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
806 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
808 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
809 &font_smoothing_orientation, 0) &&
810 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
817 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
818 But, Wine's subpixel rendering can support the portrait mode.
821 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
829 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
834 static int hinter = -1;
835 static int subpixel = -1;
838 if((ret = LookupEntry(plfsz)) != -1) return ret;
841 entry = glyphsetCache + ret;
842 entry->lfsz = *plfsz;
843 for( format = 0; format < AA_MAXVALUE; format++ ) {
844 assert( !entry->format[format] );
847 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
849 if(hinter == -1 || subpixel == -1)
851 RASTERIZER_STATUS status;
852 GetRasterizerCaps(&status, sizeof(status));
853 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
854 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
857 switch (plfsz->lf.lfQuality)
859 case ANTIALIASED_QUALITY:
860 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
861 return ret; /* ignore further configuration */
862 case CLEARTYPE_QUALITY:
863 case CLEARTYPE_NATURAL_QUALITY:
864 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
866 case DEFAULT_QUALITY:
870 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
873 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
876 entry->aa_default = AA_None;
880 font_smoothing = TRUE; /* default to enabled */
881 #ifdef SONAME_LIBFONTCONFIG
882 if (fontconfig_installed)
884 FcPattern *match, *pattern = pFcPatternCreate();
886 char family[LF_FACESIZE * 4];
888 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
889 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
890 if (plfsz->lf.lfWeight != FW_DONTCARE)
893 switch (plfsz->lf.lfWeight)
895 case FW_THIN: weight = FC_WEIGHT_THIN; break;
896 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
897 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
898 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
899 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
900 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
901 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
902 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
903 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
904 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
906 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
908 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
909 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
910 pFcDefaultSubstitute( pattern );
911 if ((match = pFcFontMatch( NULL, pattern, &result )))
916 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
918 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
921 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
923 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
924 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
928 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
929 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
930 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
931 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
932 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
935 if (!antialias) font_smoothing = FALSE;
936 pFcPatternDestroy( match );
938 pFcPatternDestroy( pattern );
940 #endif /* SONAME_LIBFONTCONFIG */
942 /* now check Xft resources */
945 BOOL antialias = TRUE;
948 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
950 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
951 value[0] == '0' || !strcasecmp( value, "off" ))
954 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
956 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
957 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
958 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
959 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
960 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
961 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
964 if (!antialias) font_smoothing = FALSE;
967 if (!font_smoothing) entry->aa_default = AA_None;
969 /* we can't support subpixel without xrender */
970 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
973 entry->aa_default = AA_None;
978 static void dec_ref_cache(int index)
981 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
982 assert(glyphsetCache[index].count > 0);
983 glyphsetCache[index].count--;
986 static void lfsz_calc_hash(LFANDSIZE *plfsz)
988 DWORD hash = 0, *ptr, two_chars;
992 hash ^= plfsz->devsize.cx;
993 hash ^= plfsz->devsize.cy;
994 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
996 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
998 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1000 pwc = (WCHAR *)&two_chars;
1002 *pwc = toupperW(*pwc);
1004 *pwc = toupperW(*pwc);
1012 /***********************************************************************
1013 * X11DRV_XRender_Finalize
1015 void X11DRV_XRender_Finalize(void)
1019 EnterCriticalSection(&xrender_cs);
1020 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1022 LeaveCriticalSection(&xrender_cs);
1025 /**********************************************************************
1026 * xrenderdrv_SelectFont
1028 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
1030 struct xrender_physdev *physdev = get_xrender_dev( dev );
1033 if (!GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf )) return HGDI_ERROR;
1037 dev = GET_NEXT_PHYSDEV( dev, pSelectFont );
1038 return dev->funcs->pSelectFont( dev, hfont, gdiFont );
1041 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1042 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1043 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1044 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1045 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1046 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1048 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1049 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1050 lfsz.xform.eM21, lfsz.xform.eM22);
1052 /* Not used fields, would break hashing */
1053 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1055 lfsz_calc_hash(&lfsz);
1057 EnterCriticalSection(&xrender_cs);
1058 if (physdev->cache_index != -1)
1059 dec_ref_cache( physdev->cache_index );
1060 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1061 LeaveCriticalSection(&xrender_cs);
1062 physdev->x11dev->has_gdi_font = TRUE;
1066 static void update_xrender_clipping( struct xrender_physdev *dev, const RGNDATA *data )
1071 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
1072 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
1073 (XRectangle *)data->Buffer, data->rdh.nCount );
1074 wine_tsx11_unlock();
1078 static RGNDATA *add_xrender_clipping_region( struct xrender_physdev *dev, HRGN rgn )
1080 RGNDATA *ret, *data;
1083 if (!(ret = X11DRV_GetRegionData( dev->x11dev->region, 0 ))) return NULL;
1084 if (!(clip = CreateRectRgn( 0, 0, 0, 0 )))
1086 HeapFree( GetProcessHeap(), 0, ret );
1089 CombineRgn( clip, dev->x11dev->region, rgn, RGN_AND );
1090 if ((data = X11DRV_GetRegionData( clip, 0 )))
1092 update_xrender_clipping( dev, data );
1093 HeapFree( GetProcessHeap(), 0, data );
1095 DeleteObject( clip );
1099 static void restore_xrender_clipping_region( struct xrender_physdev *dev, RGNDATA *data )
1102 update_xrender_clipping( dev, data );
1103 HeapFree( GetProcessHeap(), 0, data );
1106 static BOOL create_xrender_dc( PHYSDEV *pdev )
1108 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1109 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1111 if (!physdev) return FALSE;
1112 physdev->x11dev = x11dev;
1113 physdev->cache_index = -1;
1114 physdev->format = get_xrender_format_from_color_shifts( x11dev->depth, x11dev->color_shifts );
1115 physdev->pict_format = pict_formats[physdev->format];
1116 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1120 /**********************************************************************
1121 * xrenderdrv_CreateDC
1123 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1124 LPCWSTR output, const DEVMODEW* initData )
1126 return create_xrender_dc( pdev );
1129 /**********************************************************************
1130 * xrenderdrv_CreateCompatibleDC
1132 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1134 if (orig) /* chain to x11drv first */
1136 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1137 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1139 /* otherwise we have been called by x11drv */
1141 return create_xrender_dc( pdev );
1144 /**********************************************************************
1145 * xrenderdrv_DeleteDC
1147 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1149 struct xrender_physdev *physdev = get_xrender_dev( dev );
1151 free_xrender_picture( physdev );
1153 EnterCriticalSection( &xrender_cs );
1154 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1155 LeaveCriticalSection( &xrender_cs );
1157 HeapFree( GetProcessHeap(), 0, physdev );
1161 /**********************************************************************
1162 * xrenderdrv_ExtEscape
1164 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1165 INT out_count, LPVOID out_data )
1167 struct xrender_physdev *physdev = get_xrender_dev( dev );
1169 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1171 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1173 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1175 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1176 if (ret) update_xrender_drawable( physdev );
1180 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1183 /****************************************************************************
1184 * xrenderdrv_CreateBitmap
1186 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1188 XRenderPictFormat *pict_format = NULL;
1192 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1194 if (bitmap.bmPlanes == 1 && bitmap.bmBitsPixel == screen_bpp)
1196 switch (bitmap.bmBitsPixel)
1198 case 16: pict_format = pict_formats[WXR_FORMAT_R5G6B5]; break;
1199 case 24: pict_format = pict_formats[WXR_FORMAT_R8G8B8]; break;
1200 case 32: pict_format = pict_formats[WXR_FORMAT_A8R8G8B8]; break;
1206 X11DRV_PALETTE_ComputeColorShifts( &shifts,
1207 pict_format->direct.redMask << pict_format->direct.red,
1208 pict_format->direct.greenMask << pict_format->direct.green,
1209 pict_format->direct.blueMask << pict_format->direct.blue );
1210 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_format->depth, TRUE, &shifts );
1213 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1214 return dev->funcs->pCreateBitmap( dev, hbitmap );
1217 /****************************************************************************
1218 * xrenderdrv_DeleteBitmap
1220 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1222 return X11DRV_DeleteBitmap( hbitmap );
1225 /***********************************************************************
1226 * xrenderdrv_SelectBitmap
1228 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1231 struct xrender_physdev *physdev = get_xrender_dev( dev );
1233 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1234 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1235 if (ret) update_xrender_drawable( physdev );
1239 /***********************************************************************
1240 * xrenderdrv_GetImage
1242 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1243 struct gdi_image_bits *bits, struct bitblt_coords *src )
1245 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1246 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1247 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1250 /***********************************************************************
1251 * xrenderdrv_PutImage
1253 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
1254 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1255 struct bitblt_coords *dst, DWORD rop )
1257 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
1258 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
1259 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
1262 /***********************************************************************
1263 * xrenderdrv_SetDeviceClipping
1265 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1267 struct xrender_physdev *physdev = get_xrender_dev( dev );
1270 CombineRgn( physdev->x11dev->region, vis_rgn, clip_rgn, clip_rgn ? RGN_AND : RGN_COPY );
1272 if (!(data = X11DRV_GetRegionData( physdev->x11dev->region, 0 ))) return;
1273 update_x11_clipping( physdev->x11dev, data );
1274 update_xrender_clipping( physdev, data );
1275 HeapFree( GetProcessHeap(), 0, data );
1279 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1281 XRenderPictFormat *pict_format;
1283 const DWORD *bitfields;
1284 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1285 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1288 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1289 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1290 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1291 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1294 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1295 bitfields = dib->dsBitfields;
1296 else if(bits_pixel == 24 || bits_pixel == 32)
1297 bitfields = bitfields_32;
1299 bitfields = bitfields_16;
1301 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1302 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1304 /* Common formats should be in our picture format table. */
1307 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1308 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1312 physBitmap->pixmap_depth = pict_format->depth;
1313 physBitmap->trueColor = TRUE;
1314 physBitmap->pixmap_color_shifts = shifts;
1318 /************************************************************************
1321 * Helper to ExtTextOut. Must be called inside xrender_cs
1323 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1325 unsigned int buflen;
1330 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1331 gsCacheEntryFormat *formatEntry;
1332 UINT ggo_format = GGO_GLYPH_INDEX;
1333 enum wxr_format wxr_format;
1334 static const char zero[4];
1335 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1339 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1342 ggo_format |= WINE_GGO_HRGB_BITMAP;
1345 ggo_format |= WINE_GGO_HBGR_BITMAP;
1348 ggo_format |= WINE_GGO_VRGB_BITMAP;
1351 ggo_format |= WINE_GGO_VBGR_BITMAP;
1355 ERR("aa = %d - not implemented\n", format);
1357 ggo_format |= GGO_BITMAP;
1361 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1362 if(buflen == GDI_ERROR) {
1363 if(format != AA_None) {
1365 entry->aa_default = AA_None;
1366 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1367 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1369 if(buflen == GDI_ERROR) {
1370 WARN("GetGlyphOutlineW failed using default glyph\n");
1371 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1372 if(buflen == GDI_ERROR) {
1373 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1374 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1375 if(buflen == GDI_ERROR) {
1376 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1381 TRACE("Turning off antialiasing for this monochrome font\n");
1384 /* If there is nothing for the current type, we create the entry. */
1385 if( !entry->format[format] ) {
1386 entry->format[format] = HeapAlloc(GetProcessHeap(),
1388 sizeof(gsCacheEntryFormat));
1390 formatEntry = entry->format[format];
1392 if(formatEntry->nrealized <= glyph) {
1393 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1395 if (formatEntry->realized)
1396 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1398 formatEntry->realized,
1399 formatEntry->nrealized * sizeof(BOOL));
1401 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1403 formatEntry->nrealized * sizeof(BOOL));
1405 if(!X11DRV_XRender_Installed) {
1406 if (formatEntry->bitmaps)
1407 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1409 formatEntry->bitmaps,
1410 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1412 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1414 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1416 if (formatEntry->gis)
1417 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1420 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1422 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1424 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1428 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1431 wxr_format = WXR_FORMAT_GRAY;
1438 wxr_format = WXR_FORMAT_A8R8G8B8;
1442 ERR("aa = %d - not implemented\n", format);
1444 wxr_format = WXR_FORMAT_MONO;
1449 formatEntry->font_format = pict_formats[wxr_format];
1450 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1451 wine_tsx11_unlock();
1455 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1456 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1457 formatEntry->realized[glyph] = TRUE;
1459 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1461 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1462 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1464 gi.width = gm.gmBlackBoxX;
1465 gi.height = gm.gmBlackBoxY;
1466 gi.x = -gm.gmptGlyphOrigin.x;
1467 gi.y = gm.gmptGlyphOrigin.y;
1468 gi.xOff = gm.gmCellIncX;
1469 gi.yOff = gm.gmCellIncY;
1471 if(TRACE_ON(xrender)) {
1474 unsigned char *line;
1476 if(format == AA_None) {
1477 pitch = ((gi.width + 31) / 32) * 4;
1478 for(i = 0; i < gi.height; i++) {
1479 line = (unsigned char*) buf + i * pitch;
1481 for(j = 0; j < pitch * 8; j++) {
1482 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1484 TRACE("%s\n", output);
1487 static const char blks[] = " .:;!o*#";
1491 pitch = ((gi.width + 3) / 4) * 4;
1492 for(i = 0; i < gi.height; i++) {
1493 line = (unsigned char*) buf + i * pitch;
1495 for(j = 0; j < pitch; j++) {
1496 str[0] = blks[line[j] >> 5];
1497 strcat(output, str);
1499 TRACE("%s\n", output);
1505 if(formatEntry->glyphset) {
1506 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1507 unsigned char *byte = (unsigned char*) buf, c;
1513 /* magic to flip bit order */
1514 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1515 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1516 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1521 else if ( format != AA_Grey &&
1522 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1524 unsigned int i, *data = (unsigned int *)buf;
1525 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1530 XRenderCompositeText seems to ignore 0x0 glyphs when
1531 AA_None, which means we lose the advance width of glyphs
1532 like the space. We'll pretend that such glyphs are 1x1
1537 gi.width = gi.height = 1;
1540 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1541 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1542 wine_tsx11_unlock();
1543 HeapFree(GetProcessHeap(), 0, buf);
1545 formatEntry->bitmaps[glyph] = buf;
1548 formatEntry->gis[glyph] = gi;
1551 static void SharpGlyphMono(struct xrender_physdev *physDev, INT x, INT y,
1552 void *bitmap, XGlyphInfo *gi)
1554 unsigned char *srcLine = bitmap, *src;
1555 unsigned char bits, bitsMask;
1556 int width = gi->width;
1557 int stride = ((width + 31) & ~31) >> 3;
1558 int height = gi->height;
1562 TRACE("%d, %d\n", x, y);
1571 bitsMask = 0x80; /* FreeType is always MSB first */
1577 if (bits & bitsMask)
1585 bitsMask = bitsMask >> 1;
1591 } while (bits & bitsMask);
1592 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1593 physDev->x11dev->gc, xspan, y, lenspan, 1);
1605 bitsMask = bitsMask >> 1;
1611 } while (!(bits & bitsMask));
1618 static void SharpGlyphGray(struct xrender_physdev *physDev, INT x, INT y,
1619 void *bitmap, XGlyphInfo *gi)
1621 unsigned char *srcLine = bitmap, *src, bits;
1622 int width = gi->width;
1623 int stride = ((width + 3) & ~3);
1624 int height = gi->height;
1649 } while (bits >= 0x80);
1650 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1651 physDev->x11dev->gc, xspan, y, lenspan, 1);
1664 } while (bits < 0x80);
1672 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1677 while ((mask & 1) == 0)
1683 while ((mask & 1) == 1)
1692 static DWORD GetField (DWORD pixel, int shift, int len)
1694 pixel = pixel & (((1 << (len)) - 1) << shift);
1695 pixel = pixel << (32 - (shift + len)) >> 24;
1698 pixel |= (pixel >> len);
1705 static DWORD PutField (DWORD pixel, int shift, int len)
1707 shift = shift - (8 - len);
1709 pixel &= (((1 << len) - 1) << (8 - len));
1717 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1723 BYTE *maskLine, *mask, m;
1728 BYTE src_r, src_g, src_b;
1733 height = gi->height;
1736 maskStride = (width + 3) & ~3;
1738 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1739 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1740 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1742 src_r = GetField(color, r_shift, r_len);
1743 src_g = GetField(color, g_shift, g_len);
1744 src_b = GetField(color, b_shift, b_len);
1746 for(; height--; y++)
1749 maskLine += maskStride;
1754 if(y >= image->height) break;
1758 if(tx >= image->width) break;
1761 if(tx < 0) continue;
1764 XPutPixel (image, tx, y, color);
1769 pixel = XGetPixel (image, tx, y);
1771 r = GetField(pixel, r_shift, r_len);
1772 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1773 g = GetField(pixel, g_shift, g_len);
1774 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1775 b = GetField(pixel, b_shift, b_len);
1776 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1778 pixel = (PutField (r, r_shift, r_len) |
1779 PutField (g, g_shift, g_len) |
1780 PutField (b, b_shift, b_len));
1781 XPutPixel (image, tx, y, pixel);
1787 /*************************************************************
1790 * Returns an appropriate Picture for tiling the text colour.
1791 * Call and use result within the xrender_cs
1793 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1799 XRenderColor current_color;
1800 } tiles[WXR_NB_FORMATS], *tile;
1802 tile = &tiles[wxr_format];
1806 XRenderPictureAttributes pa;
1807 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1810 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1812 pa.repeat = RepeatNormal;
1813 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1814 wine_tsx11_unlock();
1816 /* init current_color to something different from text_pixel */
1817 tile->current_color = *color;
1818 tile->current_color.red ^= 0xffff;
1820 if (wxr_format == WXR_FORMAT_MONO)
1822 /* for a 1bpp bitmap we always need a 1 in the tile */
1824 col.red = col.green = col.blue = 0;
1827 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1828 wine_tsx11_unlock();
1832 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1835 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1836 wine_tsx11_unlock();
1837 tile->current_color = *color;
1842 /*************************************************************
1845 * Returns an appropriate Picture for masking with the specified alpha.
1846 * Call and use result within the xrender_cs
1848 static Picture get_mask_pict( int alpha )
1850 static Pixmap pixmap;
1851 static Picture pict;
1852 static int current_alpha;
1854 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1858 XRenderPictureAttributes pa;
1861 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1862 pa.repeat = RepeatNormal;
1863 pict = pXRenderCreatePicture( gdi_display, pixmap,
1864 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1865 wine_tsx11_unlock();
1869 if (alpha != current_alpha)
1872 col.red = col.green = col.blue = 0;
1873 col.alpha = current_alpha = alpha;
1875 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1876 wine_tsx11_unlock();
1881 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1886 /********************************************************************
1887 * is_dib_with_colortable
1889 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1891 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1895 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1896 dib.dsBmih.biBitCount <= 8 )
1902 /***********************************************************************
1903 * xrenderdrv_ExtTextOut
1905 BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1906 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1908 struct xrender_physdev *physdev = get_xrender_dev( dev );
1910 gsCacheEntry *entry;
1911 gsCacheEntryFormat *formatEntry;
1913 int textPixel, backgroundPixel;
1914 RGNDATA *saved_region = NULL;
1915 BOOL disable_antialias = FALSE;
1916 AA_Type aa_type = AA_None;
1918 Picture tile_pict = 0;
1920 if (!physdev->x11dev->has_gdi_font)
1922 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1923 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1926 if(is_dib_with_colortable( physdev->x11dev ))
1928 TRACE("Disabling antialiasing\n");
1929 disable_antialias = TRUE;
1932 xgcval.function = GXcopy;
1933 xgcval.background = physdev->x11dev->backgroundPixel;
1934 xgcval.fill_style = FillSolid;
1936 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1937 wine_tsx11_unlock();
1939 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
1941 if(physdev->x11dev->depth == 1) {
1942 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1944 backgroundPixel = 1;
1947 backgroundPixel = 0;
1950 textPixel = physdev->x11dev->textPixel;
1951 backgroundPixel = physdev->x11dev->backgroundPixel;
1954 if(flags & ETO_OPAQUE)
1957 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
1958 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
1959 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
1960 lprect->right - lprect->left, lprect->bottom - lprect->top );
1961 wine_tsx11_unlock();
1970 EnterCriticalSection(&xrender_cs);
1972 entry = glyphsetCache + physdev->cache_index;
1973 if( disable_antialias == FALSE )
1974 aa_type = entry->aa_default;
1975 formatEntry = entry->format[aa_type];
1977 for(idx = 0; idx < count; idx++) {
1978 if( !formatEntry ) {
1979 UploadGlyph(physdev, wstr[idx], aa_type);
1980 /* re-evaluate antialias since aa_default may have changed */
1981 if( disable_antialias == FALSE )
1982 aa_type = entry->aa_default;
1983 formatEntry = entry->format[aa_type];
1984 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1985 UploadGlyph(physdev, wstr[idx], aa_type);
1990 WARN("could not upload requested glyphs\n");
1991 LeaveCriticalSection(&xrender_cs);
1995 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1996 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1998 if(X11DRV_XRender_Installed)
2000 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
2001 POINT offset = {0, 0};
2002 POINT desired, current;
2003 int render_op = PictOpOver;
2004 Picture pict = get_xrender_picture( physdev );
2007 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
2008 So we pass zeros to the function and move to our starting position using the first
2009 element of the elts array. */
2011 desired.x = physdev->x11dev->dc_rect.left + x;
2012 desired.y = physdev->x11dev->dc_rect.top + y;
2013 current.x = current.y = 0;
2015 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
2016 tile_pict = get_tile_pict(physdev->format, &col);
2018 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
2020 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
2021 render_op = PictOpOutReverse; /* This gives us 'black' text */
2023 for(idx = 0; idx < count; idx++)
2025 elts[idx].glyphset = formatEntry->glyphset;
2026 elts[idx].chars = wstr + idx;
2027 elts[idx].nchars = 1;
2028 elts[idx].xOff = desired.x - current.x;
2029 elts[idx].yOff = desired.y - current.y;
2031 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
2032 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
2036 desired.x += formatEntry->gis[wstr[idx]].xOff;
2037 desired.y += formatEntry->gis[wstr[idx]].yOff;
2043 offset.x += lpDx[idx * 2];
2044 offset.y += lpDx[idx * 2 + 1];
2047 offset.x += lpDx[idx];
2048 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
2049 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
2053 if (flags & ETO_CLIPPED)
2055 HRGN clip_region = CreateRectRgnIndirect( lprect );
2056 saved_region = add_xrender_clipping_region( physdev, clip_region );
2057 DeleteObject( clip_region );
2061 /* Make sure we don't have any transforms set from a previous call */
2062 set_xrender_transformation(pict, 1, 1, 0, 0);
2063 pXRenderCompositeText16(gdi_display, render_op,
2066 formatEntry->font_format,
2067 0, 0, 0, 0, elts, count);
2068 wine_tsx11_unlock();
2069 HeapFree(GetProcessHeap(), 0, elts);
2070 restore_xrender_clipping_region( physdev, saved_region );
2072 POINT offset = {0, 0};
2074 if (flags & ETO_CLIPPED)
2076 HRGN clip_region = CreateRectRgnIndirect( lprect );
2077 saved_region = add_extra_clipping_region( physdev->x11dev, clip_region );
2078 DeleteObject( clip_region );
2082 XSetForeground( gdi_display, physdev->x11dev->gc, textPixel );
2084 if(aa_type == AA_None || physdev->x11dev->depth == 1)
2086 void (* sharp_glyph_fn)(struct xrender_physdev *, INT, INT, void *, XGlyphInfo *);
2088 if(aa_type == AA_None)
2089 sharp_glyph_fn = SharpGlyphMono;
2091 sharp_glyph_fn = SharpGlyphGray;
2093 for(idx = 0; idx < count; idx++) {
2094 sharp_glyph_fn(physdev,
2095 physdev->x11dev->dc_rect.left + x + offset.x,
2096 physdev->x11dev->dc_rect.top + y + offset.y,
2097 formatEntry->bitmaps[wstr[idx]],
2098 &formatEntry->gis[wstr[idx]]);
2103 offset.x += lpDx[idx * 2];
2104 offset.y += lpDx[idx * 2 + 1];
2107 offset.x += lpDx[idx];
2111 offset.x += formatEntry->gis[wstr[idx]].xOff;
2112 offset.y += formatEntry->gis[wstr[idx]].yOff;
2117 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2118 RECT extents = {0, 0, 0, 0};
2120 int w = physdev->x11dev->drawable_rect.right - physdev->x11dev->drawable_rect.left;
2121 int h = physdev->x11dev->drawable_rect.bottom - physdev->x11dev->drawable_rect.top;
2123 TRACE("drawable %dx%d\n", w, h);
2125 for(idx = 0; idx < count; idx++) {
2126 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2127 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2128 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2129 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2130 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2131 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2132 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2133 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2139 cur.x += lpDx[idx * 2];
2140 cur.y += lpDx[idx * 2 + 1];
2147 cur.x += formatEntry->gis[wstr[idx]].xOff;
2148 cur.y += formatEntry->gis[wstr[idx]].yOff;
2151 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2152 extents.right, extents.bottom, physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2154 if(physdev->x11dev->dc_rect.left + x + extents.left >= 0) {
2155 image_x = physdev->x11dev->dc_rect.left + x + extents.left;
2159 image_off_x = physdev->x11dev->dc_rect.left + x + extents.left;
2161 if(physdev->x11dev->dc_rect.top + y + extents.top >= 0) {
2162 image_y = physdev->x11dev->dc_rect.top + y + extents.top;
2166 image_off_y = physdev->x11dev->dc_rect.top + y + extents.top;
2168 if(physdev->x11dev->dc_rect.left + x + extents.right < w)
2169 image_w = physdev->x11dev->dc_rect.left + x + extents.right - image_x;
2171 image_w = w - image_x;
2172 if(physdev->x11dev->dc_rect.top + y + extents.bottom < h)
2173 image_h = physdev->x11dev->dc_rect.top + y + extents.bottom - image_y;
2175 image_h = h - image_y;
2177 if(image_w <= 0 || image_h <= 0) goto no_image;
2179 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2180 image = XGetImage(gdi_display, physdev->x11dev->drawable,
2181 image_x, image_y, image_w, image_h,
2182 AllPlanes, ZPixmap);
2183 X11DRV_check_error();
2185 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2186 gdi_display, (int)physdev->x11dev->drawable, image_x, image_y,
2187 image_w, image_h, AllPlanes, ZPixmap,
2188 physdev->x11dev->depth, image);
2190 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2191 physdev->x11dev->depth);
2195 gcv.graphics_exposures = False;
2196 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2197 XCopyArea(gdi_display, physdev->x11dev->drawable, xpm, gc, image_x, image_y,
2198 image_w, image_h, 0, 0);
2199 XFreeGC(gdi_display, gc);
2200 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2201 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2203 X11DRV_check_error();
2204 XFreePixmap(gdi_display, xpm);
2206 if(!image) goto no_image;
2208 image->red_mask = visual->red_mask;
2209 image->green_mask = visual->green_mask;
2210 image->blue_mask = visual->blue_mask;
2212 for(idx = 0; idx < count; idx++) {
2213 SmoothGlyphGray(image,
2214 offset.x + image_off_x - extents.left,
2215 offset.y + image_off_y - extents.top,
2216 formatEntry->bitmaps[wstr[idx]],
2217 &formatEntry->gis[wstr[idx]],
2218 physdev->x11dev->textPixel);
2223 offset.x += lpDx[idx * 2];
2224 offset.y += lpDx[idx * 2 + 1];
2227 offset.x += lpDx[idx];
2231 offset.x += formatEntry->gis[wstr[idx]].xOff;
2232 offset.y += formatEntry->gis[wstr[idx]].yOff;
2235 XPutImage(gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc, image, 0, 0,
2236 image_x, image_y, image_w, image_h);
2237 XDestroyImage(image);
2240 wine_tsx11_unlock();
2241 restore_clipping_region( physdev->x11dev, saved_region );
2243 LeaveCriticalSection(&xrender_cs);
2247 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2251 /* Helper function for (stretched) blitting using xrender */
2252 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2253 int x_src, int y_src, int x_dst, int y_dst,
2254 double xscale, double yscale, int width, int height )
2256 int x_offset, y_offset;
2258 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2259 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2260 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2261 if(xscale != 1.0 || yscale != 1.0)
2263 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2264 * in the wrong quadrant of the x-y plane.
2266 x_offset = (xscale < 0) ? -width : 0;
2267 y_offset = (yscale < 0) ? -height : 0;
2268 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2274 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2276 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2277 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2280 /* Helper function for (stretched) mono->color blitting using xrender */
2281 static void xrender_mono_blit( Picture src_pict, Picture mask_pict, Picture dst_pict,
2282 int x_src, int y_src, int x_dst, int y_dst,
2283 double xscale, double yscale, int width, int height )
2285 int x_offset, y_offset;
2287 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2288 * source data is in mask_pict. The 'mask_pict' data effectively acts as an alpha channel to the
2289 * tile data. We need PictOpOver for correct rendering.
2290 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2293 if (xscale != 1.0 || yscale != 1.0)
2295 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2296 * in the wrong quadrant of the x-y plane.
2298 x_offset = (xscale < 0) ? -width : 0;
2299 y_offset = (yscale < 0) ? -height : 0;
2300 set_xrender_transformation(mask_pict, xscale, yscale, x_src, y_src);
2306 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
2308 pXRenderComposite(gdi_display, PictOpOver, src_pict, mask_pict, dst_pict,
2309 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
2312 static void get_colors( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2313 XRenderColor *fg, XRenderColor *bg )
2315 if (physdev_src->format == WXR_FORMAT_MONO)
2320 if (GetDIBColorTable( physdev_src->dev.hdc, 0, 2, rgb ) == 2)
2322 pixel = X11DRV_PALETTE_ToPhysical( physdev_dst->x11dev,
2323 RGB( rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue ));
2324 get_xrender_color( physdev_dst->pict_format, pixel, fg );
2325 pixel = X11DRV_PALETTE_ToPhysical( physdev_dst->x11dev,
2326 RGB( rgb[1].rgbRed, rgb[1].rgbGreen, rgb[1].rgbBlue ));
2327 get_xrender_color( physdev_dst->pict_format, pixel, bg );
2331 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, fg );
2332 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, bg );
2335 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2336 Drawable drawable, const struct bitblt_coords *src,
2337 const struct bitblt_coords *dst )
2339 int width = abs( dst->width );
2340 int height = abs( dst->height );
2341 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2342 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2344 Picture src_pict = 0, dst_pict, mask_pict = 0;
2346 double xscale, yscale;
2348 use_repeat = use_source_repeat( physdev_src );
2351 xscale = src->width / (double)dst->width;
2352 yscale = src->height / (double)dst->height;
2354 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2356 if (drawable) /* using an intermediate pixmap */
2358 XRenderPictureAttributes pa;
2362 pa.repeat = RepeatNone;
2364 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2365 wine_tsx11_unlock();
2369 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2370 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2371 dst_pict = get_xrender_picture( physdev_dst );
2374 if (src->width < 0) x_src += src->width + 1;
2375 if (src->height < 0) y_src += src->height + 1;
2376 if (dst->width < 0) x_dst += dst->width + 1;
2377 if (dst->height < 0) y_dst += dst->height + 1;
2380 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2382 XRenderColor fg, bg;
2384 get_colors( physdev_src, physdev_dst, &fg, &bg );
2385 fg.alpha = bg.alpha = 0;
2387 /* We use the source drawable as a mask */
2388 mask_pict = get_xrender_picture_source( physdev_src, use_repeat );
2390 /* Use backgroundPixel as the foreground color */
2391 EnterCriticalSection( &xrender_cs );
2392 src_pict = get_tile_pict( physdev_dst->format, &bg );
2394 /* Create a destination picture and fill it with textPixel color as the background color */
2396 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, &fg, x_dst, y_dst, width, height );
2398 xrender_mono_blit( src_pict, mask_pict, dst_pict, x_src, y_src,
2399 x_dst, y_dst, xscale, yscale, width, height );
2401 wine_tsx11_unlock();
2402 LeaveCriticalSection( &xrender_cs );
2404 else /* color -> color (can be at different depths) or mono -> mono */
2406 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2407 mask_pict = get_no_alpha_mask();
2408 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2412 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2413 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2415 wine_tsx11_unlock();
2421 pXRenderFreePicture( gdi_display, dst_pict );
2422 wine_tsx11_unlock();
2427 /***********************************************************************
2428 * xrenderdrv_StretchBlt
2430 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2431 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2433 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2434 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2436 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2438 if (src_dev->funcs != dst_dev->funcs)
2440 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2441 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2444 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2446 /* XRender is of no use for color -> mono */
2447 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2448 goto x11drv_fallback;
2450 /* if not stretching, we only need to handle format conversion */
2451 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2453 sSrc = sDst = X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_None );
2454 if (physdev_dst != physdev_src) sSrc = X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_None );
2456 /* try client-side DIB copy */
2457 if (!stretch && sSrc == DIB_Status_AppMod)
2459 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2460 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2461 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2462 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2465 X11DRV_CoerceDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2466 if (physdev_dst != physdev_src) X11DRV_CoerceDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2472 struct bitblt_coords tmp;
2474 /* make coordinates relative to tmp pixmap */
2476 tmp.x -= tmp.visrect.left;
2477 tmp.y -= tmp.visrect.top;
2478 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2481 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2482 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2483 XSetGraphicsExposures( gdi_display, tmpGC, False );
2484 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2485 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2486 wine_tsx11_unlock();
2488 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2489 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2492 XFreePixmap( gdi_display, tmp_pixmap );
2493 XFreeGC( gdi_display, tmpGC );
2494 wine_tsx11_unlock();
2496 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2498 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2499 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2503 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2507 /***********************************************************************
2508 * xrenderdrv_AlphaBlend
2510 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2511 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2513 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2514 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2515 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2516 double xscale, yscale;
2519 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2521 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2522 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2525 if (physdev_src != physdev_dst) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2526 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2528 dst_pict = get_xrender_picture( physdev_dst );
2530 use_repeat = use_source_repeat( physdev_src );
2533 xscale = src->width / (double)dst->width;
2534 yscale = src->height / (double)dst->height;
2536 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2538 if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format)
2540 /* we need a source picture with no alpha */
2541 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2542 if (format != physdev_src->format)
2544 XRenderPictureAttributes pa;
2547 pa.subwindow_mode = IncludeInferiors;
2548 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2549 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2550 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2551 wine_tsx11_unlock();
2552 src_pict = tmp_pict;
2556 if (!src_pict) src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2558 EnterCriticalSection( &xrender_cs );
2559 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2562 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2563 physdev_src->x11dev->dc_rect.left + src->x,
2564 physdev_src->x11dev->dc_rect.top + src->y,
2565 physdev_dst->x11dev->dc_rect.left + dst->x,
2566 physdev_dst->x11dev->dc_rect.top + dst->y,
2567 xscale, yscale, dst->width, dst->height );
2568 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2569 wine_tsx11_unlock();
2571 LeaveCriticalSection( &xrender_cs );
2572 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2573 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2578 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2580 /* 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 */
2581 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2582 enum wxr_format src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2583 enum wxr_format dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2586 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2588 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2589 if( (physBitmap->pixmap_depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->pixmap_depth) ||
2590 (src_format == dst_format) )
2592 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2593 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2595 else /* We need depth conversion */
2597 Picture src_pict, dst_pict;
2598 XRenderPictureAttributes pa;
2599 pa.subwindow_mode = IncludeInferiors;
2600 pa.repeat = RepeatNone;
2602 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap,
2603 pict_formats[src_format], CPSubwindowMode|CPRepeat, &pa);
2604 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap,
2605 pict_formats[dst_format], CPSubwindowMode|CPRepeat, &pa);
2607 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2608 pXRenderFreePicture(gdi_display, src_pict);
2609 pXRenderFreePicture(gdi_display, dst_pict);
2611 wine_tsx11_unlock();
2614 static const struct gdi_dc_funcs xrender_funcs =
2616 NULL, /* pAbortDoc */
2617 NULL, /* pAbortPath */
2618 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2619 NULL, /* pAngleArc */
2622 NULL, /* pBeginPath */
2623 NULL, /* pBlendImage */
2624 NULL, /* pChoosePixelFormat */
2626 NULL, /* pCloseFigure */
2627 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2628 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2629 xrenderdrv_CreateDC, /* pCreateDC */
2630 NULL, /* pCreateDIBSection */
2631 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
2632 xrenderdrv_DeleteDC, /* pDeleteDC */
2633 NULL, /* pDeleteObject */
2634 NULL, /* pDescribePixelFormat */
2635 NULL, /* pDeviceCapabilities */
2636 NULL, /* pEllipse */
2638 NULL, /* pEndPage */
2639 NULL, /* pEndPath */
2640 NULL, /* pEnumDeviceFonts */
2641 NULL, /* pEnumICMProfiles */
2642 NULL, /* pExcludeClipRect */
2643 NULL, /* pExtDeviceMode */
2644 xrenderdrv_ExtEscape, /* pExtEscape */
2645 NULL, /* pExtFloodFill */
2646 NULL, /* pExtSelectClipRgn */
2647 xrenderdrv_ExtTextOut, /* pExtTextOut */
2648 NULL, /* pFillPath */
2649 NULL, /* pFillRgn */
2650 NULL, /* pFlattenPath */
2651 NULL, /* pFrameRgn */
2652 NULL, /* pGdiComment */
2653 NULL, /* pGetCharWidth */
2654 NULL, /* pGetDeviceCaps */
2655 NULL, /* pGetDeviceGammaRamp */
2656 NULL, /* pGetICMProfile */
2657 xrenderdrv_GetImage, /* pGetImage */
2658 NULL, /* pGetNearestColor */
2659 NULL, /* pGetPixel */
2660 NULL, /* pGetPixelFormat */
2661 NULL, /* pGetSystemPaletteEntries */
2662 NULL, /* pGetTextExtentExPoint */
2663 NULL, /* pGetTextMetrics */
2664 NULL, /* pIntersectClipRect */
2665 NULL, /* pInvertRgn */
2667 NULL, /* pModifyWorldTransform */
2669 NULL, /* pOffsetClipRgn */
2670 NULL, /* pOffsetViewportOrg */
2671 NULL, /* pOffsetWindowOrg */
2672 NULL, /* pPaintRgn */
2675 NULL, /* pPolyBezier */
2676 NULL, /* pPolyBezierTo */
2677 NULL, /* pPolyDraw */
2678 NULL, /* pPolyPolygon */
2679 NULL, /* pPolyPolyline */
2680 NULL, /* pPolygon */
2681 NULL, /* pPolyline */
2682 NULL, /* pPolylineTo */
2683 xrenderdrv_PutImage, /* pPutImage */
2684 NULL, /* pRealizeDefaultPalette */
2685 NULL, /* pRealizePalette */
2686 NULL, /* pRectangle */
2687 NULL, /* pResetDC */
2688 NULL, /* pRestoreDC */
2689 NULL, /* pRoundRect */
2691 NULL, /* pScaleViewportExt */
2692 NULL, /* pScaleWindowExt */
2693 xrenderdrv_SelectBitmap, /* pSelectBitmap */
2694 NULL, /* pSelectBrush */
2695 NULL, /* pSelectClipPath */
2696 xrenderdrv_SelectFont, /* pSelectFont */
2697 NULL, /* pSelectPalette */
2698 NULL, /* pSelectPen */
2699 NULL, /* pSetArcDirection */
2700 NULL, /* pSetBkColor */
2701 NULL, /* pSetBkMode */
2702 NULL, /* pSetDCBrushColor */
2703 NULL, /* pSetDCPenColor */
2704 NULL, /* pSetDIBColorTable */
2705 NULL, /* pSetDIBitsToDevice */
2706 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2707 NULL, /* pSetDeviceGammaRamp */
2708 NULL, /* pSetLayout */
2709 NULL, /* pSetMapMode */
2710 NULL, /* pSetMapperFlags */
2711 NULL, /* pSetPixel */
2712 NULL, /* pSetPixelFormat */
2713 NULL, /* pSetPolyFillMode */
2714 NULL, /* pSetROP2 */
2715 NULL, /* pSetRelAbs */
2716 NULL, /* pSetStretchBltMode */
2717 NULL, /* pSetTextAlign */
2718 NULL, /* pSetTextCharacterExtra */
2719 NULL, /* pSetTextColor */
2720 NULL, /* pSetTextJustification */
2721 NULL, /* pSetViewportExt */
2722 NULL, /* pSetViewportOrg */
2723 NULL, /* pSetWindowExt */
2724 NULL, /* pSetWindowOrg */
2725 NULL, /* pSetWorldTransform */
2726 NULL, /* pStartDoc */
2727 NULL, /* pStartPage */
2728 xrenderdrv_StretchBlt, /* pStretchBlt */
2729 NULL, /* pStretchDIBits */
2730 NULL, /* pStrokeAndFillPath */
2731 NULL, /* pStrokePath */
2732 NULL, /* pSwapBuffers */
2733 NULL, /* pUnrealizePalette */
2734 NULL, /* pWidenPath */
2735 /* OpenGL not supported */
2738 #else /* SONAME_LIBXRENDER */
2740 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2742 TRACE("XRender support not compiled in.\n");
2746 void X11DRV_XRender_Finalize(void)
2750 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2753 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
2755 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2756 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2757 wine_tsx11_unlock();
2760 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2765 #endif /* SONAME_LIBXRENDER */