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 #define MAX_FORMATS 10
59 typedef enum wine_xrformat
73 typedef struct wine_xrender_format_template
78 unsigned int alphaMask;
82 unsigned int greenMask;
84 unsigned int blueMask;
85 } WineXRenderFormatTemplate;
87 static const WineXRenderFormatTemplate wxr_formats_template[] =
89 /* Format depth alpha mask red mask green mask blue mask*/
90 {WXR_FORMAT_MONO, 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
91 {WXR_FORMAT_GRAY, 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
92 {WXR_FORMAT_X1R5G5B5, 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
93 {WXR_FORMAT_X1B5G5R5, 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
94 {WXR_FORMAT_R5G6B5, 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
95 {WXR_FORMAT_B5G6R5, 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
96 {WXR_FORMAT_R8G8B8, 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
97 {WXR_FORMAT_B8G8R8, 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
98 {WXR_FORMAT_A8R8G8B8, 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
99 {WXR_FORMAT_X8R8G8B8, 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff }
102 typedef struct wine_xrender_format
105 XRenderPictFormat *pict_format;
108 static WineXRenderFormat wxr_formats[MAX_FORMATS];
109 static int WineXRenderFormatsListSize = 0;
110 static WineXRenderFormat *default_format = NULL;
116 SIZE devsize; /* size in device coords */
120 #define INITIAL_REALIZED_BUF_SIZE 128
122 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
127 WineXRenderFormat *font_format;
132 } gsCacheEntryFormat;
138 gsCacheEntryFormat * format[AA_MAXVALUE];
150 static gsCacheEntry *glyphsetCache = NULL;
151 static DWORD glyphsetCacheSize = 0;
152 static INT lastfree = -1;
155 #define INIT_CACHE_SIZE 10
157 static int antialias = 1;
159 static void *xrender_handle;
161 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
162 MAKE_FUNCPTR(XRenderAddGlyphs)
163 MAKE_FUNCPTR(XRenderComposite)
164 MAKE_FUNCPTR(XRenderCompositeString8)
165 MAKE_FUNCPTR(XRenderCompositeString16)
166 MAKE_FUNCPTR(XRenderCompositeString32)
167 MAKE_FUNCPTR(XRenderCompositeText16)
168 MAKE_FUNCPTR(XRenderCreateGlyphSet)
169 MAKE_FUNCPTR(XRenderCreatePicture)
170 MAKE_FUNCPTR(XRenderFillRectangle)
171 MAKE_FUNCPTR(XRenderFindFormat)
172 MAKE_FUNCPTR(XRenderFindVisualFormat)
173 MAKE_FUNCPTR(XRenderFreeGlyphSet)
174 MAKE_FUNCPTR(XRenderFreePicture)
175 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
176 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
177 MAKE_FUNCPTR(XRenderSetPictureTransform)
179 MAKE_FUNCPTR(XRenderQueryExtension)
182 static CRITICAL_SECTION xrender_cs;
183 static CRITICAL_SECTION_DEBUG critsect_debug =
186 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
187 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
189 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
191 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
192 ( ( (ULONG)_x4 << 24 ) | \
193 ( (ULONG)_x3 << 16 ) | \
194 ( (ULONG)_x2 << 8 ) | \
197 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
199 #define GASP_GRIDFIT 0x01
200 #define GASP_DOGRAY 0x02
202 #ifdef WORDS_BIGENDIAN
203 #define get_be_word(x) (x)
204 #define NATIVE_BYTE_ORDER MSBFirst
206 #define get_be_word(x) RtlUshortByteSwap(x)
207 #define NATIVE_BYTE_ORDER LSBFirst
210 static struct xrender_info *get_xrender_info(X11DRV_PDEVICE *physDev)
212 if(!physDev->xrender)
214 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physDev->xrender));
216 if(!physDev->xrender)
218 ERR("Unable to allocate XRENDERINFO!\n");
221 physDev->xrender->cache_index = -1;
224 return physDev->xrender;
227 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
230 templ->type = PictTypeDirect;
231 templ->depth = fmt->depth;
232 templ->direct.alpha = fmt->alpha;
233 templ->direct.alphaMask = fmt->alphaMask;
234 templ->direct.red = fmt->red;
235 templ->direct.redMask = fmt->redMask;
236 templ->direct.green = fmt->green;
237 templ->direct.greenMask = fmt->greenMask;
238 templ->direct.blue = fmt->blue;
239 templ->direct.blueMask = fmt->blueMask;
242 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
247 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
249 if(fmt->depth != screen_depth)
251 if( (fmt->redMask << fmt->red) != visual->red_mask)
253 if( (fmt->greenMask << fmt->green) != visual->green_mask)
255 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
258 /* We never select a default ARGB visual */
265 static int load_xrender_formats(void)
268 for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
270 XRenderPictFormat templ, *pict_format;
272 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
275 pict_format = pXRenderFindVisualFormat(gdi_display, visual);
278 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
279 if (visual->class == DirectColor)
282 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
283 screen_depth, TrueColor, &info ))
285 pict_format = pXRenderFindVisualFormat(gdi_display, info.visual);
286 if (pict_format) visual = info.visual;
294 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
295 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
296 default_format = &wxr_formats[WineXRenderFormatsListSize];
297 WineXRenderFormatsListSize++;
298 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
303 unsigned long mask = 0;
304 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
307 pict_format = pXRenderFindFormat(gdi_display, mask, &templ, 0);
312 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
313 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
314 WineXRenderFormatsListSize++;
315 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
319 return WineXRenderFormatsListSize;
322 /***********************************************************************
323 * X11DRV_XRender_Init
325 * Let's see if our XServer has the extension available
328 void X11DRV_XRender_Init(void)
332 if (client_side_with_render &&
333 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
334 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
335 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
338 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
339 LOAD_FUNCPTR(XRenderAddGlyphs)
340 LOAD_FUNCPTR(XRenderComposite)
341 LOAD_FUNCPTR(XRenderCompositeString8)
342 LOAD_FUNCPTR(XRenderCompositeString16)
343 LOAD_FUNCPTR(XRenderCompositeString32)
344 LOAD_FUNCPTR(XRenderCompositeText16)
345 LOAD_FUNCPTR(XRenderCreateGlyphSet)
346 LOAD_FUNCPTR(XRenderCreatePicture)
347 LOAD_FUNCPTR(XRenderFillRectangle)
348 LOAD_FUNCPTR(XRenderFindFormat)
349 LOAD_FUNCPTR(XRenderFindVisualFormat)
350 LOAD_FUNCPTR(XRenderFreeGlyphSet)
351 LOAD_FUNCPTR(XRenderFreePicture)
352 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
353 LOAD_FUNCPTR(XRenderQueryExtension)
355 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
356 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
357 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
358 #undef LOAD_OPTIONAL_FUNCPTR
362 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
364 if(X11DRV_XRender_Installed) {
365 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
366 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
370 "Wine has detected that you probably have a buggy version\n"
371 "of libXrender.so . Because of this client side font rendering\n"
372 "will be disabled. Please upgrade this library.\n");
373 X11DRV_XRender_Installed = FALSE;
377 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
378 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
379 X11DRV_XRender_Installed = FALSE;
385 if(X11DRV_XRender_Installed || client_side_with_core)
387 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
388 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
390 glyphsetCacheSize = INIT_CACHE_SIZE;
392 for(i = 0; i < INIT_CACHE_SIZE; i++) {
393 glyphsetCache[i].next = i + 1;
394 glyphsetCache[i].count = -1;
396 glyphsetCache[i-1].next = -1;
397 using_client_side_fonts = 1;
399 if(!X11DRV_XRender_Installed) {
400 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
401 if(screen_depth <= 8 || !client_side_antialias_with_core)
404 if(screen_depth <= 8 || !client_side_antialias_with_render)
408 else TRACE("Using X11 core fonts\n");
411 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
412 static void get_xrender_color(WineXRenderFormat *wxr_format, int src_color, XRenderColor *dst_color)
414 XRenderPictFormat *pf = wxr_format->pict_format;
416 if(pf->direct.redMask)
417 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
421 if(pf->direct.greenMask)
422 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
424 dst_color->green = 0;
426 if(pf->direct.blueMask)
427 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
431 dst_color->alpha = 0xffff;
434 static WineXRenderFormat *get_xrender_format(WXRFormat format)
437 for(i=0; i<WineXRenderFormatsListSize; i++)
439 if(wxr_formats[i].format == format)
441 TRACE("Returning wxr_format=%#x\n", format);
442 return &wxr_formats[i];
448 static WineXRenderFormat *get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
450 int redMask, greenMask, blueMask;
454 return get_xrender_format(WXR_FORMAT_MONO);
456 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
458 return default_format;
460 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
461 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
462 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
464 /* Try to locate a format which matches the specification of the dibsection. */
465 for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
467 if( depth == wxr_formats_template[i].depth &&
468 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
469 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
470 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
473 /* When we reach this stage the format was found in our template table but this doesn't mean that
474 * the Xserver also supports this format (e.g. its depth might be too low). The call below verifies that.
476 return get_xrender_format(wxr_formats_template[i].wxr_format);
480 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
481 ERR("No XRender format found!\n");
485 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
487 if(p1->hash != p2->hash) return TRUE;
488 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
489 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
490 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
491 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
495 static void walk_cache(void)
499 EnterCriticalSection(&xrender_cs);
500 for(i=mru; i >= 0; i = glyphsetCache[i].next)
501 TRACE("item %d\n", i);
502 LeaveCriticalSection(&xrender_cs);
506 static int LookupEntry(LFANDSIZE *plfsz)
510 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
512 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
517 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
518 glyphsetCache[i].count++;
520 glyphsetCache[prev_i].next = glyphsetCache[i].next;
521 glyphsetCache[i].next = mru;
524 TRACE("found font in cache %d\n", i);
529 TRACE("font not in cache\n");
533 static void FreeEntry(int entry)
537 for(format = 0; format < AA_MAXVALUE; format++) {
538 gsCacheEntryFormat * formatEntry;
540 if( !glyphsetCache[entry].format[format] )
543 formatEntry = glyphsetCache[entry].format[format];
545 if(formatEntry->glyphset) {
547 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
549 formatEntry->glyphset = 0;
551 if(formatEntry->nrealized) {
552 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
553 formatEntry->realized = NULL;
554 if(formatEntry->bitmaps) {
555 for(i = 0; i < formatEntry->nrealized; i++)
556 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
557 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
558 formatEntry->bitmaps = NULL;
560 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
561 formatEntry->gis = NULL;
562 formatEntry->nrealized = 0;
565 HeapFree(GetProcessHeap(), 0, formatEntry);
566 glyphsetCache[entry].format[format] = NULL;
570 static int AllocEntry(void)
572 int best = -1, prev_best = -1, i, prev_i = -1;
575 assert(glyphsetCache[lastfree].count == -1);
576 glyphsetCache[lastfree].count = 1;
578 lastfree = glyphsetCache[lastfree].next;
580 glyphsetCache[best].next = mru;
583 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
587 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
588 if(glyphsetCache[i].count == 0) {
596 TRACE("freeing unused glyphset at cache %d\n", best);
598 glyphsetCache[best].count = 1;
600 glyphsetCache[prev_best].next = glyphsetCache[best].next;
601 glyphsetCache[best].next = mru;
609 TRACE("Growing cache\n");
612 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
614 (glyphsetCacheSize + INIT_CACHE_SIZE)
615 * sizeof(*glyphsetCache));
617 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
618 (glyphsetCacheSize + INIT_CACHE_SIZE)
619 * sizeof(*glyphsetCache));
621 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
623 glyphsetCache[i].next = i + 1;
624 glyphsetCache[i].count = -1;
626 glyphsetCache[i-1].next = -1;
627 glyphsetCacheSize += INIT_CACHE_SIZE;
629 lastfree = glyphsetCache[best].next;
630 glyphsetCache[best].count = 1;
631 glyphsetCache[best].next = mru;
633 TRACE("new free cache slot at %d\n", mru);
637 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
647 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
648 if(size == GDI_ERROR)
651 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
652 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
654 GetTextMetricsW(physDev->hdc, &tm);
655 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
658 num_recs = get_be_word(*gasp);
662 *flags = get_be_word(*(gasp + 1));
663 if(ppem <= get_be_word(*gasp))
667 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
669 HeapFree(GetProcessHeap(), 0, buffer);
673 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
677 UINT font_smoothing_type, font_smoothing_orientation;
679 if (X11DRV_XRender_Installed && subpixel &&
680 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
681 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
683 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
684 &font_smoothing_orientation, 0) &&
685 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
692 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
693 But, Wine's subpixel rendering can support the portrait mode.
696 else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
704 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
709 static int hinter = -1;
710 static int subpixel = -1;
713 if((ret = LookupEntry(plfsz)) != -1) return ret;
716 entry = glyphsetCache + ret;
717 entry->lfsz = *plfsz;
718 for( format = 0; format < AA_MAXVALUE; format++ ) {
719 assert( !entry->format[format] );
722 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
724 if(hinter == -1 || subpixel == -1)
726 RASTERIZER_STATUS status;
727 GetRasterizerCaps(&status, sizeof(status));
728 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
729 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
732 switch (plfsz->lf.lfQuality)
734 case ANTIALIASED_QUALITY:
735 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
737 case CLEARTYPE_QUALITY:
738 case CLEARTYPE_NATURAL_QUALITY:
739 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
741 case DEFAULT_QUALITY:
745 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
748 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
751 entry->aa_default = AA_None;
756 entry->aa_default = AA_None;
761 static void dec_ref_cache(int index)
764 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
765 assert(glyphsetCache[index].count > 0);
766 glyphsetCache[index].count--;
769 static void lfsz_calc_hash(LFANDSIZE *plfsz)
771 DWORD hash = 0, *ptr, two_chars;
775 hash ^= plfsz->devsize.cx;
776 hash ^= plfsz->devsize.cy;
777 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
779 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
781 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
783 pwc = (WCHAR *)&two_chars;
785 *pwc = toupperW(*pwc);
787 *pwc = toupperW(*pwc);
795 /***********************************************************************
796 * X11DRV_XRender_Finalize
798 void X11DRV_XRender_Finalize(void)
802 EnterCriticalSection(&xrender_cs);
803 for(i = mru; i >= 0; i = glyphsetCache[i].next)
805 LeaveCriticalSection(&xrender_cs);
809 /***********************************************************************
810 * X11DRV_XRender_SelectFont
812 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
815 struct xrender_info *info;
817 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
818 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
819 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
820 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
821 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
822 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
823 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
824 GetWorldTransform( physDev->hdc, &lfsz.xform );
825 lfsz_calc_hash(&lfsz);
827 info = get_xrender_info(physDev);
830 EnterCriticalSection(&xrender_cs);
831 if(info->cache_index != -1)
832 dec_ref_cache(info->cache_index);
833 info->cache_index = GetCacheEntry(physDev, &lfsz);
834 LeaveCriticalSection(&xrender_cs);
838 /***********************************************************************
839 * X11DRV_XRender_DeleteDC
841 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
843 X11DRV_XRender_UpdateDrawable(physDev);
845 EnterCriticalSection(&xrender_cs);
846 if(physDev->xrender->cache_index != -1)
847 dec_ref_cache(physDev->xrender->cache_index);
848 LeaveCriticalSection(&xrender_cs);
850 HeapFree(GetProcessHeap(), 0, physDev->xrender);
851 physDev->xrender = NULL;
855 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, const DIBSECTION *dib)
857 WineXRenderFormat *fmt;
860 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
861 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
862 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
863 if(!X11DRV_XRender_Installed || dib->dsBm.bmBitsPixel <= 8)
866 X11DRV_PALETTE_ComputeColorShifts(&shifts, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
868 /* Common formats should be in our picture format table. */
869 fmt = get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts);
872 physBitmap->pixmap_depth = fmt->pict_format->depth;
873 physBitmap->trueColor = TRUE;
874 physBitmap->pixmap_color_shifts = shifts;
877 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
878 dib->dsBm.bmBitsPixel, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
882 /***********************************************************************
883 * X11DRV_XRender_UpdateDrawable
885 * Deletes the pict and tile when the drawable changes.
887 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
891 if(physDev->xrender->pict)
893 TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
895 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
896 physDev->xrender->pict = 0;
903 /************************************************************************
906 * Helper to ExtTextOut. Must be called inside xrender_cs
908 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
915 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
916 gsCacheEntryFormat *formatEntry;
917 UINT ggo_format = GGO_GLYPH_INDEX;
918 WXRFormat wxr_format;
919 static const char zero[4];
920 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
924 ggo_format |= WINE_GGO_GRAY16_BITMAP;
927 ggo_format |= WINE_GGO_HRGB_BITMAP;
930 ggo_format |= WINE_GGO_HBGR_BITMAP;
933 ggo_format |= WINE_GGO_VRGB_BITMAP;
936 ggo_format |= WINE_GGO_VBGR_BITMAP;
940 ERR("aa = %d - not implemented\n", format);
942 ggo_format |= GGO_BITMAP;
946 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
947 if(buflen == GDI_ERROR) {
948 if(format != AA_None) {
950 entry->aa_default = AA_None;
951 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
952 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
954 if(buflen == GDI_ERROR) {
955 WARN("GetGlyphOutlineW failed\n");
958 TRACE("Turning off antialiasing for this monochrome font\n");
961 /* If there is nothing for the current type, we create the entry. */
962 if( !entry->format[format] ) {
963 entry->format[format] = HeapAlloc(GetProcessHeap(),
965 sizeof(gsCacheEntryFormat));
967 formatEntry = entry->format[format];
969 if(formatEntry->nrealized <= glyph) {
970 formatEntry->nrealized = (glyph / 128 + 1) * 128;
972 if (formatEntry->realized)
973 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
975 formatEntry->realized,
976 formatEntry->nrealized * sizeof(BOOL));
978 formatEntry->realized = HeapAlloc(GetProcessHeap(),
980 formatEntry->nrealized * sizeof(BOOL));
982 if(!X11DRV_XRender_Installed) {
983 if (formatEntry->bitmaps)
984 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
986 formatEntry->bitmaps,
987 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
989 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
991 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
993 if (formatEntry->gis)
994 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
997 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
999 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1001 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1005 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1008 wxr_format = WXR_FORMAT_GRAY;
1015 wxr_format = WXR_FORMAT_A8R8G8B8;
1019 ERR("aa = %d - not implemented\n", format);
1021 wxr_format = WXR_FORMAT_MONO;
1026 formatEntry->font_format = get_xrender_format(wxr_format);
1027 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
1028 wine_tsx11_unlock();
1032 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1033 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1034 formatEntry->realized[glyph] = TRUE;
1036 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1038 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1039 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1041 gi.width = gm.gmBlackBoxX;
1042 gi.height = gm.gmBlackBoxY;
1043 gi.x = -gm.gmptGlyphOrigin.x;
1044 gi.y = gm.gmptGlyphOrigin.y;
1045 gi.xOff = gm.gmCellIncX;
1046 gi.yOff = gm.gmCellIncY;
1048 if(TRACE_ON(xrender)) {
1051 unsigned char *line;
1053 if(format == AA_None) {
1054 pitch = ((gi.width + 31) / 32) * 4;
1055 for(i = 0; i < gi.height; i++) {
1056 line = (unsigned char*) buf + i * pitch;
1058 for(j = 0; j < pitch * 8; j++) {
1059 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1061 TRACE("%s\n", output);
1064 static const char blks[] = " .:;!o*#";
1068 pitch = ((gi.width + 3) / 4) * 4;
1069 for(i = 0; i < gi.height; i++) {
1070 line = (unsigned char*) buf + i * pitch;
1072 for(j = 0; j < pitch; j++) {
1073 str[0] = blks[line[j] >> 5];
1074 strcat(output, str);
1076 TRACE("%s\n", output);
1082 if(formatEntry->glyphset) {
1083 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1084 unsigned char *byte = (unsigned char*) buf, c;
1090 /* magic to flip bit order */
1091 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1092 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1093 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1098 else if ( format != AA_Grey &&
1099 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1101 unsigned int i, *data = (unsigned int *)buf;
1102 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1107 XRenderCompositeText seems to ignore 0x0 glyphs when
1108 AA_None, which means we lose the advance width of glyphs
1109 like the space. We'll pretend that such glyphs are 1x1
1114 gi.width = gi.height = 1;
1117 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1118 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1119 wine_tsx11_unlock();
1120 HeapFree(GetProcessHeap(), 0, buf);
1122 formatEntry->bitmaps[glyph] = buf;
1125 formatEntry->gis[glyph] = gi;
1130 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
1131 void *bitmap, XGlyphInfo *gi)
1133 unsigned char *srcLine = bitmap, *src;
1134 unsigned char bits, bitsMask;
1135 int width = gi->width;
1136 int stride = ((width + 31) & ~31) >> 3;
1137 int height = gi->height;
1141 TRACE("%d, %d\n", x, y);
1150 bitsMask = 0x80; /* FreeType is always MSB first */
1156 if (bits & bitsMask)
1164 bitsMask = bitsMask >> 1;
1170 } while (bits & bitsMask);
1171 XFillRectangle (gdi_display, physDev->drawable,
1172 physDev->gc, xspan, y, lenspan, 1);
1184 bitsMask = bitsMask >> 1;
1190 } while (!(bits & bitsMask));
1197 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
1198 void *bitmap, XGlyphInfo *gi)
1200 unsigned char *srcLine = bitmap, *src, bits;
1201 int width = gi->width;
1202 int stride = ((width + 3) & ~3);
1203 int height = gi->height;
1228 } while (bits >= 0x80);
1229 XFillRectangle (gdi_display, physDev->drawable,
1230 physDev->gc, xspan, y, lenspan, 1);
1243 } while (bits < 0x80);
1251 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1256 while ((mask & 1) == 0)
1262 while ((mask & 1) == 1)
1271 static DWORD GetField (DWORD pixel, int shift, int len)
1273 pixel = pixel & (((1 << (len)) - 1) << shift);
1274 pixel = pixel << (32 - (shift + len)) >> 24;
1277 pixel |= (pixel >> len);
1284 static DWORD PutField (DWORD pixel, int shift, int len)
1286 shift = shift - (8 - len);
1288 pixel &= (((1 << len) - 1) << (8 - len));
1296 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1302 BYTE *maskLine, *mask, m;
1307 BYTE src_r, src_g, src_b;
1312 height = gi->height;
1315 maskStride = (width + 3) & ~3;
1317 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1318 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1319 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1321 src_r = GetField(color, r_shift, r_len);
1322 src_g = GetField(color, g_shift, g_len);
1323 src_b = GetField(color, b_shift, b_len);
1325 for(; height--; y++)
1328 maskLine += maskStride;
1333 if(y >= image->height) break;
1337 if(tx >= image->width) break;
1340 if(tx < 0) continue;
1343 XPutPixel (image, tx, y, color);
1348 pixel = XGetPixel (image, tx, y);
1350 r = GetField(pixel, r_shift, r_len);
1351 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1352 g = GetField(pixel, g_shift, g_len);
1353 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1354 b = GetField(pixel, b_shift, b_len);
1355 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1357 pixel = (PutField (r, r_shift, r_len) |
1358 PutField (g, g_shift, g_len) |
1359 PutField (b, b_shift, b_len));
1360 XPutPixel (image, tx, y, pixel);
1366 /*************************************************************
1369 * Returns an appropriate Picture for tiling the text colour.
1370 * Call and use result within the xrender_cs
1372 static Picture get_tile_pict(WineXRenderFormat *wxr_format, int text_pixel)
1379 } tiles[MAX_FORMATS], *tile;
1382 tile = &tiles[wxr_format->format];
1386 XRenderPictureAttributes pa;
1389 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1391 pa.repeat = RepeatNormal;
1392 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1393 wine_tsx11_unlock();
1395 /* init current_color to something different from text_pixel */
1396 tile->current_color = ~text_pixel;
1398 if(wxr_format->format == WXR_FORMAT_MONO)
1400 /* for a 1bpp bitmap we always need a 1 in the tile */
1401 col.red = col.green = col.blue = 0;
1404 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1405 wine_tsx11_unlock();
1409 if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1411 get_xrender_color(wxr_format, text_pixel, &col);
1413 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1414 wine_tsx11_unlock();
1415 tile->current_color = text_pixel;
1420 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1425 /***********************************************************************
1426 * X11DRV_XRender_ExtTextOut
1428 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1429 const RECT *lprect, LPCWSTR wstr, UINT count,
1434 gsCacheEntry *entry;
1435 gsCacheEntryFormat *formatEntry;
1437 HDC hdc = physDev->hdc;
1438 int textPixel, backgroundPixel;
1439 HRGN saved_region = 0;
1440 BOOL disable_antialias = FALSE;
1441 AA_Type aa_type = AA_None;
1444 double cosEsc, sinEsc;
1446 WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
1447 Picture tile_pict = 0;
1449 /* Do we need to disable antialiasing because of palette mode? */
1450 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1451 TRACE("bitmap is not a DIB\n");
1453 else if (bmp.dsBmih.biBitCount <= 8) {
1454 TRACE("Disabling antialiasing\n");
1455 disable_antialias = TRUE;
1458 xgcval.function = GXcopy;
1459 xgcval.background = physDev->backgroundPixel;
1460 xgcval.fill_style = FillSolid;
1462 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1463 wine_tsx11_unlock();
1465 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1467 if(physDev->depth == 1) {
1468 if((physDev->textPixel & 0xffffff) == 0) {
1470 backgroundPixel = 1;
1473 backgroundPixel = 0;
1476 textPixel = physDev->textPixel;
1477 backgroundPixel = physDev->backgroundPixel;
1480 if(flags & ETO_OPAQUE)
1483 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1484 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1485 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1486 lprect->right - lprect->left, lprect->bottom - lprect->top );
1487 wine_tsx11_unlock();
1497 GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1498 if(lf.lfEscapement != 0) {
1499 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1500 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1506 if (flags & ETO_CLIPPED)
1510 clip_region = CreateRectRgnIndirect( lprect );
1511 /* make a copy of the current device region */
1512 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1513 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1514 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1515 DeleteObject( clip_region );
1518 if(X11DRV_XRender_Installed) {
1519 if(!physDev->xrender->pict) {
1520 XRenderPictureAttributes pa;
1521 pa.subwindow_mode = IncludeInferiors;
1524 physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1525 physDev->drawable, dst_format->pict_format,
1526 CPSubwindowMode, &pa);
1527 wine_tsx11_unlock();
1529 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1530 physDev->xrender->pict, hdc, physDev->drawable);
1532 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1533 physDev->xrender->pict, hdc, physDev->drawable);
1536 if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1539 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1540 physDev->dc_rect.left, physDev->dc_rect.top,
1541 (XRectangle *)data->Buffer, data->rdh.nCount );
1542 wine_tsx11_unlock();
1543 HeapFree( GetProcessHeap(), 0, data );
1547 EnterCriticalSection(&xrender_cs);
1549 entry = glyphsetCache + physDev->xrender->cache_index;
1550 if( disable_antialias == FALSE )
1551 aa_type = entry->aa_default;
1552 formatEntry = entry->format[aa_type];
1554 for(idx = 0; idx < count; idx++) {
1555 if( !formatEntry ) {
1556 UploadGlyph(physDev, wstr[idx], aa_type);
1557 /* re-evaluate antialias since aa_default may have changed */
1558 if( disable_antialias == FALSE )
1559 aa_type = entry->aa_default;
1560 formatEntry = entry->format[aa_type];
1561 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1562 UploadGlyph(physDev, wstr[idx], aa_type);
1567 WARN("could not upload requested glyphs\n");
1568 LeaveCriticalSection(&xrender_cs);
1572 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1573 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1575 if(X11DRV_XRender_Installed)
1577 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1579 POINT desired, current;
1580 int render_op = PictOpOver;
1582 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1583 So we pass zeros to the function and move to our starting position using the first
1584 element of the elts array. */
1586 desired.x = physDev->dc_rect.left + x;
1587 desired.y = physDev->dc_rect.top + y;
1588 current.x = current.y = 0;
1590 tile_pict = get_tile_pict(dst_format, physDev->textPixel);
1592 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1594 if((dst_format->format == WXR_FORMAT_MONO) && (textPixel == 0))
1595 render_op = PictOpOutReverse; /* This gives us 'black' text */
1597 for(idx = 0; idx < count; idx++)
1599 elts[idx].glyphset = formatEntry->glyphset;
1600 elts[idx].chars = wstr + idx;
1601 elts[idx].nchars = 1;
1602 elts[idx].xOff = desired.x - current.x;
1603 elts[idx].yOff = desired.y - current.y;
1605 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1606 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1610 desired.x += formatEntry->gis[wstr[idx]].xOff;
1611 desired.y += formatEntry->gis[wstr[idx]].yOff;
1615 offset += lpDx[idx];
1616 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1617 desired.y = physDev->dc_rect.top + y - offset * sinEsc;
1621 pXRenderCompositeText16(gdi_display, render_op,
1623 physDev->xrender->pict,
1624 formatEntry->font_format->pict_format,
1625 0, 0, 0, 0, elts, count);
1626 wine_tsx11_unlock();
1627 HeapFree(GetProcessHeap(), 0, elts);
1629 INT offset = 0, xoff = 0, yoff = 0;
1631 XSetForeground( gdi_display, physDev->gc, textPixel );
1633 if(aa_type == AA_None || physDev->depth == 1)
1635 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1637 if(aa_type == AA_None)
1638 sharp_glyph_fn = SharpGlyphMono;
1640 sharp_glyph_fn = SharpGlyphGray;
1642 for(idx = 0; idx < count; idx++) {
1643 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1644 physDev->dc_rect.top + y + yoff,
1645 formatEntry->bitmaps[wstr[idx]],
1646 &formatEntry->gis[wstr[idx]]);
1648 offset += lpDx[idx];
1649 xoff = offset * cosEsc;
1650 yoff = offset * -sinEsc;
1652 xoff += formatEntry->gis[wstr[idx]].xOff;
1653 yoff += formatEntry->gis[wstr[idx]].yOff;
1658 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1659 RECT extents = {0, 0, 0, 0};
1661 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1662 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1664 TRACE("drawable %dx%d\n", w, h);
1666 for(idx = 0; idx < count; idx++) {
1667 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1668 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1669 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1670 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1671 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1672 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1673 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1674 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1676 offset += lpDx[idx];
1677 cur.x = offset * cosEsc;
1678 cur.y = offset * -sinEsc;
1680 cur.x += formatEntry->gis[wstr[idx]].xOff;
1681 cur.y += formatEntry->gis[wstr[idx]].yOff;
1684 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1685 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1687 if(physDev->dc_rect.left + x + extents.left >= 0) {
1688 image_x = physDev->dc_rect.left + x + extents.left;
1692 image_off_x = physDev->dc_rect.left + x + extents.left;
1694 if(physDev->dc_rect.top + y + extents.top >= 0) {
1695 image_y = physDev->dc_rect.top + y + extents.top;
1699 image_off_y = physDev->dc_rect.top + y + extents.top;
1701 if(physDev->dc_rect.left + x + extents.right < w)
1702 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1704 image_w = w - image_x;
1705 if(physDev->dc_rect.top + y + extents.bottom < h)
1706 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1708 image_h = h - image_y;
1710 if(image_w <= 0 || image_h <= 0) goto no_image;
1712 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1713 image = XGetImage(gdi_display, physDev->drawable,
1714 image_x, image_y, image_w, image_h,
1715 AllPlanes, ZPixmap);
1716 X11DRV_check_error();
1718 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1719 gdi_display, (int)physDev->drawable, image_x, image_y,
1720 image_w, image_h, AllPlanes, ZPixmap,
1721 physDev->depth, image);
1723 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
1728 gcv.graphics_exposures = False;
1729 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1730 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1731 image_w, image_h, 0, 0);
1732 XFreeGC(gdi_display, gc);
1733 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1734 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1736 X11DRV_check_error();
1737 XFreePixmap(gdi_display, xpm);
1739 if(!image) goto no_image;
1741 image->red_mask = visual->red_mask;
1742 image->green_mask = visual->green_mask;
1743 image->blue_mask = visual->blue_mask;
1745 offset = xoff = yoff = 0;
1746 for(idx = 0; idx < count; idx++) {
1747 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1748 yoff + image_off_y - extents.top,
1749 formatEntry->bitmaps[wstr[idx]],
1750 &formatEntry->gis[wstr[idx]],
1751 physDev->textPixel);
1753 offset += lpDx[idx];
1754 xoff = offset * cosEsc;
1755 yoff = offset * -sinEsc;
1757 xoff += formatEntry->gis[wstr[idx]].xOff;
1758 yoff += formatEntry->gis[wstr[idx]].yOff;
1761 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1762 image_x, image_y, image_w, image_h);
1763 XDestroyImage(image);
1766 wine_tsx11_unlock();
1768 LeaveCriticalSection(&xrender_cs);
1770 if (flags & ETO_CLIPPED)
1772 /* restore the device region */
1773 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1774 DeleteObject( saved_region );
1780 X11DRV_UnlockDIBSection( physDev, TRUE );
1784 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
1785 static void set_xrender_transformation(Picture src_pict, float xscale, float yscale, int xoffset, int yoffset)
1787 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1788 XTransform xform = {{
1789 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
1790 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
1791 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1794 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1798 /* Helper function for (stretched) blitting using xrender */
1799 static void xrender_blit(Picture src_pict, Picture mask_pict, Picture dst_pict, int x_src, int y_src, float xscale, float yscale, int width, int height)
1801 /* Further down a transformation matrix is used for stretching and mirroring the source data.
1802 * xscale/yscale contain the scaling factors for the width and height. In case of mirroring
1803 * we also need a x- and y-offset because without the pixels will be in the wrong quadrant of the x-y plane.
1805 int x_offset = (xscale<0) ? width : 0;
1806 int y_offset = (yscale<0) ? height : 0;
1808 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1809 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1810 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1811 if(xscale != 1.0 || yscale != 1.0)
1813 /* When we are using a mask, 'src_pict' contains a 1x1 picture for tiling, the actual source data is in mask_pict */
1815 set_xrender_transformation(mask_pict, xscale, yscale, x_offset, y_offset);
1817 set_xrender_transformation(src_pict, xscale, yscale, x_src + x_offset, y_src + y_offset);
1819 pXRenderComposite(gdi_display, PictOpSrc, src_pict, mask_pict, dst_pict, 0, 0, 0, 0, 0, 0, width, height);
1823 /* When we are using a mask, 'src_pict' contains a 1x1 picture for tiling, the actual source data is in mask_pict */
1825 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
1827 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1829 pXRenderComposite(gdi_display, PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, 0, 0, 0, 0, width, height);
1833 /******************************************************************************
1834 * AlphaBlend (x11drv.@)
1836 BOOL CDECL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1837 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1838 BLENDFUNCTION blendfn)
1840 XRenderPictureAttributes pa;
1841 Picture dst_pict, src_pict;
1847 DWORD *dstbits, *data;
1850 BOOL top_down = FALSE;
1852 WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(devDst->depth, devDst->color_shifts);
1853 WineXRenderFormat *src_format;
1856 if(!X11DRV_XRender_Installed) {
1857 FIXME("Unable to AlphaBlend without Xrender\n");
1862 pts[1].x = xDst + widthDst;
1863 pts[1].y = yDst + heightDst;
1864 LPtoDP(devDst->hdc, pts, 2);
1867 widthDst = pts[1].x - pts[0].x;
1868 heightDst = pts[1].y - pts[0].y;
1872 pts[1].x = xSrc + widthSrc;
1873 pts[1].y = ySrc + heightSrc;
1874 LPtoDP(devSrc->hdc, pts, 2);
1877 widthSrc = pts[1].x - pts[0].x;
1878 heightSrc = pts[1].y - pts[0].y;
1879 if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1881 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1882 if(widthDst != widthSrc || heightDst != heightSrc)
1884 if(!pXRenderSetPictureTransform)
1887 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1891 if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1893 static BOOL out = FALSE;
1896 FIXME("not a dibsection\n");
1902 /* If the source is a 1x1 bitmap, tiling is equivalent to stretching, but
1903 tiling is much faster. Therefore, we do no stretching in this case. */
1904 repeat_src = dib.dsBmih.biWidth == 1 && abs(dib.dsBmih.biHeight) == 1;
1906 if (xSrc < 0 || ySrc < 0 || widthSrc < 0 || heightSrc < 0 || xSrc + widthSrc > dib.dsBmih.biWidth
1907 || ySrc + heightSrc > abs(dib.dsBmih.biHeight))
1909 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc, ySrc, widthSrc, heightSrc);
1910 SetLastError(ERROR_INVALID_PARAMETER);
1914 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && blendfn.SourceConstantAlpha != 0xff)
1915 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn.SourceConstantAlpha);
1917 if(dib.dsBm.bmBitsPixel != 32) {
1918 FIXME("not a 32 bpp dibsection\n");
1921 dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1923 if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1925 dstbits += widthSrc * (heightSrc - 1);
1927 y = y2 + heightSrc - 1;
1931 y = dib.dsBmih.biHeight - ySrc - 1;
1932 y2 = y - heightSrc + 1;
1935 if (blendfn.AlphaFormat & AC_SRC_ALPHA)
1939 memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1941 dstbits += (top_down ? -1 : 1) * widthSrc;
1946 DWORD source_alpha = (DWORD)blendfn.SourceConstantAlpha << 24;
1951 DWORD *srcbits = (DWORD *)((char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes) + xSrc;
1952 for (x = 0; x < widthSrc; x++)
1954 DWORD argb = *srcbits++;
1955 argb = (argb & 0xffffff) | source_alpha;
1958 if (top_down) /* we traversed the row forward so we should go back by two rows */
1959 dstbits -= 2 * widthSrc;
1964 rgndata = X11DRV_GetRegionData( devDst->region, 0 );
1967 image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1968 (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1970 src_format = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1971 TRACE("src_format %p\n", src_format);
1974 WARN("Unable to find a picture format supporting alpha, make sure X is running at 24-bit\n");
1978 pa.subwindow_mode = IncludeInferiors;
1979 pa.repeat = repeat_src ? RepeatNormal : RepeatNone;
1981 /* FIXME use devDst->xrender->pict ? */
1982 dst_pict = pXRenderCreatePicture(gdi_display,
1984 dst_format->pict_format,
1985 CPSubwindowMode, &pa);
1986 TRACE("dst_pict %08lx\n", dst_pict);
1987 TRACE("src_drawable = %08lx\n", devSrc->drawable);
1988 xpm = XCreatePixmap(gdi_display,
1990 widthSrc, heightSrc, 32);
1991 gcv.graphics_exposures = False;
1992 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1993 TRACE("xpm = %08lx\n", xpm);
1994 XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1996 src_pict = pXRenderCreatePicture(gdi_display,
1997 xpm, src_format->pict_format,
1998 CPSubwindowMode|CPRepeat, &pa);
1999 TRACE("src_pict %08lx\n", src_pict);
2003 pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
2004 devDst->dc_rect.left, devDst->dc_rect.top,
2005 (XRectangle *)rgndata->Buffer,
2006 rgndata->rdh.nCount );
2007 HeapFree( GetProcessHeap(), 0, rgndata );
2010 /* Make sure we ALWAYS set the transformation matrix even if we don't need to scale. The reason is
2011 * that later on we want to reuse pictures (it can bring a lot of extra performance) and each time
2012 * a different transformation matrix might have been used. */
2014 set_xrender_transformation(src_pict, 1.0, 1.0, 0, 0);
2016 set_xrender_transformation(src_pict, widthSrc/(double)widthDst, heightSrc/(double)heightDst, 0, 0);
2017 pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
2019 xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
2022 pXRenderFreePicture(gdi_display, src_pict);
2023 XFreePixmap(gdi_display, xpm);
2024 XFreeGC(gdi_display, gc);
2025 pXRenderFreePicture(gdi_display, dst_pict);
2027 XDestroyImage(image);
2029 wine_tsx11_unlock();
2030 HeapFree(GetProcessHeap(), 0, data);
2034 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2036 /* 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 */
2037 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2040 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2042 /* Use XCopyArea when the physBitmap and brush.pixmap have the same depth. */
2043 if(physBitmap->pixmap_depth == 1 || physDev->depth == physBitmap->pixmap_depth)
2045 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2046 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2048 else /* We meed depth conversion */
2050 WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2051 WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2053 Picture src_pict, dst_pict;
2054 XRenderPictureAttributes pa;
2055 pa.subwindow_mode = IncludeInferiors;
2056 pa.repeat = RepeatNone;
2058 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2059 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2061 xrender_blit(src_pict, 0, dst_pict, 0, 0, 1.0, 1.0, width, height);
2062 pXRenderFreePicture(gdi_display, src_pict);
2063 pXRenderFreePicture(gdi_display, dst_pict);
2065 wine_tsx11_unlock();
2068 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2069 Pixmap pixmap, GC gc,
2070 INT widthSrc, INT heightSrc,
2071 INT widthDst, INT heightDst,
2072 RECT *visRectSrc, RECT *visRectDst )
2074 BOOL stretch = (widthSrc != widthDst) || (heightSrc != heightDst);
2075 int width = visRectDst->right - visRectDst->left;
2076 int height = visRectDst->bottom - visRectDst->top;
2077 int x_src = physDevSrc->dc_rect.left + visRectSrc->left;
2078 int y_src = physDevSrc->dc_rect.top + visRectSrc->top;
2079 WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physDevSrc->depth, physDevSrc->color_shifts);
2080 WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDevDst->depth, physDevDst->color_shifts);
2081 Picture src_pict=0, dst_pict=0, mask_pict=0;
2083 double xscale = widthSrc/(double)widthDst;
2084 double yscale = heightSrc/(double)heightDst;
2086 XRenderPictureAttributes pa;
2087 pa.subwindow_mode = IncludeInferiors;
2088 pa.repeat = RepeatNone;
2090 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n", physDevSrc->depth, widthSrc, heightSrc, x_src, y_src);
2091 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst->depth, widthDst, heightDst);
2093 if(!X11DRV_XRender_Installed)
2095 TRACE("Not using XRender since it is not available or disabled\n");
2099 /* XRender can't handle palettes, so abort */
2100 if(X11DRV_PALETTE_XPixelToPalette)
2103 /* XRender is of no use in this case */
2104 if((physDevDst->depth == 1) && (physDevSrc->depth > 1))
2107 /* Just use traditional X copy when the depths match and we don't need stretching */
2108 if((physDevSrc->depth == physDevDst->depth) && !stretch)
2110 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2112 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
2113 wine_tsx11_unlock();
2118 if(physDevSrc->depth == 1)
2121 get_xrender_color(dst_format, physDevDst->textPixel, &col);
2123 /* We use the source drawable as a mask */
2125 mask_pict = pXRenderCreatePicture(gdi_display, physDevSrc->drawable, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2127 /* Use backgroundPixel as the foreground color */
2128 src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
2130 /* Create a destination picture and fill it with textPixel color as the background color */
2131 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2132 pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height);
2134 xrender_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
2136 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2137 if(mask_pict) pXRenderFreePicture(gdi_display, mask_pict);
2138 wine_tsx11_unlock();
2140 else /* color -> color but with different depths */
2143 src_pict = pXRenderCreatePicture(gdi_display,
2144 physDevSrc->drawable, src_format->pict_format,
2145 CPSubwindowMode|CPRepeat, &pa);
2147 dst_pict = pXRenderCreatePicture(gdi_display,
2148 pixmap, dst_format->pict_format,
2149 CPSubwindowMode|CPRepeat, &pa);
2151 xrender_blit(src_pict, 0, dst_pict, x_src, y_src, xscale, yscale, width, height);
2153 if(src_pict) pXRenderFreePicture(gdi_display, src_pict);
2154 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2155 wine_tsx11_unlock();
2160 #else /* SONAME_LIBXRENDER */
2162 void X11DRV_XRender_Init(void)
2164 TRACE("XRender support not compiled in.\n");
2168 void X11DRV_XRender_Finalize(void)
2172 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
2178 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
2184 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
2185 const RECT *lprect, LPCWSTR wstr, UINT count,
2192 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
2198 /******************************************************************************
2199 * AlphaBlend (x11drv.@)
2201 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
2202 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
2203 BLENDFUNCTION blendfn)
2205 FIXME("not supported - XRENDER headers were missing at compile time\n");
2209 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2212 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
2214 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2215 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2216 wine_tsx11_unlock();
2219 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, const DIBSECTION *dib)
2224 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2225 Pixmap pixmap, GC gc,
2226 INT widthSrc, INT heightSrc,
2227 INT widthDst, INT heightDst,
2228 RECT *visRectSrc, RECT *visRectDst )
2232 #endif /* SONAME_LIBXRENDER */