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 static BOOL X11DRV_XRender_Installed = FALSE;
40 int using_client_side_fonts = FALSE;
42 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
44 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
47 #include <X11/extensions/Xrender.h>
49 static XRenderPictFormat *screen_format; /* format of screen */
50 static XRenderPictFormat *mono_format; /* format of mono bitmap */
55 SIZE devsize; /* size in device coords */
59 #define INITIAL_REALIZED_BUF_SIZE 128
61 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
66 XRenderPictFormat *font_format;
77 gsCacheEntryFormat * format[AA_MAXVALUE];
88 COLORREF lastTextColor;
92 static gsCacheEntry *glyphsetCache = NULL;
93 static DWORD glyphsetCacheSize = 0;
94 static INT lastfree = -1;
97 #define INIT_CACHE_SIZE 10
99 static int antialias = 1;
101 /* some default values just in case */
102 #ifndef SONAME_LIBX11
103 #define SONAME_LIBX11 "libX11.so"
105 #ifndef SONAME_LIBXEXT
106 #define SONAME_LIBXEXT "libXext.so"
108 #ifndef SONAME_LIBXRENDER
109 #define SONAME_LIBXRENDER "libXrender.so"
112 static void *xrender_handle;
114 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
115 MAKE_FUNCPTR(XRenderAddGlyphs)
116 MAKE_FUNCPTR(XRenderComposite)
117 MAKE_FUNCPTR(XRenderCompositeString8)
118 MAKE_FUNCPTR(XRenderCompositeString16)
119 MAKE_FUNCPTR(XRenderCompositeString32)
120 MAKE_FUNCPTR(XRenderCompositeText16)
121 MAKE_FUNCPTR(XRenderCreateGlyphSet)
122 MAKE_FUNCPTR(XRenderCreatePicture)
123 MAKE_FUNCPTR(XRenderFillRectangle)
124 MAKE_FUNCPTR(XRenderFindFormat)
125 MAKE_FUNCPTR(XRenderFindVisualFormat)
126 MAKE_FUNCPTR(XRenderFreeGlyphSet)
127 MAKE_FUNCPTR(XRenderFreePicture)
128 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
129 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
130 MAKE_FUNCPTR(XRenderSetPictureTransform)
132 MAKE_FUNCPTR(XRenderQueryExtension)
135 static CRITICAL_SECTION xrender_cs;
136 static CRITICAL_SECTION_DEBUG critsect_debug =
139 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
140 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
142 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
144 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
145 ( ( (ULONG)_x4 << 24 ) | \
146 ( (ULONG)_x3 << 16 ) | \
147 ( (ULONG)_x2 << 8 ) | \
150 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
152 #define GASP_GRIDFIT 0x01
153 #define GASP_DOGRAY 0x02
155 #ifdef WORDS_BIGENDIAN
156 #define get_be_word(x) (x)
158 #define get_be_word(x) RtlUshortByteSwap(x)
161 /***********************************************************************
162 * X11DRV_XRender_Init
164 * Let's see if our XServer has the extension available
167 void X11DRV_XRender_Init(void)
170 XRenderPictFormat pf;
172 if (client_side_with_render &&
173 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
174 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
175 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
178 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
179 LOAD_FUNCPTR(XRenderAddGlyphs)
180 LOAD_FUNCPTR(XRenderComposite)
181 LOAD_FUNCPTR(XRenderCompositeString8)
182 LOAD_FUNCPTR(XRenderCompositeString16)
183 LOAD_FUNCPTR(XRenderCompositeString32)
184 LOAD_FUNCPTR(XRenderCompositeText16)
185 LOAD_FUNCPTR(XRenderCreateGlyphSet)
186 LOAD_FUNCPTR(XRenderCreatePicture)
187 LOAD_FUNCPTR(XRenderFillRectangle)
188 LOAD_FUNCPTR(XRenderFindFormat)
189 LOAD_FUNCPTR(XRenderFindVisualFormat)
190 LOAD_FUNCPTR(XRenderFreeGlyphSet)
191 LOAD_FUNCPTR(XRenderFreePicture)
192 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
193 LOAD_FUNCPTR(XRenderQueryExtension)
195 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
196 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
197 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
198 #undef LOAD_OPTIONAL_FUNCPTR
203 if(pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) {
204 X11DRV_XRender_Installed = TRUE;
205 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
206 screen_format = pXRenderFindVisualFormat(gdi_display, visual);
209 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
210 if (visual->class == DirectColor)
213 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
214 screen_depth, TrueColor, &info ))
216 screen_format = pXRenderFindVisualFormat(gdi_display, info.visual);
217 if (screen_format) visual = info.visual;
221 if(!screen_format) /* This fails in buggy versions of libXrender.so */
225 "Wine has detected that you probably have a buggy version\n"
226 "of libXrender.so . Because of this client side font rendering\n"
227 "will be disabled. Please upgrade this library.\n");
228 X11DRV_XRender_Installed = FALSE;
231 pf.type = PictTypeDirect;
234 pf.direct.alphaMask = 1;
235 mono_format = pXRenderFindFormat(gdi_display, PictFormatType |
236 PictFormatDepth | PictFormatAlpha |
237 PictFormatAlphaMask, &pf, 0);
239 ERR("mono_format == NULL?\n");
240 X11DRV_XRender_Installed = FALSE;
242 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
243 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
244 X11DRV_XRender_Installed = FALSE;
251 if(X11DRV_XRender_Installed || client_side_with_core)
253 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
254 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
256 glyphsetCacheSize = INIT_CACHE_SIZE;
258 for(i = 0; i < INIT_CACHE_SIZE; i++) {
259 glyphsetCache[i].next = i + 1;
260 glyphsetCache[i].count = -1;
262 glyphsetCache[i-1].next = -1;
263 using_client_side_fonts = 1;
265 if(!X11DRV_XRender_Installed) {
266 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
267 if(screen_depth <= 8 || !client_side_antialias_with_core)
270 if(screen_depth <= 8 || !client_side_antialias_with_render)
274 else TRACE("Using X11 core fonts\n");
277 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
279 if(p1->hash != p2->hash) return TRUE;
280 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
281 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
282 return strcmpW(p1->lf.lfFaceName, p2->lf.lfFaceName);
286 static void walk_cache(void)
290 EnterCriticalSection(&xrender_cs);
291 for(i=mru; i >= 0; i = glyphsetCache[i].next)
292 TRACE("item %d\n", i);
293 LeaveCriticalSection(&xrender_cs);
297 static int LookupEntry(LFANDSIZE *plfsz)
301 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
303 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
308 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
309 glyphsetCache[i].count++;
311 glyphsetCache[prev_i].next = glyphsetCache[i].next;
312 glyphsetCache[i].next = mru;
315 TRACE("found font in cache %d\n", i);
320 TRACE("font not in cache\n");
324 static void FreeEntry(int entry)
328 for(format = 0; format < AA_MAXVALUE; format++) {
329 gsCacheEntryFormat * formatEntry;
331 if( !glyphsetCache[entry].format[format] )
334 formatEntry = glyphsetCache[entry].format[format];
336 if(formatEntry->glyphset) {
338 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
340 formatEntry->glyphset = 0;
342 if(formatEntry->nrealized) {
343 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
344 formatEntry->realized = NULL;
345 if(formatEntry->bitmaps) {
346 for(i = 0; i < formatEntry->nrealized; i++)
347 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
348 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
349 formatEntry->bitmaps = NULL;
351 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
352 formatEntry->gis = NULL;
353 formatEntry->nrealized = 0;
356 HeapFree(GetProcessHeap(), 0, formatEntry);
357 glyphsetCache[entry].format[format] = NULL;
361 static int AllocEntry(void)
363 int best = -1, prev_best = -1, i, prev_i = -1;
366 assert(glyphsetCache[lastfree].count == -1);
367 glyphsetCache[lastfree].count = 1;
369 lastfree = glyphsetCache[lastfree].next;
371 glyphsetCache[best].next = mru;
374 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
378 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
379 if(glyphsetCache[i].count == 0) {
387 TRACE("freeing unused glyphset at cache %d\n", best);
389 glyphsetCache[best].count = 1;
391 glyphsetCache[prev_best].next = glyphsetCache[best].next;
392 glyphsetCache[best].next = mru;
400 TRACE("Growing cache\n");
403 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
405 (glyphsetCacheSize + INIT_CACHE_SIZE)
406 * sizeof(*glyphsetCache));
408 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
409 (glyphsetCacheSize + INIT_CACHE_SIZE)
410 * sizeof(*glyphsetCache));
412 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
414 glyphsetCache[i].next = i + 1;
415 glyphsetCache[i].count = -1;
417 glyphsetCache[i-1].next = -1;
418 glyphsetCacheSize += INIT_CACHE_SIZE;
420 lastfree = glyphsetCache[best].next;
421 glyphsetCache[best].count = 1;
422 glyphsetCache[best].next = mru;
424 TRACE("new free cache slot at %d\n", mru);
428 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
438 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
439 if(size == GDI_ERROR)
442 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
443 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
445 GetTextMetricsW(physDev->hdc, &tm);
446 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
449 num_recs = get_be_word(*gasp);
453 *flags = get_be_word(*(gasp + 1));
454 if(ppem <= get_be_word(*gasp))
458 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
460 HeapFree(GetProcessHeap(), 0, buffer);
464 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
470 static int hinter = -1;
472 if((ret = LookupEntry(plfsz)) != -1) return ret;
475 entry = glyphsetCache + ret;
476 entry->lfsz = *plfsz;
477 for( format = 0; format < AA_MAXVALUE; format++ ) {
478 assert( !entry->format[format] );
481 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
485 RASTERIZER_STATUS status;
486 GetRasterizerCaps(&status, sizeof(status));
487 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
489 if(!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
490 entry->aa_default = AA_Grey;
492 entry->aa_default = AA_None;
495 entry->aa_default = AA_None;
500 static void dec_ref_cache(int index)
503 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
504 assert(glyphsetCache[index].count > 0);
505 glyphsetCache[index].count--;
508 static void lfsz_calc_hash(LFANDSIZE *plfsz)
510 DWORD hash = 0, *ptr;
513 hash ^= plfsz->devsize.cx;
514 hash ^= plfsz->devsize.cy;
515 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
517 for(i = 0, ptr = (DWORD*)&plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
518 WCHAR *pwc = (WCHAR *)ptr;
528 /***********************************************************************
529 * X11DRV_XRender_Finalize
531 void X11DRV_XRender_Finalize(void)
535 EnterCriticalSection(&xrender_cs);
536 for(i = mru; i >= 0; i = glyphsetCache[i].next)
538 LeaveCriticalSection(&xrender_cs);
542 /***********************************************************************
543 * X11DRV_XRender_SelectFont
545 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
549 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
550 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
551 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
552 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
553 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
554 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
555 lfsz_calc_hash(&lfsz);
557 EnterCriticalSection(&xrender_cs);
558 if(!physDev->xrender) {
559 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
560 sizeof(*physDev->xrender));
561 physDev->xrender->cache_index = -1;
563 else if(physDev->xrender->cache_index != -1)
564 dec_ref_cache(physDev->xrender->cache_index);
565 physDev->xrender->cache_index = GetCacheEntry(physDev, &lfsz);
566 LeaveCriticalSection(&xrender_cs);
570 /***********************************************************************
571 * X11DRV_XRender_DeleteDC
573 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
575 X11DRV_XRender_UpdateDrawable(physDev);
577 EnterCriticalSection(&xrender_cs);
578 if(physDev->xrender->cache_index != -1)
579 dec_ref_cache(physDev->xrender->cache_index);
580 LeaveCriticalSection(&xrender_cs);
582 HeapFree(GetProcessHeap(), 0, physDev->xrender);
583 physDev->xrender = NULL;
587 /***********************************************************************
588 * X11DRV_XRender_UpdateDrawable
590 * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
591 * It deletes the pict and tile when the drawable changes.
593 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
597 if(physDev->xrender->pict)
599 TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
601 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
602 physDev->xrender->pict = 0;
604 if(physDev->xrender->tile_pict)
606 pXRenderFreePicture(gdi_display, physDev->xrender->tile_pict);
607 physDev->xrender->tile_pict = 0;
609 if(physDev->xrender->tile_xpm)
611 XFreePixmap(gdi_display, physDev->xrender->tile_xpm);
612 physDev->xrender->tile_xpm = 0;
620 /************************************************************************
623 * Helper to ExtTextOut. Must be called inside xrender_cs
625 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
632 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
633 gsCacheEntryFormat *formatEntry;
634 UINT ggo_format = GGO_GLYPH_INDEX;
635 XRenderPictFormat pf;
639 ggo_format |= WINE_GGO_GRAY16_BITMAP;
643 ERR("aa = %d - not implemented\n", format);
645 ggo_format |= GGO_BITMAP;
649 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
651 if(buflen == GDI_ERROR) {
652 if(format != AA_None) {
654 entry->aa_default = AA_None;
655 ggo_format &= ~WINE_GGO_GRAY16_BITMAP;
656 ggo_format |= GGO_BITMAP;
657 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
660 if(buflen == GDI_ERROR) {
661 WARN("GetGlyphOutlineW failed\n");
664 TRACE("Turning off antialiasing for this monochrome font\n");
667 /* If there is nothing for the current type, we create the entry. */
668 if( !entry->format[format] ) {
669 entry->format[format] = HeapAlloc(GetProcessHeap(),
671 sizeof(gsCacheEntryFormat));
673 formatEntry = entry->format[format];
675 if(formatEntry->nrealized <= glyph) {
676 formatEntry->nrealized = (glyph / 128 + 1) * 128;
678 if (formatEntry->realized)
679 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
681 formatEntry->realized,
682 formatEntry->nrealized * sizeof(BOOL));
684 formatEntry->realized = HeapAlloc(GetProcessHeap(),
686 formatEntry->nrealized * sizeof(BOOL));
688 if(!X11DRV_XRender_Installed) {
689 if (formatEntry->bitmaps)
690 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
692 formatEntry->bitmaps,
693 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
695 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
697 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
699 if (formatEntry->gis)
700 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
703 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
705 formatEntry->gis = HeapAlloc(GetProcessHeap(),
707 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
711 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
715 pf.direct.alphaMask = 0xff;
719 ERR("aa = %d - not implemented\n", format);
722 pf.direct.alphaMask = 1;
726 pf.type = PictTypeDirect;
730 formatEntry->font_format = pXRenderFindFormat(gdi_display,
737 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
742 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
743 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, NULL);
744 formatEntry->realized[glyph] = TRUE;
746 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
748 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
749 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
751 gi.width = gm.gmBlackBoxX;
752 gi.height = gm.gmBlackBoxY;
753 gi.x = -gm.gmptGlyphOrigin.x;
754 gi.y = gm.gmptGlyphOrigin.y;
755 gi.xOff = gm.gmCellIncX;
756 gi.yOff = gm.gmCellIncY;
758 if(TRACE_ON(xrender)) {
763 if(format == AA_None) {
764 pitch = ((gi.width + 31) / 32) * 4;
765 for(i = 0; i < gi.height; i++) {
766 line = (unsigned char*) buf + i * pitch;
768 for(j = 0; j < pitch * 8; j++) {
769 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
771 strcat(output, "\n");
775 static const char blks[] = " .:;!o*#";
779 pitch = ((gi.width + 3) / 4) * 4;
780 for(i = 0; i < gi.height; i++) {
781 line = (unsigned char*) buf + i * pitch;
783 for(j = 0; j < pitch; j++) {
784 str[0] = blks[line[j] >> 5];
787 strcat(output, "\n");
793 memcpy(&formatEntry->gis[glyph], &gi, sizeof(gi));
795 if(formatEntry->glyphset) {
796 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
797 unsigned char *byte = (unsigned char*) buf, c;
803 /* magic to flip bit order */
804 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
805 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
806 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
813 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
816 HeapFree(GetProcessHeap(), 0, buf);
818 formatEntry->bitmaps[glyph] = buf;
823 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
824 void *bitmap, XGlyphInfo *gi)
826 unsigned char *srcLine = bitmap, *src;
827 unsigned char bits, bitsMask;
828 int width = gi->width;
829 int stride = ((width + 31) & ~31) >> 3;
830 int height = gi->height;
834 TRACE("%d, %d\n", x, y);
843 bitsMask = 0x80; /* FreeType is always MSB first */
857 bitsMask = bitsMask >> 1;
863 } while (bits & bitsMask);
864 XFillRectangle (gdi_display, physDev->drawable,
865 physDev->gc, xspan, y, lenspan, 1);
877 bitsMask = bitsMask >> 1;
883 } while (!(bits & bitsMask));
890 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
891 void *bitmap, XGlyphInfo *gi)
893 unsigned char *srcLine = bitmap, *src, bits;
894 int width = gi->width;
895 int stride = ((width + 3) & ~3);
896 int height = gi->height;
921 } while (bits >= 0x80);
922 XFillRectangle (gdi_display, physDev->drawable,
923 physDev->gc, xspan, y, lenspan, 1);
936 } while (bits < 0x80);
944 static void ExamineBitfield (DWORD mask, int *shift, int *len)
949 while ((mask & 1) == 0)
955 while ((mask & 1) == 1)
964 static DWORD GetField (DWORD pixel, int shift, int len)
966 pixel = pixel & (((1 << (len)) - 1) << shift);
967 pixel = pixel << (32 - (shift + len)) >> 24;
970 pixel |= (pixel >> len);
977 static DWORD PutField (DWORD pixel, int shift, int len)
979 shift = shift - (8 - len);
981 pixel &= (((1 << len) - 1) << (8 - len));
989 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
995 BYTE *maskLine, *mask, m;
1000 BYTE src_r, src_g, src_b;
1005 height = gi->height;
1007 maskLine = (unsigned char *) bitmap;
1008 maskStride = (width + 3) & ~3;
1010 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1011 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1012 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1014 src_r = GetField(color, r_shift, r_len);
1015 src_g = GetField(color, g_shift, g_len);
1016 src_b = GetField(color, b_shift, b_len);
1018 for(; height--; y++)
1021 maskLine += maskStride;
1026 if(y >= image->height) break;
1030 if(tx >= image->width) break;
1033 if(tx < 0) continue;
1036 XPutPixel (image, tx, y, color);
1041 pixel = XGetPixel (image, tx, y);
1043 r = GetField(pixel, r_shift, r_len);
1044 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1045 g = GetField(pixel, g_shift, g_len);
1046 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1047 b = GetField(pixel, b_shift, b_len);
1048 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1050 pixel = (PutField (r, r_shift, r_len) |
1051 PutField (g, g_shift, g_len) |
1052 PutField (b, b_shift, b_len));
1053 XPutPixel (image, tx, y, pixel);
1059 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1064 /***********************************************************************
1065 * X11DRV_XRender_ExtTextOut
1067 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1068 const RECT *lprect, LPCWSTR wstr, UINT count,
1074 int render_op = PictOpOver;
1075 gsCacheEntry *entry;
1076 gsCacheEntryFormat *formatEntry;
1078 HDC hdc = physDev->hdc;
1079 int textPixel, backgroundPixel;
1080 HRGN saved_region = 0;
1081 BOOL disable_antialias = FALSE;
1082 AA_Type aa_type = AA_None;
1085 double cosEsc, sinEsc;
1088 /* Do we need to disable antialiasing because of palette mode? */
1089 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1090 TRACE("bitmap is not a DIB\n");
1092 else if (bmp.dsBmih.biBitCount <= 8) {
1093 TRACE("Disabling antialiasing\n");
1094 disable_antialias = TRUE;
1097 xgcval.function = GXcopy;
1098 xgcval.background = physDev->backgroundPixel;
1099 xgcval.fill_style = FillSolid;
1101 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1102 wine_tsx11_unlock();
1104 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1106 if(physDev->depth == 1) {
1107 if((physDev->textPixel & 0xffffff) == 0) {
1109 backgroundPixel = 1;
1112 backgroundPixel = 0;
1115 textPixel = physDev->textPixel;
1116 backgroundPixel = physDev->backgroundPixel;
1119 if(flags & ETO_OPAQUE)
1122 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1123 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1124 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1125 lprect->right - lprect->left, lprect->bottom - lprect->top );
1126 wine_tsx11_unlock();
1136 GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1137 if(lf.lfEscapement != 0) {
1138 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1139 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1145 if (flags & ETO_CLIPPED)
1149 clip_region = CreateRectRgnIndirect( lprect );
1150 /* make a copy of the current device region */
1151 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1152 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1153 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1154 DeleteObject( clip_region );
1157 if(X11DRV_XRender_Installed) {
1158 if(!physDev->xrender->pict) {
1159 XRenderPictureAttributes pa;
1160 pa.subwindow_mode = IncludeInferiors;
1163 physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1165 (physDev->depth == 1) ?
1166 mono_format : screen_format,
1167 CPSubwindowMode, &pa);
1168 wine_tsx11_unlock();
1170 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1171 physDev->xrender->pict, hdc, physDev->drawable);
1173 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1174 physDev->xrender->pict, hdc, physDev->drawable);
1177 if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1180 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1181 physDev->dc_rect.left, physDev->dc_rect.top,
1182 (XRectangle *)data->Buffer, data->rdh.nCount );
1183 wine_tsx11_unlock();
1184 HeapFree( GetProcessHeap(), 0, data );
1188 if(X11DRV_XRender_Installed) {
1189 /* Create a 1x1 pixmap to tile over the font mask */
1190 if(!physDev->xrender->tile_xpm) {
1191 XRenderPictureAttributes pa;
1193 XRenderPictFormat *format = (physDev->depth == 1) ? mono_format : screen_format;
1195 physDev->xrender->tile_xpm = XCreatePixmap(gdi_display,
1200 physDev->xrender->tile_pict = pXRenderCreatePicture(gdi_display,
1201 physDev->xrender->tile_xpm,
1204 wine_tsx11_unlock();
1205 TRACE("Created pixmap of depth %d\n", format->depth);
1206 /* init lastTextColor to something different from textPixel */
1207 physDev->xrender->lastTextColor = ~physDev->textPixel;
1211 if(physDev->textPixel != physDev->xrender->lastTextColor) {
1212 if(physDev->depth != 1) {
1213 /* Map 0 -- 0xff onto 0 -- 0xffff */
1218 ExamineBitfield (visual->red_mask, &r_shift, &r_len );
1219 ExamineBitfield (visual->green_mask, &g_shift, &g_len);
1220 ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
1222 col.red = GetField(physDev->textPixel, r_shift, r_len);
1223 col.red |= col.red << 8;
1224 col.green = GetField(physDev->textPixel, g_shift, g_len);
1225 col.green |= col.green << 8;
1226 col.blue = GetField(physDev->textPixel, b_shift, b_len);
1227 col.blue |= col.blue << 8;
1229 } else { /* for a 1bpp bitmap we always need a 1 in the tile */
1230 col.red = col.green = col.blue = 0;
1234 pXRenderFillRectangle(gdi_display, PictOpSrc,
1235 physDev->xrender->tile_pict,
1237 wine_tsx11_unlock();
1238 physDev->xrender->lastTextColor = physDev->textPixel;
1241 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1243 if((physDev->depth == 1) && (textPixel == 0))
1244 render_op = PictOpOutReverse; /* This gives us 'black' text */
1247 EnterCriticalSection(&xrender_cs);
1248 entry = glyphsetCache + physDev->xrender->cache_index;
1249 if( disable_antialias == FALSE )
1250 aa_type = entry->aa_default;
1251 formatEntry = entry->format[aa_type];
1253 for(idx = 0; idx < count; idx++) {
1254 if( !formatEntry ) {
1255 UploadGlyph(physDev, wstr[idx], aa_type);
1256 /* re-evaluate antialias since aa_default may have changed */
1257 if( disable_antialias == FALSE )
1258 aa_type = entry->aa_default;
1259 formatEntry = entry->format[aa_type];
1260 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1261 UploadGlyph(physDev, wstr[idx], aa_type);
1266 WARN("could not upload requested glyphs\n");
1267 LeaveCriticalSection(&xrender_cs);
1271 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1272 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1274 if(X11DRV_XRender_Installed)
1276 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1278 POINT desired, current;
1280 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1281 So we pass zeros to the function and move to our starting position using the first
1282 element of the elts array. */
1284 desired.x = physDev->dc_rect.left + x;
1285 desired.y = physDev->dc_rect.top + y;
1286 current.x = current.y = 0;
1288 for(idx = 0; idx < count; idx++)
1290 elts[idx].glyphset = formatEntry->glyphset;
1291 elts[idx].chars = wstr + idx;
1292 elts[idx].nchars = 1;
1293 elts[idx].xOff = desired.x - current.x;
1294 elts[idx].yOff = desired.y - current.y;
1296 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1297 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1301 desired.x += formatEntry->gis[wstr[idx]].xOff;
1302 desired.y += formatEntry->gis[wstr[idx]].yOff;
1306 offset += lpDx[idx];
1307 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1308 desired.y = physDev->dc_rect.top + y - offset * sinEsc;
1312 pXRenderCompositeText16(gdi_display, render_op,
1313 physDev->xrender->tile_pict,
1314 physDev->xrender->pict,
1315 formatEntry->font_format,
1316 0, 0, 0, 0, elts, count);
1317 wine_tsx11_unlock();
1318 HeapFree(GetProcessHeap(), 0, elts);
1320 INT offset = 0, xoff = 0, yoff = 0;
1322 XSetForeground( gdi_display, physDev->gc, textPixel );
1324 if(aa_type == AA_None || physDev->depth == 1)
1326 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1328 if(aa_type == AA_None)
1329 sharp_glyph_fn = SharpGlyphMono;
1331 sharp_glyph_fn = SharpGlyphGray;
1333 for(idx = 0; idx < count; idx++) {
1334 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1335 physDev->dc_rect.top + y + yoff,
1336 formatEntry->bitmaps[wstr[idx]],
1337 &formatEntry->gis[wstr[idx]]);
1339 offset += lpDx[idx];
1340 xoff = offset * cosEsc;
1341 yoff = offset * -sinEsc;
1343 xoff += formatEntry->gis[wstr[idx]].xOff;
1344 yoff += formatEntry->gis[wstr[idx]].yOff;
1349 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1350 RECT extents = {0, 0, 0, 0};
1352 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1353 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1355 TRACE("drawable %dx%d\n", w, h);
1357 for(idx = 0; idx < count; idx++) {
1358 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1359 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1360 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1361 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1362 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1363 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1364 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1365 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1367 offset += lpDx[idx];
1368 cur.x = offset * cosEsc;
1369 cur.y = offset * -sinEsc;
1371 cur.x += formatEntry->gis[wstr[idx]].xOff;
1372 cur.y += formatEntry->gis[wstr[idx]].yOff;
1375 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1376 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1378 if(physDev->dc_rect.left + x + extents.left >= 0) {
1379 image_x = physDev->dc_rect.left + x + extents.left;
1383 image_off_x = physDev->dc_rect.left + x + extents.left;
1385 if(physDev->dc_rect.top + y + extents.top >= 0) {
1386 image_y = physDev->dc_rect.top + y + extents.top;
1390 image_off_y = physDev->dc_rect.top + y + extents.top;
1392 if(physDev->dc_rect.left + x + extents.right < w)
1393 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1395 image_w = w - image_x;
1396 if(physDev->dc_rect.top + y + extents.bottom < h)
1397 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1399 image_h = h - image_y;
1401 if(image_w <= 0 || image_h <= 0) goto no_image;
1403 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1404 image = XGetImage(gdi_display, physDev->drawable,
1405 image_x, image_y, image_w, image_h,
1406 AllPlanes, ZPixmap);
1407 X11DRV_check_error();
1409 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1410 gdi_display, (int)physDev->drawable, image_x, image_y,
1411 image_w, image_h, AllPlanes, ZPixmap,
1412 physDev->depth, image);
1414 Pixmap xpm = XCreatePixmap(gdi_display, physDev->drawable, image_w, image_h,
1419 gcv.graphics_exposures = False;
1420 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1421 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1422 image_w, image_h, 0, 0);
1423 XFreeGC(gdi_display, gc);
1424 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1425 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1427 X11DRV_check_error();
1428 XFreePixmap(gdi_display, xpm);
1430 if(!image) goto no_image;
1432 image->red_mask = visual->red_mask;
1433 image->green_mask = visual->green_mask;
1434 image->blue_mask = visual->blue_mask;
1436 offset = xoff = yoff = 0;
1437 for(idx = 0; idx < count; idx++) {
1438 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1439 yoff + image_off_y - extents.top,
1440 formatEntry->bitmaps[wstr[idx]],
1441 &formatEntry->gis[wstr[idx]],
1442 physDev->textPixel);
1444 offset += lpDx[idx];
1445 xoff = offset * cosEsc;
1446 yoff = offset * -sinEsc;
1448 xoff += formatEntry->gis[wstr[idx]].xOff;
1449 yoff += formatEntry->gis[wstr[idx]].yOff;
1452 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1453 image_x, image_y, image_w, image_h);
1454 XDestroyImage(image);
1457 wine_tsx11_unlock();
1459 LeaveCriticalSection(&xrender_cs);
1461 if (flags & ETO_CLIPPED)
1463 /* restore the device region */
1464 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1465 DeleteObject( saved_region );
1471 X11DRV_UnlockDIBSection( physDev, TRUE );
1475 /******************************************************************************
1476 * AlphaBlend (x11drv.@)
1478 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1479 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1480 BLENDFUNCTION blendfn)
1482 XRenderPictureAttributes pa;
1483 XRenderPictFormat *src_format;
1484 XRenderPictFormat argb32_templ = {
1486 PictTypeDirect, /* type */
1489 16, /* direct.red */
1490 0xff, /* direct.redMask */
1491 8, /* direct.green */
1492 0xff, /* direct.greenMask */
1493 0, /* direct.blue */
1494 0xff, /* direct.blueMask */
1495 24, /* direct.alpha */
1496 0xff, /* direct.alphaMask */
1500 unsigned long argb32_templ_mask =
1506 PictFormatGreenMask |
1508 PictFormatBlueMask |
1510 PictFormatAlphaMask;
1512 Picture dst_pict, src_pict;
1518 BYTE *dstbits, *data;
1521 BOOL top_down = FALSE;
1524 if(!X11DRV_XRender_Installed) {
1525 FIXME("Unable to AlphaBlend without Xrender\n");
1530 pts[1].x = xDst + widthDst;
1531 pts[1].y = yDst + heightDst;
1532 LPtoDP(devDst->hdc, pts, 2);
1535 widthDst = pts[1].x - pts[0].x;
1536 heightDst = pts[1].y - pts[0].y;
1540 pts[1].x = xSrc + widthSrc;
1541 pts[1].y = ySrc + heightSrc;
1542 LPtoDP(devSrc->hdc, pts, 2);
1545 widthSrc = pts[1].x - pts[0].x;
1546 heightSrc = pts[1].y - pts[0].y;
1547 if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1549 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1550 if(widthDst != widthSrc || heightDst != heightSrc)
1552 if(!pXRenderSetPictureTransform)
1555 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1559 if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1561 FIXME("not a dibsection\n");
1565 if(dib.dsBm.bmBitsPixel != 32) {
1566 FIXME("not a 32 bpp dibsection\n");
1569 dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1571 if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1573 dstbits += widthSrc * (heightSrc - 1) * 4;
1575 y = y2 + heightSrc - 1;
1579 y = dib.dsBmih.biHeight - ySrc - 1;
1580 y2 = y - heightSrc + 1;
1582 for(; y >= y2; y--) {
1583 memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1585 dstbits += (top_down ? -1 : 1) * widthSrc * 4;
1589 image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1590 (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1593 Avoid using XRenderFindStandardFormat as older libraries don't have it
1594 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1596 src_format = pXRenderFindFormat(gdi_display, argb32_templ_mask, &argb32_templ, 0);
1598 TRACE("src_format %p\n", src_format);
1600 pa.subwindow_mode = IncludeInferiors;
1602 /* FIXME use devDst->xrender->pict ? */
1603 dst_pict = pXRenderCreatePicture(gdi_display,
1605 (devDst->depth == 1) ?
1606 mono_format : screen_format,
1607 CPSubwindowMode, &pa);
1608 TRACE("dst_pict %08lx\n", dst_pict);
1609 TRACE("src_drawable = %08lx\n", devSrc->drawable);
1610 xpm = XCreatePixmap(gdi_display,
1612 widthSrc, heightSrc, 32);
1613 gcv.graphics_exposures = False;
1614 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1615 TRACE("xpm = %08lx\n", xpm);
1616 XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1618 src_pict = pXRenderCreatePicture(gdi_display,
1620 CPSubwindowMode, &pa);
1621 TRACE("src_pict %08lx\n", src_pict);
1623 if ((rgndata = X11DRV_GetRegionData( devDst->region, 0 )))
1625 pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
1626 devDst->dc_rect.left, devDst->dc_rect.top,
1627 (XRectangle *)rgndata->Buffer,
1628 rgndata->rdh.nCount );
1629 HeapFree( GetProcessHeap(), 0, rgndata );
1632 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1633 if(widthDst != widthSrc || heightDst != heightSrc) {
1634 double xscale = widthSrc/(double)widthDst;
1635 double yscale = heightSrc/(double)heightDst;
1636 XTransform xform = {{
1637 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0) },
1638 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0) },
1639 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1641 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1644 pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
1646 xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
1649 pXRenderFreePicture(gdi_display, src_pict);
1650 XFreePixmap(gdi_display, xpm);
1651 XFreeGC(gdi_display, gc);
1652 pXRenderFreePicture(gdi_display, dst_pict);
1654 XDestroyImage(image);
1656 wine_tsx11_unlock();
1657 HeapFree(GetProcessHeap(), 0, data);
1661 #else /* HAVE_X11_EXTENSIONS_XRENDER_H */
1663 void X11DRV_XRender_Init(void)
1665 TRACE("XRender support not compiled in.\n");
1669 void X11DRV_XRender_Finalize(void)
1673 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1679 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1685 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1686 const RECT *lprect, LPCWSTR wstr, UINT count,
1693 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1699 /******************************************************************************
1700 * AlphaBlend (x11drv.@)
1702 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1703 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1704 BLENDFUNCTION blendfn)
1706 FIXME("not supported - XRENDER headers were missing at compile time\n");
1710 #endif /* HAVE_X11_EXTENSIONS_XRENDER_H */