2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
8 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
36 #include "wine/library.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
40 int using_client_side_fonts = FALSE;
42 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
44 #ifdef SONAME_LIBXRENDER
46 static BOOL X11DRV_XRender_Installed = FALSE;
49 #include <X11/extensions/Xrender.h>
51 #ifndef RepeatNone /* added in 0.10 */
53 #define RepeatNormal 1
55 #define RepeatReflect 3
58 typedef enum wine_xrformat
75 typedef struct wine_xrender_format_template
80 unsigned int alphaMask;
84 unsigned int greenMask;
86 unsigned int blueMask;
87 } WineXRenderFormatTemplate;
89 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
91 /* Format depth alpha mask red mask green mask blue mask*/
92 {WXR_FORMAT_MONO, 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
93 {WXR_FORMAT_GRAY, 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
94 {WXR_FORMAT_X1R5G5B5, 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
95 {WXR_FORMAT_X1B5G5R5, 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
96 {WXR_FORMAT_R5G6B5, 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
97 {WXR_FORMAT_B5G6R5, 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
98 {WXR_FORMAT_R8G8B8, 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
99 {WXR_FORMAT_B8G8R8, 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
100 {WXR_FORMAT_A8R8G8B8, 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
101 {WXR_FORMAT_B8G8R8A8, 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
102 {WXR_FORMAT_X8R8G8B8, 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
103 {WXR_FORMAT_B8G8R8X8, 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
106 typedef struct wine_xrender_format
109 XRenderPictFormat *pict_format;
112 static WineXRenderFormat wxr_formats[WXR_NB_FORMATS];
113 static int WineXRenderFormatsListSize = 0;
114 static WineXRenderFormat *default_format = NULL;
120 SIZE devsize; /* size in device coords */
124 #define INITIAL_REALIZED_BUF_SIZE 128
126 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
131 const WineXRenderFormat *font_format;
136 } gsCacheEntryFormat;
142 gsCacheEntryFormat * format[AA_MAXVALUE];
152 const WineXRenderFormat *format;
155 static gsCacheEntry *glyphsetCache = NULL;
156 static DWORD glyphsetCacheSize = 0;
157 static INT lastfree = -1;
160 #define INIT_CACHE_SIZE 10
162 static int antialias = 1;
164 static void *xrender_handle;
166 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
167 MAKE_FUNCPTR(XRenderAddGlyphs)
168 MAKE_FUNCPTR(XRenderComposite)
169 MAKE_FUNCPTR(XRenderCompositeString8)
170 MAKE_FUNCPTR(XRenderCompositeString16)
171 MAKE_FUNCPTR(XRenderCompositeString32)
172 MAKE_FUNCPTR(XRenderCompositeText16)
173 MAKE_FUNCPTR(XRenderCreateGlyphSet)
174 MAKE_FUNCPTR(XRenderCreatePicture)
175 MAKE_FUNCPTR(XRenderFillRectangle)
176 MAKE_FUNCPTR(XRenderFindFormat)
177 MAKE_FUNCPTR(XRenderFindVisualFormat)
178 MAKE_FUNCPTR(XRenderFreeGlyphSet)
179 MAKE_FUNCPTR(XRenderFreePicture)
180 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
181 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
182 MAKE_FUNCPTR(XRenderSetPictureTransform)
184 MAKE_FUNCPTR(XRenderQueryExtension)
187 static CRITICAL_SECTION xrender_cs;
188 static CRITICAL_SECTION_DEBUG critsect_debug =
191 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
192 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
194 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
196 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
197 ( ( (ULONG)_x4 << 24 ) | \
198 ( (ULONG)_x3 << 16 ) | \
199 ( (ULONG)_x2 << 8 ) | \
202 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
204 #define GASP_GRIDFIT 0x01
205 #define GASP_DOGRAY 0x02
207 #ifdef WORDS_BIGENDIAN
208 #define get_be_word(x) (x)
209 #define NATIVE_BYTE_ORDER MSBFirst
211 #define get_be_word(x) RtlUshortByteSwap(x)
212 #define NATIVE_BYTE_ORDER LSBFirst
215 static WXRFormat get_format_without_alpha( WXRFormat format )
219 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
220 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
221 default: return format;
225 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
228 templ->type = PictTypeDirect;
229 templ->depth = fmt->depth;
230 templ->direct.alpha = fmt->alpha;
231 templ->direct.alphaMask = fmt->alphaMask;
232 templ->direct.red = fmt->red;
233 templ->direct.redMask = fmt->redMask;
234 templ->direct.green = fmt->green;
235 templ->direct.greenMask = fmt->greenMask;
236 templ->direct.blue = fmt->blue;
237 templ->direct.blueMask = fmt->blueMask;
240 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
245 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
247 if(fmt->depth != screen_depth)
249 if( (fmt->redMask << fmt->red) != visual->red_mask)
251 if( (fmt->greenMask << fmt->green) != visual->green_mask)
253 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
256 /* We never select a default ARGB visual */
263 static int load_xrender_formats(void)
266 for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
268 XRenderPictFormat templ, *pict_format;
270 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
273 pict_format = pXRenderFindVisualFormat(gdi_display, visual);
276 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
277 if (visual->class == DirectColor)
280 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
281 screen_depth, TrueColor, &info ))
283 pict_format = pXRenderFindVisualFormat(gdi_display, info.visual);
284 if (pict_format) visual = info.visual;
292 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
293 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
294 default_format = &wxr_formats[WineXRenderFormatsListSize];
295 WineXRenderFormatsListSize++;
296 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
301 unsigned long mask = 0;
302 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
305 pict_format = pXRenderFindFormat(gdi_display, mask, &templ, 0);
310 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
311 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
312 WineXRenderFormatsListSize++;
313 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
317 return WineXRenderFormatsListSize;
320 /***********************************************************************
321 * X11DRV_XRender_Init
323 * Let's see if our XServer has the extension available
326 void X11DRV_XRender_Init(void)
330 if (client_side_with_render &&
331 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
332 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
333 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
336 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
337 LOAD_FUNCPTR(XRenderAddGlyphs)
338 LOAD_FUNCPTR(XRenderComposite)
339 LOAD_FUNCPTR(XRenderCompositeString8)
340 LOAD_FUNCPTR(XRenderCompositeString16)
341 LOAD_FUNCPTR(XRenderCompositeString32)
342 LOAD_FUNCPTR(XRenderCompositeText16)
343 LOAD_FUNCPTR(XRenderCreateGlyphSet)
344 LOAD_FUNCPTR(XRenderCreatePicture)
345 LOAD_FUNCPTR(XRenderFillRectangle)
346 LOAD_FUNCPTR(XRenderFindFormat)
347 LOAD_FUNCPTR(XRenderFindVisualFormat)
348 LOAD_FUNCPTR(XRenderFreeGlyphSet)
349 LOAD_FUNCPTR(XRenderFreePicture)
350 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
351 LOAD_FUNCPTR(XRenderQueryExtension)
353 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
354 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
355 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
356 #undef LOAD_OPTIONAL_FUNCPTR
360 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
362 if(X11DRV_XRender_Installed) {
363 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
364 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
368 "Wine has detected that you probably have a buggy version\n"
369 "of libXrender.so . Because of this client side font rendering\n"
370 "will be disabled. Please upgrade this library.\n");
371 X11DRV_XRender_Installed = FALSE;
375 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
376 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
377 X11DRV_XRender_Installed = FALSE;
383 if(X11DRV_XRender_Installed || client_side_with_core)
385 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
386 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
388 glyphsetCacheSize = INIT_CACHE_SIZE;
390 for(i = 0; i < INIT_CACHE_SIZE; i++) {
391 glyphsetCache[i].next = i + 1;
392 glyphsetCache[i].count = -1;
394 glyphsetCache[i-1].next = -1;
395 using_client_side_fonts = 1;
397 if(!X11DRV_XRender_Installed) {
398 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
399 if(screen_depth <= 8 || !client_side_antialias_with_core)
402 if(screen_depth <= 8 || !client_side_antialias_with_render)
406 else TRACE("Using X11 core fonts\n");
409 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
410 static void get_xrender_color(const WineXRenderFormat *wxr_format, int src_color, XRenderColor *dst_color)
412 XRenderPictFormat *pf = wxr_format->pict_format;
414 if(pf->direct.redMask)
415 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
419 if(pf->direct.greenMask)
420 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
422 dst_color->green = 0;
424 if(pf->direct.blueMask)
425 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
429 dst_color->alpha = 0xffff;
432 static const WineXRenderFormat *get_xrender_format(WXRFormat format)
435 for(i=0; i<WineXRenderFormatsListSize; i++)
437 if(wxr_formats[i].format == format)
439 TRACE("Returning wxr_format=%#x\n", format);
440 return &wxr_formats[i];
446 static const WineXRenderFormat *get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
448 int redMask, greenMask, blueMask;
452 return get_xrender_format(WXR_FORMAT_MONO);
454 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
456 return default_format;
458 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
459 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
460 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
462 /* Try to locate a format which matches the specification of the dibsection. */
463 for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
465 if( depth == wxr_formats_template[i].depth &&
466 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
467 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
468 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
471 /* When we reach this stage the format was found in our template table but this doesn't mean that
472 * the Xserver also supports this format (e.g. its depth might be too low). The call below verifies that.
474 return get_xrender_format(wxr_formats_template[i].wxr_format);
478 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
479 ERR("No XRender format found!\n");
483 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
484 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
486 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
487 XTransform xform = {{
488 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
489 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
490 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
493 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
497 /* check if we can use repeating instead of scaling for the specified source DC */
498 static BOOL use_source_repeat( X11DRV_PDEVICE *physDev )
500 return (physDev->bitmap &&
501 physDev->drawable_rect.right - physDev->drawable_rect.left == 1 &&
502 physDev->drawable_rect.bottom - physDev->drawable_rect.top == 1);
505 static struct xrender_info *get_xrender_info(X11DRV_PDEVICE *physDev)
507 if(!physDev->xrender)
509 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physDev->xrender));
511 if(!physDev->xrender)
513 ERR("Unable to allocate XRENDERINFO!\n");
516 physDev->xrender->cache_index = -1;
518 if (!physDev->xrender->format)
519 physDev->xrender->format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
521 return physDev->xrender;
524 static Picture get_xrender_picture(X11DRV_PDEVICE *physDev)
526 struct xrender_info *info = get_xrender_info(physDev);
529 if (!info->pict && info->format)
531 XRenderPictureAttributes pa;
532 RGNDATA *clip = X11DRV_GetRegionData( physDev->region, 0 );
535 pa.subwindow_mode = IncludeInferiors;
536 info->pict = pXRenderCreatePicture(gdi_display, physDev->drawable, info->format->pict_format,
537 CPSubwindowMode, &pa);
538 if (info->pict && clip)
539 pXRenderSetPictureClipRectangles( gdi_display, info->pict,
540 physDev->dc_rect.left, physDev->dc_rect.top,
541 (XRectangle *)clip->Buffer, clip->rdh.nCount );
543 TRACE("Allocing pict=%lx dc=%p drawable=%08lx\n", info->pict, physDev->hdc, physDev->drawable);
544 HeapFree( GetProcessHeap(), 0, clip );
550 static Picture get_xrender_picture_source(X11DRV_PDEVICE *physDev, BOOL repeat)
552 struct xrender_info *info = get_xrender_info(physDev);
555 if (!info->pict_src && info->format)
557 XRenderPictureAttributes pa;
560 pa.subwindow_mode = IncludeInferiors;
561 pa.repeat = repeat ? RepeatNormal : RepeatNone;
562 info->pict_src = pXRenderCreatePicture(gdi_display, physDev->drawable, info->format->pict_format,
563 CPSubwindowMode|CPRepeat, &pa);
566 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
567 info->pict_src, physDev->hdc, physDev->drawable, pa.repeat);
570 return info->pict_src;
573 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
575 if(p1->hash != p2->hash) return TRUE;
576 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
577 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
578 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
579 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
583 static void walk_cache(void)
587 EnterCriticalSection(&xrender_cs);
588 for(i=mru; i >= 0; i = glyphsetCache[i].next)
589 TRACE("item %d\n", i);
590 LeaveCriticalSection(&xrender_cs);
594 static int LookupEntry(LFANDSIZE *plfsz)
598 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
600 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
605 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
606 glyphsetCache[i].count++;
608 glyphsetCache[prev_i].next = glyphsetCache[i].next;
609 glyphsetCache[i].next = mru;
612 TRACE("found font in cache %d\n", i);
617 TRACE("font not in cache\n");
621 static void FreeEntry(int entry)
625 for(format = 0; format < AA_MAXVALUE; format++) {
626 gsCacheEntryFormat * formatEntry;
628 if( !glyphsetCache[entry].format[format] )
631 formatEntry = glyphsetCache[entry].format[format];
633 if(formatEntry->glyphset) {
635 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
637 formatEntry->glyphset = 0;
639 if(formatEntry->nrealized) {
640 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
641 formatEntry->realized = NULL;
642 if(formatEntry->bitmaps) {
643 for(i = 0; i < formatEntry->nrealized; i++)
644 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
645 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
646 formatEntry->bitmaps = NULL;
648 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
649 formatEntry->gis = NULL;
650 formatEntry->nrealized = 0;
653 HeapFree(GetProcessHeap(), 0, formatEntry);
654 glyphsetCache[entry].format[format] = NULL;
658 static int AllocEntry(void)
660 int best = -1, prev_best = -1, i, prev_i = -1;
663 assert(glyphsetCache[lastfree].count == -1);
664 glyphsetCache[lastfree].count = 1;
666 lastfree = glyphsetCache[lastfree].next;
668 glyphsetCache[best].next = mru;
671 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
675 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
676 if(glyphsetCache[i].count == 0) {
684 TRACE("freeing unused glyphset at cache %d\n", best);
686 glyphsetCache[best].count = 1;
688 glyphsetCache[prev_best].next = glyphsetCache[best].next;
689 glyphsetCache[best].next = mru;
697 TRACE("Growing cache\n");
700 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
702 (glyphsetCacheSize + INIT_CACHE_SIZE)
703 * sizeof(*glyphsetCache));
705 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
706 (glyphsetCacheSize + INIT_CACHE_SIZE)
707 * sizeof(*glyphsetCache));
709 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
711 glyphsetCache[i].next = i + 1;
712 glyphsetCache[i].count = -1;
714 glyphsetCache[i-1].next = -1;
715 glyphsetCacheSize += INIT_CACHE_SIZE;
717 lastfree = glyphsetCache[best].next;
718 glyphsetCache[best].count = 1;
719 glyphsetCache[best].next = mru;
721 TRACE("new free cache slot at %d\n", mru);
725 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
735 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
736 if(size == GDI_ERROR)
739 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
740 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
742 GetTextMetricsW(physDev->hdc, &tm);
743 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
746 num_recs = get_be_word(*gasp);
750 *flags = get_be_word(*(gasp + 1));
751 if(ppem <= get_be_word(*gasp))
755 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
757 HeapFree(GetProcessHeap(), 0, buffer);
761 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
765 UINT font_smoothing_type, font_smoothing_orientation;
767 if (X11DRV_XRender_Installed && subpixel &&
768 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
769 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
771 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
772 &font_smoothing_orientation, 0) &&
773 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
780 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
781 But, Wine's subpixel rendering can support the portrait mode.
784 else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
792 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
797 static int hinter = -1;
798 static int subpixel = -1;
801 if((ret = LookupEntry(plfsz)) != -1) return ret;
804 entry = glyphsetCache + ret;
805 entry->lfsz = *plfsz;
806 for( format = 0; format < AA_MAXVALUE; format++ ) {
807 assert( !entry->format[format] );
810 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
812 if(hinter == -1 || subpixel == -1)
814 RASTERIZER_STATUS status;
815 GetRasterizerCaps(&status, sizeof(status));
816 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
817 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
820 switch (plfsz->lf.lfQuality)
822 case ANTIALIASED_QUALITY:
823 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
825 case CLEARTYPE_QUALITY:
826 case CLEARTYPE_NATURAL_QUALITY:
827 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
829 case DEFAULT_QUALITY:
833 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
836 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
839 entry->aa_default = AA_None;
844 entry->aa_default = AA_None;
849 static void dec_ref_cache(int index)
852 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
853 assert(glyphsetCache[index].count > 0);
854 glyphsetCache[index].count--;
857 static void lfsz_calc_hash(LFANDSIZE *plfsz)
859 DWORD hash = 0, *ptr, two_chars;
863 hash ^= plfsz->devsize.cx;
864 hash ^= plfsz->devsize.cy;
865 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
867 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
869 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
871 pwc = (WCHAR *)&two_chars;
873 *pwc = toupperW(*pwc);
875 *pwc = toupperW(*pwc);
883 /***********************************************************************
884 * X11DRV_XRender_Finalize
886 void X11DRV_XRender_Finalize(void)
890 EnterCriticalSection(&xrender_cs);
891 for(i = mru; i >= 0; i = glyphsetCache[i].next)
893 LeaveCriticalSection(&xrender_cs);
897 /***********************************************************************
898 * X11DRV_XRender_SelectFont
900 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
903 struct xrender_info *info;
905 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
906 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
907 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
908 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
909 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
910 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
911 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
912 GetWorldTransform( physDev->hdc, &lfsz.xform );
913 lfsz_calc_hash(&lfsz);
915 info = get_xrender_info(physDev);
918 EnterCriticalSection(&xrender_cs);
919 if(info->cache_index != -1)
920 dec_ref_cache(info->cache_index);
921 info->cache_index = GetCacheEntry(physDev, &lfsz);
922 LeaveCriticalSection(&xrender_cs);
926 /***********************************************************************
927 * X11DRV_XRender_SetDeviceClipping
929 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
931 if (physDev->xrender->pict)
934 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
935 physDev->dc_rect.left, physDev->dc_rect.top,
936 (XRectangle *)data->Buffer, data->rdh.nCount );
941 /***********************************************************************
942 * X11DRV_XRender_DeleteDC
944 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
946 X11DRV_XRender_UpdateDrawable(physDev);
948 EnterCriticalSection(&xrender_cs);
949 if(physDev->xrender->cache_index != -1)
950 dec_ref_cache(physDev->xrender->cache_index);
951 LeaveCriticalSection(&xrender_cs);
953 HeapFree(GetProcessHeap(), 0, physDev->xrender);
954 physDev->xrender = NULL;
958 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
960 const WineXRenderFormat *fmt;
963 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
964 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
965 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
966 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
971 X11DRV_PALETTE_ComputeColorShifts(&shifts, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
972 fmt = get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts);
974 /* Common formats should be in our picture format table. */
977 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
978 dib->dsBm.bmBitsPixel, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
984 int red_mask, green_mask, blue_mask;
986 /* We are dealing with a DDB */
990 fmt = get_xrender_format(WXR_FORMAT_R5G6B5);
993 fmt = get_xrender_format(WXR_FORMAT_R8G8B8);
996 fmt = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1004 TRACE("Unhandled DDB bits_pixel=%d\n", bits_pixel);
1008 red_mask = fmt->pict_format->direct.redMask << fmt->pict_format->direct.red;
1009 green_mask = fmt->pict_format->direct.greenMask << fmt->pict_format->direct.green;
1010 blue_mask = fmt->pict_format->direct.blueMask << fmt->pict_format->direct.blue;
1011 X11DRV_PALETTE_ComputeColorShifts(&shifts, red_mask, green_mask, blue_mask);
1014 physBitmap->pixmap_depth = fmt->pict_format->depth;
1015 physBitmap->trueColor = TRUE;
1016 physBitmap->pixmap_color_shifts = shifts;
1020 /***********************************************************************
1021 * X11DRV_XRender_UpdateDrawable
1023 * Deletes the pict and tile when the drawable changes.
1025 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1027 struct xrender_info *info = physDev->xrender;
1029 if (info->pict || info->pict_src)
1032 XFlush( gdi_display );
1035 TRACE("freeing pict = %lx dc = %p\n", info->pict, physDev->hdc);
1036 pXRenderFreePicture(gdi_display, info->pict);
1041 TRACE("freeing pict = %lx dc = %p\n", info->pict_src, physDev->hdc);
1042 pXRenderFreePicture(gdi_display, info->pict_src);
1045 wine_tsx11_unlock();
1048 info->format = NULL;
1051 /************************************************************************
1054 * Helper to ExtTextOut. Must be called inside xrender_cs
1056 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
1058 unsigned int buflen;
1063 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
1064 gsCacheEntryFormat *formatEntry;
1065 UINT ggo_format = GGO_GLYPH_INDEX;
1066 WXRFormat wxr_format;
1067 static const char zero[4];
1068 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1072 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1075 ggo_format |= WINE_GGO_HRGB_BITMAP;
1078 ggo_format |= WINE_GGO_HBGR_BITMAP;
1081 ggo_format |= WINE_GGO_VRGB_BITMAP;
1084 ggo_format |= WINE_GGO_VBGR_BITMAP;
1088 ERR("aa = %d - not implemented\n", format);
1090 ggo_format |= GGO_BITMAP;
1094 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1095 if(buflen == GDI_ERROR) {
1096 if(format != AA_None) {
1098 entry->aa_default = AA_None;
1099 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1100 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1102 if(buflen == GDI_ERROR) {
1103 WARN("GetGlyphOutlineW failed\n");
1106 TRACE("Turning off antialiasing for this monochrome font\n");
1109 /* If there is nothing for the current type, we create the entry. */
1110 if( !entry->format[format] ) {
1111 entry->format[format] = HeapAlloc(GetProcessHeap(),
1113 sizeof(gsCacheEntryFormat));
1115 formatEntry = entry->format[format];
1117 if(formatEntry->nrealized <= glyph) {
1118 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1120 if (formatEntry->realized)
1121 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1123 formatEntry->realized,
1124 formatEntry->nrealized * sizeof(BOOL));
1126 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1128 formatEntry->nrealized * sizeof(BOOL));
1130 if(!X11DRV_XRender_Installed) {
1131 if (formatEntry->bitmaps)
1132 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1134 formatEntry->bitmaps,
1135 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1137 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1139 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1141 if (formatEntry->gis)
1142 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1145 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1147 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1149 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1153 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1156 wxr_format = WXR_FORMAT_GRAY;
1163 wxr_format = WXR_FORMAT_A8R8G8B8;
1167 ERR("aa = %d - not implemented\n", format);
1169 wxr_format = WXR_FORMAT_MONO;
1174 formatEntry->font_format = get_xrender_format(wxr_format);
1175 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
1176 wine_tsx11_unlock();
1180 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1181 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1182 formatEntry->realized[glyph] = TRUE;
1184 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1186 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1187 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1189 gi.width = gm.gmBlackBoxX;
1190 gi.height = gm.gmBlackBoxY;
1191 gi.x = -gm.gmptGlyphOrigin.x;
1192 gi.y = gm.gmptGlyphOrigin.y;
1193 gi.xOff = gm.gmCellIncX;
1194 gi.yOff = gm.gmCellIncY;
1196 if(TRACE_ON(xrender)) {
1199 unsigned char *line;
1201 if(format == AA_None) {
1202 pitch = ((gi.width + 31) / 32) * 4;
1203 for(i = 0; i < gi.height; i++) {
1204 line = (unsigned char*) buf + i * pitch;
1206 for(j = 0; j < pitch * 8; j++) {
1207 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1209 TRACE("%s\n", output);
1212 static const char blks[] = " .:;!o*#";
1216 pitch = ((gi.width + 3) / 4) * 4;
1217 for(i = 0; i < gi.height; i++) {
1218 line = (unsigned char*) buf + i * pitch;
1220 for(j = 0; j < pitch; j++) {
1221 str[0] = blks[line[j] >> 5];
1222 strcat(output, str);
1224 TRACE("%s\n", output);
1230 if(formatEntry->glyphset) {
1231 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1232 unsigned char *byte = (unsigned char*) buf, c;
1238 /* magic to flip bit order */
1239 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1240 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1241 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1246 else if ( format != AA_Grey &&
1247 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1249 unsigned int i, *data = (unsigned int *)buf;
1250 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1255 XRenderCompositeText seems to ignore 0x0 glyphs when
1256 AA_None, which means we lose the advance width of glyphs
1257 like the space. We'll pretend that such glyphs are 1x1
1262 gi.width = gi.height = 1;
1265 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1266 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1267 wine_tsx11_unlock();
1268 HeapFree(GetProcessHeap(), 0, buf);
1270 formatEntry->bitmaps[glyph] = buf;
1273 formatEntry->gis[glyph] = gi;
1278 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
1279 void *bitmap, XGlyphInfo *gi)
1281 unsigned char *srcLine = bitmap, *src;
1282 unsigned char bits, bitsMask;
1283 int width = gi->width;
1284 int stride = ((width + 31) & ~31) >> 3;
1285 int height = gi->height;
1289 TRACE("%d, %d\n", x, y);
1298 bitsMask = 0x80; /* FreeType is always MSB first */
1304 if (bits & bitsMask)
1312 bitsMask = bitsMask >> 1;
1318 } while (bits & bitsMask);
1319 XFillRectangle (gdi_display, physDev->drawable,
1320 physDev->gc, xspan, y, lenspan, 1);
1332 bitsMask = bitsMask >> 1;
1338 } while (!(bits & bitsMask));
1345 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
1346 void *bitmap, XGlyphInfo *gi)
1348 unsigned char *srcLine = bitmap, *src, bits;
1349 int width = gi->width;
1350 int stride = ((width + 3) & ~3);
1351 int height = gi->height;
1376 } while (bits >= 0x80);
1377 XFillRectangle (gdi_display, physDev->drawable,
1378 physDev->gc, xspan, y, lenspan, 1);
1391 } while (bits < 0x80);
1399 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1404 while ((mask & 1) == 0)
1410 while ((mask & 1) == 1)
1419 static DWORD GetField (DWORD pixel, int shift, int len)
1421 pixel = pixel & (((1 << (len)) - 1) << shift);
1422 pixel = pixel << (32 - (shift + len)) >> 24;
1425 pixel |= (pixel >> len);
1432 static DWORD PutField (DWORD pixel, int shift, int len)
1434 shift = shift - (8 - len);
1436 pixel &= (((1 << len) - 1) << (8 - len));
1444 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1450 BYTE *maskLine, *mask, m;
1455 BYTE src_r, src_g, src_b;
1460 height = gi->height;
1463 maskStride = (width + 3) & ~3;
1465 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1466 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1467 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1469 src_r = GetField(color, r_shift, r_len);
1470 src_g = GetField(color, g_shift, g_len);
1471 src_b = GetField(color, b_shift, b_len);
1473 for(; height--; y++)
1476 maskLine += maskStride;
1481 if(y >= image->height) break;
1485 if(tx >= image->width) break;
1488 if(tx < 0) continue;
1491 XPutPixel (image, tx, y, color);
1496 pixel = XGetPixel (image, tx, y);
1498 r = GetField(pixel, r_shift, r_len);
1499 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1500 g = GetField(pixel, g_shift, g_len);
1501 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1502 b = GetField(pixel, b_shift, b_len);
1503 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1505 pixel = (PutField (r, r_shift, r_len) |
1506 PutField (g, g_shift, g_len) |
1507 PutField (b, b_shift, b_len));
1508 XPutPixel (image, tx, y, pixel);
1514 /*************************************************************
1517 * Returns an appropriate Picture for tiling the text colour.
1518 * Call and use result within the xrender_cs
1520 static Picture get_tile_pict(const WineXRenderFormat *wxr_format, int text_pixel)
1527 } tiles[WXR_NB_FORMATS], *tile;
1530 tile = &tiles[wxr_format->format];
1534 XRenderPictureAttributes pa;
1537 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1539 pa.repeat = RepeatNormal;
1540 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1541 wine_tsx11_unlock();
1543 /* init current_color to something different from text_pixel */
1544 tile->current_color = ~text_pixel;
1546 if(wxr_format->format == WXR_FORMAT_MONO)
1548 /* for a 1bpp bitmap we always need a 1 in the tile */
1549 col.red = col.green = col.blue = 0;
1552 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1553 wine_tsx11_unlock();
1557 if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1559 get_xrender_color(wxr_format, text_pixel, &col);
1561 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1562 wine_tsx11_unlock();
1563 tile->current_color = text_pixel;
1568 /*************************************************************
1571 * Returns an appropriate Picture for masking with the specified alpha.
1572 * Call and use result within the xrender_cs
1574 static Picture get_mask_pict( int alpha )
1576 static Pixmap pixmap;
1577 static Picture pict;
1578 static int current_alpha;
1580 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1584 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
1585 XRenderPictureAttributes pa;
1588 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1589 pa.repeat = RepeatNormal;
1590 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format, CPRepeat, &pa );
1591 wine_tsx11_unlock();
1595 if (alpha != current_alpha)
1598 col.red = col.green = col.blue = 0;
1599 col.alpha = current_alpha = alpha;
1601 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1602 wine_tsx11_unlock();
1607 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1612 /***********************************************************************
1613 * X11DRV_XRender_ExtTextOut
1615 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1616 const RECT *lprect, LPCWSTR wstr, UINT count,
1620 gsCacheEntry *entry;
1621 gsCacheEntryFormat *formatEntry;
1623 int textPixel, backgroundPixel;
1624 HRGN saved_region = 0;
1625 BOOL disable_antialias = FALSE;
1626 AA_Type aa_type = AA_None;
1629 double cosEsc, sinEsc;
1631 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
1632 Picture tile_pict = 0;
1634 /* Do we need to disable antialiasing because of palette mode? */
1635 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1636 TRACE("bitmap is not a DIB\n");
1638 else if (bmp.dsBmih.biBitCount <= 8) {
1639 TRACE("Disabling antialiasing\n");
1640 disable_antialias = TRUE;
1643 xgcval.function = GXcopy;
1644 xgcval.background = physDev->backgroundPixel;
1645 xgcval.fill_style = FillSolid;
1647 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1648 wine_tsx11_unlock();
1650 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1652 if(physDev->depth == 1) {
1653 if((physDev->textPixel & 0xffffff) == 0) {
1655 backgroundPixel = 1;
1658 backgroundPixel = 0;
1661 textPixel = physDev->textPixel;
1662 backgroundPixel = physDev->backgroundPixel;
1665 if(flags & ETO_OPAQUE)
1668 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1669 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1670 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1671 lprect->right - lprect->left, lprect->bottom - lprect->top );
1672 wine_tsx11_unlock();
1682 GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1683 if(lf.lfEscapement != 0) {
1684 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1685 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1691 if (flags & ETO_CLIPPED)
1695 clip_region = CreateRectRgnIndirect( lprect );
1696 /* make a copy of the current device region */
1697 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1698 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1699 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1700 DeleteObject( clip_region );
1703 EnterCriticalSection(&xrender_cs);
1705 entry = glyphsetCache + physDev->xrender->cache_index;
1706 if( disable_antialias == FALSE )
1707 aa_type = entry->aa_default;
1708 formatEntry = entry->format[aa_type];
1710 for(idx = 0; idx < count; idx++) {
1711 if( !formatEntry ) {
1712 UploadGlyph(physDev, wstr[idx], aa_type);
1713 /* re-evaluate antialias since aa_default may have changed */
1714 if( disable_antialias == FALSE )
1715 aa_type = entry->aa_default;
1716 formatEntry = entry->format[aa_type];
1717 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1718 UploadGlyph(physDev, wstr[idx], aa_type);
1723 WARN("could not upload requested glyphs\n");
1724 LeaveCriticalSection(&xrender_cs);
1728 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1729 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1731 if(X11DRV_XRender_Installed)
1733 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1735 POINT desired, current;
1736 int render_op = PictOpOver;
1737 Picture pict = get_xrender_picture(physDev);
1739 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1740 So we pass zeros to the function and move to our starting position using the first
1741 element of the elts array. */
1743 desired.x = physDev->dc_rect.left + x;
1744 desired.y = physDev->dc_rect.top + y;
1745 current.x = current.y = 0;
1747 tile_pict = get_tile_pict(dst_format, physDev->textPixel);
1749 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1751 if((dst_format->format == WXR_FORMAT_MONO) && (textPixel == 0))
1752 render_op = PictOpOutReverse; /* This gives us 'black' text */
1754 for(idx = 0; idx < count; idx++)
1756 elts[idx].glyphset = formatEntry->glyphset;
1757 elts[idx].chars = wstr + idx;
1758 elts[idx].nchars = 1;
1759 elts[idx].xOff = desired.x - current.x;
1760 elts[idx].yOff = desired.y - current.y;
1762 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1763 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1767 desired.x += formatEntry->gis[wstr[idx]].xOff;
1768 desired.y += formatEntry->gis[wstr[idx]].yOff;
1772 offset += lpDx[idx];
1773 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1774 desired.y = physDev->dc_rect.top + y - offset * sinEsc;
1778 /* Make sure we don't have any transforms set from a previous call */
1779 set_xrender_transformation(pict, 1, 1, 0, 0);
1780 pXRenderCompositeText16(gdi_display, render_op,
1783 formatEntry->font_format->pict_format,
1784 0, 0, 0, 0, elts, count);
1785 wine_tsx11_unlock();
1786 HeapFree(GetProcessHeap(), 0, elts);
1788 INT offset = 0, xoff = 0, yoff = 0;
1790 XSetForeground( gdi_display, physDev->gc, textPixel );
1792 if(aa_type == AA_None || physDev->depth == 1)
1794 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1796 if(aa_type == AA_None)
1797 sharp_glyph_fn = SharpGlyphMono;
1799 sharp_glyph_fn = SharpGlyphGray;
1801 for(idx = 0; idx < count; idx++) {
1802 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1803 physDev->dc_rect.top + y + yoff,
1804 formatEntry->bitmaps[wstr[idx]],
1805 &formatEntry->gis[wstr[idx]]);
1807 offset += lpDx[idx];
1808 xoff = offset * cosEsc;
1809 yoff = offset * -sinEsc;
1811 xoff += formatEntry->gis[wstr[idx]].xOff;
1812 yoff += formatEntry->gis[wstr[idx]].yOff;
1817 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1818 RECT extents = {0, 0, 0, 0};
1820 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1821 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1823 TRACE("drawable %dx%d\n", w, h);
1825 for(idx = 0; idx < count; idx++) {
1826 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1827 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1828 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1829 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1830 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1831 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1832 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1833 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1835 offset += lpDx[idx];
1836 cur.x = offset * cosEsc;
1837 cur.y = offset * -sinEsc;
1839 cur.x += formatEntry->gis[wstr[idx]].xOff;
1840 cur.y += formatEntry->gis[wstr[idx]].yOff;
1843 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1844 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1846 if(physDev->dc_rect.left + x + extents.left >= 0) {
1847 image_x = physDev->dc_rect.left + x + extents.left;
1851 image_off_x = physDev->dc_rect.left + x + extents.left;
1853 if(physDev->dc_rect.top + y + extents.top >= 0) {
1854 image_y = physDev->dc_rect.top + y + extents.top;
1858 image_off_y = physDev->dc_rect.top + y + extents.top;
1860 if(physDev->dc_rect.left + x + extents.right < w)
1861 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1863 image_w = w - image_x;
1864 if(physDev->dc_rect.top + y + extents.bottom < h)
1865 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1867 image_h = h - image_y;
1869 if(image_w <= 0 || image_h <= 0) goto no_image;
1871 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1872 image = XGetImage(gdi_display, physDev->drawable,
1873 image_x, image_y, image_w, image_h,
1874 AllPlanes, ZPixmap);
1875 X11DRV_check_error();
1877 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1878 gdi_display, (int)physDev->drawable, image_x, image_y,
1879 image_w, image_h, AllPlanes, ZPixmap,
1880 physDev->depth, image);
1882 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
1887 gcv.graphics_exposures = False;
1888 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1889 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1890 image_w, image_h, 0, 0);
1891 XFreeGC(gdi_display, gc);
1892 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1893 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1895 X11DRV_check_error();
1896 XFreePixmap(gdi_display, xpm);
1898 if(!image) goto no_image;
1900 image->red_mask = visual->red_mask;
1901 image->green_mask = visual->green_mask;
1902 image->blue_mask = visual->blue_mask;
1904 offset = xoff = yoff = 0;
1905 for(idx = 0; idx < count; idx++) {
1906 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1907 yoff + image_off_y - extents.top,
1908 formatEntry->bitmaps[wstr[idx]],
1909 &formatEntry->gis[wstr[idx]],
1910 physDev->textPixel);
1912 offset += lpDx[idx];
1913 xoff = offset * cosEsc;
1914 yoff = offset * -sinEsc;
1916 xoff += formatEntry->gis[wstr[idx]].xOff;
1917 yoff += formatEntry->gis[wstr[idx]].yOff;
1920 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1921 image_x, image_y, image_w, image_h);
1922 XDestroyImage(image);
1925 wine_tsx11_unlock();
1927 LeaveCriticalSection(&xrender_cs);
1929 if (flags & ETO_CLIPPED)
1931 /* restore the device region */
1932 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1933 DeleteObject( saved_region );
1939 X11DRV_UnlockDIBSection( physDev, TRUE );
1943 /* Helper function for (stretched) blitting using xrender */
1944 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1945 int x_src, int y_src, int x_dst, int y_dst,
1946 double xscale, double yscale, int width, int height )
1948 int x_offset, y_offset;
1950 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1951 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1952 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1953 if(xscale != 1.0 || yscale != 1.0)
1955 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1956 * in the wrong quadrant of the x-y plane.
1958 x_offset = (xscale < 0) ? -width : 0;
1959 y_offset = (yscale < 0) ? -height : 0;
1960 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1966 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1968 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1969 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
1972 /* Helper function for (stretched) mono->color blitting using xrender */
1973 static void xrender_mono_blit( Picture src_pict, Picture mask_pict, Picture dst_pict,
1974 int x_src, int y_src, double xscale, double yscale, int width, int height )
1976 int x_offset, y_offset;
1978 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
1979 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
1980 * tile data. We need PictOpOver for correct rendering.
1981 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
1984 if (xscale != 1.0 || yscale != 1.0)
1986 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1987 * in the wrong quadrant of the x-y plane.
1989 x_offset = (xscale < 0) ? -width : 0;
1990 y_offset = (yscale < 0) ? -height : 0;
1991 set_xrender_transformation(mask_pict, xscale, yscale, x_src, y_src);
1997 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
1999 pXRenderComposite(gdi_display, PictOpOver, src_pict, mask_pict, dst_pict,
2000 0, 0, x_offset, y_offset, 0, 0, width, height);
2003 /******************************************************************************
2006 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2007 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2009 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2010 struct xrender_info *src_info = get_xrender_info( devSrc );
2011 double xscale, yscale;
2014 if(!X11DRV_XRender_Installed) {
2015 FIXME("Unable to AlphaBlend without Xrender\n");
2019 if (devSrc != devDst) X11DRV_LockDIBSection( devSrc, DIB_Status_GdiMod );
2020 X11DRV_LockDIBSection( devDst, DIB_Status_GdiMod );
2022 dst_pict = get_xrender_picture( devDst );
2024 use_repeat = use_source_repeat( devSrc );
2027 xscale = src->width / (double)dst->width;
2028 yscale = src->height / (double)dst->height;
2030 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2032 if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && src_info->format)
2034 /* we need a source picture with no alpha */
2035 WXRFormat format = get_format_without_alpha( src_info->format->format );
2036 if (format != src_info->format->format)
2038 XRenderPictureAttributes pa;
2039 const WineXRenderFormat *fmt = get_xrender_format( format );
2042 pa.subwindow_mode = IncludeInferiors;
2043 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2044 tmp_pict = pXRenderCreatePicture( gdi_display, devSrc->drawable, fmt->pict_format,
2045 CPSubwindowMode|CPRepeat, &pa );
2046 wine_tsx11_unlock();
2047 src_pict = tmp_pict;
2051 if (!src_pict) src_pict = get_xrender_picture_source( devSrc, use_repeat );
2053 EnterCriticalSection( &xrender_cs );
2054 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2057 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2058 devSrc->dc_rect.left + src->visrect.left, devSrc->dc_rect.top + src->visrect.top,
2059 devDst->dc_rect.left + dst->visrect.left, devDst->dc_rect.top + dst->visrect.top,
2061 dst->visrect.right - dst->visrect.left, dst->visrect.bottom - dst->visrect.top );
2062 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2063 wine_tsx11_unlock();
2065 LeaveCriticalSection( &xrender_cs );
2066 if (devSrc != devDst) X11DRV_UnlockDIBSection( devSrc, FALSE );
2067 X11DRV_UnlockDIBSection( devDst, TRUE );
2072 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2074 /* 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 */
2075 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2076 const WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2077 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2080 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2082 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2083 if( (physBitmap->pixmap_depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->pixmap_depth) ||
2084 (src_format->format == dst_format->format) )
2086 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2087 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2089 else /* We need depth conversion */
2091 Picture src_pict, dst_pict;
2092 XRenderPictureAttributes pa;
2093 pa.subwindow_mode = IncludeInferiors;
2094 pa.repeat = RepeatNone;
2096 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2097 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2099 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2100 pXRenderFreePicture(gdi_display, src_pict);
2101 pXRenderFreePicture(gdi_display, dst_pict);
2103 wine_tsx11_unlock();
2106 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2107 Pixmap pixmap, GC gc,
2108 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2110 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2111 int width = dst->visrect.right - dst->visrect.left;
2112 int height = dst->visrect.bottom - dst->visrect.top;
2113 int x_src = physDevSrc->dc_rect.left + src->visrect.left;
2114 int y_src = physDevSrc->dc_rect.top + src->visrect.top;
2115 struct xrender_info *src_info = get_xrender_info(physDevSrc);
2116 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDevDst->depth, physDevDst->color_shifts);
2117 Picture src_pict=0, dst_pict=0, mask_pict=0;
2119 double xscale, yscale;
2121 XRenderPictureAttributes pa;
2122 pa.subwindow_mode = IncludeInferiors;
2123 pa.repeat = RepeatNone;
2125 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2126 physDevSrc->depth, src->width, src->height, x_src, y_src);
2127 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst->depth, dst->width, dst->height);
2129 if(!X11DRV_XRender_Installed)
2131 TRACE("Not using XRender since it is not available or disabled\n");
2135 /* XRender can't handle palettes, so abort */
2136 if(X11DRV_PALETTE_XPixelToPalette)
2139 /* XRender is of no use in this case */
2140 if((physDevDst->depth == 1) && (physDevSrc->depth > 1))
2143 /* Just use traditional X copy when the formats match and we don't need stretching */
2144 if((src_info->format->format == dst_format->format) && !stretch)
2146 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2148 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
2149 wine_tsx11_unlock();
2153 use_repeat = use_source_repeat( physDevSrc );
2156 xscale = src->width / (double)dst->width;
2157 yscale = src->height / (double)dst->height;
2159 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2162 if(physDevSrc->depth == 1 && physDevDst->depth > 1)
2165 get_xrender_color(dst_format, physDevDst->textPixel, &col);
2167 /* We use the source drawable as a mask */
2168 mask_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2170 /* Use backgroundPixel as the foreground color */
2171 EnterCriticalSection( &xrender_cs );
2172 src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
2174 /* Create a destination picture and fill it with textPixel color as the background color */
2176 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2177 pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height);
2179 xrender_mono_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
2181 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2182 wine_tsx11_unlock();
2183 LeaveCriticalSection( &xrender_cs );
2185 else /* color -> color (can be at different depths) or mono -> mono */
2187 src_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2190 dst_pict = pXRenderCreatePicture(gdi_display,
2191 pixmap, dst_format->pict_format,
2192 CPSubwindowMode|CPRepeat, &pa);
2194 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, x_src, y_src, 0, 0, xscale, yscale, width, height);
2196 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2197 wine_tsx11_unlock();
2202 #else /* SONAME_LIBXRENDER */
2204 void X11DRV_XRender_Init(void)
2206 TRACE("XRender support not compiled in.\n");
2210 void X11DRV_XRender_Finalize(void)
2214 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
2220 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
2226 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
2232 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
2233 const RECT *lprect, LPCWSTR wstr, UINT count,
2240 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
2246 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2247 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2249 FIXME("not supported - XRENDER headers were missing at compile time\n");
2253 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2256 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
2258 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2259 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2260 wine_tsx11_unlock();
2263 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2268 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2269 Pixmap pixmap, GC gc,
2270 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2274 #endif /* SONAME_LIBXRENDER */