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>
51 enum drawable_depth_type {mono_drawable, color_drawable};
52 static XRenderPictFormat *pict_formats[2];
57 SIZE devsize; /* size in device coords */
61 #define INITIAL_REALIZED_BUF_SIZE 128
63 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
68 XRenderPictFormat *font_format;
79 gsCacheEntryFormat * format[AA_MAXVALUE];
91 static gsCacheEntry *glyphsetCache = NULL;
92 static DWORD glyphsetCacheSize = 0;
93 static INT lastfree = -1;
96 #define INIT_CACHE_SIZE 10
98 static int antialias = 1;
100 static void *xrender_handle;
102 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
103 MAKE_FUNCPTR(XRenderAddGlyphs)
104 MAKE_FUNCPTR(XRenderComposite)
105 MAKE_FUNCPTR(XRenderCompositeString8)
106 MAKE_FUNCPTR(XRenderCompositeString16)
107 MAKE_FUNCPTR(XRenderCompositeString32)
108 MAKE_FUNCPTR(XRenderCompositeText16)
109 MAKE_FUNCPTR(XRenderCreateGlyphSet)
110 MAKE_FUNCPTR(XRenderCreatePicture)
111 MAKE_FUNCPTR(XRenderFillRectangle)
112 MAKE_FUNCPTR(XRenderFindFormat)
113 MAKE_FUNCPTR(XRenderFindVisualFormat)
114 MAKE_FUNCPTR(XRenderFreeGlyphSet)
115 MAKE_FUNCPTR(XRenderFreePicture)
116 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
117 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
118 MAKE_FUNCPTR(XRenderSetPictureTransform)
120 MAKE_FUNCPTR(XRenderQueryExtension)
123 static CRITICAL_SECTION xrender_cs;
124 static CRITICAL_SECTION_DEBUG critsect_debug =
127 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
128 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
130 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
132 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
133 ( ( (ULONG)_x4 << 24 ) | \
134 ( (ULONG)_x3 << 16 ) | \
135 ( (ULONG)_x2 << 8 ) | \
138 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
140 #define GASP_GRIDFIT 0x01
141 #define GASP_DOGRAY 0x02
143 #ifdef WORDS_BIGENDIAN
144 #define get_be_word(x) (x)
146 #define get_be_word(x) RtlUshortByteSwap(x)
149 /***********************************************************************
150 * X11DRV_XRender_Init
152 * Let's see if our XServer has the extension available
155 void X11DRV_XRender_Init(void)
158 XRenderPictFormat pf;
160 if (client_side_with_render &&
161 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
162 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
163 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
166 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
167 LOAD_FUNCPTR(XRenderAddGlyphs)
168 LOAD_FUNCPTR(XRenderComposite)
169 LOAD_FUNCPTR(XRenderCompositeString8)
170 LOAD_FUNCPTR(XRenderCompositeString16)
171 LOAD_FUNCPTR(XRenderCompositeString32)
172 LOAD_FUNCPTR(XRenderCompositeText16)
173 LOAD_FUNCPTR(XRenderCreateGlyphSet)
174 LOAD_FUNCPTR(XRenderCreatePicture)
175 LOAD_FUNCPTR(XRenderFillRectangle)
176 LOAD_FUNCPTR(XRenderFindFormat)
177 LOAD_FUNCPTR(XRenderFindVisualFormat)
178 LOAD_FUNCPTR(XRenderFreeGlyphSet)
179 LOAD_FUNCPTR(XRenderFreePicture)
180 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
181 LOAD_FUNCPTR(XRenderQueryExtension)
183 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
184 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
185 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
186 #undef LOAD_OPTIONAL_FUNCPTR
191 if(pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) {
192 X11DRV_XRender_Installed = TRUE;
193 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
194 pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, visual);
195 if(!pict_formats[color_drawable])
197 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
198 if (visual->class == DirectColor)
201 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
202 screen_depth, TrueColor, &info ))
204 pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, info.visual);
205 if (pict_formats[color_drawable]) visual = info.visual;
209 if(!pict_formats[color_drawable]) /* This fails in buggy versions of libXrender.so */
213 "Wine has detected that you probably have a buggy version\n"
214 "of libXrender.so . Because of this client side font rendering\n"
215 "will be disabled. Please upgrade this library.\n");
216 X11DRV_XRender_Installed = FALSE;
219 pf.type = PictTypeDirect;
222 pf.direct.alphaMask = 1;
223 pict_formats[mono_drawable] = pXRenderFindFormat(gdi_display, PictFormatType |
224 PictFormatDepth | PictFormatAlpha |
225 PictFormatAlphaMask, &pf, 0);
226 if(!pict_formats[mono_drawable]) {
227 ERR("mono_format == NULL?\n");
228 X11DRV_XRender_Installed = FALSE;
230 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
231 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
232 X11DRV_XRender_Installed = FALSE;
239 if(X11DRV_XRender_Installed || client_side_with_core)
241 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
242 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
244 glyphsetCacheSize = INIT_CACHE_SIZE;
246 for(i = 0; i < INIT_CACHE_SIZE; i++) {
247 glyphsetCache[i].next = i + 1;
248 glyphsetCache[i].count = -1;
250 glyphsetCache[i-1].next = -1;
251 using_client_side_fonts = 1;
253 if(!X11DRV_XRender_Installed) {
254 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
255 if(screen_depth <= 8 || !client_side_antialias_with_core)
258 if(screen_depth <= 8 || !client_side_antialias_with_render)
262 else TRACE("Using X11 core fonts\n");
265 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
267 if(p1->hash != p2->hash) return TRUE;
268 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
269 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
270 return strcmpW(p1->lf.lfFaceName, p2->lf.lfFaceName);
274 static void walk_cache(void)
278 EnterCriticalSection(&xrender_cs);
279 for(i=mru; i >= 0; i = glyphsetCache[i].next)
280 TRACE("item %d\n", i);
281 LeaveCriticalSection(&xrender_cs);
285 static int LookupEntry(LFANDSIZE *plfsz)
289 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
291 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
296 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
297 glyphsetCache[i].count++;
299 glyphsetCache[prev_i].next = glyphsetCache[i].next;
300 glyphsetCache[i].next = mru;
303 TRACE("found font in cache %d\n", i);
308 TRACE("font not in cache\n");
312 static void FreeEntry(int entry)
316 for(format = 0; format < AA_MAXVALUE; format++) {
317 gsCacheEntryFormat * formatEntry;
319 if( !glyphsetCache[entry].format[format] )
322 formatEntry = glyphsetCache[entry].format[format];
324 if(formatEntry->glyphset) {
326 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
328 formatEntry->glyphset = 0;
330 if(formatEntry->nrealized) {
331 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
332 formatEntry->realized = NULL;
333 if(formatEntry->bitmaps) {
334 for(i = 0; i < formatEntry->nrealized; i++)
335 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
336 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
337 formatEntry->bitmaps = NULL;
339 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
340 formatEntry->gis = NULL;
341 formatEntry->nrealized = 0;
344 HeapFree(GetProcessHeap(), 0, formatEntry);
345 glyphsetCache[entry].format[format] = NULL;
349 static int AllocEntry(void)
351 int best = -1, prev_best = -1, i, prev_i = -1;
354 assert(glyphsetCache[lastfree].count == -1);
355 glyphsetCache[lastfree].count = 1;
357 lastfree = glyphsetCache[lastfree].next;
359 glyphsetCache[best].next = mru;
362 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
366 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
367 if(glyphsetCache[i].count == 0) {
375 TRACE("freeing unused glyphset at cache %d\n", best);
377 glyphsetCache[best].count = 1;
379 glyphsetCache[prev_best].next = glyphsetCache[best].next;
380 glyphsetCache[best].next = mru;
388 TRACE("Growing cache\n");
391 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
393 (glyphsetCacheSize + INIT_CACHE_SIZE)
394 * sizeof(*glyphsetCache));
396 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
397 (glyphsetCacheSize + INIT_CACHE_SIZE)
398 * sizeof(*glyphsetCache));
400 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
402 glyphsetCache[i].next = i + 1;
403 glyphsetCache[i].count = -1;
405 glyphsetCache[i-1].next = -1;
406 glyphsetCacheSize += INIT_CACHE_SIZE;
408 lastfree = glyphsetCache[best].next;
409 glyphsetCache[best].count = 1;
410 glyphsetCache[best].next = mru;
412 TRACE("new free cache slot at %d\n", mru);
416 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
426 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
427 if(size == GDI_ERROR)
430 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
431 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
433 GetTextMetricsW(physDev->hdc, &tm);
434 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
437 num_recs = get_be_word(*gasp);
441 *flags = get_be_word(*(gasp + 1));
442 if(ppem <= get_be_word(*gasp))
446 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
448 HeapFree(GetProcessHeap(), 0, buffer);
452 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
458 static int hinter = -1;
460 if((ret = LookupEntry(plfsz)) != -1) return ret;
463 entry = glyphsetCache + ret;
464 entry->lfsz = *plfsz;
465 for( format = 0; format < AA_MAXVALUE; format++ ) {
466 assert( !entry->format[format] );
469 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
473 RASTERIZER_STATUS status;
474 GetRasterizerCaps(&status, sizeof(status));
475 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
477 if(!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
478 entry->aa_default = AA_Grey;
480 entry->aa_default = AA_None;
483 entry->aa_default = AA_None;
488 static void dec_ref_cache(int index)
491 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
492 assert(glyphsetCache[index].count > 0);
493 glyphsetCache[index].count--;
496 static void lfsz_calc_hash(LFANDSIZE *plfsz)
498 DWORD hash = 0, *ptr;
501 hash ^= plfsz->devsize.cx;
502 hash ^= plfsz->devsize.cy;
503 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
505 for(i = 0, ptr = (DWORD*)&plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
506 WCHAR *pwc = (WCHAR *)ptr;
516 /***********************************************************************
517 * X11DRV_XRender_Finalize
519 void X11DRV_XRender_Finalize(void)
523 EnterCriticalSection(&xrender_cs);
524 for(i = mru; i >= 0; i = glyphsetCache[i].next)
526 LeaveCriticalSection(&xrender_cs);
530 /***********************************************************************
531 * X11DRV_XRender_SelectFont
533 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
537 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
538 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
539 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
540 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
541 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
542 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
543 lfsz_calc_hash(&lfsz);
545 EnterCriticalSection(&xrender_cs);
546 if(!physDev->xrender) {
547 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
548 sizeof(*physDev->xrender));
549 physDev->xrender->cache_index = -1;
551 else if(physDev->xrender->cache_index != -1)
552 dec_ref_cache(physDev->xrender->cache_index);
553 physDev->xrender->cache_index = GetCacheEntry(physDev, &lfsz);
554 LeaveCriticalSection(&xrender_cs);
558 /***********************************************************************
559 * X11DRV_XRender_DeleteDC
561 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
563 X11DRV_XRender_UpdateDrawable(physDev);
565 EnterCriticalSection(&xrender_cs);
566 if(physDev->xrender->cache_index != -1)
567 dec_ref_cache(physDev->xrender->cache_index);
568 LeaveCriticalSection(&xrender_cs);
570 HeapFree(GetProcessHeap(), 0, physDev->xrender);
571 physDev->xrender = NULL;
575 /***********************************************************************
576 * X11DRV_XRender_UpdateDrawable
578 * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
579 * It deletes the pict and tile when the drawable changes.
581 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
585 if(physDev->xrender->pict)
587 TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
589 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
590 physDev->xrender->pict = 0;
597 /************************************************************************
600 * Helper to ExtTextOut. Must be called inside xrender_cs
602 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
609 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
610 gsCacheEntryFormat *formatEntry;
611 UINT ggo_format = GGO_GLYPH_INDEX;
612 XRenderPictFormat pf;
613 static const char zero[4];
617 ggo_format |= WINE_GGO_GRAY16_BITMAP;
621 ERR("aa = %d - not implemented\n", format);
623 ggo_format |= GGO_BITMAP;
627 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
629 if(buflen == GDI_ERROR) {
630 if(format != AA_None) {
632 entry->aa_default = AA_None;
633 ggo_format &= ~WINE_GGO_GRAY16_BITMAP;
634 ggo_format |= GGO_BITMAP;
635 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
638 if(buflen == GDI_ERROR) {
639 WARN("GetGlyphOutlineW failed\n");
642 TRACE("Turning off antialiasing for this monochrome font\n");
645 /* If there is nothing for the current type, we create the entry. */
646 if( !entry->format[format] ) {
647 entry->format[format] = HeapAlloc(GetProcessHeap(),
649 sizeof(gsCacheEntryFormat));
651 formatEntry = entry->format[format];
653 if(formatEntry->nrealized <= glyph) {
654 formatEntry->nrealized = (glyph / 128 + 1) * 128;
656 if (formatEntry->realized)
657 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
659 formatEntry->realized,
660 formatEntry->nrealized * sizeof(BOOL));
662 formatEntry->realized = HeapAlloc(GetProcessHeap(),
664 formatEntry->nrealized * sizeof(BOOL));
666 if(!X11DRV_XRender_Installed) {
667 if (formatEntry->bitmaps)
668 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
670 formatEntry->bitmaps,
671 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
673 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
675 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
677 if (formatEntry->gis)
678 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
681 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
683 formatEntry->gis = HeapAlloc(GetProcessHeap(),
685 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
689 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
693 pf.direct.alphaMask = 0xff;
697 ERR("aa = %d - not implemented\n", format);
700 pf.direct.alphaMask = 1;
704 pf.type = PictTypeDirect;
708 formatEntry->font_format = pXRenderFindFormat(gdi_display,
715 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
720 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
721 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, NULL);
722 formatEntry->realized[glyph] = TRUE;
724 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
726 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
727 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
729 gi.width = gm.gmBlackBoxX;
730 gi.height = gm.gmBlackBoxY;
731 gi.x = -gm.gmptGlyphOrigin.x;
732 gi.y = gm.gmptGlyphOrigin.y;
733 gi.xOff = gm.gmCellIncX;
734 gi.yOff = gm.gmCellIncY;
736 if(TRACE_ON(xrender)) {
741 if(format == AA_None) {
742 pitch = ((gi.width + 31) / 32) * 4;
743 for(i = 0; i < gi.height; i++) {
744 line = (unsigned char*) buf + i * pitch;
746 for(j = 0; j < pitch * 8; j++) {
747 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
749 strcat(output, "\n");
753 static const char blks[] = " .:;!o*#";
757 pitch = ((gi.width + 3) / 4) * 4;
758 for(i = 0; i < gi.height; i++) {
759 line = (unsigned char*) buf + i * pitch;
761 for(j = 0; j < pitch; j++) {
762 str[0] = blks[line[j] >> 5];
765 strcat(output, "\n");
772 if(formatEntry->glyphset) {
773 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
774 unsigned char *byte = (unsigned char*) buf, c;
780 /* magic to flip bit order */
781 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
782 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
783 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
791 XRenderCompositeText seems to ignore 0x0 glyphs when
792 AA_None, which means we lose the advance width of glyphs
793 like the space. We'll pretend that such glyphs are 1x1
798 gi.width = gi.height = 1;
801 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
802 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
804 HeapFree(GetProcessHeap(), 0, buf);
806 formatEntry->bitmaps[glyph] = buf;
809 memcpy(&formatEntry->gis[glyph], &gi, sizeof(gi));
814 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
815 void *bitmap, XGlyphInfo *gi)
817 unsigned char *srcLine = bitmap, *src;
818 unsigned char bits, bitsMask;
819 int width = gi->width;
820 int stride = ((width + 31) & ~31) >> 3;
821 int height = gi->height;
825 TRACE("%d, %d\n", x, y);
834 bitsMask = 0x80; /* FreeType is always MSB first */
848 bitsMask = bitsMask >> 1;
854 } while (bits & bitsMask);
855 XFillRectangle (gdi_display, physDev->drawable,
856 physDev->gc, xspan, y, lenspan, 1);
868 bitsMask = bitsMask >> 1;
874 } while (!(bits & bitsMask));
881 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
882 void *bitmap, XGlyphInfo *gi)
884 unsigned char *srcLine = bitmap, *src, bits;
885 int width = gi->width;
886 int stride = ((width + 3) & ~3);
887 int height = gi->height;
912 } while (bits >= 0x80);
913 XFillRectangle (gdi_display, physDev->drawable,
914 physDev->gc, xspan, y, lenspan, 1);
927 } while (bits < 0x80);
935 static void ExamineBitfield (DWORD mask, int *shift, int *len)
940 while ((mask & 1) == 0)
946 while ((mask & 1) == 1)
955 static DWORD GetField (DWORD pixel, int shift, int len)
957 pixel = pixel & (((1 << (len)) - 1) << shift);
958 pixel = pixel << (32 - (shift + len)) >> 24;
961 pixel |= (pixel >> len);
968 static DWORD PutField (DWORD pixel, int shift, int len)
970 shift = shift - (8 - len);
972 pixel &= (((1 << len) - 1) << (8 - len));
980 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
986 BYTE *maskLine, *mask, m;
991 BYTE src_r, src_g, src_b;
998 maskLine = (unsigned char *) bitmap;
999 maskStride = (width + 3) & ~3;
1001 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1002 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1003 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1005 src_r = GetField(color, r_shift, r_len);
1006 src_g = GetField(color, g_shift, g_len);
1007 src_b = GetField(color, b_shift, b_len);
1009 for(; height--; y++)
1012 maskLine += maskStride;
1017 if(y >= image->height) break;
1021 if(tx >= image->width) break;
1024 if(tx < 0) continue;
1027 XPutPixel (image, tx, y, color);
1032 pixel = XGetPixel (image, tx, y);
1034 r = GetField(pixel, r_shift, r_len);
1035 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1036 g = GetField(pixel, g_shift, g_len);
1037 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1038 b = GetField(pixel, b_shift, b_len);
1039 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1041 pixel = (PutField (r, r_shift, r_len) |
1042 PutField (g, g_shift, g_len) |
1043 PutField (b, b_shift, b_len));
1044 XPutPixel (image, tx, y, pixel);
1050 /*************************************************************
1053 * Returns an appropiate Picture for tiling the text colour.
1054 * Call and use result within the xrender_cs
1056 static Picture get_tile_pict(enum drawable_depth_type type, int text_pixel)
1066 tile = &tiles[type];
1070 XRenderPictureAttributes pa;
1073 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_formats[type]->depth);
1076 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_formats[type], CPRepeat, &pa);
1077 wine_tsx11_unlock();
1079 /* init current_color to something different from text_pixel */
1080 tile->current_color = ~text_pixel;
1082 if(type == mono_drawable)
1084 /* for a 1bpp bitmap we always need a 1 in the tile */
1085 col.red = col.green = col.blue = 0;
1088 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1089 wine_tsx11_unlock();
1093 if(text_pixel != tile->current_color && type == color_drawable)
1095 /* Map 0 -- 0xff onto 0 -- 0xffff */
1100 ExamineBitfield (visual->red_mask, &r_shift, &r_len );
1101 ExamineBitfield (visual->green_mask, &g_shift, &g_len);
1102 ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
1104 col.red = GetField(text_pixel, r_shift, r_len);
1105 col.red |= col.red << 8;
1106 col.green = GetField(text_pixel, g_shift, g_len);
1107 col.green |= col.green << 8;
1108 col.blue = GetField(text_pixel, b_shift, b_len);
1109 col.blue |= col.blue << 8;
1113 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1114 wine_tsx11_unlock();
1115 tile->current_color = text_pixel;
1120 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1125 /***********************************************************************
1126 * X11DRV_XRender_ExtTextOut
1128 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1129 const RECT *lprect, LPCWSTR wstr, UINT count,
1134 gsCacheEntry *entry;
1135 gsCacheEntryFormat *formatEntry;
1137 HDC hdc = physDev->hdc;
1138 int textPixel, backgroundPixel;
1139 HRGN saved_region = 0;
1140 BOOL disable_antialias = FALSE;
1141 AA_Type aa_type = AA_None;
1144 double cosEsc, sinEsc;
1146 enum drawable_depth_type depth_type = (physDev->depth == 1) ? mono_drawable : color_drawable;
1147 Picture tile_pict = 0;
1149 /* Do we need to disable antialiasing because of palette mode? */
1150 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1151 TRACE("bitmap is not a DIB\n");
1153 else if (bmp.dsBmih.biBitCount <= 8) {
1154 TRACE("Disabling antialiasing\n");
1155 disable_antialias = TRUE;
1158 xgcval.function = GXcopy;
1159 xgcval.background = physDev->backgroundPixel;
1160 xgcval.fill_style = FillSolid;
1162 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1163 wine_tsx11_unlock();
1165 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1167 if(physDev->depth == 1) {
1168 if((physDev->textPixel & 0xffffff) == 0) {
1170 backgroundPixel = 1;
1173 backgroundPixel = 0;
1176 textPixel = physDev->textPixel;
1177 backgroundPixel = physDev->backgroundPixel;
1180 if(flags & ETO_OPAQUE)
1183 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1184 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1185 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1186 lprect->right - lprect->left, lprect->bottom - lprect->top );
1187 wine_tsx11_unlock();
1197 GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1198 if(lf.lfEscapement != 0) {
1199 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1200 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1206 if (flags & ETO_CLIPPED)
1210 clip_region = CreateRectRgnIndirect( lprect );
1211 /* make a copy of the current device region */
1212 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1213 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1214 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1215 DeleteObject( clip_region );
1218 if(X11DRV_XRender_Installed) {
1219 if(!physDev->xrender->pict) {
1220 XRenderPictureAttributes pa;
1221 pa.subwindow_mode = IncludeInferiors;
1224 physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1226 pict_formats[depth_type],
1227 CPSubwindowMode, &pa);
1228 wine_tsx11_unlock();
1230 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1231 physDev->xrender->pict, hdc, physDev->drawable);
1233 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1234 physDev->xrender->pict, hdc, physDev->drawable);
1237 if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1240 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1241 physDev->dc_rect.left, physDev->dc_rect.top,
1242 (XRectangle *)data->Buffer, data->rdh.nCount );
1243 wine_tsx11_unlock();
1244 HeapFree( GetProcessHeap(), 0, data );
1248 EnterCriticalSection(&xrender_cs);
1250 entry = glyphsetCache + physDev->xrender->cache_index;
1251 if( disable_antialias == FALSE )
1252 aa_type = entry->aa_default;
1253 formatEntry = entry->format[aa_type];
1255 for(idx = 0; idx < count; idx++) {
1256 if( !formatEntry ) {
1257 UploadGlyph(physDev, wstr[idx], aa_type);
1258 /* re-evaluate antialias since aa_default may have changed */
1259 if( disable_antialias == FALSE )
1260 aa_type = entry->aa_default;
1261 formatEntry = entry->format[aa_type];
1262 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1263 UploadGlyph(physDev, wstr[idx], aa_type);
1268 WARN("could not upload requested glyphs\n");
1269 LeaveCriticalSection(&xrender_cs);
1273 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1274 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1276 if(X11DRV_XRender_Installed)
1278 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1280 POINT desired, current;
1281 int render_op = PictOpOver;
1283 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1284 So we pass zeros to the function and move to our starting position using the first
1285 element of the elts array. */
1287 desired.x = physDev->dc_rect.left + x;
1288 desired.y = physDev->dc_rect.top + y;
1289 current.x = current.y = 0;
1291 tile_pict = get_tile_pict(depth_type, physDev->textPixel);
1293 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1295 if((depth_type == mono_drawable) && (textPixel == 0))
1296 render_op = PictOpOutReverse; /* This gives us 'black' text */
1298 for(idx = 0; idx < count; idx++)
1300 elts[idx].glyphset = formatEntry->glyphset;
1301 elts[idx].chars = wstr + idx;
1302 elts[idx].nchars = 1;
1303 elts[idx].xOff = desired.x - current.x;
1304 elts[idx].yOff = desired.y - current.y;
1306 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1307 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1311 desired.x += formatEntry->gis[wstr[idx]].xOff;
1312 desired.y += formatEntry->gis[wstr[idx]].yOff;
1316 offset += lpDx[idx];
1317 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1318 desired.y = physDev->dc_rect.top + y - offset * sinEsc;
1322 pXRenderCompositeText16(gdi_display, render_op,
1324 physDev->xrender->pict,
1325 formatEntry->font_format,
1326 0, 0, 0, 0, elts, count);
1327 wine_tsx11_unlock();
1328 HeapFree(GetProcessHeap(), 0, elts);
1330 INT offset = 0, xoff = 0, yoff = 0;
1332 XSetForeground( gdi_display, physDev->gc, textPixel );
1334 if(aa_type == AA_None || physDev->depth == 1)
1336 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1338 if(aa_type == AA_None)
1339 sharp_glyph_fn = SharpGlyphMono;
1341 sharp_glyph_fn = SharpGlyphGray;
1343 for(idx = 0; idx < count; idx++) {
1344 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1345 physDev->dc_rect.top + y + yoff,
1346 formatEntry->bitmaps[wstr[idx]],
1347 &formatEntry->gis[wstr[idx]]);
1349 offset += lpDx[idx];
1350 xoff = offset * cosEsc;
1351 yoff = offset * -sinEsc;
1353 xoff += formatEntry->gis[wstr[idx]].xOff;
1354 yoff += formatEntry->gis[wstr[idx]].yOff;
1359 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1360 RECT extents = {0, 0, 0, 0};
1362 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1363 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1365 TRACE("drawable %dx%d\n", w, h);
1367 for(idx = 0; idx < count; idx++) {
1368 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1369 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1370 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1371 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1372 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1373 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1374 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1375 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1377 offset += lpDx[idx];
1378 cur.x = offset * cosEsc;
1379 cur.y = offset * -sinEsc;
1381 cur.x += formatEntry->gis[wstr[idx]].xOff;
1382 cur.y += formatEntry->gis[wstr[idx]].yOff;
1385 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1386 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1388 if(physDev->dc_rect.left + x + extents.left >= 0) {
1389 image_x = physDev->dc_rect.left + x + extents.left;
1393 image_off_x = physDev->dc_rect.left + x + extents.left;
1395 if(physDev->dc_rect.top + y + extents.top >= 0) {
1396 image_y = physDev->dc_rect.top + y + extents.top;
1400 image_off_y = physDev->dc_rect.top + y + extents.top;
1402 if(physDev->dc_rect.left + x + extents.right < w)
1403 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1405 image_w = w - image_x;
1406 if(physDev->dc_rect.top + y + extents.bottom < h)
1407 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1409 image_h = h - image_y;
1411 if(image_w <= 0 || image_h <= 0) goto no_image;
1413 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1414 image = XGetImage(gdi_display, physDev->drawable,
1415 image_x, image_y, image_w, image_h,
1416 AllPlanes, ZPixmap);
1417 X11DRV_check_error();
1419 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1420 gdi_display, (int)physDev->drawable, image_x, image_y,
1421 image_w, image_h, AllPlanes, ZPixmap,
1422 physDev->depth, image);
1424 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
1429 gcv.graphics_exposures = False;
1430 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1431 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1432 image_w, image_h, 0, 0);
1433 XFreeGC(gdi_display, gc);
1434 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1435 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1437 X11DRV_check_error();
1438 XFreePixmap(gdi_display, xpm);
1440 if(!image) goto no_image;
1442 image->red_mask = visual->red_mask;
1443 image->green_mask = visual->green_mask;
1444 image->blue_mask = visual->blue_mask;
1446 offset = xoff = yoff = 0;
1447 for(idx = 0; idx < count; idx++) {
1448 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1449 yoff + image_off_y - extents.top,
1450 formatEntry->bitmaps[wstr[idx]],
1451 &formatEntry->gis[wstr[idx]],
1452 physDev->textPixel);
1454 offset += lpDx[idx];
1455 xoff = offset * cosEsc;
1456 yoff = offset * -sinEsc;
1458 xoff += formatEntry->gis[wstr[idx]].xOff;
1459 yoff += formatEntry->gis[wstr[idx]].yOff;
1462 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1463 image_x, image_y, image_w, image_h);
1464 XDestroyImage(image);
1467 wine_tsx11_unlock();
1469 LeaveCriticalSection(&xrender_cs);
1471 if (flags & ETO_CLIPPED)
1473 /* restore the device region */
1474 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1475 DeleteObject( saved_region );
1481 X11DRV_UnlockDIBSection( physDev, TRUE );
1485 /******************************************************************************
1486 * AlphaBlend (x11drv.@)
1488 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1489 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1490 BLENDFUNCTION blendfn)
1492 XRenderPictureAttributes pa;
1493 XRenderPictFormat *src_format;
1494 XRenderPictFormat argb32_templ = {
1496 PictTypeDirect, /* type */
1499 16, /* direct.red */
1500 0xff, /* direct.redMask */
1501 8, /* direct.green */
1502 0xff, /* direct.greenMask */
1503 0, /* direct.blue */
1504 0xff, /* direct.blueMask */
1505 24, /* direct.alpha */
1506 0xff, /* direct.alphaMask */
1510 unsigned long argb32_templ_mask =
1516 PictFormatGreenMask |
1518 PictFormatBlueMask |
1520 PictFormatAlphaMask;
1522 Picture dst_pict, src_pict;
1528 DWORD *dstbits, *data;
1531 BOOL top_down = FALSE;
1533 enum drawable_depth_type dst_depth_type = (devDst->depth == 1) ? mono_drawable : color_drawable;
1535 if(!X11DRV_XRender_Installed) {
1536 FIXME("Unable to AlphaBlend without Xrender\n");
1541 pts[1].x = xDst + widthDst;
1542 pts[1].y = yDst + heightDst;
1543 LPtoDP(devDst->hdc, pts, 2);
1546 widthDst = pts[1].x - pts[0].x;
1547 heightDst = pts[1].y - pts[0].y;
1551 pts[1].x = xSrc + widthSrc;
1552 pts[1].y = ySrc + heightSrc;
1553 LPtoDP(devSrc->hdc, pts, 2);
1556 widthSrc = pts[1].x - pts[0].x;
1557 heightSrc = pts[1].y - pts[0].y;
1558 if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1560 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1561 if(widthDst != widthSrc || heightDst != heightSrc)
1563 if(!pXRenderSetPictureTransform)
1566 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1570 if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1572 FIXME("not a dibsection\n");
1576 if (xSrc < 0 || ySrc < 0 || widthSrc < 0 || heightSrc < 0 || xSrc + widthSrc > dib.dsBmih.biWidth
1577 || ySrc + heightSrc > abs(dib.dsBmih.biHeight))
1579 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc, ySrc, widthSrc, heightSrc);
1580 SetLastError(ERROR_INVALID_PARAMETER);
1584 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && blendfn.SourceConstantAlpha != 0xff)
1585 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn.SourceConstantAlpha);
1587 if(dib.dsBm.bmBitsPixel != 32) {
1588 FIXME("not a 32 bpp dibsection\n");
1591 dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1593 if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1595 dstbits += widthSrc * (heightSrc - 1);
1597 y = y2 + heightSrc - 1;
1601 y = dib.dsBmih.biHeight - ySrc - 1;
1602 y2 = y - heightSrc + 1;
1605 if (blendfn.AlphaFormat & AC_SRC_ALPHA)
1609 memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1611 dstbits += (top_down ? -1 : 1) * widthSrc;
1616 DWORD source_alpha = (DWORD)blendfn.SourceConstantAlpha << 24;
1621 DWORD *srcbits = (DWORD *)((char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes) + xSrc;
1622 for (x = 0; x < widthSrc; x++)
1624 DWORD argb = *srcbits++;
1625 argb = (argb & 0xffffff) | source_alpha;
1628 if (top_down) /* we traversed the row forward so we should go back by two rows */
1629 dstbits -= 2 * widthSrc;
1634 rgndata = X11DRV_GetRegionData( devDst->region, 0 );
1637 image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1638 (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1641 Avoid using XRenderFindStandardFormat as older libraries don't have it
1642 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1644 src_format = pXRenderFindFormat(gdi_display, argb32_templ_mask, &argb32_templ, 0);
1646 TRACE("src_format %p\n", src_format);
1648 pa.subwindow_mode = IncludeInferiors;
1650 /* FIXME use devDst->xrender->pict ? */
1651 dst_pict = pXRenderCreatePicture(gdi_display,
1653 pict_formats[dst_depth_type],
1654 CPSubwindowMode, &pa);
1655 TRACE("dst_pict %08lx\n", dst_pict);
1656 TRACE("src_drawable = %08lx\n", devSrc->drawable);
1657 xpm = XCreatePixmap(gdi_display,
1659 widthSrc, heightSrc, 32);
1660 gcv.graphics_exposures = False;
1661 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1662 TRACE("xpm = %08lx\n", xpm);
1663 XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1665 src_pict = pXRenderCreatePicture(gdi_display,
1667 CPSubwindowMode, &pa);
1668 TRACE("src_pict %08lx\n", src_pict);
1672 pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
1673 devDst->dc_rect.left, devDst->dc_rect.top,
1674 (XRectangle *)rgndata->Buffer,
1675 rgndata->rdh.nCount );
1676 HeapFree( GetProcessHeap(), 0, rgndata );
1679 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1680 if(widthDst != widthSrc || heightDst != heightSrc) {
1681 double xscale = widthSrc/(double)widthDst;
1682 double yscale = heightSrc/(double)heightDst;
1683 XTransform xform = {{
1684 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0) },
1685 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0) },
1686 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1688 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1691 pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
1693 xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
1696 pXRenderFreePicture(gdi_display, src_pict);
1697 XFreePixmap(gdi_display, xpm);
1698 XFreeGC(gdi_display, gc);
1699 pXRenderFreePicture(gdi_display, dst_pict);
1701 XDestroyImage(image);
1703 wine_tsx11_unlock();
1704 HeapFree(GetProcessHeap(), 0, data);
1708 #else /* SONAME_LIBXRENDER */
1710 void X11DRV_XRender_Init(void)
1712 TRACE("XRender support not compiled in.\n");
1716 void X11DRV_XRender_Finalize(void)
1720 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1726 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1732 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1733 const RECT *lprect, LPCWSTR wstr, UINT count,
1740 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1746 /******************************************************************************
1747 * AlphaBlend (x11drv.@)
1749 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1750 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1751 BLENDFUNCTION blendfn)
1753 FIXME("not supported - XRENDER headers were missing at compile time\n");
1757 #endif /* SONAME_LIBXRENDER */