2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
7 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
35 #include "wine/library.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 int using_client_side_fonts = FALSE;
41 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
43 #ifdef SONAME_LIBXRENDER
45 static BOOL X11DRV_XRender_Installed = FALSE;
48 #include <X11/extensions/Xrender.h>
50 #ifndef RepeatNone /* added in 0.10 */
52 #define RepeatNormal 1
54 #define RepeatReflect 3
57 #define MAX_FORMATS 10
58 typedef enum wine_xrformat
72 typedef struct wine_xrender_format_template
77 unsigned int alphaMask;
81 unsigned int greenMask;
83 unsigned int blueMask;
84 } WineXRenderFormatTemplate;
86 static const WineXRenderFormatTemplate wxr_formats_template[] =
88 /* Format depth alpha mask red mask green mask blue mask*/
89 {WXR_FORMAT_MONO, 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
90 {WXR_FORMAT_GRAY, 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
91 {WXR_FORMAT_X1R5G5B5, 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
92 {WXR_FORMAT_X1B5G5R5, 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
93 {WXR_FORMAT_R5G6B5, 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
94 {WXR_FORMAT_B5G6R5, 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
95 {WXR_FORMAT_R8G8B8, 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
96 {WXR_FORMAT_B8G8R8, 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
97 {WXR_FORMAT_A8R8G8B8, 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
98 {WXR_FORMAT_X8R8G8B8, 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff }
101 typedef struct wine_xrender_format
104 XRenderPictFormat *pict_format;
107 static WineXRenderFormat wxr_formats[MAX_FORMATS];
108 static int WineXRenderFormatsListSize = 0;
109 static WineXRenderFormat *default_format = NULL;
115 SIZE devsize; /* size in device coords */
119 #define INITIAL_REALIZED_BUF_SIZE 128
121 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
126 WineXRenderFormat *font_format;
131 } gsCacheEntryFormat;
137 gsCacheEntryFormat * format[AA_MAXVALUE];
142 struct tagXRENDERINFO
149 static gsCacheEntry *glyphsetCache = NULL;
150 static DWORD glyphsetCacheSize = 0;
151 static INT lastfree = -1;
154 #define INIT_CACHE_SIZE 10
156 static int antialias = 1;
158 static void *xrender_handle;
160 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
161 MAKE_FUNCPTR(XRenderAddGlyphs)
162 MAKE_FUNCPTR(XRenderComposite)
163 MAKE_FUNCPTR(XRenderCompositeString8)
164 MAKE_FUNCPTR(XRenderCompositeString16)
165 MAKE_FUNCPTR(XRenderCompositeString32)
166 MAKE_FUNCPTR(XRenderCompositeText16)
167 MAKE_FUNCPTR(XRenderCreateGlyphSet)
168 MAKE_FUNCPTR(XRenderCreatePicture)
169 MAKE_FUNCPTR(XRenderFillRectangle)
170 MAKE_FUNCPTR(XRenderFindFormat)
171 MAKE_FUNCPTR(XRenderFindVisualFormat)
172 MAKE_FUNCPTR(XRenderFreeGlyphSet)
173 MAKE_FUNCPTR(XRenderFreePicture)
174 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
175 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
176 MAKE_FUNCPTR(XRenderSetPictureTransform)
178 MAKE_FUNCPTR(XRenderQueryExtension)
181 static CRITICAL_SECTION xrender_cs;
182 static CRITICAL_SECTION_DEBUG critsect_debug =
185 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
186 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
188 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
190 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
191 ( ( (ULONG)_x4 << 24 ) | \
192 ( (ULONG)_x3 << 16 ) | \
193 ( (ULONG)_x2 << 8 ) | \
196 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
198 #define GASP_GRIDFIT 0x01
199 #define GASP_DOGRAY 0x02
201 #ifdef WORDS_BIGENDIAN
202 #define get_be_word(x) (x)
203 #define NATIVE_BYTE_ORDER MSBFirst
205 #define get_be_word(x) RtlUshortByteSwap(x)
206 #define NATIVE_BYTE_ORDER LSBFirst
209 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
212 templ->type = PictTypeDirect;
213 templ->depth = fmt->depth;
214 templ->direct.alpha = fmt->alpha;
215 templ->direct.alphaMask = fmt->alphaMask;
216 templ->direct.red = fmt->red;
217 templ->direct.redMask = fmt->redMask;
218 templ->direct.green = fmt->green;
219 templ->direct.greenMask = fmt->greenMask;
220 templ->direct.blue = fmt->blue;
221 templ->direct.blueMask = fmt->blueMask;
224 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
229 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
231 if(fmt->depth != screen_depth)
233 if( (fmt->redMask << fmt->red) != visual->red_mask)
235 if( (fmt->greenMask << fmt->green) != visual->green_mask)
237 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
240 /* We never select a default ARGB visual */
247 static int load_xrender_formats(void)
250 for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
252 XRenderPictFormat templ, *pict_format;
254 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
257 pict_format = pXRenderFindVisualFormat(gdi_display, visual);
260 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
261 if (visual->class == DirectColor)
264 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
265 screen_depth, TrueColor, &info ))
267 pict_format = pXRenderFindVisualFormat(gdi_display, info.visual);
268 if (pict_format) visual = info.visual;
276 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
277 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
278 default_format = &wxr_formats[WineXRenderFormatsListSize];
279 WineXRenderFormatsListSize++;
280 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
285 unsigned long mask = 0;
286 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
289 pict_format = pXRenderFindFormat(gdi_display, mask, &templ, 0);
294 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
295 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
296 WineXRenderFormatsListSize++;
297 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
301 return WineXRenderFormatsListSize;
304 /***********************************************************************
305 * X11DRV_XRender_Init
307 * Let's see if our XServer has the extension available
310 void X11DRV_XRender_Init(void)
314 if (client_side_with_render &&
315 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
316 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
317 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
320 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
321 LOAD_FUNCPTR(XRenderAddGlyphs)
322 LOAD_FUNCPTR(XRenderComposite)
323 LOAD_FUNCPTR(XRenderCompositeString8)
324 LOAD_FUNCPTR(XRenderCompositeString16)
325 LOAD_FUNCPTR(XRenderCompositeString32)
326 LOAD_FUNCPTR(XRenderCompositeText16)
327 LOAD_FUNCPTR(XRenderCreateGlyphSet)
328 LOAD_FUNCPTR(XRenderCreatePicture)
329 LOAD_FUNCPTR(XRenderFillRectangle)
330 LOAD_FUNCPTR(XRenderFindFormat)
331 LOAD_FUNCPTR(XRenderFindVisualFormat)
332 LOAD_FUNCPTR(XRenderFreeGlyphSet)
333 LOAD_FUNCPTR(XRenderFreePicture)
334 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
335 LOAD_FUNCPTR(XRenderQueryExtension)
337 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
338 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
339 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
340 #undef LOAD_OPTIONAL_FUNCPTR
344 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
346 if(X11DRV_XRender_Installed) {
347 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
348 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
352 "Wine has detected that you probably have a buggy version\n"
353 "of libXrender.so . Because of this client side font rendering\n"
354 "will be disabled. Please upgrade this library.\n");
355 X11DRV_XRender_Installed = FALSE;
359 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
360 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
361 X11DRV_XRender_Installed = FALSE;
367 if(X11DRV_XRender_Installed || client_side_with_core)
369 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
370 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
372 glyphsetCacheSize = INIT_CACHE_SIZE;
374 for(i = 0; i < INIT_CACHE_SIZE; i++) {
375 glyphsetCache[i].next = i + 1;
376 glyphsetCache[i].count = -1;
378 glyphsetCache[i-1].next = -1;
379 using_client_side_fonts = 1;
381 if(!X11DRV_XRender_Installed) {
382 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
383 if(screen_depth <= 8 || !client_side_antialias_with_core)
386 if(screen_depth <= 8 || !client_side_antialias_with_render)
390 else TRACE("Using X11 core fonts\n");
393 static WineXRenderFormat *get_xrender_format(WXRFormat format)
396 for(i=0; i<WineXRenderFormatsListSize; i++)
398 if(wxr_formats[i].format == format)
400 TRACE("Returning wxr_format=%#x\n", format);
401 return &wxr_formats[i];
407 static WineXRenderFormat *get_xrender_format_from_pdevice(X11DRV_PDEVICE *physDev)
411 switch(physDev->depth)
414 format = WXR_FORMAT_MONO;
417 /* For now fall back to the format of the default visual.
418 In the future we should check if we are using a DDB/DIB and what exact format we need.
420 return default_format;
423 return get_xrender_format(format);
426 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
428 if(p1->hash != p2->hash) return TRUE;
429 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
430 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
431 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
432 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
436 static void walk_cache(void)
440 EnterCriticalSection(&xrender_cs);
441 for(i=mru; i >= 0; i = glyphsetCache[i].next)
442 TRACE("item %d\n", i);
443 LeaveCriticalSection(&xrender_cs);
447 static int LookupEntry(LFANDSIZE *plfsz)
451 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
453 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
458 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
459 glyphsetCache[i].count++;
461 glyphsetCache[prev_i].next = glyphsetCache[i].next;
462 glyphsetCache[i].next = mru;
465 TRACE("found font in cache %d\n", i);
470 TRACE("font not in cache\n");
474 static void FreeEntry(int entry)
478 for(format = 0; format < AA_MAXVALUE; format++) {
479 gsCacheEntryFormat * formatEntry;
481 if( !glyphsetCache[entry].format[format] )
484 formatEntry = glyphsetCache[entry].format[format];
486 if(formatEntry->glyphset) {
488 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
490 formatEntry->glyphset = 0;
492 if(formatEntry->nrealized) {
493 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
494 formatEntry->realized = NULL;
495 if(formatEntry->bitmaps) {
496 for(i = 0; i < formatEntry->nrealized; i++)
497 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
498 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
499 formatEntry->bitmaps = NULL;
501 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
502 formatEntry->gis = NULL;
503 formatEntry->nrealized = 0;
506 HeapFree(GetProcessHeap(), 0, formatEntry);
507 glyphsetCache[entry].format[format] = NULL;
511 static int AllocEntry(void)
513 int best = -1, prev_best = -1, i, prev_i = -1;
516 assert(glyphsetCache[lastfree].count == -1);
517 glyphsetCache[lastfree].count = 1;
519 lastfree = glyphsetCache[lastfree].next;
521 glyphsetCache[best].next = mru;
524 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
528 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
529 if(glyphsetCache[i].count == 0) {
537 TRACE("freeing unused glyphset at cache %d\n", best);
539 glyphsetCache[best].count = 1;
541 glyphsetCache[prev_best].next = glyphsetCache[best].next;
542 glyphsetCache[best].next = mru;
550 TRACE("Growing cache\n");
553 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
555 (glyphsetCacheSize + INIT_CACHE_SIZE)
556 * sizeof(*glyphsetCache));
558 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
559 (glyphsetCacheSize + INIT_CACHE_SIZE)
560 * sizeof(*glyphsetCache));
562 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
564 glyphsetCache[i].next = i + 1;
565 glyphsetCache[i].count = -1;
567 glyphsetCache[i-1].next = -1;
568 glyphsetCacheSize += INIT_CACHE_SIZE;
570 lastfree = glyphsetCache[best].next;
571 glyphsetCache[best].count = 1;
572 glyphsetCache[best].next = mru;
574 TRACE("new free cache slot at %d\n", mru);
578 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
588 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
589 if(size == GDI_ERROR)
592 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
593 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
595 GetTextMetricsW(physDev->hdc, &tm);
596 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
599 num_recs = get_be_word(*gasp);
603 *flags = get_be_word(*(gasp + 1));
604 if(ppem <= get_be_word(*gasp))
608 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
610 HeapFree(GetProcessHeap(), 0, buffer);
614 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
618 UINT font_smoothing_type, font_smoothing_orientation;
620 if (X11DRV_XRender_Installed && subpixel &&
621 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
622 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
624 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
625 &font_smoothing_orientation, 0) &&
626 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
633 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
634 But, Wine's subpixel rendering can support the portrait mode.
637 else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
645 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
650 static int hinter = -1;
651 static int subpixel = -1;
654 if((ret = LookupEntry(plfsz)) != -1) return ret;
657 entry = glyphsetCache + ret;
658 entry->lfsz = *plfsz;
659 for( format = 0; format < AA_MAXVALUE; format++ ) {
660 assert( !entry->format[format] );
663 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
665 if(hinter == -1 || subpixel == -1)
667 RASTERIZER_STATUS status;
668 GetRasterizerCaps(&status, sizeof(status));
669 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
670 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
673 switch (plfsz->lf.lfQuality)
675 case ANTIALIASED_QUALITY:
676 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
678 case CLEARTYPE_QUALITY:
679 case CLEARTYPE_NATURAL_QUALITY:
680 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
682 case DEFAULT_QUALITY:
686 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
689 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
692 entry->aa_default = AA_None;
697 entry->aa_default = AA_None;
702 static void dec_ref_cache(int index)
705 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
706 assert(glyphsetCache[index].count > 0);
707 glyphsetCache[index].count--;
710 static void lfsz_calc_hash(LFANDSIZE *plfsz)
712 DWORD hash = 0, *ptr, two_chars;
716 hash ^= plfsz->devsize.cx;
717 hash ^= plfsz->devsize.cy;
718 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
720 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
722 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
724 pwc = (WCHAR *)&two_chars;
726 *pwc = toupperW(*pwc);
728 *pwc = toupperW(*pwc);
736 /***********************************************************************
737 * X11DRV_XRender_Finalize
739 void X11DRV_XRender_Finalize(void)
743 EnterCriticalSection(&xrender_cs);
744 for(i = mru; i >= 0; i = glyphsetCache[i].next)
746 LeaveCriticalSection(&xrender_cs);
750 /***********************************************************************
751 * X11DRV_XRender_SelectFont
753 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
757 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
758 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
759 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
760 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
761 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
762 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
763 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
764 GetWorldTransform( physDev->hdc, &lfsz.xform );
765 lfsz_calc_hash(&lfsz);
767 EnterCriticalSection(&xrender_cs);
768 if(!physDev->xrender) {
769 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
770 sizeof(*physDev->xrender));
771 physDev->xrender->cache_index = -1;
773 else if(physDev->xrender->cache_index != -1)
774 dec_ref_cache(physDev->xrender->cache_index);
775 physDev->xrender->cache_index = GetCacheEntry(physDev, &lfsz);
776 LeaveCriticalSection(&xrender_cs);
780 /***********************************************************************
781 * X11DRV_XRender_DeleteDC
783 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
785 X11DRV_XRender_UpdateDrawable(physDev);
787 EnterCriticalSection(&xrender_cs);
788 if(physDev->xrender->cache_index != -1)
789 dec_ref_cache(physDev->xrender->cache_index);
790 LeaveCriticalSection(&xrender_cs);
792 HeapFree(GetProcessHeap(), 0, physDev->xrender);
793 physDev->xrender = NULL;
797 /***********************************************************************
798 * X11DRV_XRender_UpdateDrawable
800 * Deletes the pict and tile when the drawable changes.
802 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
806 if(physDev->xrender->pict)
808 TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
810 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
811 physDev->xrender->pict = 0;
818 /************************************************************************
821 * Helper to ExtTextOut. Must be called inside xrender_cs
823 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
830 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
831 gsCacheEntryFormat *formatEntry;
832 UINT ggo_format = GGO_GLYPH_INDEX;
833 WXRFormat wxr_format;
834 static const char zero[4];
835 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
839 ggo_format |= WINE_GGO_GRAY16_BITMAP;
842 ggo_format |= WINE_GGO_HRGB_BITMAP;
845 ggo_format |= WINE_GGO_HBGR_BITMAP;
848 ggo_format |= WINE_GGO_VRGB_BITMAP;
851 ggo_format |= WINE_GGO_VBGR_BITMAP;
855 ERR("aa = %d - not implemented\n", format);
857 ggo_format |= GGO_BITMAP;
861 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
862 if(buflen == GDI_ERROR) {
863 if(format != AA_None) {
865 entry->aa_default = AA_None;
866 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
867 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
869 if(buflen == GDI_ERROR) {
870 WARN("GetGlyphOutlineW failed\n");
873 TRACE("Turning off antialiasing for this monochrome font\n");
876 /* If there is nothing for the current type, we create the entry. */
877 if( !entry->format[format] ) {
878 entry->format[format] = HeapAlloc(GetProcessHeap(),
880 sizeof(gsCacheEntryFormat));
882 formatEntry = entry->format[format];
884 if(formatEntry->nrealized <= glyph) {
885 formatEntry->nrealized = (glyph / 128 + 1) * 128;
887 if (formatEntry->realized)
888 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
890 formatEntry->realized,
891 formatEntry->nrealized * sizeof(BOOL));
893 formatEntry->realized = HeapAlloc(GetProcessHeap(),
895 formatEntry->nrealized * sizeof(BOOL));
897 if(!X11DRV_XRender_Installed) {
898 if (formatEntry->bitmaps)
899 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
901 formatEntry->bitmaps,
902 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
904 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
906 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
908 if (formatEntry->gis)
909 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
912 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
914 formatEntry->gis = HeapAlloc(GetProcessHeap(),
916 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
920 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
923 wxr_format = WXR_FORMAT_GRAY;
930 wxr_format = WXR_FORMAT_A8R8G8B8;
934 ERR("aa = %d - not implemented\n", format);
936 wxr_format = WXR_FORMAT_MONO;
941 formatEntry->font_format = get_xrender_format(wxr_format);
942 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
947 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
948 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
949 formatEntry->realized[glyph] = TRUE;
951 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
953 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
954 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
956 gi.width = gm.gmBlackBoxX;
957 gi.height = gm.gmBlackBoxY;
958 gi.x = -gm.gmptGlyphOrigin.x;
959 gi.y = gm.gmptGlyphOrigin.y;
960 gi.xOff = gm.gmCellIncX;
961 gi.yOff = gm.gmCellIncY;
963 if(TRACE_ON(xrender)) {
968 if(format == AA_None) {
969 pitch = ((gi.width + 31) / 32) * 4;
970 for(i = 0; i < gi.height; i++) {
971 line = (unsigned char*) buf + i * pitch;
973 for(j = 0; j < pitch * 8; j++) {
974 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
976 TRACE("%s\n", output);
979 static const char blks[] = " .:;!o*#";
983 pitch = ((gi.width + 3) / 4) * 4;
984 for(i = 0; i < gi.height; i++) {
985 line = (unsigned char*) buf + i * pitch;
987 for(j = 0; j < pitch; j++) {
988 str[0] = blks[line[j] >> 5];
991 TRACE("%s\n", output);
997 if(formatEntry->glyphset) {
998 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
999 unsigned char *byte = (unsigned char*) buf, c;
1005 /* magic to flip bit order */
1006 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1007 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1008 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1013 else if ( format != AA_Grey &&
1014 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1016 unsigned int i, *data = (unsigned int *)buf;
1017 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1022 XRenderCompositeText seems to ignore 0x0 glyphs when
1023 AA_None, which means we lose the advance width of glyphs
1024 like the space. We'll pretend that such glyphs are 1x1
1029 gi.width = gi.height = 1;
1032 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1033 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1034 wine_tsx11_unlock();
1035 HeapFree(GetProcessHeap(), 0, buf);
1037 formatEntry->bitmaps[glyph] = buf;
1040 formatEntry->gis[glyph] = gi;
1045 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
1046 void *bitmap, XGlyphInfo *gi)
1048 unsigned char *srcLine = bitmap, *src;
1049 unsigned char bits, bitsMask;
1050 int width = gi->width;
1051 int stride = ((width + 31) & ~31) >> 3;
1052 int height = gi->height;
1056 TRACE("%d, %d\n", x, y);
1065 bitsMask = 0x80; /* FreeType is always MSB first */
1071 if (bits & bitsMask)
1079 bitsMask = bitsMask >> 1;
1085 } while (bits & bitsMask);
1086 XFillRectangle (gdi_display, physDev->drawable,
1087 physDev->gc, xspan, y, lenspan, 1);
1099 bitsMask = bitsMask >> 1;
1105 } while (!(bits & bitsMask));
1112 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
1113 void *bitmap, XGlyphInfo *gi)
1115 unsigned char *srcLine = bitmap, *src, bits;
1116 int width = gi->width;
1117 int stride = ((width + 3) & ~3);
1118 int height = gi->height;
1143 } while (bits >= 0x80);
1144 XFillRectangle (gdi_display, physDev->drawable,
1145 physDev->gc, xspan, y, lenspan, 1);
1158 } while (bits < 0x80);
1166 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1171 while ((mask & 1) == 0)
1177 while ((mask & 1) == 1)
1186 static DWORD GetField (DWORD pixel, int shift, int len)
1188 pixel = pixel & (((1 << (len)) - 1) << shift);
1189 pixel = pixel << (32 - (shift + len)) >> 24;
1192 pixel |= (pixel >> len);
1199 static DWORD PutField (DWORD pixel, int shift, int len)
1201 shift = shift - (8 - len);
1203 pixel &= (((1 << len) - 1) << (8 - len));
1211 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1217 BYTE *maskLine, *mask, m;
1222 BYTE src_r, src_g, src_b;
1227 height = gi->height;
1230 maskStride = (width + 3) & ~3;
1232 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1233 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1234 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1236 src_r = GetField(color, r_shift, r_len);
1237 src_g = GetField(color, g_shift, g_len);
1238 src_b = GetField(color, b_shift, b_len);
1240 for(; height--; y++)
1243 maskLine += maskStride;
1248 if(y >= image->height) break;
1252 if(tx >= image->width) break;
1255 if(tx < 0) continue;
1258 XPutPixel (image, tx, y, color);
1263 pixel = XGetPixel (image, tx, y);
1265 r = GetField(pixel, r_shift, r_len);
1266 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1267 g = GetField(pixel, g_shift, g_len);
1268 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1269 b = GetField(pixel, b_shift, b_len);
1270 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1272 pixel = (PutField (r, r_shift, r_len) |
1273 PutField (g, g_shift, g_len) |
1274 PutField (b, b_shift, b_len));
1275 XPutPixel (image, tx, y, pixel);
1281 /*************************************************************
1284 * Returns an appropriate Picture for tiling the text colour.
1285 * Call and use result within the xrender_cs
1287 static Picture get_tile_pict(WineXRenderFormat *wxr_format, int text_pixel)
1294 } tiles[MAX_FORMATS], *tile;
1297 tile = &tiles[wxr_format->format];
1301 XRenderPictureAttributes pa;
1304 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1306 pa.repeat = RepeatNormal;
1307 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1308 wine_tsx11_unlock();
1310 /* init current_color to something different from text_pixel */
1311 tile->current_color = ~text_pixel;
1313 if(wxr_format->format == WXR_FORMAT_MONO)
1315 /* for a 1bpp bitmap we always need a 1 in the tile */
1316 col.red = col.green = col.blue = 0;
1319 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1320 wine_tsx11_unlock();
1324 if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1326 /* Map 0 -- 0xff onto 0 -- 0xffff */
1331 ExamineBitfield (visual->red_mask, &r_shift, &r_len );
1332 ExamineBitfield (visual->green_mask, &g_shift, &g_len);
1333 ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
1335 col.red = GetField(text_pixel, r_shift, r_len);
1336 col.red |= col.red << 8;
1337 col.green = GetField(text_pixel, g_shift, g_len);
1338 col.green |= col.green << 8;
1339 col.blue = GetField(text_pixel, b_shift, b_len);
1340 col.blue |= col.blue << 8;
1344 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1345 wine_tsx11_unlock();
1346 tile->current_color = text_pixel;
1351 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1356 /***********************************************************************
1357 * X11DRV_XRender_ExtTextOut
1359 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1360 const RECT *lprect, LPCWSTR wstr, UINT count,
1365 gsCacheEntry *entry;
1366 gsCacheEntryFormat *formatEntry;
1368 HDC hdc = physDev->hdc;
1369 int textPixel, backgroundPixel;
1370 HRGN saved_region = 0;
1371 BOOL disable_antialias = FALSE;
1372 AA_Type aa_type = AA_None;
1375 double cosEsc, sinEsc;
1377 WineXRenderFormat *dst_format = get_xrender_format_from_pdevice(physDev);
1378 Picture tile_pict = 0;
1380 /* Do we need to disable antialiasing because of palette mode? */
1381 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1382 TRACE("bitmap is not a DIB\n");
1384 else if (bmp.dsBmih.biBitCount <= 8) {
1385 TRACE("Disabling antialiasing\n");
1386 disable_antialias = TRUE;
1389 xgcval.function = GXcopy;
1390 xgcval.background = physDev->backgroundPixel;
1391 xgcval.fill_style = FillSolid;
1393 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1394 wine_tsx11_unlock();
1396 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1398 if(physDev->depth == 1) {
1399 if((physDev->textPixel & 0xffffff) == 0) {
1401 backgroundPixel = 1;
1404 backgroundPixel = 0;
1407 textPixel = physDev->textPixel;
1408 backgroundPixel = physDev->backgroundPixel;
1411 if(flags & ETO_OPAQUE)
1414 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1415 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1416 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1417 lprect->right - lprect->left, lprect->bottom - lprect->top );
1418 wine_tsx11_unlock();
1428 GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1429 if(lf.lfEscapement != 0) {
1430 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1431 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1437 if (flags & ETO_CLIPPED)
1441 clip_region = CreateRectRgnIndirect( lprect );
1442 /* make a copy of the current device region */
1443 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1444 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1445 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1446 DeleteObject( clip_region );
1449 if(X11DRV_XRender_Installed) {
1450 if(!physDev->xrender->pict) {
1451 XRenderPictureAttributes pa;
1452 pa.subwindow_mode = IncludeInferiors;
1455 physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1456 physDev->drawable, dst_format->pict_format,
1457 CPSubwindowMode, &pa);
1458 wine_tsx11_unlock();
1460 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1461 physDev->xrender->pict, hdc, physDev->drawable);
1463 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1464 physDev->xrender->pict, hdc, physDev->drawable);
1467 if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1470 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1471 physDev->dc_rect.left, physDev->dc_rect.top,
1472 (XRectangle *)data->Buffer, data->rdh.nCount );
1473 wine_tsx11_unlock();
1474 HeapFree( GetProcessHeap(), 0, data );
1478 EnterCriticalSection(&xrender_cs);
1480 entry = glyphsetCache + physDev->xrender->cache_index;
1481 if( disable_antialias == FALSE )
1482 aa_type = entry->aa_default;
1483 formatEntry = entry->format[aa_type];
1485 for(idx = 0; idx < count; idx++) {
1486 if( !formatEntry ) {
1487 UploadGlyph(physDev, wstr[idx], aa_type);
1488 /* re-evaluate antialias since aa_default may have changed */
1489 if( disable_antialias == FALSE )
1490 aa_type = entry->aa_default;
1491 formatEntry = entry->format[aa_type];
1492 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1493 UploadGlyph(physDev, wstr[idx], aa_type);
1498 WARN("could not upload requested glyphs\n");
1499 LeaveCriticalSection(&xrender_cs);
1503 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1504 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1506 if(X11DRV_XRender_Installed)
1508 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1510 POINT desired, current;
1511 int render_op = PictOpOver;
1513 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1514 So we pass zeros to the function and move to our starting position using the first
1515 element of the elts array. */
1517 desired.x = physDev->dc_rect.left + x;
1518 desired.y = physDev->dc_rect.top + y;
1519 current.x = current.y = 0;
1521 tile_pict = get_tile_pict(dst_format, physDev->textPixel);
1523 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1525 if((dst_format->format == WXR_FORMAT_MONO) && (textPixel == 0))
1526 render_op = PictOpOutReverse; /* This gives us 'black' text */
1528 for(idx = 0; idx < count; idx++)
1530 elts[idx].glyphset = formatEntry->glyphset;
1531 elts[idx].chars = wstr + idx;
1532 elts[idx].nchars = 1;
1533 elts[idx].xOff = desired.x - current.x;
1534 elts[idx].yOff = desired.y - current.y;
1536 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1537 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1541 desired.x += formatEntry->gis[wstr[idx]].xOff;
1542 desired.y += formatEntry->gis[wstr[idx]].yOff;
1546 offset += lpDx[idx];
1547 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1548 desired.y = physDev->dc_rect.top + y - offset * sinEsc;
1552 pXRenderCompositeText16(gdi_display, render_op,
1554 physDev->xrender->pict,
1555 formatEntry->font_format->pict_format,
1556 0, 0, 0, 0, elts, count);
1557 wine_tsx11_unlock();
1558 HeapFree(GetProcessHeap(), 0, elts);
1560 INT offset = 0, xoff = 0, yoff = 0;
1562 XSetForeground( gdi_display, physDev->gc, textPixel );
1564 if(aa_type == AA_None || physDev->depth == 1)
1566 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1568 if(aa_type == AA_None)
1569 sharp_glyph_fn = SharpGlyphMono;
1571 sharp_glyph_fn = SharpGlyphGray;
1573 for(idx = 0; idx < count; idx++) {
1574 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1575 physDev->dc_rect.top + y + yoff,
1576 formatEntry->bitmaps[wstr[idx]],
1577 &formatEntry->gis[wstr[idx]]);
1579 offset += lpDx[idx];
1580 xoff = offset * cosEsc;
1581 yoff = offset * -sinEsc;
1583 xoff += formatEntry->gis[wstr[idx]].xOff;
1584 yoff += formatEntry->gis[wstr[idx]].yOff;
1589 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1590 RECT extents = {0, 0, 0, 0};
1592 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1593 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1595 TRACE("drawable %dx%d\n", w, h);
1597 for(idx = 0; idx < count; idx++) {
1598 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1599 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1600 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1601 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1602 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1603 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1604 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1605 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1607 offset += lpDx[idx];
1608 cur.x = offset * cosEsc;
1609 cur.y = offset * -sinEsc;
1611 cur.x += formatEntry->gis[wstr[idx]].xOff;
1612 cur.y += formatEntry->gis[wstr[idx]].yOff;
1615 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1616 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1618 if(physDev->dc_rect.left + x + extents.left >= 0) {
1619 image_x = physDev->dc_rect.left + x + extents.left;
1623 image_off_x = physDev->dc_rect.left + x + extents.left;
1625 if(physDev->dc_rect.top + y + extents.top >= 0) {
1626 image_y = physDev->dc_rect.top + y + extents.top;
1630 image_off_y = physDev->dc_rect.top + y + extents.top;
1632 if(physDev->dc_rect.left + x + extents.right < w)
1633 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1635 image_w = w - image_x;
1636 if(physDev->dc_rect.top + y + extents.bottom < h)
1637 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1639 image_h = h - image_y;
1641 if(image_w <= 0 || image_h <= 0) goto no_image;
1643 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1644 image = XGetImage(gdi_display, physDev->drawable,
1645 image_x, image_y, image_w, image_h,
1646 AllPlanes, ZPixmap);
1647 X11DRV_check_error();
1649 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1650 gdi_display, (int)physDev->drawable, image_x, image_y,
1651 image_w, image_h, AllPlanes, ZPixmap,
1652 physDev->depth, image);
1654 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
1659 gcv.graphics_exposures = False;
1660 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1661 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1662 image_w, image_h, 0, 0);
1663 XFreeGC(gdi_display, gc);
1664 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1665 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1667 X11DRV_check_error();
1668 XFreePixmap(gdi_display, xpm);
1670 if(!image) goto no_image;
1672 image->red_mask = visual->red_mask;
1673 image->green_mask = visual->green_mask;
1674 image->blue_mask = visual->blue_mask;
1676 offset = xoff = yoff = 0;
1677 for(idx = 0; idx < count; idx++) {
1678 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1679 yoff + image_off_y - extents.top,
1680 formatEntry->bitmaps[wstr[idx]],
1681 &formatEntry->gis[wstr[idx]],
1682 physDev->textPixel);
1684 offset += lpDx[idx];
1685 xoff = offset * cosEsc;
1686 yoff = offset * -sinEsc;
1688 xoff += formatEntry->gis[wstr[idx]].xOff;
1689 yoff += formatEntry->gis[wstr[idx]].yOff;
1692 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1693 image_x, image_y, image_w, image_h);
1694 XDestroyImage(image);
1697 wine_tsx11_unlock();
1699 LeaveCriticalSection(&xrender_cs);
1701 if (flags & ETO_CLIPPED)
1703 /* restore the device region */
1704 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1705 DeleteObject( saved_region );
1711 X11DRV_UnlockDIBSection( physDev, TRUE );
1715 /******************************************************************************
1716 * AlphaBlend (x11drv.@)
1718 BOOL CDECL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1719 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1720 BLENDFUNCTION blendfn)
1722 XRenderPictureAttributes pa;
1723 Picture dst_pict, src_pict;
1729 DWORD *dstbits, *data;
1732 BOOL top_down = FALSE;
1734 WineXRenderFormat *dst_format = get_xrender_format_from_pdevice(devDst);
1735 WineXRenderFormat *src_format;
1738 if(!X11DRV_XRender_Installed) {
1739 FIXME("Unable to AlphaBlend without Xrender\n");
1744 pts[1].x = xDst + widthDst;
1745 pts[1].y = yDst + heightDst;
1746 LPtoDP(devDst->hdc, pts, 2);
1749 widthDst = pts[1].x - pts[0].x;
1750 heightDst = pts[1].y - pts[0].y;
1754 pts[1].x = xSrc + widthSrc;
1755 pts[1].y = ySrc + heightSrc;
1756 LPtoDP(devSrc->hdc, pts, 2);
1759 widthSrc = pts[1].x - pts[0].x;
1760 heightSrc = pts[1].y - pts[0].y;
1761 if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1763 /* If the source is a 1x1 bitmap, tiling is equivalent to stretching, but
1764 tiling is much faster. Therefore, we do no stretching in this case. */
1765 repeat_src = widthSrc == 1 && heightSrc == 1;
1767 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1768 if((widthDst != widthSrc || heightDst != heightSrc) && !repeat_src)
1770 if(!pXRenderSetPictureTransform && !repeat_src)
1773 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1777 if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1779 static BOOL out = FALSE;
1782 FIXME("not a dibsection\n");
1788 if (xSrc < 0 || ySrc < 0 || widthSrc < 0 || heightSrc < 0 || xSrc + widthSrc > dib.dsBmih.biWidth
1789 || ySrc + heightSrc > abs(dib.dsBmih.biHeight))
1791 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc, ySrc, widthSrc, heightSrc);
1792 SetLastError(ERROR_INVALID_PARAMETER);
1796 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && blendfn.SourceConstantAlpha != 0xff)
1797 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn.SourceConstantAlpha);
1799 if(dib.dsBm.bmBitsPixel != 32) {
1800 FIXME("not a 32 bpp dibsection\n");
1803 dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1805 if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1807 dstbits += widthSrc * (heightSrc - 1);
1809 y = y2 + heightSrc - 1;
1813 y = dib.dsBmih.biHeight - ySrc - 1;
1814 y2 = y - heightSrc + 1;
1817 if (blendfn.AlphaFormat & AC_SRC_ALPHA)
1821 memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1823 dstbits += (top_down ? -1 : 1) * widthSrc;
1828 DWORD source_alpha = (DWORD)blendfn.SourceConstantAlpha << 24;
1833 DWORD *srcbits = (DWORD *)((char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes) + xSrc;
1834 for (x = 0; x < widthSrc; x++)
1836 DWORD argb = *srcbits++;
1837 argb = (argb & 0xffffff) | source_alpha;
1840 if (top_down) /* we traversed the row forward so we should go back by two rows */
1841 dstbits -= 2 * widthSrc;
1846 rgndata = X11DRV_GetRegionData( devDst->region, 0 );
1849 image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1850 (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1852 src_format = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1853 TRACE("src_format %p\n", src_format);
1856 WARN("Unable to find a picture format supporting alpha, make sure X is running at 24-bit\n");
1860 pa.subwindow_mode = IncludeInferiors;
1861 pa.repeat = repeat_src ? RepeatNormal : RepeatNone;
1863 /* FIXME use devDst->xrender->pict ? */
1864 dst_pict = pXRenderCreatePicture(gdi_display,
1866 dst_format->pict_format,
1867 CPSubwindowMode, &pa);
1868 TRACE("dst_pict %08lx\n", dst_pict);
1869 TRACE("src_drawable = %08lx\n", devSrc->drawable);
1870 xpm = XCreatePixmap(gdi_display,
1872 widthSrc, heightSrc, 32);
1873 gcv.graphics_exposures = False;
1874 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1875 TRACE("xpm = %08lx\n", xpm);
1876 XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1878 src_pict = pXRenderCreatePicture(gdi_display,
1879 xpm, src_format->pict_format,
1880 CPSubwindowMode|CPRepeat, &pa);
1881 TRACE("src_pict %08lx\n", src_pict);
1885 pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
1886 devDst->dc_rect.left, devDst->dc_rect.top,
1887 (XRectangle *)rgndata->Buffer,
1888 rgndata->rdh.nCount );
1889 HeapFree( GetProcessHeap(), 0, rgndata );
1892 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1893 if(!repeat_src && (widthDst != widthSrc || heightDst != heightSrc)) {
1894 double xscale = widthSrc/(double)widthDst;
1895 double yscale = heightSrc/(double)heightDst;
1896 XTransform xform = {{
1897 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0) },
1898 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0) },
1899 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1901 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1904 pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
1906 xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
1909 pXRenderFreePicture(gdi_display, src_pict);
1910 XFreePixmap(gdi_display, xpm);
1911 XFreeGC(gdi_display, gc);
1912 pXRenderFreePicture(gdi_display, dst_pict);
1914 XDestroyImage(image);
1916 wine_tsx11_unlock();
1917 HeapFree(GetProcessHeap(), 0, data);
1921 #else /* SONAME_LIBXRENDER */
1923 void X11DRV_XRender_Init(void)
1925 TRACE("XRender support not compiled in.\n");
1929 void X11DRV_XRender_Finalize(void)
1933 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1939 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1945 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1946 const RECT *lprect, LPCWSTR wstr, UINT count,
1953 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1959 /******************************************************************************
1960 * AlphaBlend (x11drv.@)
1962 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1963 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1964 BLENDFUNCTION blendfn)
1966 FIXME("not supported - XRENDER headers were missing at compile time\n");
1970 #endif /* SONAME_LIBXRENDER */