2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
8 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
36 #include "wine/library.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
40 int using_client_side_fonts = FALSE;
42 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
44 #ifdef SONAME_LIBXRENDER
46 static BOOL X11DRV_XRender_Installed = FALSE;
49 #include <X11/extensions/Xrender.h>
51 #ifndef RepeatNone /* added in 0.10 */
53 #define RepeatNormal 1
55 #define RepeatReflect 3
58 typedef enum wine_xrformat
75 typedef struct wine_xrender_format_template
80 unsigned int alphaMask;
84 unsigned int greenMask;
86 unsigned int blueMask;
87 } WineXRenderFormatTemplate;
89 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
91 /* Format depth alpha mask red mask green mask blue mask*/
92 {WXR_FORMAT_MONO, 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
93 {WXR_FORMAT_GRAY, 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
94 {WXR_FORMAT_X1R5G5B5, 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
95 {WXR_FORMAT_X1B5G5R5, 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
96 {WXR_FORMAT_R5G6B5, 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
97 {WXR_FORMAT_B5G6R5, 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
98 {WXR_FORMAT_R8G8B8, 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
99 {WXR_FORMAT_B8G8R8, 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
100 {WXR_FORMAT_A8R8G8B8, 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
101 {WXR_FORMAT_B8G8R8A8, 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
102 {WXR_FORMAT_X8R8G8B8, 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
103 {WXR_FORMAT_B8G8R8X8, 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
106 typedef struct wine_xrender_format
109 XRenderPictFormat *pict_format;
112 static WineXRenderFormat wxr_formats[WXR_NB_FORMATS];
113 static int WineXRenderFormatsListSize = 0;
114 static WineXRenderFormat *default_format = NULL;
120 SIZE devsize; /* size in device coords */
124 #define INITIAL_REALIZED_BUF_SIZE 128
126 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
131 const WineXRenderFormat *font_format;
136 } gsCacheEntryFormat;
142 gsCacheEntryFormat * format[AA_MAXVALUE];
152 const WineXRenderFormat *format;
155 struct xrender_physdev
157 struct gdi_physdev dev;
158 X11DRV_PDEVICE *x11dev;
159 struct xrender_info info;
162 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
164 return (struct xrender_physdev *)dev;
167 static const struct gdi_dc_funcs xrender_funcs;
169 static gsCacheEntry *glyphsetCache = NULL;
170 static DWORD glyphsetCacheSize = 0;
171 static INT lastfree = -1;
174 #define INIT_CACHE_SIZE 10
176 static int antialias = 1;
178 static void *xrender_handle;
180 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
181 MAKE_FUNCPTR(XRenderAddGlyphs)
182 MAKE_FUNCPTR(XRenderComposite)
183 MAKE_FUNCPTR(XRenderCompositeString8)
184 MAKE_FUNCPTR(XRenderCompositeString16)
185 MAKE_FUNCPTR(XRenderCompositeString32)
186 MAKE_FUNCPTR(XRenderCompositeText16)
187 MAKE_FUNCPTR(XRenderCreateGlyphSet)
188 MAKE_FUNCPTR(XRenderCreatePicture)
189 MAKE_FUNCPTR(XRenderFillRectangle)
190 MAKE_FUNCPTR(XRenderFindFormat)
191 MAKE_FUNCPTR(XRenderFindVisualFormat)
192 MAKE_FUNCPTR(XRenderFreeGlyphSet)
193 MAKE_FUNCPTR(XRenderFreePicture)
194 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
195 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
196 MAKE_FUNCPTR(XRenderSetPictureTransform)
198 MAKE_FUNCPTR(XRenderQueryExtension)
200 #ifdef SONAME_LIBFONTCONFIG
201 #include <fontconfig/fontconfig.h>
202 MAKE_FUNCPTR(FcConfigSubstitute)
203 MAKE_FUNCPTR(FcDefaultSubstitute)
204 MAKE_FUNCPTR(FcFontMatch)
206 MAKE_FUNCPTR(FcPatternCreate)
207 MAKE_FUNCPTR(FcPatternDestroy)
208 MAKE_FUNCPTR(FcPatternAddInteger)
209 MAKE_FUNCPTR(FcPatternAddString)
210 MAKE_FUNCPTR(FcPatternGetBool)
211 MAKE_FUNCPTR(FcPatternGetInteger)
212 MAKE_FUNCPTR(FcPatternGetString)
213 static void *fontconfig_handle;
214 static BOOL fontconfig_installed;
219 static CRITICAL_SECTION xrender_cs;
220 static CRITICAL_SECTION_DEBUG critsect_debug =
223 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
224 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
226 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
228 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
229 ( ( (ULONG)_x4 << 24 ) | \
230 ( (ULONG)_x3 << 16 ) | \
231 ( (ULONG)_x2 << 8 ) | \
234 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
236 #define GASP_GRIDFIT 0x01
237 #define GASP_DOGRAY 0x02
239 #ifdef WORDS_BIGENDIAN
240 #define get_be_word(x) (x)
241 #define NATIVE_BYTE_ORDER MSBFirst
243 #define get_be_word(x) RtlUshortByteSwap(x)
244 #define NATIVE_BYTE_ORDER LSBFirst
247 static WXRFormat get_format_without_alpha( WXRFormat format )
251 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
252 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
253 default: return format;
257 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
260 templ->type = PictTypeDirect;
261 templ->depth = fmt->depth;
262 templ->direct.alpha = fmt->alpha;
263 templ->direct.alphaMask = fmt->alphaMask;
264 templ->direct.red = fmt->red;
265 templ->direct.redMask = fmt->redMask;
266 templ->direct.green = fmt->green;
267 templ->direct.greenMask = fmt->greenMask;
268 templ->direct.blue = fmt->blue;
269 templ->direct.blueMask = fmt->blueMask;
272 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
277 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
279 if(fmt->depth != screen_depth)
281 if( (fmt->redMask << fmt->red) != visual->red_mask)
283 if( (fmt->greenMask << fmt->green) != visual->green_mask)
285 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
288 /* We never select a default ARGB visual */
295 static int load_xrender_formats(void)
298 for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
300 XRenderPictFormat templ, *pict_format;
302 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
305 pict_format = pXRenderFindVisualFormat(gdi_display, visual);
308 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
309 if (visual->class == DirectColor)
312 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
313 screen_depth, TrueColor, &info ))
315 pict_format = pXRenderFindVisualFormat(gdi_display, info.visual);
316 if (pict_format) visual = info.visual;
324 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
325 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
326 default_format = &wxr_formats[WineXRenderFormatsListSize];
327 WineXRenderFormatsListSize++;
328 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
333 unsigned long mask = 0;
334 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
337 pict_format = pXRenderFindFormat(gdi_display, mask, &templ, 0);
342 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
343 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
344 WineXRenderFormatsListSize++;
345 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
349 return WineXRenderFormatsListSize;
352 /***********************************************************************
353 * X11DRV_XRender_Init
355 * Let's see if our XServer has the extension available
358 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
362 if (client_side_with_render &&
363 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
366 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
367 LOAD_FUNCPTR(XRenderAddGlyphs)
368 LOAD_FUNCPTR(XRenderComposite)
369 LOAD_FUNCPTR(XRenderCompositeString8)
370 LOAD_FUNCPTR(XRenderCompositeString16)
371 LOAD_FUNCPTR(XRenderCompositeString32)
372 LOAD_FUNCPTR(XRenderCompositeText16)
373 LOAD_FUNCPTR(XRenderCreateGlyphSet)
374 LOAD_FUNCPTR(XRenderCreatePicture)
375 LOAD_FUNCPTR(XRenderFillRectangle)
376 LOAD_FUNCPTR(XRenderFindFormat)
377 LOAD_FUNCPTR(XRenderFindVisualFormat)
378 LOAD_FUNCPTR(XRenderFreeGlyphSet)
379 LOAD_FUNCPTR(XRenderFreePicture)
380 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
381 LOAD_FUNCPTR(XRenderQueryExtension)
383 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
384 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
385 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
386 #undef LOAD_OPTIONAL_FUNCPTR
390 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
392 if(X11DRV_XRender_Installed) {
393 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
394 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
398 "Wine has detected that you probably have a buggy version\n"
399 "of libXrender.so . Because of this client side font rendering\n"
400 "will be disabled. Please upgrade this library.\n");
401 X11DRV_XRender_Installed = FALSE;
405 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
406 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
407 X11DRV_XRender_Installed = FALSE;
412 #ifdef SONAME_LIBFONTCONFIG
413 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
415 #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;}
416 LOAD_FUNCPTR(FcConfigSubstitute);
417 LOAD_FUNCPTR(FcDefaultSubstitute);
418 LOAD_FUNCPTR(FcFontMatch);
419 LOAD_FUNCPTR(FcInit);
420 LOAD_FUNCPTR(FcPatternCreate);
421 LOAD_FUNCPTR(FcPatternDestroy);
422 LOAD_FUNCPTR(FcPatternAddInteger);
423 LOAD_FUNCPTR(FcPatternAddString);
424 LOAD_FUNCPTR(FcPatternGetBool);
425 LOAD_FUNCPTR(FcPatternGetInteger);
426 LOAD_FUNCPTR(FcPatternGetString);
428 fontconfig_installed = pFcInit();
430 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
434 if(X11DRV_XRender_Installed || client_side_with_core)
436 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
437 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
439 glyphsetCacheSize = INIT_CACHE_SIZE;
441 for(i = 0; i < INIT_CACHE_SIZE; i++) {
442 glyphsetCache[i].next = i + 1;
443 glyphsetCache[i].count = -1;
445 glyphsetCache[i-1].next = -1;
446 using_client_side_fonts = 1;
448 if(!X11DRV_XRender_Installed) {
449 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
450 if(screen_depth <= 8 || !client_side_antialias_with_core)
453 if(screen_depth <= 8 || !client_side_antialias_with_render)
456 return &xrender_funcs;
458 TRACE("Using X11 core fonts\n");
462 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
463 static void get_xrender_color(const WineXRenderFormat *wxr_format, int src_color, XRenderColor *dst_color)
465 XRenderPictFormat *pf = wxr_format->pict_format;
467 if(pf->direct.redMask)
468 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
472 if(pf->direct.greenMask)
473 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
475 dst_color->green = 0;
477 if(pf->direct.blueMask)
478 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
482 dst_color->alpha = 0xffff;
485 static const WineXRenderFormat *get_xrender_format(WXRFormat format)
488 for(i=0; i<WineXRenderFormatsListSize; i++)
490 if(wxr_formats[i].format == format)
492 TRACE("Returning wxr_format=%#x\n", format);
493 return &wxr_formats[i];
499 static const WineXRenderFormat *get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
501 int redMask, greenMask, blueMask;
505 return get_xrender_format(WXR_FORMAT_MONO);
507 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
509 return default_format;
511 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
512 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
513 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
515 /* Try to locate a format which matches the specification of the dibsection. */
516 for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
518 if( depth == wxr_formats_template[i].depth &&
519 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
520 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
521 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
524 /* When we reach this stage the format was found in our template table but this doesn't mean that
525 * the Xserver also supports this format (e.g. its depth might be too low). The call below verifies that.
527 return get_xrender_format(wxr_formats_template[i].wxr_format);
531 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
532 ERR("No XRender format found!\n");
536 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
537 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
539 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
540 XTransform xform = {{
541 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
542 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
543 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
546 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
550 /* check if we can use repeating instead of scaling for the specified source DC */
551 static BOOL use_source_repeat( X11DRV_PDEVICE *physDev )
553 return (physDev->bitmap &&
554 physDev->drawable_rect.right - physDev->drawable_rect.left == 1 &&
555 physDev->drawable_rect.bottom - physDev->drawable_rect.top == 1);
558 static struct xrender_info *get_xrender_info(X11DRV_PDEVICE *physDev)
560 if(!physDev->xrender)
562 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physDev->xrender));
564 if(!physDev->xrender)
566 ERR("Unable to allocate XRENDERINFO!\n");
569 physDev->xrender->cache_index = -1;
571 if (!physDev->xrender->format)
572 physDev->xrender->format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
574 return physDev->xrender;
577 static Picture get_xrender_picture(X11DRV_PDEVICE *physDev)
579 struct xrender_info *info = get_xrender_info(physDev);
582 if (!info->pict && info->format)
584 XRenderPictureAttributes pa;
585 RGNDATA *clip = X11DRV_GetRegionData( physDev->region, 0 );
588 pa.subwindow_mode = IncludeInferiors;
589 info->pict = pXRenderCreatePicture(gdi_display, physDev->drawable, info->format->pict_format,
590 CPSubwindowMode, &pa);
591 if (info->pict && clip)
592 pXRenderSetPictureClipRectangles( gdi_display, info->pict,
593 physDev->dc_rect.left, physDev->dc_rect.top,
594 (XRectangle *)clip->Buffer, clip->rdh.nCount );
596 TRACE("Allocing pict=%lx dc=%p drawable=%08lx\n", info->pict, physDev->dev.hdc, physDev->drawable);
597 HeapFree( GetProcessHeap(), 0, clip );
603 static Picture get_xrender_picture_source(X11DRV_PDEVICE *physDev, BOOL repeat)
605 struct xrender_info *info = get_xrender_info(physDev);
608 if (!info->pict_src && info->format)
610 XRenderPictureAttributes pa;
613 pa.subwindow_mode = IncludeInferiors;
614 pa.repeat = repeat ? RepeatNormal : RepeatNone;
615 info->pict_src = pXRenderCreatePicture(gdi_display, physDev->drawable, info->format->pict_format,
616 CPSubwindowMode|CPRepeat, &pa);
619 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
620 info->pict_src, physDev->dev.hdc, physDev->drawable, pa.repeat);
623 return info->pict_src;
626 static void free_xrender_picture( struct xrender_physdev *dev )
628 if (dev->info.pict || dev->info.pict_src)
631 XFlush( gdi_display );
634 TRACE("freeing pict = %lx dc = %p\n", dev->info.pict, dev->dev.hdc);
635 pXRenderFreePicture(gdi_display, dev->info.pict);
638 if(dev->info.pict_src)
640 TRACE("freeing pict = %lx dc = %p\n", dev->info.pict_src, dev->dev.hdc);
641 pXRenderFreePicture(gdi_display, dev->info.pict_src);
642 dev->info.pict_src = 0;
646 dev->info.format = NULL;
649 static void update_xrender_drawable( struct xrender_physdev *dev )
651 free_xrender_picture( dev );
652 dev->info.format = get_xrender_format_from_color_shifts( dev->x11dev->depth,
653 dev->x11dev->color_shifts );
656 /* return a mask picture used to force alpha to 0 */
657 static Picture get_no_alpha_mask(void)
659 static Pixmap pixmap;
665 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
666 XRenderPictureAttributes pa;
669 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
670 pa.repeat = RepeatNormal;
671 pa.component_alpha = True;
672 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format,
673 CPRepeat|CPComponentAlpha, &pa );
674 col.red = col.green = col.blue = 0xffff;
676 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
682 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
684 if(p1->hash != p2->hash) return TRUE;
685 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
686 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
687 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
688 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
692 static void walk_cache(void)
696 EnterCriticalSection(&xrender_cs);
697 for(i=mru; i >= 0; i = glyphsetCache[i].next)
698 TRACE("item %d\n", i);
699 LeaveCriticalSection(&xrender_cs);
703 static int LookupEntry(LFANDSIZE *plfsz)
707 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
709 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
711 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
712 glyphsetCache[i].count++;
714 glyphsetCache[prev_i].next = glyphsetCache[i].next;
715 glyphsetCache[i].next = mru;
718 TRACE("found font in cache %d\n", i);
723 TRACE("font not in cache\n");
727 static void FreeEntry(int entry)
731 for(format = 0; format < AA_MAXVALUE; format++) {
732 gsCacheEntryFormat * formatEntry;
734 if( !glyphsetCache[entry].format[format] )
737 formatEntry = glyphsetCache[entry].format[format];
739 if(formatEntry->glyphset) {
741 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
743 formatEntry->glyphset = 0;
745 if(formatEntry->nrealized) {
746 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
747 formatEntry->realized = NULL;
748 if(formatEntry->bitmaps) {
749 for(i = 0; i < formatEntry->nrealized; i++)
750 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
751 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
752 formatEntry->bitmaps = NULL;
754 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
755 formatEntry->gis = NULL;
756 formatEntry->nrealized = 0;
759 HeapFree(GetProcessHeap(), 0, formatEntry);
760 glyphsetCache[entry].format[format] = NULL;
764 static int AllocEntry(void)
766 int best = -1, prev_best = -1, i, prev_i = -1;
769 assert(glyphsetCache[lastfree].count == -1);
770 glyphsetCache[lastfree].count = 1;
772 lastfree = glyphsetCache[lastfree].next;
774 glyphsetCache[best].next = mru;
777 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
781 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
782 if(glyphsetCache[i].count == 0) {
790 TRACE("freeing unused glyphset at cache %d\n", best);
792 glyphsetCache[best].count = 1;
794 glyphsetCache[prev_best].next = glyphsetCache[best].next;
795 glyphsetCache[best].next = mru;
803 TRACE("Growing cache\n");
806 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
808 (glyphsetCacheSize + INIT_CACHE_SIZE)
809 * sizeof(*glyphsetCache));
811 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
812 (glyphsetCacheSize + INIT_CACHE_SIZE)
813 * sizeof(*glyphsetCache));
815 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
817 glyphsetCache[i].next = i + 1;
818 glyphsetCache[i].count = -1;
820 glyphsetCache[i-1].next = -1;
821 glyphsetCacheSize += INIT_CACHE_SIZE;
823 lastfree = glyphsetCache[best].next;
824 glyphsetCache[best].count = 1;
825 glyphsetCache[best].next = mru;
827 TRACE("new free cache slot at %d\n", mru);
831 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
841 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
842 if(size == GDI_ERROR)
845 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
846 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
848 GetTextMetricsW(hdc, &tm);
849 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
852 num_recs = get_be_word(*gasp);
856 *flags = get_be_word(*(gasp + 1));
857 if(ppem <= get_be_word(*gasp))
861 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
863 HeapFree(GetProcessHeap(), 0, buffer);
867 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
871 UINT font_smoothing_type, font_smoothing_orientation;
873 if (X11DRV_XRender_Installed && subpixel &&
874 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
875 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
877 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
878 &font_smoothing_orientation, 0) &&
879 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
886 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
887 But, Wine's subpixel rendering can support the portrait mode.
890 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
898 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
903 static int hinter = -1;
904 static int subpixel = -1;
907 if((ret = LookupEntry(plfsz)) != -1) return ret;
910 entry = glyphsetCache + ret;
911 entry->lfsz = *plfsz;
912 for( format = 0; format < AA_MAXVALUE; format++ ) {
913 assert( !entry->format[format] );
916 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
918 if(hinter == -1 || subpixel == -1)
920 RASTERIZER_STATUS status;
921 GetRasterizerCaps(&status, sizeof(status));
922 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
923 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
926 switch (plfsz->lf.lfQuality)
928 case ANTIALIASED_QUALITY:
929 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
930 return ret; /* ignore further configuration */
931 case CLEARTYPE_QUALITY:
932 case CLEARTYPE_NATURAL_QUALITY:
933 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
935 case DEFAULT_QUALITY:
939 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
942 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
945 entry->aa_default = AA_None;
949 font_smoothing = TRUE; /* default to enabled */
950 #ifdef SONAME_LIBFONTCONFIG
951 if (fontconfig_installed)
953 FcPattern *match, *pattern = pFcPatternCreate();
955 char family[LF_FACESIZE * 4];
957 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
958 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
959 if (plfsz->lf.lfWeight != FW_DONTCARE)
962 switch (plfsz->lf.lfWeight)
964 case FW_THIN: weight = FC_WEIGHT_THIN; break;
965 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
966 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
967 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
968 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
969 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
970 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
971 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
972 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
973 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
975 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
977 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
978 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
979 pFcDefaultSubstitute( pattern );
980 if ((match = pFcFontMatch( NULL, pattern, &result )))
985 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
987 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
990 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
992 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
993 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
997 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
998 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
999 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1000 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1001 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1004 if (!antialias) font_smoothing = FALSE;
1005 pFcPatternDestroy( match );
1007 pFcPatternDestroy( pattern );
1009 #endif /* SONAME_LIBFONTCONFIG */
1011 /* now check Xft resources */
1014 BOOL antialias = TRUE;
1017 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1019 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1020 value[0] == '0' || !strcasecmp( value, "off" ))
1023 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1025 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1026 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1027 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1028 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1029 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1030 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1032 wine_tsx11_unlock();
1033 if (!antialias) font_smoothing = FALSE;
1036 if (!font_smoothing) entry->aa_default = AA_None;
1038 /* we can't support subpixel without xrender */
1039 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1042 entry->aa_default = AA_None;
1047 static void dec_ref_cache(int index)
1050 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1051 assert(glyphsetCache[index].count > 0);
1052 glyphsetCache[index].count--;
1055 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1057 DWORD hash = 0, *ptr, two_chars;
1061 hash ^= plfsz->devsize.cx;
1062 hash ^= plfsz->devsize.cy;
1063 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1065 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1067 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1069 pwc = (WCHAR *)&two_chars;
1071 *pwc = toupperW(*pwc);
1073 *pwc = toupperW(*pwc);
1081 /***********************************************************************
1082 * X11DRV_XRender_Finalize
1084 void X11DRV_XRender_Finalize(void)
1088 EnterCriticalSection(&xrender_cs);
1089 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1091 LeaveCriticalSection(&xrender_cs);
1094 /**********************************************************************
1095 * xrenderdrv_SelectFont
1097 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
1099 struct xrender_physdev *physdev = get_xrender_dev( dev );
1102 if (!GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf )) return HGDI_ERROR;
1106 dev = GET_NEXT_PHYSDEV( dev, pSelectFont );
1107 return dev->funcs->pSelectFont( dev, hfont, gdiFont );
1110 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1111 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1112 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1113 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1114 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1115 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1117 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1118 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1119 lfsz.xform.eM21, lfsz.xform.eM22);
1121 /* Not used fields, would break hashing */
1122 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1124 lfsz_calc_hash(&lfsz);
1126 EnterCriticalSection(&xrender_cs);
1127 if (physdev->info.cache_index != -1)
1128 dec_ref_cache( physdev->info.cache_index );
1129 physdev->info.cache_index = GetCacheEntry( dev->hdc, &lfsz );
1130 LeaveCriticalSection(&xrender_cs);
1131 physdev->x11dev->has_gdi_font = TRUE;
1135 static void update_xrender_clipping( struct xrender_physdev *dev, const RGNDATA *data )
1140 pXRenderSetPictureClipRectangles( gdi_display, dev->info.pict,
1141 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
1142 (XRectangle *)data->Buffer, data->rdh.nCount );
1143 wine_tsx11_unlock();
1147 static RGNDATA *add_xrender_clipping_region( struct xrender_physdev *dev, HRGN rgn )
1149 RGNDATA *ret, *data;
1152 if (!(ret = X11DRV_GetRegionData( dev->x11dev->region, 0 ))) return NULL;
1153 if (!(clip = CreateRectRgn( 0, 0, 0, 0 )))
1155 HeapFree( GetProcessHeap(), 0, ret );
1158 CombineRgn( clip, dev->x11dev->region, rgn, RGN_AND );
1159 if ((data = X11DRV_GetRegionData( clip, 0 )))
1161 update_xrender_clipping( dev, data );
1162 HeapFree( GetProcessHeap(), 0, data );
1164 DeleteObject( clip );
1168 static void restore_xrender_clipping_region( struct xrender_physdev *dev, RGNDATA *data )
1171 update_xrender_clipping( dev, data );
1172 HeapFree( GetProcessHeap(), 0, data );
1175 static BOOL create_xrender_dc( PHYSDEV *pdev )
1177 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1178 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1180 if (!physdev) return FALSE;
1181 physdev->x11dev = x11dev;
1182 physdev->info.cache_index = -1;
1183 physdev->info.format = get_xrender_format_from_color_shifts( x11dev->depth, x11dev->color_shifts );
1184 x11dev->xrender = &physdev->info;
1185 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1189 /**********************************************************************
1190 * xrenderdrv_CreateDC
1192 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1193 LPCWSTR output, const DEVMODEW* initData )
1195 return create_xrender_dc( pdev );
1198 /**********************************************************************
1199 * xrenderdrv_CreateCompatibleDC
1201 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1203 if (orig) /* chain to x11drv first */
1205 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1206 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1208 /* otherwise we have been called by x11drv */
1210 return create_xrender_dc( pdev );
1213 /**********************************************************************
1214 * xrenderdrv_DeleteDC
1216 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1218 struct xrender_physdev *physdev = get_xrender_dev( dev );
1220 free_xrender_picture( physdev );
1222 EnterCriticalSection( &xrender_cs );
1223 if (physdev->info.cache_index != -1) dec_ref_cache( physdev->info.cache_index );
1224 LeaveCriticalSection( &xrender_cs );
1226 physdev->x11dev->xrender = NULL;
1227 HeapFree( GetProcessHeap(), 0, physdev );
1231 /**********************************************************************
1232 * xrenderdrv_ExtEscape
1234 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1235 INT out_count, LPVOID out_data )
1237 struct xrender_physdev *physdev = get_xrender_dev( dev );
1239 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1241 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1243 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1245 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1246 if (ret) update_xrender_drawable( physdev );
1250 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1253 /****************************************************************************
1254 * xrenderdrv_CreateBitmap
1256 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1258 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1259 return dev->funcs->pCreateBitmap( dev, hbitmap );
1262 /****************************************************************************
1263 * xrenderdrv_DeleteBitmap
1265 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1267 return X11DRV_DeleteBitmap( hbitmap );
1270 /***********************************************************************
1271 * xrenderdrv_SelectBitmap
1273 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1276 struct xrender_physdev *physdev = get_xrender_dev( dev );
1278 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1279 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1280 if (ret) update_xrender_drawable( physdev );
1284 /***********************************************************************
1285 * xrenderdrv_GetImage
1287 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1288 struct gdi_image_bits *bits, struct bitblt_coords *src )
1290 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1291 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1292 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1295 /***********************************************************************
1296 * xrenderdrv_PutImage
1298 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
1299 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1300 struct bitblt_coords *dst, DWORD rop )
1302 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
1303 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
1304 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
1307 /***********************************************************************
1308 * xrenderdrv_SetDeviceClipping
1310 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1312 struct xrender_physdev *physdev = get_xrender_dev( dev );
1315 CombineRgn( physdev->x11dev->region, vis_rgn, clip_rgn, clip_rgn ? RGN_AND : RGN_COPY );
1317 if (!(data = X11DRV_GetRegionData( physdev->x11dev->region, 0 ))) return;
1318 update_x11_clipping( physdev->x11dev, data );
1319 update_xrender_clipping( physdev, data );
1320 HeapFree( GetProcessHeap(), 0, data );
1324 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1326 const WineXRenderFormat *fmt;
1329 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1330 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1331 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1332 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1337 const DWORD *bitfields;
1338 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1339 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1341 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1342 bitfields = dib->dsBitfields;
1343 else if(bits_pixel == 24 || bits_pixel == 32)
1344 bitfields = bitfields_32;
1346 bitfields = bitfields_16;
1348 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1349 fmt = get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts);
1351 /* Common formats should be in our picture format table. */
1354 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1355 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1361 int red_mask, green_mask, blue_mask;
1363 /* We are dealing with a DDB */
1367 fmt = get_xrender_format(WXR_FORMAT_R5G6B5);
1370 fmt = get_xrender_format(WXR_FORMAT_R8G8B8);
1373 fmt = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1381 TRACE("Unhandled DDB bits_pixel=%d\n", bits_pixel);
1385 red_mask = fmt->pict_format->direct.redMask << fmt->pict_format->direct.red;
1386 green_mask = fmt->pict_format->direct.greenMask << fmt->pict_format->direct.green;
1387 blue_mask = fmt->pict_format->direct.blueMask << fmt->pict_format->direct.blue;
1388 X11DRV_PALETTE_ComputeColorShifts(&shifts, red_mask, green_mask, blue_mask);
1391 physBitmap->pixmap_depth = fmt->pict_format->depth;
1392 physBitmap->trueColor = TRUE;
1393 physBitmap->pixmap_color_shifts = shifts;
1397 /************************************************************************
1400 * Helper to ExtTextOut. Must be called inside xrender_cs
1402 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1404 unsigned int buflen;
1409 gsCacheEntry *entry = glyphsetCache + physDev->info.cache_index;
1410 gsCacheEntryFormat *formatEntry;
1411 UINT ggo_format = GGO_GLYPH_INDEX;
1412 WXRFormat wxr_format;
1413 static const char zero[4];
1414 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1418 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1421 ggo_format |= WINE_GGO_HRGB_BITMAP;
1424 ggo_format |= WINE_GGO_HBGR_BITMAP;
1427 ggo_format |= WINE_GGO_VRGB_BITMAP;
1430 ggo_format |= WINE_GGO_VBGR_BITMAP;
1434 ERR("aa = %d - not implemented\n", format);
1436 ggo_format |= GGO_BITMAP;
1440 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1441 if(buflen == GDI_ERROR) {
1442 if(format != AA_None) {
1444 entry->aa_default = AA_None;
1445 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1446 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1448 if(buflen == GDI_ERROR) {
1449 WARN("GetGlyphOutlineW failed using default glyph\n");
1450 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1451 if(buflen == GDI_ERROR) {
1452 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1453 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1454 if(buflen == GDI_ERROR) {
1455 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1460 TRACE("Turning off antialiasing for this monochrome font\n");
1463 /* If there is nothing for the current type, we create the entry. */
1464 if( !entry->format[format] ) {
1465 entry->format[format] = HeapAlloc(GetProcessHeap(),
1467 sizeof(gsCacheEntryFormat));
1469 formatEntry = entry->format[format];
1471 if(formatEntry->nrealized <= glyph) {
1472 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1474 if (formatEntry->realized)
1475 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1477 formatEntry->realized,
1478 formatEntry->nrealized * sizeof(BOOL));
1480 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1482 formatEntry->nrealized * sizeof(BOOL));
1484 if(!X11DRV_XRender_Installed) {
1485 if (formatEntry->bitmaps)
1486 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1488 formatEntry->bitmaps,
1489 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1491 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1493 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1495 if (formatEntry->gis)
1496 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1499 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1501 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1503 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1507 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1510 wxr_format = WXR_FORMAT_GRAY;
1517 wxr_format = WXR_FORMAT_A8R8G8B8;
1521 ERR("aa = %d - not implemented\n", format);
1523 wxr_format = WXR_FORMAT_MONO;
1528 formatEntry->font_format = get_xrender_format(wxr_format);
1529 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
1530 wine_tsx11_unlock();
1534 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1535 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1536 formatEntry->realized[glyph] = TRUE;
1538 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1540 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1541 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1543 gi.width = gm.gmBlackBoxX;
1544 gi.height = gm.gmBlackBoxY;
1545 gi.x = -gm.gmptGlyphOrigin.x;
1546 gi.y = gm.gmptGlyphOrigin.y;
1547 gi.xOff = gm.gmCellIncX;
1548 gi.yOff = gm.gmCellIncY;
1550 if(TRACE_ON(xrender)) {
1553 unsigned char *line;
1555 if(format == AA_None) {
1556 pitch = ((gi.width + 31) / 32) * 4;
1557 for(i = 0; i < gi.height; i++) {
1558 line = (unsigned char*) buf + i * pitch;
1560 for(j = 0; j < pitch * 8; j++) {
1561 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1563 TRACE("%s\n", output);
1566 static const char blks[] = " .:;!o*#";
1570 pitch = ((gi.width + 3) / 4) * 4;
1571 for(i = 0; i < gi.height; i++) {
1572 line = (unsigned char*) buf + i * pitch;
1574 for(j = 0; j < pitch; j++) {
1575 str[0] = blks[line[j] >> 5];
1576 strcat(output, str);
1578 TRACE("%s\n", output);
1584 if(formatEntry->glyphset) {
1585 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1586 unsigned char *byte = (unsigned char*) buf, c;
1592 /* magic to flip bit order */
1593 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1594 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1595 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1600 else if ( format != AA_Grey &&
1601 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1603 unsigned int i, *data = (unsigned int *)buf;
1604 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1609 XRenderCompositeText seems to ignore 0x0 glyphs when
1610 AA_None, which means we lose the advance width of glyphs
1611 like the space. We'll pretend that such glyphs are 1x1
1616 gi.width = gi.height = 1;
1619 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1620 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1621 wine_tsx11_unlock();
1622 HeapFree(GetProcessHeap(), 0, buf);
1624 formatEntry->bitmaps[glyph] = buf;
1627 formatEntry->gis[glyph] = gi;
1630 static void SharpGlyphMono(struct xrender_physdev *physDev, INT x, INT y,
1631 void *bitmap, XGlyphInfo *gi)
1633 unsigned char *srcLine = bitmap, *src;
1634 unsigned char bits, bitsMask;
1635 int width = gi->width;
1636 int stride = ((width + 31) & ~31) >> 3;
1637 int height = gi->height;
1641 TRACE("%d, %d\n", x, y);
1650 bitsMask = 0x80; /* FreeType is always MSB first */
1656 if (bits & bitsMask)
1664 bitsMask = bitsMask >> 1;
1670 } while (bits & bitsMask);
1671 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1672 physDev->x11dev->gc, xspan, y, lenspan, 1);
1684 bitsMask = bitsMask >> 1;
1690 } while (!(bits & bitsMask));
1697 static void SharpGlyphGray(struct xrender_physdev *physDev, INT x, INT y,
1698 void *bitmap, XGlyphInfo *gi)
1700 unsigned char *srcLine = bitmap, *src, bits;
1701 int width = gi->width;
1702 int stride = ((width + 3) & ~3);
1703 int height = gi->height;
1728 } while (bits >= 0x80);
1729 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1730 physDev->x11dev->gc, xspan, y, lenspan, 1);
1743 } while (bits < 0x80);
1751 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1756 while ((mask & 1) == 0)
1762 while ((mask & 1) == 1)
1771 static DWORD GetField (DWORD pixel, int shift, int len)
1773 pixel = pixel & (((1 << (len)) - 1) << shift);
1774 pixel = pixel << (32 - (shift + len)) >> 24;
1777 pixel |= (pixel >> len);
1784 static DWORD PutField (DWORD pixel, int shift, int len)
1786 shift = shift - (8 - len);
1788 pixel &= (((1 << len) - 1) << (8 - len));
1796 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1802 BYTE *maskLine, *mask, m;
1807 BYTE src_r, src_g, src_b;
1812 height = gi->height;
1815 maskStride = (width + 3) & ~3;
1817 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1818 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1819 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1821 src_r = GetField(color, r_shift, r_len);
1822 src_g = GetField(color, g_shift, g_len);
1823 src_b = GetField(color, b_shift, b_len);
1825 for(; height--; y++)
1828 maskLine += maskStride;
1833 if(y >= image->height) break;
1837 if(tx >= image->width) break;
1840 if(tx < 0) continue;
1843 XPutPixel (image, tx, y, color);
1848 pixel = XGetPixel (image, tx, y);
1850 r = GetField(pixel, r_shift, r_len);
1851 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1852 g = GetField(pixel, g_shift, g_len);
1853 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1854 b = GetField(pixel, b_shift, b_len);
1855 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1857 pixel = (PutField (r, r_shift, r_len) |
1858 PutField (g, g_shift, g_len) |
1859 PutField (b, b_shift, b_len));
1860 XPutPixel (image, tx, y, pixel);
1866 /*************************************************************
1869 * Returns an appropriate Picture for tiling the text colour.
1870 * Call and use result within the xrender_cs
1872 static Picture get_tile_pict(const WineXRenderFormat *wxr_format, int text_pixel)
1879 } tiles[WXR_NB_FORMATS], *tile;
1882 tile = &tiles[wxr_format->format];
1886 XRenderPictureAttributes pa;
1889 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1891 pa.repeat = RepeatNormal;
1892 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1893 wine_tsx11_unlock();
1895 /* init current_color to something different from text_pixel */
1896 tile->current_color = ~text_pixel;
1898 if(wxr_format->format == WXR_FORMAT_MONO)
1900 /* for a 1bpp bitmap we always need a 1 in the tile */
1901 col.red = col.green = col.blue = 0;
1904 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1905 wine_tsx11_unlock();
1909 if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1911 get_xrender_color(wxr_format, text_pixel, &col);
1913 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1914 wine_tsx11_unlock();
1915 tile->current_color = text_pixel;
1920 /*************************************************************
1923 * Returns an appropriate Picture for masking with the specified alpha.
1924 * Call and use result within the xrender_cs
1926 static Picture get_mask_pict( int alpha )
1928 static Pixmap pixmap;
1929 static Picture pict;
1930 static int current_alpha;
1932 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1936 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
1937 XRenderPictureAttributes pa;
1940 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1941 pa.repeat = RepeatNormal;
1942 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format, CPRepeat, &pa );
1943 wine_tsx11_unlock();
1947 if (alpha != current_alpha)
1950 col.red = col.green = col.blue = 0;
1951 col.alpha = current_alpha = alpha;
1953 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1954 wine_tsx11_unlock();
1959 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1964 /********************************************************************
1965 * is_dib_with_colortable
1967 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1969 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1973 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1974 dib.dsBmih.biBitCount <= 8 )
1980 /***********************************************************************
1981 * xrenderdrv_ExtTextOut
1983 BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1984 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1986 struct xrender_physdev *physdev = get_xrender_dev( dev );
1988 gsCacheEntry *entry;
1989 gsCacheEntryFormat *formatEntry;
1991 int textPixel, backgroundPixel;
1992 RGNDATA *saved_region = NULL;
1993 BOOL disable_antialias = FALSE;
1994 AA_Type aa_type = AA_None;
1996 Picture tile_pict = 0;
1998 if (!physdev->x11dev->has_gdi_font)
2000 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
2001 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
2004 if(is_dib_with_colortable( physdev->x11dev ))
2006 TRACE("Disabling antialiasing\n");
2007 disable_antialias = TRUE;
2010 xgcval.function = GXcopy;
2011 xgcval.background = physdev->x11dev->backgroundPixel;
2012 xgcval.fill_style = FillSolid;
2014 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
2015 wine_tsx11_unlock();
2017 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2019 if(physdev->x11dev->depth == 1) {
2020 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
2022 backgroundPixel = 1;
2025 backgroundPixel = 0;
2028 textPixel = physdev->x11dev->textPixel;
2029 backgroundPixel = physdev->x11dev->backgroundPixel;
2032 if(flags & ETO_OPAQUE)
2035 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
2036 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
2037 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
2038 lprect->right - lprect->left, lprect->bottom - lprect->top );
2039 wine_tsx11_unlock();
2048 EnterCriticalSection(&xrender_cs);
2050 entry = glyphsetCache + physdev->info.cache_index;
2051 if( disable_antialias == FALSE )
2052 aa_type = entry->aa_default;
2053 formatEntry = entry->format[aa_type];
2055 for(idx = 0; idx < count; idx++) {
2056 if( !formatEntry ) {
2057 UploadGlyph(physdev, wstr[idx], aa_type);
2058 /* re-evaluate antialias since aa_default may have changed */
2059 if( disable_antialias == FALSE )
2060 aa_type = entry->aa_default;
2061 formatEntry = entry->format[aa_type];
2062 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
2063 UploadGlyph(physdev, wstr[idx], aa_type);
2068 WARN("could not upload requested glyphs\n");
2069 LeaveCriticalSection(&xrender_cs);
2073 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
2074 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2076 if(X11DRV_XRender_Installed)
2078 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
2079 POINT offset = {0, 0};
2080 POINT desired, current;
2081 int render_op = PictOpOver;
2082 Picture pict = get_xrender_picture(physdev->x11dev);
2084 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
2085 So we pass zeros to the function and move to our starting position using the first
2086 element of the elts array. */
2088 desired.x = physdev->x11dev->dc_rect.left + x;
2089 desired.y = physdev->x11dev->dc_rect.top + y;
2090 current.x = current.y = 0;
2092 tile_pict = get_tile_pict(physdev->info.format, physdev->x11dev->textPixel);
2094 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
2096 if((physdev->info.format->format == WXR_FORMAT_MONO) && (textPixel == 0))
2097 render_op = PictOpOutReverse; /* This gives us 'black' text */
2099 for(idx = 0; idx < count; idx++)
2101 elts[idx].glyphset = formatEntry->glyphset;
2102 elts[idx].chars = wstr + idx;
2103 elts[idx].nchars = 1;
2104 elts[idx].xOff = desired.x - current.x;
2105 elts[idx].yOff = desired.y - current.y;
2107 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
2108 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
2112 desired.x += formatEntry->gis[wstr[idx]].xOff;
2113 desired.y += formatEntry->gis[wstr[idx]].yOff;
2119 offset.x += lpDx[idx * 2];
2120 offset.y += lpDx[idx * 2 + 1];
2123 offset.x += lpDx[idx];
2124 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
2125 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
2129 if (flags & ETO_CLIPPED)
2131 HRGN clip_region = CreateRectRgnIndirect( lprect );
2132 saved_region = add_xrender_clipping_region( physdev, clip_region );
2133 DeleteObject( clip_region );
2137 /* Make sure we don't have any transforms set from a previous call */
2138 set_xrender_transformation(pict, 1, 1, 0, 0);
2139 pXRenderCompositeText16(gdi_display, render_op,
2142 formatEntry->font_format->pict_format,
2143 0, 0, 0, 0, elts, count);
2144 wine_tsx11_unlock();
2145 HeapFree(GetProcessHeap(), 0, elts);
2146 restore_xrender_clipping_region( physdev, saved_region );
2148 POINT offset = {0, 0};
2150 if (flags & ETO_CLIPPED)
2152 HRGN clip_region = CreateRectRgnIndirect( lprect );
2153 saved_region = add_extra_clipping_region( physdev->x11dev, clip_region );
2154 DeleteObject( clip_region );
2158 XSetForeground( gdi_display, physdev->x11dev->gc, textPixel );
2160 if(aa_type == AA_None || physdev->x11dev->depth == 1)
2162 void (* sharp_glyph_fn)(struct xrender_physdev *, INT, INT, void *, XGlyphInfo *);
2164 if(aa_type == AA_None)
2165 sharp_glyph_fn = SharpGlyphMono;
2167 sharp_glyph_fn = SharpGlyphGray;
2169 for(idx = 0; idx < count; idx++) {
2170 sharp_glyph_fn(physdev,
2171 physdev->x11dev->dc_rect.left + x + offset.x,
2172 physdev->x11dev->dc_rect.top + y + offset.y,
2173 formatEntry->bitmaps[wstr[idx]],
2174 &formatEntry->gis[wstr[idx]]);
2179 offset.x += lpDx[idx * 2];
2180 offset.y += lpDx[idx * 2 + 1];
2183 offset.x += lpDx[idx];
2187 offset.x += formatEntry->gis[wstr[idx]].xOff;
2188 offset.y += formatEntry->gis[wstr[idx]].yOff;
2193 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2194 RECT extents = {0, 0, 0, 0};
2196 int w = physdev->x11dev->drawable_rect.right - physdev->x11dev->drawable_rect.left;
2197 int h = physdev->x11dev->drawable_rect.bottom - physdev->x11dev->drawable_rect.top;
2199 TRACE("drawable %dx%d\n", w, h);
2201 for(idx = 0; idx < count; idx++) {
2202 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2203 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2204 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2205 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2206 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2207 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2208 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2209 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2215 cur.x += lpDx[idx * 2];
2216 cur.y += lpDx[idx * 2 + 1];
2223 cur.x += formatEntry->gis[wstr[idx]].xOff;
2224 cur.y += formatEntry->gis[wstr[idx]].yOff;
2227 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2228 extents.right, extents.bottom, physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2230 if(physdev->x11dev->dc_rect.left + x + extents.left >= 0) {
2231 image_x = physdev->x11dev->dc_rect.left + x + extents.left;
2235 image_off_x = physdev->x11dev->dc_rect.left + x + extents.left;
2237 if(physdev->x11dev->dc_rect.top + y + extents.top >= 0) {
2238 image_y = physdev->x11dev->dc_rect.top + y + extents.top;
2242 image_off_y = physdev->x11dev->dc_rect.top + y + extents.top;
2244 if(physdev->x11dev->dc_rect.left + x + extents.right < w)
2245 image_w = physdev->x11dev->dc_rect.left + x + extents.right - image_x;
2247 image_w = w - image_x;
2248 if(physdev->x11dev->dc_rect.top + y + extents.bottom < h)
2249 image_h = physdev->x11dev->dc_rect.top + y + extents.bottom - image_y;
2251 image_h = h - image_y;
2253 if(image_w <= 0 || image_h <= 0) goto no_image;
2255 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2256 image = XGetImage(gdi_display, physdev->x11dev->drawable,
2257 image_x, image_y, image_w, image_h,
2258 AllPlanes, ZPixmap);
2259 X11DRV_check_error();
2261 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2262 gdi_display, (int)physdev->x11dev->drawable, image_x, image_y,
2263 image_w, image_h, AllPlanes, ZPixmap,
2264 physdev->x11dev->depth, image);
2266 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2267 physdev->x11dev->depth);
2271 gcv.graphics_exposures = False;
2272 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2273 XCopyArea(gdi_display, physdev->x11dev->drawable, xpm, gc, image_x, image_y,
2274 image_w, image_h, 0, 0);
2275 XFreeGC(gdi_display, gc);
2276 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2277 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2279 X11DRV_check_error();
2280 XFreePixmap(gdi_display, xpm);
2282 if(!image) goto no_image;
2284 image->red_mask = visual->red_mask;
2285 image->green_mask = visual->green_mask;
2286 image->blue_mask = visual->blue_mask;
2288 for(idx = 0; idx < count; idx++) {
2289 SmoothGlyphGray(image,
2290 offset.x + image_off_x - extents.left,
2291 offset.y + image_off_y - extents.top,
2292 formatEntry->bitmaps[wstr[idx]],
2293 &formatEntry->gis[wstr[idx]],
2294 physdev->x11dev->textPixel);
2299 offset.x += lpDx[idx * 2];
2300 offset.y += lpDx[idx * 2 + 1];
2303 offset.x += lpDx[idx];
2307 offset.x += formatEntry->gis[wstr[idx]].xOff;
2308 offset.y += formatEntry->gis[wstr[idx]].yOff;
2311 XPutImage(gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc, image, 0, 0,
2312 image_x, image_y, image_w, image_h);
2313 XDestroyImage(image);
2316 wine_tsx11_unlock();
2317 restore_clipping_region( physdev->x11dev, saved_region );
2319 LeaveCriticalSection(&xrender_cs);
2323 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2327 /* Helper function for (stretched) blitting using xrender */
2328 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2329 int x_src, int y_src, int x_dst, int y_dst,
2330 double xscale, double yscale, int width, int height )
2332 int x_offset, y_offset;
2334 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2335 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2336 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2337 if(xscale != 1.0 || yscale != 1.0)
2339 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2340 * in the wrong quadrant of the x-y plane.
2342 x_offset = (xscale < 0) ? -width : 0;
2343 y_offset = (yscale < 0) ? -height : 0;
2344 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2350 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2352 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2353 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2356 /* Helper function for (stretched) mono->color blitting using xrender */
2357 static void xrender_mono_blit( Picture src_pict, Picture mask_pict, Picture dst_pict,
2358 int x_src, int y_src, double xscale, double yscale, int width, int height )
2360 int x_offset, y_offset;
2362 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2363 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
2364 * tile data. We need PictOpOver for correct rendering.
2365 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2368 if (xscale != 1.0 || yscale != 1.0)
2370 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2371 * in the wrong quadrant of the x-y plane.
2373 x_offset = (xscale < 0) ? -width : 0;
2374 y_offset = (yscale < 0) ? -height : 0;
2375 set_xrender_transformation(mask_pict, xscale, yscale, x_src, y_src);
2381 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
2383 pXRenderComposite(gdi_display, PictOpOver, src_pict, mask_pict, dst_pict,
2384 0, 0, x_offset, y_offset, 0, 0, width, height);
2387 /***********************************************************************
2388 * xrenderdrv_AlphaBlend
2390 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2391 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2393 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2394 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2395 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2396 double xscale, yscale;
2399 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2401 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2402 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2405 if (physdev_src != physdev_dst) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2406 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2408 dst_pict = get_xrender_picture( physdev_dst->x11dev );
2410 use_repeat = use_source_repeat( physdev_src->x11dev );
2413 xscale = src->width / (double)dst->width;
2414 yscale = src->height / (double)dst->height;
2416 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2418 if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->info.format)
2420 /* we need a source picture with no alpha */
2421 WXRFormat format = get_format_without_alpha( physdev_src->info.format->format );
2422 if (format != physdev_src->info.format->format)
2424 XRenderPictureAttributes pa;
2425 const WineXRenderFormat *fmt = get_xrender_format( format );
2428 pa.subwindow_mode = IncludeInferiors;
2429 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2430 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable, fmt->pict_format,
2431 CPSubwindowMode|CPRepeat, &pa );
2432 wine_tsx11_unlock();
2433 src_pict = tmp_pict;
2437 if (!src_pict) src_pict = get_xrender_picture_source( physdev_src->x11dev, use_repeat );
2439 EnterCriticalSection( &xrender_cs );
2440 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2443 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2444 physdev_src->x11dev->dc_rect.left + src->visrect.left,
2445 physdev_src->x11dev->dc_rect.top + src->visrect.top,
2446 physdev_dst->x11dev->dc_rect.left + dst->visrect.left,
2447 physdev_dst->x11dev->dc_rect.top + dst->visrect.top,
2449 dst->visrect.right - dst->visrect.left, dst->visrect.bottom - dst->visrect.top );
2450 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2451 wine_tsx11_unlock();
2453 LeaveCriticalSection( &xrender_cs );
2454 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2455 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2460 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2462 /* 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 */
2463 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2464 const WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2465 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2468 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2470 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2471 if( (physBitmap->pixmap_depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->pixmap_depth) ||
2472 (src_format->format == dst_format->format) )
2474 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2475 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2477 else /* We need depth conversion */
2479 Picture src_pict, dst_pict;
2480 XRenderPictureAttributes pa;
2481 pa.subwindow_mode = IncludeInferiors;
2482 pa.repeat = RepeatNone;
2484 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2485 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2487 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2488 pXRenderFreePicture(gdi_display, src_pict);
2489 pXRenderFreePicture(gdi_display, dst_pict);
2491 wine_tsx11_unlock();
2494 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2495 Pixmap pixmap, GC gc,
2496 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2498 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2499 int width = dst->visrect.right - dst->visrect.left;
2500 int height = dst->visrect.bottom - dst->visrect.top;
2501 int x_src = physDevSrc->dc_rect.left + src->visrect.left;
2502 int y_src = physDevSrc->dc_rect.top + src->visrect.top;
2503 struct xrender_info *src_info = get_xrender_info(physDevSrc);
2504 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDevDst->depth, physDevDst->color_shifts);
2505 Picture src_pict=0, dst_pict=0, mask_pict=0;
2507 double xscale, yscale;
2509 XRenderPictureAttributes pa;
2510 pa.subwindow_mode = IncludeInferiors;
2511 pa.repeat = RepeatNone;
2513 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2514 physDevSrc->depth, src->width, src->height, x_src, y_src);
2515 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst->depth, dst->width, dst->height);
2517 if(!X11DRV_XRender_Installed)
2519 TRACE("Not using XRender since it is not available or disabled\n");
2523 /* XRender can't handle palettes, so abort */
2524 if(X11DRV_PALETTE_XPixelToPalette)
2527 /* XRender is of no use in this case */
2528 if((physDevDst->depth == 1) && (physDevSrc->depth > 1))
2531 /* Just use traditional X copy when the formats match and we don't need stretching */
2532 if((src_info->format->format == dst_format->format) && !stretch)
2534 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2536 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
2537 wine_tsx11_unlock();
2541 use_repeat = use_source_repeat( physDevSrc );
2544 xscale = src->width / (double)dst->width;
2545 yscale = src->height / (double)dst->height;
2547 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2550 if(physDevSrc->depth == 1 && physDevDst->depth > 1)
2553 get_xrender_color(dst_format, physDevDst->textPixel, &col);
2555 /* We use the source drawable as a mask */
2556 mask_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2558 /* Use backgroundPixel as the foreground color */
2559 EnterCriticalSection( &xrender_cs );
2560 src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
2562 /* Create a destination picture and fill it with textPixel color as the background color */
2564 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2565 pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height);
2567 xrender_mono_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
2569 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2570 wine_tsx11_unlock();
2571 LeaveCriticalSection( &xrender_cs );
2573 else /* color -> color (can be at different depths) or mono -> mono */
2575 if (physDevDst->depth == 32 && physDevSrc->depth < 32) mask_pict = get_no_alpha_mask();
2576 src_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2579 dst_pict = pXRenderCreatePicture(gdi_display,
2580 pixmap, dst_format->pict_format,
2581 CPSubwindowMode|CPRepeat, &pa);
2583 xrender_blit(PictOpSrc, src_pict, mask_pict, dst_pict,
2584 x_src, y_src, 0, 0, xscale, yscale, width, height);
2586 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2587 wine_tsx11_unlock();
2592 static const struct gdi_dc_funcs xrender_funcs =
2594 NULL, /* pAbortDoc */
2595 NULL, /* pAbortPath */
2596 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2597 NULL, /* pAngleArc */
2600 NULL, /* pBeginPath */
2601 NULL, /* pChoosePixelFormat */
2603 NULL, /* pCloseFigure */
2604 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2605 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2606 xrenderdrv_CreateDC, /* pCreateDC */
2607 NULL, /* pCreateDIBSection */
2608 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
2609 xrenderdrv_DeleteDC, /* pDeleteDC */
2610 NULL, /* pDeleteObject */
2611 NULL, /* pDescribePixelFormat */
2612 NULL, /* pDeviceCapabilities */
2613 NULL, /* pEllipse */
2615 NULL, /* pEndPage */
2616 NULL, /* pEndPath */
2617 NULL, /* pEnumDeviceFonts */
2618 NULL, /* pEnumICMProfiles */
2619 NULL, /* pExcludeClipRect */
2620 NULL, /* pExtDeviceMode */
2621 xrenderdrv_ExtEscape, /* pExtEscape */
2622 NULL, /* pExtFloodFill */
2623 NULL, /* pExtSelectClipRgn */
2624 xrenderdrv_ExtTextOut, /* pExtTextOut */
2625 NULL, /* pFillPath */
2626 NULL, /* pFillRgn */
2627 NULL, /* pFlattenPath */
2628 NULL, /* pFrameRgn */
2629 NULL, /* pGdiComment */
2630 NULL, /* pGetCharWidth */
2631 NULL, /* pGetDeviceCaps */
2632 NULL, /* pGetDeviceGammaRamp */
2633 NULL, /* pGetICMProfile */
2634 xrenderdrv_GetImage, /* pGetImage */
2635 NULL, /* pGetNearestColor */
2636 NULL, /* pGetPixel */
2637 NULL, /* pGetPixelFormat */
2638 NULL, /* pGetSystemPaletteEntries */
2639 NULL, /* pGetTextExtentExPoint */
2640 NULL, /* pGetTextMetrics */
2641 NULL, /* pIntersectClipRect */
2642 NULL, /* pInvertRgn */
2644 NULL, /* pModifyWorldTransform */
2646 NULL, /* pOffsetClipRgn */
2647 NULL, /* pOffsetViewportOrg */
2648 NULL, /* pOffsetWindowOrg */
2649 NULL, /* pPaintRgn */
2652 NULL, /* pPolyBezier */
2653 NULL, /* pPolyBezierTo */
2654 NULL, /* pPolyDraw */
2655 NULL, /* pPolyPolygon */
2656 NULL, /* pPolyPolyline */
2657 NULL, /* pPolygon */
2658 NULL, /* pPolyline */
2659 NULL, /* pPolylineTo */
2660 xrenderdrv_PutImage, /* pPutImage */
2661 NULL, /* pRealizeDefaultPalette */
2662 NULL, /* pRealizePalette */
2663 NULL, /* pRectangle */
2664 NULL, /* pResetDC */
2665 NULL, /* pRestoreDC */
2666 NULL, /* pRoundRect */
2668 NULL, /* pScaleViewportExt */
2669 NULL, /* pScaleWindowExt */
2670 xrenderdrv_SelectBitmap, /* pSelectBitmap */
2671 NULL, /* pSelectBrush */
2672 NULL, /* pSelectClipPath */
2673 xrenderdrv_SelectFont, /* pSelectFont */
2674 NULL, /* pSelectPalette */
2675 NULL, /* pSelectPen */
2676 NULL, /* pSetArcDirection */
2677 NULL, /* pSetBkColor */
2678 NULL, /* pSetBkMode */
2679 NULL, /* pSetDCBrushColor */
2680 NULL, /* pSetDCPenColor */
2681 NULL, /* pSetDIBColorTable */
2682 NULL, /* pSetDIBitsToDevice */
2683 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2684 NULL, /* pSetDeviceGammaRamp */
2685 NULL, /* pSetLayout */
2686 NULL, /* pSetMapMode */
2687 NULL, /* pSetMapperFlags */
2688 NULL, /* pSetPixel */
2689 NULL, /* pSetPixelFormat */
2690 NULL, /* pSetPolyFillMode */
2691 NULL, /* pSetROP2 */
2692 NULL, /* pSetRelAbs */
2693 NULL, /* pSetStretchBltMode */
2694 NULL, /* pSetTextAlign */
2695 NULL, /* pSetTextCharacterExtra */
2696 NULL, /* pSetTextColor */
2697 NULL, /* pSetTextJustification */
2698 NULL, /* pSetViewportExt */
2699 NULL, /* pSetViewportOrg */
2700 NULL, /* pSetWindowExt */
2701 NULL, /* pSetWindowOrg */
2702 NULL, /* pSetWorldTransform */
2703 NULL, /* pStartDoc */
2704 NULL, /* pStartPage */
2705 NULL, /* pStretchBlt */
2706 NULL, /* pStretchDIBits */
2707 NULL, /* pStrokeAndFillPath */
2708 NULL, /* pStrokePath */
2709 NULL, /* pSwapBuffers */
2710 NULL, /* pUnrealizePalette */
2711 NULL, /* pWidenPath */
2712 /* OpenGL not supported */
2715 #else /* SONAME_LIBXRENDER */
2717 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2719 TRACE("XRender support not compiled in.\n");
2723 void X11DRV_XRender_Finalize(void)
2727 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2730 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
2732 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2733 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2734 wine_tsx11_unlock();
2737 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2742 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2743 Pixmap pixmap, GC gc,
2744 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2748 #endif /* SONAME_LIBXRENDER */