2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
6 * Copyright 2011 Alexandre Julliard
9 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
37 #include "wine/library.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 int using_client_side_fonts = FALSE;
43 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
45 #ifdef SONAME_LIBXRENDER
47 static BOOL X11DRV_XRender_Installed = FALSE;
50 #include <X11/extensions/Xrender.h>
52 #ifndef RepeatNone /* added in 0.10 */
54 #define RepeatNormal 1
56 #define RepeatReflect 3
74 WXR_INVALID_FORMAT = WXR_NB_FORMATS
77 typedef struct wine_xrender_format_template
81 unsigned int alphaMask;
85 unsigned int greenMask;
87 unsigned int blueMask;
88 } WineXRenderFormatTemplate;
90 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
92 /* Format depth alpha mask red mask green mask blue mask*/
93 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
94 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
95 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
96 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
97 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
98 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
99 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
101 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
103 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
107 static enum wxr_format default_format;
108 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
114 SIZE devsize; /* size in device coords */
118 #define INITIAL_REALIZED_BUF_SIZE 128
120 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
125 XRenderPictFormat *font_format;
130 } gsCacheEntryFormat;
136 gsCacheEntryFormat * format[AA_MAXVALUE];
141 struct xrender_physdev
143 struct gdi_physdev dev;
144 X11DRV_PDEVICE *x11dev;
145 enum wxr_format format;
150 XRenderPictFormat *pict_format;
153 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
155 return (struct xrender_physdev *)dev;
158 static const struct gdi_dc_funcs xrender_funcs;
160 static gsCacheEntry *glyphsetCache = NULL;
161 static DWORD glyphsetCacheSize = 0;
162 static INT lastfree = -1;
165 #define INIT_CACHE_SIZE 10
167 static int antialias = 1;
169 static void *xrender_handle;
171 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
172 MAKE_FUNCPTR(XRenderAddGlyphs)
173 MAKE_FUNCPTR(XRenderComposite)
174 MAKE_FUNCPTR(XRenderCompositeString8)
175 MAKE_FUNCPTR(XRenderCompositeString16)
176 MAKE_FUNCPTR(XRenderCompositeString32)
177 MAKE_FUNCPTR(XRenderCompositeText16)
178 MAKE_FUNCPTR(XRenderCreateGlyphSet)
179 MAKE_FUNCPTR(XRenderCreatePicture)
180 MAKE_FUNCPTR(XRenderFillRectangle)
181 MAKE_FUNCPTR(XRenderFindFormat)
182 MAKE_FUNCPTR(XRenderFindVisualFormat)
183 MAKE_FUNCPTR(XRenderFreeGlyphSet)
184 MAKE_FUNCPTR(XRenderFreePicture)
185 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
186 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
187 MAKE_FUNCPTR(XRenderSetPictureTransform)
189 MAKE_FUNCPTR(XRenderQueryExtension)
191 #ifdef SONAME_LIBFONTCONFIG
192 #include <fontconfig/fontconfig.h>
193 MAKE_FUNCPTR(FcConfigSubstitute)
194 MAKE_FUNCPTR(FcDefaultSubstitute)
195 MAKE_FUNCPTR(FcFontMatch)
197 MAKE_FUNCPTR(FcPatternCreate)
198 MAKE_FUNCPTR(FcPatternDestroy)
199 MAKE_FUNCPTR(FcPatternAddInteger)
200 MAKE_FUNCPTR(FcPatternAddString)
201 MAKE_FUNCPTR(FcPatternGetBool)
202 MAKE_FUNCPTR(FcPatternGetInteger)
203 MAKE_FUNCPTR(FcPatternGetString)
204 static void *fontconfig_handle;
205 static BOOL fontconfig_installed;
210 static CRITICAL_SECTION xrender_cs;
211 static CRITICAL_SECTION_DEBUG critsect_debug =
214 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
215 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
217 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
219 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
220 ( ( (ULONG)_x4 << 24 ) | \
221 ( (ULONG)_x3 << 16 ) | \
222 ( (ULONG)_x2 << 8 ) | \
225 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
227 #define GASP_GRIDFIT 0x01
228 #define GASP_DOGRAY 0x02
230 #ifdef WORDS_BIGENDIAN
231 #define get_be_word(x) (x)
232 #define NATIVE_BYTE_ORDER MSBFirst
234 #define get_be_word(x) RtlUshortByteSwap(x)
235 #define NATIVE_BYTE_ORDER LSBFirst
238 static enum wxr_format get_format_without_alpha( enum wxr_format format )
242 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
243 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
244 default: return format;
248 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
251 templ->type = PictTypeDirect;
252 templ->depth = fmt->depth;
253 templ->direct.alpha = fmt->alpha;
254 templ->direct.alphaMask = fmt->alphaMask;
255 templ->direct.red = fmt->red;
256 templ->direct.redMask = fmt->redMask;
257 templ->direct.green = fmt->green;
258 templ->direct.greenMask = fmt->greenMask;
259 templ->direct.blue = fmt->blue;
260 templ->direct.blueMask = fmt->blueMask;
263 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
268 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
270 if(fmt->depth != screen_depth)
272 if( (fmt->redMask << fmt->red) != visual->red_mask)
274 if( (fmt->greenMask << fmt->green) != visual->green_mask)
276 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
279 /* We never select a default ARGB visual */
286 static int load_xrender_formats(void)
291 for (i = 0; i < WXR_NB_FORMATS; i++)
293 XRenderPictFormat templ;
295 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
298 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
299 if (!pict_formats[i])
301 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
302 if (visual->class == DirectColor)
305 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
306 screen_depth, TrueColor, &info ))
308 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
309 if (pict_formats[i]) visual = info.visual;
314 if (pict_formats[i]) default_format = i;
318 unsigned long mask = 0;
319 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
322 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
328 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
334 /***********************************************************************
335 * X11DRV_XRender_Init
337 * Let's see if our XServer has the extension available
340 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
344 if (client_side_with_render &&
345 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
348 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
349 LOAD_FUNCPTR(XRenderAddGlyphs)
350 LOAD_FUNCPTR(XRenderComposite)
351 LOAD_FUNCPTR(XRenderCompositeString8)
352 LOAD_FUNCPTR(XRenderCompositeString16)
353 LOAD_FUNCPTR(XRenderCompositeString32)
354 LOAD_FUNCPTR(XRenderCompositeText16)
355 LOAD_FUNCPTR(XRenderCreateGlyphSet)
356 LOAD_FUNCPTR(XRenderCreatePicture)
357 LOAD_FUNCPTR(XRenderFillRectangle)
358 LOAD_FUNCPTR(XRenderFindFormat)
359 LOAD_FUNCPTR(XRenderFindVisualFormat)
360 LOAD_FUNCPTR(XRenderFreeGlyphSet)
361 LOAD_FUNCPTR(XRenderFreePicture)
362 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
363 LOAD_FUNCPTR(XRenderQueryExtension)
365 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
366 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
367 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
368 #undef LOAD_OPTIONAL_FUNCPTR
372 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
374 if(X11DRV_XRender_Installed) {
375 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
376 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
380 "Wine has detected that you probably have a buggy version\n"
381 "of libXrender.so . Because of this client side font rendering\n"
382 "will be disabled. Please upgrade this library.\n");
383 X11DRV_XRender_Installed = FALSE;
387 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
388 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
389 X11DRV_XRender_Installed = FALSE;
394 #ifdef SONAME_LIBFONTCONFIG
395 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
397 #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;}
398 LOAD_FUNCPTR(FcConfigSubstitute);
399 LOAD_FUNCPTR(FcDefaultSubstitute);
400 LOAD_FUNCPTR(FcFontMatch);
401 LOAD_FUNCPTR(FcInit);
402 LOAD_FUNCPTR(FcPatternCreate);
403 LOAD_FUNCPTR(FcPatternDestroy);
404 LOAD_FUNCPTR(FcPatternAddInteger);
405 LOAD_FUNCPTR(FcPatternAddString);
406 LOAD_FUNCPTR(FcPatternGetBool);
407 LOAD_FUNCPTR(FcPatternGetInteger);
408 LOAD_FUNCPTR(FcPatternGetString);
410 fontconfig_installed = pFcInit();
412 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
416 if(X11DRV_XRender_Installed || client_side_with_core)
418 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
419 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
421 glyphsetCacheSize = INIT_CACHE_SIZE;
423 for(i = 0; i < INIT_CACHE_SIZE; i++) {
424 glyphsetCache[i].next = i + 1;
425 glyphsetCache[i].count = -1;
427 glyphsetCache[i-1].next = -1;
428 using_client_side_fonts = 1;
430 if(!X11DRV_XRender_Installed) {
431 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
432 if(screen_depth <= 8 || !client_side_antialias_with_core)
435 if(screen_depth <= 8 || !client_side_antialias_with_render)
438 return &xrender_funcs;
440 TRACE("Using X11 core fonts\n");
444 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
445 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
447 if(pf->direct.redMask)
448 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
452 if(pf->direct.greenMask)
453 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
455 dst_color->green = 0;
457 if(pf->direct.blueMask)
458 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
462 dst_color->alpha = 0xffff;
465 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
467 int redMask, greenMask, blueMask;
470 if (depth == 1) return WXR_FORMAT_MONO;
472 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
473 if (!shifts) return default_format;
475 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
476 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
477 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
479 /* Try to locate a format which matches the specification of the dibsection. */
480 for(i = 0; i < WXR_NB_FORMATS; i++)
482 if( depth == wxr_formats_template[i].depth &&
483 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
484 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
485 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
489 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
490 ERR("No XRender format found!\n");
491 return WXR_INVALID_FORMAT;
494 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info, BOOL use_alpha )
496 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
498 switch (info->bmiHeader.biBitCount)
501 return WXR_FORMAT_MONO;
506 if (info->bmiHeader.biCompression != BI_RGB) break;
507 return WXR_FORMAT_R8G8B8;
510 if (info->bmiHeader.biCompression == BI_BITFIELDS)
512 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
515 for (i = 0; i < WXR_NB_FORMATS; i++)
517 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
518 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
519 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
520 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
525 if (info->bmiHeader.biCompression != BI_RGB) break;
526 if (info->bmiHeader.biBitCount == 16) return WXR_FORMAT_X1R5G5B5;
527 return use_alpha ? WXR_FORMAT_A8R8G8B8 : WXR_FORMAT_X8R8G8B8;
529 return WXR_INVALID_FORMAT;
532 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
533 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
535 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
536 XTransform xform = {{
537 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
538 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
539 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
542 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
546 /* check if we can use repeating instead of scaling for the specified source DC */
547 static BOOL use_source_repeat( struct xrender_physdev *dev )
549 return (dev->x11dev->bitmap &&
550 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
551 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
554 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
556 if (!dev->pict && dev->pict_format)
558 XRenderPictureAttributes pa;
561 pa.subwindow_mode = IncludeInferiors;
562 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
563 dev->pict_format, CPSubwindowMode, &pa );
565 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
566 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
567 dev->update_clip = TRUE;
570 if (dev->update_clip)
577 rgn = CreateRectRgnIndirect( clip_rect );
578 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
579 CombineRgn( rgn, rgn, dev->x11dev->region, RGN_AND );
583 rgn = CreateRectRgn( 0, 0, 0, 0 );
584 CombineRgn( rgn, clip_rgn, dev->x11dev->region, RGN_AND );
587 if ((clip_data = X11DRV_GetRegionData( rgn ? rgn : dev->x11dev->region, 0 )))
590 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
591 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
592 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
594 HeapFree( GetProcessHeap(), 0, clip_data );
596 dev->update_clip = (rgn != 0); /* have to update again if we are using a custom region */
597 if (rgn) DeleteObject( rgn );
602 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
604 if (!dev->pict_src && dev->pict_format)
606 XRenderPictureAttributes pa;
609 pa.subwindow_mode = IncludeInferiors;
610 pa.repeat = repeat ? RepeatNormal : RepeatNone;
611 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
612 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
615 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
616 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
619 return dev->pict_src;
622 static void free_xrender_picture( struct xrender_physdev *dev )
624 if (dev->pict || dev->pict_src)
627 XFlush( gdi_display );
630 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
631 pXRenderFreePicture(gdi_display, dev->pict);
636 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
637 pXRenderFreePicture(gdi_display, dev->pict_src);
642 dev->pict_format = NULL;
645 static void update_xrender_drawable( struct xrender_physdev *dev )
647 free_xrender_picture( dev );
648 dev->format = get_xrender_format_from_color_shifts( dev->x11dev->depth, dev->x11dev->color_shifts );
649 dev->pict_format = pict_formats[dev->format];
652 /* return a mask picture used to force alpha to 0 */
653 static Picture get_no_alpha_mask(void)
655 static Pixmap pixmap;
661 XRenderPictureAttributes pa;
664 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
665 pa.repeat = RepeatNormal;
666 pa.component_alpha = True;
667 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
668 CPRepeat|CPComponentAlpha, &pa );
669 col.red = col.green = col.blue = 0xffff;
671 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
677 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
679 if(p1->hash != p2->hash) return TRUE;
680 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
681 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
682 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
683 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
687 static void walk_cache(void)
691 EnterCriticalSection(&xrender_cs);
692 for(i=mru; i >= 0; i = glyphsetCache[i].next)
693 TRACE("item %d\n", i);
694 LeaveCriticalSection(&xrender_cs);
698 static int LookupEntry(LFANDSIZE *plfsz)
702 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
704 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
706 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
707 glyphsetCache[i].count++;
709 glyphsetCache[prev_i].next = glyphsetCache[i].next;
710 glyphsetCache[i].next = mru;
713 TRACE("found font in cache %d\n", i);
718 TRACE("font not in cache\n");
722 static void FreeEntry(int entry)
726 for(format = 0; format < AA_MAXVALUE; format++) {
727 gsCacheEntryFormat * formatEntry;
729 if( !glyphsetCache[entry].format[format] )
732 formatEntry = glyphsetCache[entry].format[format];
734 if(formatEntry->glyphset) {
736 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
738 formatEntry->glyphset = 0;
740 if(formatEntry->nrealized) {
741 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
742 formatEntry->realized = NULL;
743 if(formatEntry->bitmaps) {
744 for(i = 0; i < formatEntry->nrealized; i++)
745 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
746 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
747 formatEntry->bitmaps = NULL;
749 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
750 formatEntry->gis = NULL;
751 formatEntry->nrealized = 0;
754 HeapFree(GetProcessHeap(), 0, formatEntry);
755 glyphsetCache[entry].format[format] = NULL;
759 static int AllocEntry(void)
761 int best = -1, prev_best = -1, i, prev_i = -1;
764 assert(glyphsetCache[lastfree].count == -1);
765 glyphsetCache[lastfree].count = 1;
767 lastfree = glyphsetCache[lastfree].next;
769 glyphsetCache[best].next = mru;
772 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
776 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
777 if(glyphsetCache[i].count == 0) {
785 TRACE("freeing unused glyphset at cache %d\n", best);
787 glyphsetCache[best].count = 1;
789 glyphsetCache[prev_best].next = glyphsetCache[best].next;
790 glyphsetCache[best].next = mru;
798 TRACE("Growing cache\n");
801 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
803 (glyphsetCacheSize + INIT_CACHE_SIZE)
804 * sizeof(*glyphsetCache));
806 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
807 (glyphsetCacheSize + INIT_CACHE_SIZE)
808 * sizeof(*glyphsetCache));
810 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
812 glyphsetCache[i].next = i + 1;
813 glyphsetCache[i].count = -1;
815 glyphsetCache[i-1].next = -1;
816 glyphsetCacheSize += INIT_CACHE_SIZE;
818 lastfree = glyphsetCache[best].next;
819 glyphsetCache[best].count = 1;
820 glyphsetCache[best].next = mru;
822 TRACE("new free cache slot at %d\n", mru);
826 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
836 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
837 if(size == GDI_ERROR)
840 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
841 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
843 GetTextMetricsW(hdc, &tm);
844 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
847 num_recs = get_be_word(*gasp);
851 *flags = get_be_word(*(gasp + 1));
852 if(ppem <= get_be_word(*gasp))
856 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
858 HeapFree(GetProcessHeap(), 0, buffer);
862 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
866 UINT font_smoothing_type, font_smoothing_orientation;
868 if (X11DRV_XRender_Installed && subpixel &&
869 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
870 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
872 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
873 &font_smoothing_orientation, 0) &&
874 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
881 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
882 But, Wine's subpixel rendering can support the portrait mode.
885 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
893 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
898 static int hinter = -1;
899 static int subpixel = -1;
902 if((ret = LookupEntry(plfsz)) != -1) return ret;
905 entry = glyphsetCache + ret;
906 entry->lfsz = *plfsz;
907 for( format = 0; format < AA_MAXVALUE; format++ ) {
908 assert( !entry->format[format] );
911 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
913 if(hinter == -1 || subpixel == -1)
915 RASTERIZER_STATUS status;
916 GetRasterizerCaps(&status, sizeof(status));
917 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
918 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
921 switch (plfsz->lf.lfQuality)
923 case ANTIALIASED_QUALITY:
924 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
925 return ret; /* ignore further configuration */
926 case CLEARTYPE_QUALITY:
927 case CLEARTYPE_NATURAL_QUALITY:
928 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
930 case DEFAULT_QUALITY:
934 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
937 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
940 entry->aa_default = AA_None;
944 font_smoothing = TRUE; /* default to enabled */
945 #ifdef SONAME_LIBFONTCONFIG
946 if (fontconfig_installed)
948 FcPattern *match, *pattern = pFcPatternCreate();
950 char family[LF_FACESIZE * 4];
952 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
953 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
954 if (plfsz->lf.lfWeight != FW_DONTCARE)
957 switch (plfsz->lf.lfWeight)
959 case FW_THIN: weight = FC_WEIGHT_THIN; break;
960 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
961 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
962 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
963 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
964 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
965 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
966 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
967 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
968 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
970 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
972 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
973 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
974 pFcDefaultSubstitute( pattern );
975 if ((match = pFcFontMatch( NULL, pattern, &result )))
980 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
982 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
985 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
987 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
988 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
992 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
993 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
994 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
995 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
996 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
999 if (!antialias) font_smoothing = FALSE;
1000 pFcPatternDestroy( match );
1002 pFcPatternDestroy( pattern );
1004 #endif /* SONAME_LIBFONTCONFIG */
1006 /* now check Xft resources */
1009 BOOL antialias = TRUE;
1012 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1014 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1015 value[0] == '0' || !strcasecmp( value, "off" ))
1018 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1020 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1021 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1022 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1023 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1024 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1025 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1027 wine_tsx11_unlock();
1028 if (!antialias) font_smoothing = FALSE;
1031 if (!font_smoothing) entry->aa_default = AA_None;
1033 /* we can't support subpixel without xrender */
1034 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1037 entry->aa_default = AA_None;
1042 static void dec_ref_cache(int index)
1045 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1046 assert(glyphsetCache[index].count > 0);
1047 glyphsetCache[index].count--;
1050 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1052 DWORD hash = 0, *ptr, two_chars;
1056 hash ^= plfsz->devsize.cx;
1057 hash ^= plfsz->devsize.cy;
1058 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1060 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1062 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1064 pwc = (WCHAR *)&two_chars;
1066 *pwc = toupperW(*pwc);
1068 *pwc = toupperW(*pwc);
1076 /***********************************************************************
1077 * X11DRV_XRender_Finalize
1079 void X11DRV_XRender_Finalize(void)
1083 EnterCriticalSection(&xrender_cs);
1084 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1086 LeaveCriticalSection(&xrender_cs);
1089 /**********************************************************************
1090 * xrenderdrv_SelectFont
1092 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
1094 struct xrender_physdev *physdev = get_xrender_dev( dev );
1097 if (!GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf )) return HGDI_ERROR;
1101 dev = GET_NEXT_PHYSDEV( dev, pSelectFont );
1102 return dev->funcs->pSelectFont( dev, hfont, gdiFont );
1105 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1106 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1107 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1108 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1109 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1110 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1112 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1113 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1114 lfsz.xform.eM21, lfsz.xform.eM22);
1116 /* Not used fields, would break hashing */
1117 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1119 lfsz_calc_hash(&lfsz);
1121 EnterCriticalSection(&xrender_cs);
1122 if (physdev->cache_index != -1)
1123 dec_ref_cache( physdev->cache_index );
1124 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1125 LeaveCriticalSection(&xrender_cs);
1126 physdev->x11dev->has_gdi_font = TRUE;
1130 static BOOL create_xrender_dc( PHYSDEV *pdev )
1132 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1133 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1135 if (!physdev) return FALSE;
1136 physdev->x11dev = x11dev;
1137 physdev->cache_index = -1;
1138 physdev->format = get_xrender_format_from_color_shifts( x11dev->depth, x11dev->color_shifts );
1139 physdev->pict_format = pict_formats[physdev->format];
1140 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1144 /* store the color mask data in the bitmap info structure */
1145 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1147 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1149 info->bmiHeader.biPlanes = 1;
1150 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1151 info->bmiHeader.biCompression = BI_RGB;
1152 info->bmiHeader.biClrUsed = 0;
1154 switch (info->bmiHeader.biBitCount)
1157 colors[0] = format->direct.redMask << format->direct.red;
1158 colors[1] = format->direct.greenMask << format->direct.green;
1159 colors[2] = format->direct.blueMask << format->direct.blue;
1160 info->bmiHeader.biCompression = BI_BITFIELDS;
1163 colors[0] = format->direct.redMask << format->direct.red;
1164 colors[1] = format->direct.greenMask << format->direct.green;
1165 colors[2] = format->direct.blueMask << format->direct.blue;
1166 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1167 info->bmiHeader.biCompression = BI_BITFIELDS;
1173 /**********************************************************************
1174 * xrenderdrv_CreateDC
1176 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1177 LPCWSTR output, const DEVMODEW* initData )
1179 return create_xrender_dc( pdev );
1182 /**********************************************************************
1183 * xrenderdrv_CreateCompatibleDC
1185 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1187 if (orig) /* chain to x11drv first */
1189 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1190 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1192 /* otherwise we have been called by x11drv */
1194 return create_xrender_dc( pdev );
1197 /**********************************************************************
1198 * xrenderdrv_DeleteDC
1200 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1202 struct xrender_physdev *physdev = get_xrender_dev( dev );
1204 free_xrender_picture( physdev );
1206 EnterCriticalSection( &xrender_cs );
1207 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1208 LeaveCriticalSection( &xrender_cs );
1210 HeapFree( GetProcessHeap(), 0, physdev );
1214 /**********************************************************************
1215 * xrenderdrv_ExtEscape
1217 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1218 INT out_count, LPVOID out_data )
1220 struct xrender_physdev *physdev = get_xrender_dev( dev );
1222 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1224 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1226 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1228 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1229 if (ret) update_xrender_drawable( physdev );
1233 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1236 /****************************************************************************
1237 * xrenderdrv_CreateBitmap
1239 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1241 XRenderPictFormat *pict_format = NULL;
1245 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1247 if (bitmap.bmPlanes == 1 && bitmap.bmBitsPixel == screen_bpp)
1249 switch (bitmap.bmBitsPixel)
1251 case 16: pict_format = pict_formats[WXR_FORMAT_R5G6B5]; break;
1252 case 24: pict_format = pict_formats[WXR_FORMAT_R8G8B8]; break;
1253 case 32: pict_format = pict_formats[WXR_FORMAT_A8R8G8B8]; break;
1259 X11DRV_PALETTE_ComputeColorShifts( &shifts,
1260 pict_format->direct.redMask << pict_format->direct.red,
1261 pict_format->direct.greenMask << pict_format->direct.green,
1262 pict_format->direct.blueMask << pict_format->direct.blue );
1263 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_format->depth, TRUE, &shifts );
1266 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1267 return dev->funcs->pCreateBitmap( dev, hbitmap );
1270 /****************************************************************************
1271 * xrenderdrv_DeleteBitmap
1273 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1275 return X11DRV_DeleteBitmap( hbitmap );
1278 /***********************************************************************
1279 * xrenderdrv_SelectBitmap
1281 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1284 struct xrender_physdev *physdev = get_xrender_dev( dev );
1286 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1287 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1288 if (ret) update_xrender_drawable( physdev );
1292 /***********************************************************************
1293 * xrenderdrv_GetImage
1295 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1296 struct gdi_image_bits *bits, struct bitblt_coords *src )
1298 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1299 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1300 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1303 /***********************************************************************
1304 * xrenderdrv_SetDeviceClipping
1306 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1308 struct xrender_physdev *physdev = get_xrender_dev( dev );
1310 physdev->update_clip = TRUE;
1312 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1313 dev->funcs->pSetDeviceClipping( dev, vis_rgn, clip_rgn );
1317 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1319 XRenderPictFormat *pict_format;
1321 const DWORD *bitfields;
1322 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1323 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1326 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1327 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1328 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1329 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1332 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1333 bitfields = dib->dsBitfields;
1334 else if(bits_pixel == 24 || bits_pixel == 32)
1335 bitfields = bitfields_32;
1337 bitfields = bitfields_16;
1339 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1340 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1342 /* Common formats should be in our picture format table. */
1345 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1346 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1350 physBitmap->pixmap_depth = pict_format->depth;
1351 physBitmap->trueColor = TRUE;
1352 physBitmap->pixmap_color_shifts = shifts;
1356 /************************************************************************
1359 * Helper to ExtTextOut. Must be called inside xrender_cs
1361 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1363 unsigned int buflen;
1368 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1369 gsCacheEntryFormat *formatEntry;
1370 UINT ggo_format = GGO_GLYPH_INDEX;
1371 enum wxr_format wxr_format;
1372 static const char zero[4];
1373 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1377 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1380 ggo_format |= WINE_GGO_HRGB_BITMAP;
1383 ggo_format |= WINE_GGO_HBGR_BITMAP;
1386 ggo_format |= WINE_GGO_VRGB_BITMAP;
1389 ggo_format |= WINE_GGO_VBGR_BITMAP;
1393 ERR("aa = %d - not implemented\n", format);
1395 ggo_format |= GGO_BITMAP;
1399 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1400 if(buflen == GDI_ERROR) {
1401 if(format != AA_None) {
1403 entry->aa_default = AA_None;
1404 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1405 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1407 if(buflen == GDI_ERROR) {
1408 WARN("GetGlyphOutlineW failed using default glyph\n");
1409 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1410 if(buflen == GDI_ERROR) {
1411 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1412 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1413 if(buflen == GDI_ERROR) {
1414 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1419 TRACE("Turning off antialiasing for this monochrome font\n");
1422 /* If there is nothing for the current type, we create the entry. */
1423 if( !entry->format[format] ) {
1424 entry->format[format] = HeapAlloc(GetProcessHeap(),
1426 sizeof(gsCacheEntryFormat));
1428 formatEntry = entry->format[format];
1430 if(formatEntry->nrealized <= glyph) {
1431 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1433 if (formatEntry->realized)
1434 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1436 formatEntry->realized,
1437 formatEntry->nrealized * sizeof(BOOL));
1439 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1441 formatEntry->nrealized * sizeof(BOOL));
1443 if(!X11DRV_XRender_Installed) {
1444 if (formatEntry->bitmaps)
1445 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1447 formatEntry->bitmaps,
1448 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1450 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1452 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1454 if (formatEntry->gis)
1455 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1458 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1460 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1462 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1466 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1469 wxr_format = WXR_FORMAT_GRAY;
1476 wxr_format = WXR_FORMAT_A8R8G8B8;
1480 ERR("aa = %d - not implemented\n", format);
1482 wxr_format = WXR_FORMAT_MONO;
1487 formatEntry->font_format = pict_formats[wxr_format];
1488 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1489 wine_tsx11_unlock();
1493 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1494 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1495 formatEntry->realized[glyph] = TRUE;
1497 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1499 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1500 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1502 gi.width = gm.gmBlackBoxX;
1503 gi.height = gm.gmBlackBoxY;
1504 gi.x = -gm.gmptGlyphOrigin.x;
1505 gi.y = gm.gmptGlyphOrigin.y;
1506 gi.xOff = gm.gmCellIncX;
1507 gi.yOff = gm.gmCellIncY;
1509 if(TRACE_ON(xrender)) {
1512 unsigned char *line;
1514 if(format == AA_None) {
1515 pitch = ((gi.width + 31) / 32) * 4;
1516 for(i = 0; i < gi.height; i++) {
1517 line = (unsigned char*) buf + i * pitch;
1519 for(j = 0; j < pitch * 8; j++) {
1520 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1522 TRACE("%s\n", output);
1525 static const char blks[] = " .:;!o*#";
1529 pitch = ((gi.width + 3) / 4) * 4;
1530 for(i = 0; i < gi.height; i++) {
1531 line = (unsigned char*) buf + i * pitch;
1533 for(j = 0; j < pitch; j++) {
1534 str[0] = blks[line[j] >> 5];
1535 strcat(output, str);
1537 TRACE("%s\n", output);
1543 if(formatEntry->glyphset) {
1544 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1545 unsigned char *byte = (unsigned char*) buf, c;
1551 /* magic to flip bit order */
1552 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1553 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1554 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1559 else if ( format != AA_Grey &&
1560 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1562 unsigned int i, *data = (unsigned int *)buf;
1563 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1568 XRenderCompositeText seems to ignore 0x0 glyphs when
1569 AA_None, which means we lose the advance width of glyphs
1570 like the space. We'll pretend that such glyphs are 1x1
1575 gi.width = gi.height = 1;
1578 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1579 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1580 wine_tsx11_unlock();
1581 HeapFree(GetProcessHeap(), 0, buf);
1583 formatEntry->bitmaps[glyph] = buf;
1586 formatEntry->gis[glyph] = gi;
1589 static void SharpGlyphMono(struct xrender_physdev *physDev, INT x, INT y,
1590 void *bitmap, XGlyphInfo *gi)
1592 unsigned char *srcLine = bitmap, *src;
1593 unsigned char bits, bitsMask;
1594 int width = gi->width;
1595 int stride = ((width + 31) & ~31) >> 3;
1596 int height = gi->height;
1600 TRACE("%d, %d\n", x, y);
1609 bitsMask = 0x80; /* FreeType is always MSB first */
1615 if (bits & bitsMask)
1623 bitsMask = bitsMask >> 1;
1629 } while (bits & bitsMask);
1630 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1631 physDev->x11dev->gc, xspan, y, lenspan, 1);
1643 bitsMask = bitsMask >> 1;
1649 } while (!(bits & bitsMask));
1656 static void SharpGlyphGray(struct xrender_physdev *physDev, INT x, INT y,
1657 void *bitmap, XGlyphInfo *gi)
1659 unsigned char *srcLine = bitmap, *src, bits;
1660 int width = gi->width;
1661 int stride = ((width + 3) & ~3);
1662 int height = gi->height;
1687 } while (bits >= 0x80);
1688 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1689 physDev->x11dev->gc, xspan, y, lenspan, 1);
1702 } while (bits < 0x80);
1710 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1715 while ((mask & 1) == 0)
1721 while ((mask & 1) == 1)
1730 static DWORD GetField (DWORD pixel, int shift, int len)
1732 pixel = pixel & (((1 << (len)) - 1) << shift);
1733 pixel = pixel << (32 - (shift + len)) >> 24;
1736 pixel |= (pixel >> len);
1743 static DWORD PutField (DWORD pixel, int shift, int len)
1745 shift = shift - (8 - len);
1747 pixel &= (((1 << len) - 1) << (8 - len));
1755 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1761 BYTE *maskLine, *mask, m;
1766 BYTE src_r, src_g, src_b;
1771 height = gi->height;
1774 maskStride = (width + 3) & ~3;
1776 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1777 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1778 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1780 src_r = GetField(color, r_shift, r_len);
1781 src_g = GetField(color, g_shift, g_len);
1782 src_b = GetField(color, b_shift, b_len);
1784 for(; height--; y++)
1787 maskLine += maskStride;
1792 if(y >= image->height) break;
1796 if(tx >= image->width) break;
1799 if(tx < 0) continue;
1802 XPutPixel (image, tx, y, color);
1807 pixel = XGetPixel (image, tx, y);
1809 r = GetField(pixel, r_shift, r_len);
1810 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1811 g = GetField(pixel, g_shift, g_len);
1812 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1813 b = GetField(pixel, b_shift, b_len);
1814 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1816 pixel = (PutField (r, r_shift, r_len) |
1817 PutField (g, g_shift, g_len) |
1818 PutField (b, b_shift, b_len));
1819 XPutPixel (image, tx, y, pixel);
1825 /*************************************************************
1828 * Returns an appropriate Picture for tiling the text colour.
1829 * Call and use result within the xrender_cs
1831 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1837 XRenderColor current_color;
1838 } tiles[WXR_NB_FORMATS], *tile;
1840 tile = &tiles[wxr_format];
1844 XRenderPictureAttributes pa;
1845 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1848 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1850 pa.repeat = RepeatNormal;
1851 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1852 wine_tsx11_unlock();
1854 /* init current_color to something different from text_pixel */
1855 tile->current_color = *color;
1856 tile->current_color.red ^= 0xffff;
1858 if (wxr_format == WXR_FORMAT_MONO)
1860 /* for a 1bpp bitmap we always need a 1 in the tile */
1862 col.red = col.green = col.blue = 0;
1865 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1866 wine_tsx11_unlock();
1870 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1873 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1874 wine_tsx11_unlock();
1875 tile->current_color = *color;
1880 /*************************************************************
1883 * Returns an appropriate Picture for masking with the specified alpha.
1884 * Call and use result within the xrender_cs
1886 static Picture get_mask_pict( int alpha )
1888 static Pixmap pixmap;
1889 static Picture pict;
1890 static int current_alpha;
1892 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1896 XRenderPictureAttributes pa;
1899 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1900 pa.repeat = RepeatNormal;
1901 pict = pXRenderCreatePicture( gdi_display, pixmap,
1902 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1903 wine_tsx11_unlock();
1907 if (alpha != current_alpha)
1910 col.red = col.green = col.blue = 0;
1911 col.alpha = current_alpha = alpha;
1913 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1914 wine_tsx11_unlock();
1919 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1924 /********************************************************************
1925 * is_dib_with_colortable
1927 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1929 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1933 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1934 dib.dsBmih.biBitCount <= 8 )
1940 /***********************************************************************
1941 * xrenderdrv_ExtTextOut
1943 BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1944 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1946 struct xrender_physdev *physdev = get_xrender_dev( dev );
1948 gsCacheEntry *entry;
1949 gsCacheEntryFormat *formatEntry;
1951 int textPixel, backgroundPixel;
1952 RGNDATA *saved_region = NULL;
1953 BOOL disable_antialias = FALSE;
1954 AA_Type aa_type = AA_None;
1956 Picture tile_pict = 0;
1958 if (!physdev->x11dev->has_gdi_font)
1960 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1961 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1964 if(is_dib_with_colortable( physdev->x11dev ))
1966 TRACE("Disabling antialiasing\n");
1967 disable_antialias = TRUE;
1970 xgcval.function = GXcopy;
1971 xgcval.background = physdev->x11dev->backgroundPixel;
1972 xgcval.fill_style = FillSolid;
1974 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1975 wine_tsx11_unlock();
1977 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
1979 if(physdev->x11dev->depth == 1) {
1980 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1982 backgroundPixel = 1;
1985 backgroundPixel = 0;
1988 textPixel = physdev->x11dev->textPixel;
1989 backgroundPixel = physdev->x11dev->backgroundPixel;
1992 if(flags & ETO_OPAQUE)
1995 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
1996 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
1997 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
1998 lprect->right - lprect->left, lprect->bottom - lprect->top );
1999 wine_tsx11_unlock();
2008 EnterCriticalSection(&xrender_cs);
2010 entry = glyphsetCache + physdev->cache_index;
2011 if( disable_antialias == FALSE )
2012 aa_type = entry->aa_default;
2013 formatEntry = entry->format[aa_type];
2015 for(idx = 0; idx < count; idx++) {
2016 if( !formatEntry ) {
2017 UploadGlyph(physdev, wstr[idx], aa_type);
2018 /* re-evaluate antialias since aa_default may have changed */
2019 if( disable_antialias == FALSE )
2020 aa_type = entry->aa_default;
2021 formatEntry = entry->format[aa_type];
2022 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
2023 UploadGlyph(physdev, wstr[idx], aa_type);
2028 WARN("could not upload requested glyphs\n");
2029 LeaveCriticalSection(&xrender_cs);
2033 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
2034 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2036 if(X11DRV_XRender_Installed)
2038 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
2039 POINT offset = {0, 0};
2040 POINT desired, current;
2041 int render_op = PictOpOver;
2042 Picture pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
2045 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
2046 So we pass zeros to the function and move to our starting position using the first
2047 element of the elts array. */
2049 desired.x = physdev->x11dev->dc_rect.left + x;
2050 desired.y = physdev->x11dev->dc_rect.top + y;
2051 current.x = current.y = 0;
2053 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
2054 tile_pict = get_tile_pict(physdev->format, &col);
2056 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
2058 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
2059 render_op = PictOpOutReverse; /* This gives us 'black' text */
2061 for(idx = 0; idx < count; idx++)
2063 elts[idx].glyphset = formatEntry->glyphset;
2064 elts[idx].chars = wstr + idx;
2065 elts[idx].nchars = 1;
2066 elts[idx].xOff = desired.x - current.x;
2067 elts[idx].yOff = desired.y - current.y;
2069 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
2070 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
2074 desired.x += formatEntry->gis[wstr[idx]].xOff;
2075 desired.y += formatEntry->gis[wstr[idx]].yOff;
2081 offset.x += lpDx[idx * 2];
2082 offset.y += lpDx[idx * 2 + 1];
2085 offset.x += lpDx[idx];
2086 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
2087 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
2092 /* Make sure we don't have any transforms set from a previous call */
2093 set_xrender_transformation(pict, 1, 1, 0, 0);
2094 pXRenderCompositeText16(gdi_display, render_op,
2097 formatEntry->font_format,
2098 0, 0, 0, 0, elts, count);
2099 wine_tsx11_unlock();
2100 HeapFree(GetProcessHeap(), 0, elts);
2102 POINT offset = {0, 0};
2104 if (flags & ETO_CLIPPED)
2106 HRGN clip_region = CreateRectRgnIndirect( lprect );
2107 saved_region = add_extra_clipping_region( physdev->x11dev, clip_region );
2108 DeleteObject( clip_region );
2112 XSetForeground( gdi_display, physdev->x11dev->gc, textPixel );
2114 if(aa_type == AA_None || physdev->x11dev->depth == 1)
2116 void (* sharp_glyph_fn)(struct xrender_physdev *, INT, INT, void *, XGlyphInfo *);
2118 if(aa_type == AA_None)
2119 sharp_glyph_fn = SharpGlyphMono;
2121 sharp_glyph_fn = SharpGlyphGray;
2123 for(idx = 0; idx < count; idx++) {
2124 sharp_glyph_fn(physdev,
2125 physdev->x11dev->dc_rect.left + x + offset.x,
2126 physdev->x11dev->dc_rect.top + y + offset.y,
2127 formatEntry->bitmaps[wstr[idx]],
2128 &formatEntry->gis[wstr[idx]]);
2133 offset.x += lpDx[idx * 2];
2134 offset.y += lpDx[idx * 2 + 1];
2137 offset.x += lpDx[idx];
2141 offset.x += formatEntry->gis[wstr[idx]].xOff;
2142 offset.y += formatEntry->gis[wstr[idx]].yOff;
2147 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2148 RECT extents = {0, 0, 0, 0};
2150 int w = physdev->x11dev->drawable_rect.right - physdev->x11dev->drawable_rect.left;
2151 int h = physdev->x11dev->drawable_rect.bottom - physdev->x11dev->drawable_rect.top;
2153 TRACE("drawable %dx%d\n", w, h);
2155 for(idx = 0; idx < count; idx++) {
2156 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2157 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2158 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2159 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2160 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2161 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2162 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2163 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2169 cur.x += lpDx[idx * 2];
2170 cur.y += lpDx[idx * 2 + 1];
2177 cur.x += formatEntry->gis[wstr[idx]].xOff;
2178 cur.y += formatEntry->gis[wstr[idx]].yOff;
2181 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2182 extents.right, extents.bottom, physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2184 if(physdev->x11dev->dc_rect.left + x + extents.left >= 0) {
2185 image_x = physdev->x11dev->dc_rect.left + x + extents.left;
2189 image_off_x = physdev->x11dev->dc_rect.left + x + extents.left;
2191 if(physdev->x11dev->dc_rect.top + y + extents.top >= 0) {
2192 image_y = physdev->x11dev->dc_rect.top + y + extents.top;
2196 image_off_y = physdev->x11dev->dc_rect.top + y + extents.top;
2198 if(physdev->x11dev->dc_rect.left + x + extents.right < w)
2199 image_w = physdev->x11dev->dc_rect.left + x + extents.right - image_x;
2201 image_w = w - image_x;
2202 if(physdev->x11dev->dc_rect.top + y + extents.bottom < h)
2203 image_h = physdev->x11dev->dc_rect.top + y + extents.bottom - image_y;
2205 image_h = h - image_y;
2207 if(image_w <= 0 || image_h <= 0) goto no_image;
2209 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2210 image = XGetImage(gdi_display, physdev->x11dev->drawable,
2211 image_x, image_y, image_w, image_h,
2212 AllPlanes, ZPixmap);
2213 X11DRV_check_error();
2215 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2216 gdi_display, (int)physdev->x11dev->drawable, image_x, image_y,
2217 image_w, image_h, AllPlanes, ZPixmap,
2218 physdev->x11dev->depth, image);
2220 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2221 physdev->x11dev->depth);
2225 gcv.graphics_exposures = False;
2226 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2227 XCopyArea(gdi_display, physdev->x11dev->drawable, xpm, gc, image_x, image_y,
2228 image_w, image_h, 0, 0);
2229 XFreeGC(gdi_display, gc);
2230 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2231 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2233 X11DRV_check_error();
2234 XFreePixmap(gdi_display, xpm);
2236 if(!image) goto no_image;
2238 image->red_mask = visual->red_mask;
2239 image->green_mask = visual->green_mask;
2240 image->blue_mask = visual->blue_mask;
2242 for(idx = 0; idx < count; idx++) {
2243 SmoothGlyphGray(image,
2244 offset.x + image_off_x - extents.left,
2245 offset.y + image_off_y - extents.top,
2246 formatEntry->bitmaps[wstr[idx]],
2247 &formatEntry->gis[wstr[idx]],
2248 physdev->x11dev->textPixel);
2253 offset.x += lpDx[idx * 2];
2254 offset.y += lpDx[idx * 2 + 1];
2257 offset.x += lpDx[idx];
2261 offset.x += formatEntry->gis[wstr[idx]].xOff;
2262 offset.y += formatEntry->gis[wstr[idx]].yOff;
2265 XPutImage(gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc, image, 0, 0,
2266 image_x, image_y, image_w, image_h);
2267 XDestroyImage(image);
2270 wine_tsx11_unlock();
2271 restore_clipping_region( physdev->x11dev, saved_region );
2273 LeaveCriticalSection(&xrender_cs);
2277 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2281 /* Helper function for (stretched) blitting using xrender */
2282 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2283 int x_src, int y_src, int x_dst, int y_dst,
2284 double xscale, double yscale, int width, int height )
2286 int x_offset, y_offset;
2288 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2289 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2290 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2291 if(xscale != 1.0 || yscale != 1.0)
2293 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2294 * in the wrong quadrant of the x-y plane.
2296 x_offset = (xscale < 0) ? -width : 0;
2297 y_offset = (yscale < 0) ? -height : 0;
2298 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2304 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2306 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2307 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2310 /* Helper function for (stretched) mono->color blitting using xrender */
2311 static void xrender_mono_blit( Picture src_pict, Picture mask_pict, Picture dst_pict,
2312 int x_src, int y_src, int x_dst, int y_dst,
2313 double xscale, double yscale, int width, int height )
2315 int x_offset, y_offset;
2317 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2318 * source data is in mask_pict. The 'mask_pict' data effectively acts as an alpha channel to the
2319 * tile data. We need PictOpOver for correct rendering.
2320 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2323 if (xscale != 1.0 || yscale != 1.0)
2325 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2326 * in the wrong quadrant of the x-y plane.
2328 x_offset = (xscale < 0) ? -width : 0;
2329 y_offset = (yscale < 0) ? -height : 0;
2330 set_xrender_transformation(mask_pict, xscale, yscale, x_src, y_src);
2336 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
2338 pXRenderComposite(gdi_display, PictOpOver, src_pict, mask_pict, dst_pict,
2339 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
2342 static void get_colors( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2343 XRenderColor *fg, XRenderColor *bg )
2345 if (physdev_src->format == WXR_FORMAT_MONO)
2350 if (GetDIBColorTable( physdev_src->dev.hdc, 0, 2, rgb ) == 2)
2352 pixel = X11DRV_PALETTE_ToPhysical( physdev_dst->x11dev,
2353 RGB( rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue ));
2354 get_xrender_color( physdev_dst->pict_format, pixel, fg );
2355 pixel = X11DRV_PALETTE_ToPhysical( physdev_dst->x11dev,
2356 RGB( rgb[1].rgbRed, rgb[1].rgbGreen, rgb[1].rgbBlue ));
2357 get_xrender_color( physdev_dst->pict_format, pixel, bg );
2361 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, fg );
2362 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, bg );
2365 /* create a pixmap and render picture for an image */
2366 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
2367 struct bitblt_coords *src, enum wxr_format format,
2368 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
2371 int width = src->visrect.right - src->visrect.left;
2372 int height = src->visrect.bottom - src->visrect.top;
2373 int depth = pict_formats[format]->depth;
2374 struct gdi_image_bits dst_bits;
2375 XRenderPictureAttributes pa;
2379 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
2380 info->bmiHeader.biWidth, height, 32, 0 );
2381 wine_tsx11_unlock();
2382 if (!image) return ERROR_OUTOFMEMORY;
2384 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
2385 if (ret) return ret;
2387 image->data = dst_bits.ptr;
2388 /* hack: make sure the bits are readable if we are reading from a DIB section */
2389 /* to be removed once we get rid of DIB access protections */
2390 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2392 *use_repeat = (width == 1 && height == 1);
2393 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2396 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2397 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2398 src->visrect.left, 0, 0, 0, width, height );
2399 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2400 wine_tsx11_unlock();
2402 /* make coordinates relative to the pixmap */
2403 src->x -= src->visrect.left;
2404 src->y -= src->visrect.top;
2405 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2409 XDestroyImage( image );
2410 wine_tsx11_unlock();
2411 if (dst_bits.free) dst_bits.free( &dst_bits );
2415 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2416 Drawable drawable, const struct bitblt_coords *src,
2417 const struct bitblt_coords *dst )
2419 int width = abs( dst->width );
2420 int height = abs( dst->height );
2421 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2422 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2424 Picture src_pict = 0, dst_pict, mask_pict = 0;
2426 double xscale, yscale;
2428 use_repeat = use_source_repeat( physdev_src );
2431 xscale = src->width / (double)dst->width;
2432 yscale = src->height / (double)dst->height;
2434 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2436 if (drawable) /* using an intermediate pixmap */
2438 XRenderPictureAttributes pa;
2442 pa.repeat = RepeatNone;
2444 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2445 wine_tsx11_unlock();
2449 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2450 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2451 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2454 if (src->width < 0) x_src += src->width + 1;
2455 if (src->height < 0) y_src += src->height + 1;
2456 if (dst->width < 0) x_dst += dst->width + 1;
2457 if (dst->height < 0) y_dst += dst->height + 1;
2460 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2462 XRenderColor fg, bg;
2464 get_colors( physdev_src, physdev_dst, &fg, &bg );
2465 fg.alpha = bg.alpha = 0;
2467 /* We use the source drawable as a mask */
2468 mask_pict = get_xrender_picture_source( physdev_src, use_repeat );
2470 /* Use backgroundPixel as the foreground color */
2471 EnterCriticalSection( &xrender_cs );
2472 src_pict = get_tile_pict( physdev_dst->format, &bg );
2474 /* Create a destination picture and fill it with textPixel color as the background color */
2476 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, &fg, x_dst, y_dst, width, height );
2478 xrender_mono_blit( src_pict, mask_pict, dst_pict, x_src, y_src,
2479 x_dst, y_dst, xscale, yscale, width, height );
2481 wine_tsx11_unlock();
2482 LeaveCriticalSection( &xrender_cs );
2484 else /* color -> color (can be at different depths) or mono -> mono */
2486 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2487 mask_pict = get_no_alpha_mask();
2488 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2492 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2493 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2495 wine_tsx11_unlock();
2501 pXRenderFreePicture( gdi_display, dst_pict );
2502 wine_tsx11_unlock();
2507 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, HRGN clip,
2508 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2509 Drawable drawable, struct bitblt_coords *src,
2510 struct bitblt_coords *dst, BOOL use_repeat )
2512 int x_src, y_src, x_dst, y_dst;
2514 XRenderPictureAttributes pa;
2515 double xscale, yscale;
2517 if (drawable) /* using an intermediate pixmap */
2519 RGNDATA *clip_data = NULL;
2521 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2524 pa.repeat = RepeatNone;
2526 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2528 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2529 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2530 wine_tsx11_unlock();
2531 HeapFree( GetProcessHeap(), 0, clip_data );
2535 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2536 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2537 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2542 xscale = src->width / (double)dst->width;
2543 yscale = src->height / (double)dst->height;
2545 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2549 if (src->width < 0) x_src += src->width + 1;
2550 if (src->height < 0) y_src += src->height + 1;
2551 if (dst->width < 0) x_dst += dst->width + 1;
2552 if (dst->height < 0) y_dst += dst->height + 1;
2555 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, x_src, y_src, x_dst, y_dst,
2556 xscale, yscale, abs( dst->width ), abs( dst->height ));
2558 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
2559 wine_tsx11_unlock();
2563 /***********************************************************************
2564 * xrenderdrv_StretchBlt
2566 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2567 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2569 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2570 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2572 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2574 if (src_dev->funcs != dst_dev->funcs)
2576 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2577 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2580 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2582 /* XRender is of no use for color -> mono */
2583 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2584 goto x11drv_fallback;
2586 /* if not stretching, we only need to handle format conversion */
2587 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2589 sSrc = sDst = X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_None );
2590 if (physdev_dst != physdev_src) sSrc = X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_None );
2592 /* try client-side DIB copy */
2593 if (!stretch && sSrc == DIB_Status_AppMod)
2595 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2596 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2597 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2598 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2601 X11DRV_CoerceDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2602 if (physdev_dst != physdev_src) X11DRV_CoerceDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2608 struct bitblt_coords tmp;
2610 /* make coordinates relative to tmp pixmap */
2612 tmp.x -= tmp.visrect.left;
2613 tmp.y -= tmp.visrect.top;
2614 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2617 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2618 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2619 XSetGraphicsExposures( gdi_display, tmpGC, False );
2620 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2621 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2622 wine_tsx11_unlock();
2624 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2625 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2628 XFreePixmap( gdi_display, tmp_pixmap );
2629 XFreeGC( gdi_display, tmpGC );
2630 wine_tsx11_unlock();
2632 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2634 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2635 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2639 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2643 /***********************************************************************
2644 * xrenderdrv_PutImage
2646 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2647 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2648 struct bitblt_coords *dst, DWORD rop )
2650 struct xrender_physdev *physdev;
2651 X_PHYSBITMAP *bitmap;
2655 enum wxr_format src_format, dst_format;
2656 XRenderPictFormat *pict_format;
2661 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2665 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2667 dst_format = get_xrender_format_from_color_shifts( bitmap->pixmap_depth,
2668 &bitmap->pixmap_color_shifts );
2672 physdev = get_xrender_dev( dev );
2674 dst_format = physdev->format;
2677 src_format = get_xrender_format_from_bitmapinfo( info, TRUE );
2678 if (!(pict_format = pict_formats[src_format])) goto update_format;
2680 /* make sure we can create an image with the same bpp */
2681 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2684 /* mono <-> color conversions not supported */
2685 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2686 goto x11drv_fallback;
2688 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2690 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2693 struct bitblt_coords tmp;
2697 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2698 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2700 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2702 xrender_put_image( src_pixmap, src_pict, rgn, pict_formats[dst_format],
2703 NULL, bitmap->pixmap, src, dst, use_repeat );
2705 X11DRV_DIB_Unlock( bitmap, TRUE );
2706 DeleteObject( rgn );
2710 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2714 RGNDATA *clip_data = NULL;
2716 /* make coordinates relative to tmp pixmap */
2718 tmp.x -= tmp.visrect.left;
2719 tmp.y -= tmp.visrect.top;
2720 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2722 if (clip) clip_data = add_extra_clipping_region( physdev->x11dev, clip );
2725 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2726 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2727 XSetGraphicsExposures( gdi_display, gc, False );
2728 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2729 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2730 wine_tsx11_unlock();
2732 xrender_put_image( src_pixmap, src_pict, NULL, physdev->pict_format,
2733 NULL, tmp_pixmap, src, &tmp, use_repeat );
2734 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2737 XFreePixmap( gdi_display, tmp_pixmap );
2738 XFreeGC( gdi_display, gc );
2739 wine_tsx11_unlock();
2741 restore_clipping_region( physdev->x11dev, clip_data );
2743 else xrender_put_image( src_pixmap, src_pict, clip,
2744 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2746 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2750 pXRenderFreePicture( gdi_display, src_pict );
2751 XFreePixmap( gdi_display, src_pixmap );
2752 wine_tsx11_unlock();
2757 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2758 set_color_info( pict_formats[dst_format], info );
2759 return ERROR_BAD_FORMAT;
2762 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2763 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2764 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2768 /***********************************************************************
2769 * xrenderdrv_BlendImage
2771 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2772 struct bitblt_coords *src, struct bitblt_coords *dst,
2773 BLENDFUNCTION func )
2775 struct xrender_physdev *physdev = get_xrender_dev( dev );
2777 enum wxr_format format;
2778 XRenderPictFormat *pict_format;
2779 Picture dst_pict, src_pict, mask_pict;
2783 if (!X11DRV_XRender_Installed)
2785 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2786 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2789 format = get_xrender_format_from_bitmapinfo( info, func.AlphaFormat & AC_SRC_ALPHA );
2790 if (!(pict_format = pict_formats[format])) goto update_format;
2792 /* make sure we can create an image with the same bpp */
2793 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2796 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2799 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2801 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2804 double xscale, yscale;
2806 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2810 xscale = src->width / (double)dst->width;
2811 yscale = src->height / (double)dst->height;
2813 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2815 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2817 EnterCriticalSection( &xrender_cs );
2818 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2821 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2822 physdev->x11dev->dc_rect.left + dst->x,
2823 physdev->x11dev->dc_rect.top + dst->y,
2824 xscale, yscale, dst->width, dst->height );
2825 pXRenderFreePicture( gdi_display, src_pict );
2826 XFreePixmap( gdi_display, src_pixmap );
2827 wine_tsx11_unlock();
2829 LeaveCriticalSection( &xrender_cs );
2831 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2836 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2837 set_color_info( physdev->pict_format, info );
2838 return ERROR_BAD_FORMAT;
2842 /***********************************************************************
2843 * xrenderdrv_AlphaBlend
2845 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2846 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2848 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2849 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2850 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2851 double xscale, yscale;
2854 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2856 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2857 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2860 if (physdev_src != physdev_dst) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2861 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2863 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2865 use_repeat = use_source_repeat( physdev_src );
2868 xscale = src->width / (double)dst->width;
2869 yscale = src->height / (double)dst->height;
2871 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2873 if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format)
2875 /* we need a source picture with no alpha */
2876 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2877 if (format != physdev_src->format)
2879 XRenderPictureAttributes pa;
2882 pa.subwindow_mode = IncludeInferiors;
2883 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2884 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2885 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2886 wine_tsx11_unlock();
2887 src_pict = tmp_pict;
2891 if (!src_pict) src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2893 EnterCriticalSection( &xrender_cs );
2894 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2897 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2898 physdev_src->x11dev->dc_rect.left + src->x,
2899 physdev_src->x11dev->dc_rect.top + src->y,
2900 physdev_dst->x11dev->dc_rect.left + dst->x,
2901 physdev_dst->x11dev->dc_rect.top + dst->y,
2902 xscale, yscale, dst->width, dst->height );
2903 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2904 wine_tsx11_unlock();
2906 LeaveCriticalSection( &xrender_cs );
2907 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2908 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2913 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2915 /* 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 */
2916 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2917 enum wxr_format src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2918 enum wxr_format dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2921 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2923 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2924 if( (physBitmap->pixmap_depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->pixmap_depth) ||
2925 (src_format == dst_format) )
2927 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2928 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2930 else /* We need depth conversion */
2932 Picture src_pict, dst_pict;
2933 XRenderPictureAttributes pa;
2934 pa.subwindow_mode = IncludeInferiors;
2935 pa.repeat = RepeatNone;
2937 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap,
2938 pict_formats[src_format], CPSubwindowMode|CPRepeat, &pa);
2939 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap,
2940 pict_formats[dst_format], CPSubwindowMode|CPRepeat, &pa);
2942 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2943 pXRenderFreePicture(gdi_display, src_pict);
2944 pXRenderFreePicture(gdi_display, dst_pict);
2946 wine_tsx11_unlock();
2949 static const struct gdi_dc_funcs xrender_funcs =
2951 NULL, /* pAbortDoc */
2952 NULL, /* pAbortPath */
2953 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2954 NULL, /* pAngleArc */
2957 NULL, /* pBeginPath */
2958 xrenderdrv_BlendImage, /* pBlendImage */
2959 NULL, /* pChoosePixelFormat */
2961 NULL, /* pCloseFigure */
2962 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2963 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2964 xrenderdrv_CreateDC, /* pCreateDC */
2965 NULL, /* pCreateDIBSection */
2966 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
2967 xrenderdrv_DeleteDC, /* pDeleteDC */
2968 NULL, /* pDeleteObject */
2969 NULL, /* pDescribePixelFormat */
2970 NULL, /* pDeviceCapabilities */
2971 NULL, /* pEllipse */
2973 NULL, /* pEndPage */
2974 NULL, /* pEndPath */
2975 NULL, /* pEnumDeviceFonts */
2976 NULL, /* pEnumICMProfiles */
2977 NULL, /* pExcludeClipRect */
2978 NULL, /* pExtDeviceMode */
2979 xrenderdrv_ExtEscape, /* pExtEscape */
2980 NULL, /* pExtFloodFill */
2981 NULL, /* pExtSelectClipRgn */
2982 xrenderdrv_ExtTextOut, /* pExtTextOut */
2983 NULL, /* pFillPath */
2984 NULL, /* pFillRgn */
2985 NULL, /* pFlattenPath */
2986 NULL, /* pFrameRgn */
2987 NULL, /* pGdiComment */
2988 NULL, /* pGetCharWidth */
2989 NULL, /* pGetDeviceCaps */
2990 NULL, /* pGetDeviceGammaRamp */
2991 NULL, /* pGetICMProfile */
2992 xrenderdrv_GetImage, /* pGetImage */
2993 NULL, /* pGetNearestColor */
2994 NULL, /* pGetPixel */
2995 NULL, /* pGetPixelFormat */
2996 NULL, /* pGetSystemPaletteEntries */
2997 NULL, /* pGetTextExtentExPoint */
2998 NULL, /* pGetTextMetrics */
2999 NULL, /* pIntersectClipRect */
3000 NULL, /* pInvertRgn */
3002 NULL, /* pModifyWorldTransform */
3004 NULL, /* pOffsetClipRgn */
3005 NULL, /* pOffsetViewportOrg */
3006 NULL, /* pOffsetWindowOrg */
3007 NULL, /* pPaintRgn */
3010 NULL, /* pPolyBezier */
3011 NULL, /* pPolyBezierTo */
3012 NULL, /* pPolyDraw */
3013 NULL, /* pPolyPolygon */
3014 NULL, /* pPolyPolyline */
3015 NULL, /* pPolygon */
3016 NULL, /* pPolyline */
3017 NULL, /* pPolylineTo */
3018 xrenderdrv_PutImage, /* pPutImage */
3019 NULL, /* pRealizeDefaultPalette */
3020 NULL, /* pRealizePalette */
3021 NULL, /* pRectangle */
3022 NULL, /* pResetDC */
3023 NULL, /* pRestoreDC */
3024 NULL, /* pRoundRect */
3026 NULL, /* pScaleViewportExt */
3027 NULL, /* pScaleWindowExt */
3028 xrenderdrv_SelectBitmap, /* pSelectBitmap */
3029 NULL, /* pSelectBrush */
3030 NULL, /* pSelectClipPath */
3031 xrenderdrv_SelectFont, /* pSelectFont */
3032 NULL, /* pSelectPalette */
3033 NULL, /* pSelectPen */
3034 NULL, /* pSetArcDirection */
3035 NULL, /* pSetBkColor */
3036 NULL, /* pSetBkMode */
3037 NULL, /* pSetDCBrushColor */
3038 NULL, /* pSetDCPenColor */
3039 NULL, /* pSetDIBColorTable */
3040 NULL, /* pSetDIBitsToDevice */
3041 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
3042 NULL, /* pSetDeviceGammaRamp */
3043 NULL, /* pSetLayout */
3044 NULL, /* pSetMapMode */
3045 NULL, /* pSetMapperFlags */
3046 NULL, /* pSetPixel */
3047 NULL, /* pSetPixelFormat */
3048 NULL, /* pSetPolyFillMode */
3049 NULL, /* pSetROP2 */
3050 NULL, /* pSetRelAbs */
3051 NULL, /* pSetStretchBltMode */
3052 NULL, /* pSetTextAlign */
3053 NULL, /* pSetTextCharacterExtra */
3054 NULL, /* pSetTextColor */
3055 NULL, /* pSetTextJustification */
3056 NULL, /* pSetViewportExt */
3057 NULL, /* pSetViewportOrg */
3058 NULL, /* pSetWindowExt */
3059 NULL, /* pSetWindowOrg */
3060 NULL, /* pSetWorldTransform */
3061 NULL, /* pStartDoc */
3062 NULL, /* pStartPage */
3063 xrenderdrv_StretchBlt, /* pStretchBlt */
3064 NULL, /* pStretchDIBits */
3065 NULL, /* pStrokeAndFillPath */
3066 NULL, /* pStrokePath */
3067 NULL, /* pSwapBuffers */
3068 NULL, /* pUnrealizePalette */
3069 NULL, /* pWidenPath */
3070 /* OpenGL not supported */
3073 #else /* SONAME_LIBXRENDER */
3075 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
3077 TRACE("XRender support not compiled in.\n");
3081 void X11DRV_XRender_Finalize(void)
3085 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
3088 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
3090 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
3091 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
3092 wine_tsx11_unlock();
3095 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
3100 #endif /* SONAME_LIBXRENDER */