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 SONAME_LIBXRENDER
47 #include <X11/extensions/Xrender.h>
50 enum drawable_depth_type {mono_drawable, color_drawable};
51 static XRenderPictFormat *pict_formats[2];
56 SIZE devsize; /* size in device coords */
60 #define INITIAL_REALIZED_BUF_SIZE 128
62 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
67 XRenderPictFormat *font_format;
78 gsCacheEntryFormat * format[AA_MAXVALUE];
90 static gsCacheEntry *glyphsetCache = NULL;
91 static DWORD glyphsetCacheSize = 0;
92 static INT lastfree = -1;
95 #define INIT_CACHE_SIZE 10
97 static int antialias = 1;
99 static void *xrender_handle;
101 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
102 MAKE_FUNCPTR(XRenderAddGlyphs)
103 MAKE_FUNCPTR(XRenderComposite)
104 MAKE_FUNCPTR(XRenderCompositeString8)
105 MAKE_FUNCPTR(XRenderCompositeString16)
106 MAKE_FUNCPTR(XRenderCompositeString32)
107 MAKE_FUNCPTR(XRenderCompositeText16)
108 MAKE_FUNCPTR(XRenderCreateGlyphSet)
109 MAKE_FUNCPTR(XRenderCreatePicture)
110 MAKE_FUNCPTR(XRenderFillRectangle)
111 MAKE_FUNCPTR(XRenderFindFormat)
112 MAKE_FUNCPTR(XRenderFindVisualFormat)
113 MAKE_FUNCPTR(XRenderFreeGlyphSet)
114 MAKE_FUNCPTR(XRenderFreePicture)
115 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
116 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
117 MAKE_FUNCPTR(XRenderSetPictureTransform)
119 MAKE_FUNCPTR(XRenderQueryExtension)
122 static CRITICAL_SECTION xrender_cs;
123 static CRITICAL_SECTION_DEBUG critsect_debug =
126 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
127 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
129 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
131 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
132 ( ( (ULONG)_x4 << 24 ) | \
133 ( (ULONG)_x3 << 16 ) | \
134 ( (ULONG)_x2 << 8 ) | \
137 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
139 #define GASP_GRIDFIT 0x01
140 #define GASP_DOGRAY 0x02
142 #ifdef WORDS_BIGENDIAN
143 #define get_be_word(x) (x)
145 #define get_be_word(x) RtlUshortByteSwap(x)
148 /***********************************************************************
149 * X11DRV_XRender_Init
151 * Let's see if our XServer has the extension available
154 void X11DRV_XRender_Init(void)
157 XRenderPictFormat pf;
159 if (client_side_with_render &&
160 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
161 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
162 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
165 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
166 LOAD_FUNCPTR(XRenderAddGlyphs)
167 LOAD_FUNCPTR(XRenderComposite)
168 LOAD_FUNCPTR(XRenderCompositeString8)
169 LOAD_FUNCPTR(XRenderCompositeString16)
170 LOAD_FUNCPTR(XRenderCompositeString32)
171 LOAD_FUNCPTR(XRenderCompositeText16)
172 LOAD_FUNCPTR(XRenderCreateGlyphSet)
173 LOAD_FUNCPTR(XRenderCreatePicture)
174 LOAD_FUNCPTR(XRenderFillRectangle)
175 LOAD_FUNCPTR(XRenderFindFormat)
176 LOAD_FUNCPTR(XRenderFindVisualFormat)
177 LOAD_FUNCPTR(XRenderFreeGlyphSet)
178 LOAD_FUNCPTR(XRenderFreePicture)
179 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
180 LOAD_FUNCPTR(XRenderQueryExtension)
182 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
183 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
184 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
185 #undef LOAD_OPTIONAL_FUNCPTR
190 if(pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) {
191 X11DRV_XRender_Installed = TRUE;
192 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
193 pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, visual);
194 if(!pict_formats[color_drawable])
196 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
197 if (visual->class == DirectColor)
200 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
201 screen_depth, TrueColor, &info ))
203 pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, info.visual);
204 if (pict_formats[color_drawable]) visual = info.visual;
208 if(!pict_formats[color_drawable]) /* This fails in buggy versions of libXrender.so */
212 "Wine has detected that you probably have a buggy version\n"
213 "of libXrender.so . Because of this client side font rendering\n"
214 "will be disabled. Please upgrade this library.\n");
215 X11DRV_XRender_Installed = FALSE;
218 pf.type = PictTypeDirect;
221 pf.direct.alphaMask = 1;
222 pict_formats[mono_drawable] = pXRenderFindFormat(gdi_display, PictFormatType |
223 PictFormatDepth | PictFormatAlpha |
224 PictFormatAlphaMask, &pf, 0);
225 if(!pict_formats[mono_drawable]) {
226 ERR("mono_format == NULL?\n");
227 X11DRV_XRender_Installed = FALSE;
229 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
230 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
231 X11DRV_XRender_Installed = FALSE;
238 if(X11DRV_XRender_Installed || client_side_with_core)
240 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
241 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
243 glyphsetCacheSize = INIT_CACHE_SIZE;
245 for(i = 0; i < INIT_CACHE_SIZE; i++) {
246 glyphsetCache[i].next = i + 1;
247 glyphsetCache[i].count = -1;
249 glyphsetCache[i-1].next = -1;
250 using_client_side_fonts = 1;
252 if(!X11DRV_XRender_Installed) {
253 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
254 if(screen_depth <= 8 || !client_side_antialias_with_core)
257 if(screen_depth <= 8 || !client_side_antialias_with_render)
261 else TRACE("Using X11 core fonts\n");
264 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
266 if(p1->hash != p2->hash) return TRUE;
267 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
268 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
269 return strcmpW(p1->lf.lfFaceName, p2->lf.lfFaceName);
273 static void walk_cache(void)
277 EnterCriticalSection(&xrender_cs);
278 for(i=mru; i >= 0; i = glyphsetCache[i].next)
279 TRACE("item %d\n", i);
280 LeaveCriticalSection(&xrender_cs);
284 static int LookupEntry(LFANDSIZE *plfsz)
288 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
290 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
295 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
296 glyphsetCache[i].count++;
298 glyphsetCache[prev_i].next = glyphsetCache[i].next;
299 glyphsetCache[i].next = mru;
302 TRACE("found font in cache %d\n", i);
307 TRACE("font not in cache\n");
311 static void FreeEntry(int entry)
315 for(format = 0; format < AA_MAXVALUE; format++) {
316 gsCacheEntryFormat * formatEntry;
318 if( !glyphsetCache[entry].format[format] )
321 formatEntry = glyphsetCache[entry].format[format];
323 if(formatEntry->glyphset) {
325 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
327 formatEntry->glyphset = 0;
329 if(formatEntry->nrealized) {
330 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
331 formatEntry->realized = NULL;
332 if(formatEntry->bitmaps) {
333 for(i = 0; i < formatEntry->nrealized; i++)
334 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
335 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
336 formatEntry->bitmaps = NULL;
338 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
339 formatEntry->gis = NULL;
340 formatEntry->nrealized = 0;
343 HeapFree(GetProcessHeap(), 0, formatEntry);
344 glyphsetCache[entry].format[format] = NULL;
348 static int AllocEntry(void)
350 int best = -1, prev_best = -1, i, prev_i = -1;
353 assert(glyphsetCache[lastfree].count == -1);
354 glyphsetCache[lastfree].count = 1;
356 lastfree = glyphsetCache[lastfree].next;
358 glyphsetCache[best].next = mru;
361 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
365 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
366 if(glyphsetCache[i].count == 0) {
374 TRACE("freeing unused glyphset at cache %d\n", best);
376 glyphsetCache[best].count = 1;
378 glyphsetCache[prev_best].next = glyphsetCache[best].next;
379 glyphsetCache[best].next = mru;
387 TRACE("Growing cache\n");
390 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
392 (glyphsetCacheSize + INIT_CACHE_SIZE)
393 * sizeof(*glyphsetCache));
395 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
396 (glyphsetCacheSize + INIT_CACHE_SIZE)
397 * sizeof(*glyphsetCache));
399 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
401 glyphsetCache[i].next = i + 1;
402 glyphsetCache[i].count = -1;
404 glyphsetCache[i-1].next = -1;
405 glyphsetCacheSize += INIT_CACHE_SIZE;
407 lastfree = glyphsetCache[best].next;
408 glyphsetCache[best].count = 1;
409 glyphsetCache[best].next = mru;
411 TRACE("new free cache slot at %d\n", mru);
415 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
425 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
426 if(size == GDI_ERROR)
429 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
430 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
432 GetTextMetricsW(physDev->hdc, &tm);
433 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
436 num_recs = get_be_word(*gasp);
440 *flags = get_be_word(*(gasp + 1));
441 if(ppem <= get_be_word(*gasp))
445 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
447 HeapFree(GetProcessHeap(), 0, buffer);
451 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
457 static int hinter = -1;
459 if((ret = LookupEntry(plfsz)) != -1) return ret;
462 entry = glyphsetCache + ret;
463 entry->lfsz = *plfsz;
464 for( format = 0; format < AA_MAXVALUE; format++ ) {
465 assert( !entry->format[format] );
468 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
472 RASTERIZER_STATUS status;
473 GetRasterizerCaps(&status, sizeof(status));
474 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
476 if(!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
477 entry->aa_default = AA_Grey;
479 entry->aa_default = AA_None;
482 entry->aa_default = AA_None;
487 static void dec_ref_cache(int index)
490 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
491 assert(glyphsetCache[index].count > 0);
492 glyphsetCache[index].count--;
495 static void lfsz_calc_hash(LFANDSIZE *plfsz)
497 DWORD hash = 0, *ptr;
500 hash ^= plfsz->devsize.cx;
501 hash ^= plfsz->devsize.cy;
502 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
504 for(i = 0, ptr = (DWORD*)&plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
505 WCHAR *pwc = (WCHAR *)ptr;
515 /***********************************************************************
516 * X11DRV_XRender_Finalize
518 void X11DRV_XRender_Finalize(void)
522 EnterCriticalSection(&xrender_cs);
523 for(i = mru; i >= 0; i = glyphsetCache[i].next)
525 LeaveCriticalSection(&xrender_cs);
529 /***********************************************************************
530 * X11DRV_XRender_SelectFont
532 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
536 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
537 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
538 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
539 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
540 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
541 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
542 lfsz_calc_hash(&lfsz);
544 EnterCriticalSection(&xrender_cs);
545 if(!physDev->xrender) {
546 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
547 sizeof(*physDev->xrender));
548 physDev->xrender->cache_index = -1;
550 else if(physDev->xrender->cache_index != -1)
551 dec_ref_cache(physDev->xrender->cache_index);
552 physDev->xrender->cache_index = GetCacheEntry(physDev, &lfsz);
553 LeaveCriticalSection(&xrender_cs);
557 /***********************************************************************
558 * X11DRV_XRender_DeleteDC
560 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
562 X11DRV_XRender_UpdateDrawable(physDev);
564 EnterCriticalSection(&xrender_cs);
565 if(physDev->xrender->cache_index != -1)
566 dec_ref_cache(physDev->xrender->cache_index);
567 LeaveCriticalSection(&xrender_cs);
569 HeapFree(GetProcessHeap(), 0, physDev->xrender);
570 physDev->xrender = NULL;
574 /***********************************************************************
575 * X11DRV_XRender_UpdateDrawable
577 * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
578 * It deletes the pict and tile when the drawable changes.
580 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
584 if(physDev->xrender->pict)
586 TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
588 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
589 physDev->xrender->pict = 0;
596 /************************************************************************
599 * Helper to ExtTextOut. Must be called inside xrender_cs
601 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
608 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
609 gsCacheEntryFormat *formatEntry;
610 UINT ggo_format = GGO_GLYPH_INDEX;
611 XRenderPictFormat pf;
612 static const char zero[4];
616 ggo_format |= WINE_GGO_GRAY16_BITMAP;
620 ERR("aa = %d - not implemented\n", format);
622 ggo_format |= GGO_BITMAP;
626 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
628 if(buflen == GDI_ERROR) {
629 if(format != AA_None) {
631 entry->aa_default = AA_None;
632 ggo_format &= ~WINE_GGO_GRAY16_BITMAP;
633 ggo_format |= GGO_BITMAP;
634 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
637 if(buflen == GDI_ERROR) {
638 WARN("GetGlyphOutlineW failed\n");
641 TRACE("Turning off antialiasing for this monochrome font\n");
644 /* If there is nothing for the current type, we create the entry. */
645 if( !entry->format[format] ) {
646 entry->format[format] = HeapAlloc(GetProcessHeap(),
648 sizeof(gsCacheEntryFormat));
650 formatEntry = entry->format[format];
652 if(formatEntry->nrealized <= glyph) {
653 formatEntry->nrealized = (glyph / 128 + 1) * 128;
655 if (formatEntry->realized)
656 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
658 formatEntry->realized,
659 formatEntry->nrealized * sizeof(BOOL));
661 formatEntry->realized = HeapAlloc(GetProcessHeap(),
663 formatEntry->nrealized * sizeof(BOOL));
665 if(!X11DRV_XRender_Installed) {
666 if (formatEntry->bitmaps)
667 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
669 formatEntry->bitmaps,
670 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
672 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
674 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
676 if (formatEntry->gis)
677 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
680 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
682 formatEntry->gis = HeapAlloc(GetProcessHeap(),
684 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
688 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
692 pf.direct.alphaMask = 0xff;
696 ERR("aa = %d - not implemented\n", format);
699 pf.direct.alphaMask = 1;
703 pf.type = PictTypeDirect;
707 formatEntry->font_format = pXRenderFindFormat(gdi_display,
714 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
719 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
720 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, NULL);
721 formatEntry->realized[glyph] = TRUE;
723 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
725 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
726 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
728 gi.width = gm.gmBlackBoxX;
729 gi.height = gm.gmBlackBoxY;
730 gi.x = -gm.gmptGlyphOrigin.x;
731 gi.y = gm.gmptGlyphOrigin.y;
732 gi.xOff = gm.gmCellIncX;
733 gi.yOff = gm.gmCellIncY;
735 if(TRACE_ON(xrender)) {
740 if(format == AA_None) {
741 pitch = ((gi.width + 31) / 32) * 4;
742 for(i = 0; i < gi.height; i++) {
743 line = (unsigned char*) buf + i * pitch;
745 for(j = 0; j < pitch * 8; j++) {
746 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
748 strcat(output, "\n");
752 static const char blks[] = " .:;!o*#";
756 pitch = ((gi.width + 3) / 4) * 4;
757 for(i = 0; i < gi.height; i++) {
758 line = (unsigned char*) buf + i * pitch;
760 for(j = 0; j < pitch; j++) {
761 str[0] = blks[line[j] >> 5];
764 strcat(output, "\n");
771 if(formatEntry->glyphset) {
772 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
773 unsigned char *byte = (unsigned char*) buf, c;
779 /* magic to flip bit order */
780 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
781 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
782 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
790 XRenderCompositeText seems to ignore 0x0 glyphs when
791 AA_None, which means we lose the advance width of glyphs
792 like the space. We'll pretend that such glyphs are 1x1
797 gi.width = gi.height = 1;
800 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
801 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
803 HeapFree(GetProcessHeap(), 0, buf);
805 formatEntry->bitmaps[glyph] = buf;
808 memcpy(&formatEntry->gis[glyph], &gi, sizeof(gi));
813 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
814 void *bitmap, XGlyphInfo *gi)
816 unsigned char *srcLine = bitmap, *src;
817 unsigned char bits, bitsMask;
818 int width = gi->width;
819 int stride = ((width + 31) & ~31) >> 3;
820 int height = gi->height;
824 TRACE("%d, %d\n", x, y);
833 bitsMask = 0x80; /* FreeType is always MSB first */
847 bitsMask = bitsMask >> 1;
853 } while (bits & bitsMask);
854 XFillRectangle (gdi_display, physDev->drawable,
855 physDev->gc, xspan, y, lenspan, 1);
867 bitsMask = bitsMask >> 1;
873 } while (!(bits & bitsMask));
880 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
881 void *bitmap, XGlyphInfo *gi)
883 unsigned char *srcLine = bitmap, *src, bits;
884 int width = gi->width;
885 int stride = ((width + 3) & ~3);
886 int height = gi->height;
911 } while (bits >= 0x80);
912 XFillRectangle (gdi_display, physDev->drawable,
913 physDev->gc, xspan, y, lenspan, 1);
926 } while (bits < 0x80);
934 static void ExamineBitfield (DWORD mask, int *shift, int *len)
939 while ((mask & 1) == 0)
945 while ((mask & 1) == 1)
954 static DWORD GetField (DWORD pixel, int shift, int len)
956 pixel = pixel & (((1 << (len)) - 1) << shift);
957 pixel = pixel << (32 - (shift + len)) >> 24;
960 pixel |= (pixel >> len);
967 static DWORD PutField (DWORD pixel, int shift, int len)
969 shift = shift - (8 - len);
971 pixel &= (((1 << len) - 1) << (8 - len));
979 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
985 BYTE *maskLine, *mask, m;
990 BYTE src_r, src_g, src_b;
997 maskLine = (unsigned char *) bitmap;
998 maskStride = (width + 3) & ~3;
1000 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1001 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1002 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1004 src_r = GetField(color, r_shift, r_len);
1005 src_g = GetField(color, g_shift, g_len);
1006 src_b = GetField(color, b_shift, b_len);
1008 for(; height--; y++)
1011 maskLine += maskStride;
1016 if(y >= image->height) break;
1020 if(tx >= image->width) break;
1023 if(tx < 0) continue;
1026 XPutPixel (image, tx, y, color);
1031 pixel = XGetPixel (image, tx, y);
1033 r = GetField(pixel, r_shift, r_len);
1034 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1035 g = GetField(pixel, g_shift, g_len);
1036 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1037 b = GetField(pixel, b_shift, b_len);
1038 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1040 pixel = (PutField (r, r_shift, r_len) |
1041 PutField (g, g_shift, g_len) |
1042 PutField (b, b_shift, b_len));
1043 XPutPixel (image, tx, y, pixel);
1049 /*************************************************************
1052 * Returns an appropiate Picture for tiling the text colour.
1053 * Call and use result within the xrender_cs
1055 static Picture get_tile_pict(enum drawable_depth_type type, int text_pixel)
1065 tile = &tiles[type];
1069 XRenderPictureAttributes pa;
1072 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_formats[type]->depth);
1075 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_formats[type], CPRepeat, &pa);
1076 wine_tsx11_unlock();
1078 /* init current_color to something different from text_pixel */
1079 tile->current_color = ~text_pixel;
1081 if(type == mono_drawable)
1083 /* for a 1bpp bitmap we always need a 1 in the tile */
1084 col.red = col.green = col.blue = 0;
1087 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1088 wine_tsx11_unlock();
1092 if(text_pixel != tile->current_color && type == color_drawable)
1094 /* Map 0 -- 0xff onto 0 -- 0xffff */
1099 ExamineBitfield (visual->red_mask, &r_shift, &r_len );
1100 ExamineBitfield (visual->green_mask, &g_shift, &g_len);
1101 ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
1103 col.red = GetField(text_pixel, r_shift, r_len);
1104 col.red |= col.red << 8;
1105 col.green = GetField(text_pixel, g_shift, g_len);
1106 col.green |= col.green << 8;
1107 col.blue = GetField(text_pixel, b_shift, b_len);
1108 col.blue |= col.blue << 8;
1112 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1113 wine_tsx11_unlock();
1114 tile->current_color = text_pixel;
1119 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1124 /***********************************************************************
1125 * X11DRV_XRender_ExtTextOut
1127 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1128 const RECT *lprect, LPCWSTR wstr, UINT count,
1133 gsCacheEntry *entry;
1134 gsCacheEntryFormat *formatEntry;
1136 HDC hdc = physDev->hdc;
1137 int textPixel, backgroundPixel;
1138 HRGN saved_region = 0;
1139 BOOL disable_antialias = FALSE;
1140 AA_Type aa_type = AA_None;
1143 double cosEsc, sinEsc;
1145 enum drawable_depth_type depth_type = (physDev->depth == 1) ? mono_drawable : color_drawable;
1146 Picture tile_pict = 0;
1148 /* Do we need to disable antialiasing because of palette mode? */
1149 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1150 TRACE("bitmap is not a DIB\n");
1152 else if (bmp.dsBmih.biBitCount <= 8) {
1153 TRACE("Disabling antialiasing\n");
1154 disable_antialias = TRUE;
1157 xgcval.function = GXcopy;
1158 xgcval.background = physDev->backgroundPixel;
1159 xgcval.fill_style = FillSolid;
1161 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1162 wine_tsx11_unlock();
1164 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1166 if(physDev->depth == 1) {
1167 if((physDev->textPixel & 0xffffff) == 0) {
1169 backgroundPixel = 1;
1172 backgroundPixel = 0;
1175 textPixel = physDev->textPixel;
1176 backgroundPixel = physDev->backgroundPixel;
1179 if(flags & ETO_OPAQUE)
1182 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1183 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1184 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1185 lprect->right - lprect->left, lprect->bottom - lprect->top );
1186 wine_tsx11_unlock();
1196 GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1197 if(lf.lfEscapement != 0) {
1198 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1199 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1205 if (flags & ETO_CLIPPED)
1209 clip_region = CreateRectRgnIndirect( lprect );
1210 /* make a copy of the current device region */
1211 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1212 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1213 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1214 DeleteObject( clip_region );
1217 if(X11DRV_XRender_Installed) {
1218 if(!physDev->xrender->pict) {
1219 XRenderPictureAttributes pa;
1220 pa.subwindow_mode = IncludeInferiors;
1223 physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1225 pict_formats[depth_type],
1226 CPSubwindowMode, &pa);
1227 wine_tsx11_unlock();
1229 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1230 physDev->xrender->pict, hdc, physDev->drawable);
1232 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1233 physDev->xrender->pict, hdc, physDev->drawable);
1236 if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1239 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1240 physDev->dc_rect.left, physDev->dc_rect.top,
1241 (XRectangle *)data->Buffer, data->rdh.nCount );
1242 wine_tsx11_unlock();
1243 HeapFree( GetProcessHeap(), 0, data );
1247 EnterCriticalSection(&xrender_cs);
1249 entry = glyphsetCache + physDev->xrender->cache_index;
1250 if( disable_antialias == FALSE )
1251 aa_type = entry->aa_default;
1252 formatEntry = entry->format[aa_type];
1254 for(idx = 0; idx < count; idx++) {
1255 if( !formatEntry ) {
1256 UploadGlyph(physDev, wstr[idx], aa_type);
1257 /* re-evaluate antialias since aa_default may have changed */
1258 if( disable_antialias == FALSE )
1259 aa_type = entry->aa_default;
1260 formatEntry = entry->format[aa_type];
1261 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1262 UploadGlyph(physDev, wstr[idx], aa_type);
1267 WARN("could not upload requested glyphs\n");
1268 LeaveCriticalSection(&xrender_cs);
1272 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1273 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1275 if(X11DRV_XRender_Installed)
1277 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1279 POINT desired, current;
1280 int render_op = PictOpOver;
1282 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1283 So we pass zeros to the function and move to our starting position using the first
1284 element of the elts array. */
1286 desired.x = physDev->dc_rect.left + x;
1287 desired.y = physDev->dc_rect.top + y;
1288 current.x = current.y = 0;
1290 tile_pict = get_tile_pict(depth_type, physDev->textPixel);
1292 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1294 if((depth_type == mono_drawable) && (textPixel == 0))
1295 render_op = PictOpOutReverse; /* This gives us 'black' text */
1297 for(idx = 0; idx < count; idx++)
1299 elts[idx].glyphset = formatEntry->glyphset;
1300 elts[idx].chars = wstr + idx;
1301 elts[idx].nchars = 1;
1302 elts[idx].xOff = desired.x - current.x;
1303 elts[idx].yOff = desired.y - current.y;
1305 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1306 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1310 desired.x += formatEntry->gis[wstr[idx]].xOff;
1311 desired.y += formatEntry->gis[wstr[idx]].yOff;
1315 offset += lpDx[idx];
1316 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1317 desired.y = physDev->dc_rect.top + y - offset * sinEsc;
1321 pXRenderCompositeText16(gdi_display, render_op,
1323 physDev->xrender->pict,
1324 formatEntry->font_format,
1325 0, 0, 0, 0, elts, count);
1326 wine_tsx11_unlock();
1327 HeapFree(GetProcessHeap(), 0, elts);
1329 INT offset = 0, xoff = 0, yoff = 0;
1331 XSetForeground( gdi_display, physDev->gc, textPixel );
1333 if(aa_type == AA_None || physDev->depth == 1)
1335 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1337 if(aa_type == AA_None)
1338 sharp_glyph_fn = SharpGlyphMono;
1340 sharp_glyph_fn = SharpGlyphGray;
1342 for(idx = 0; idx < count; idx++) {
1343 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1344 physDev->dc_rect.top + y + yoff,
1345 formatEntry->bitmaps[wstr[idx]],
1346 &formatEntry->gis[wstr[idx]]);
1348 offset += lpDx[idx];
1349 xoff = offset * cosEsc;
1350 yoff = offset * -sinEsc;
1352 xoff += formatEntry->gis[wstr[idx]].xOff;
1353 yoff += formatEntry->gis[wstr[idx]].yOff;
1358 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1359 RECT extents = {0, 0, 0, 0};
1361 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1362 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1364 TRACE("drawable %dx%d\n", w, h);
1366 for(idx = 0; idx < count; idx++) {
1367 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1368 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1369 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1370 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1371 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1372 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1373 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1374 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1376 offset += lpDx[idx];
1377 cur.x = offset * cosEsc;
1378 cur.y = offset * -sinEsc;
1380 cur.x += formatEntry->gis[wstr[idx]].xOff;
1381 cur.y += formatEntry->gis[wstr[idx]].yOff;
1384 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1385 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1387 if(physDev->dc_rect.left + x + extents.left >= 0) {
1388 image_x = physDev->dc_rect.left + x + extents.left;
1392 image_off_x = physDev->dc_rect.left + x + extents.left;
1394 if(physDev->dc_rect.top + y + extents.top >= 0) {
1395 image_y = physDev->dc_rect.top + y + extents.top;
1399 image_off_y = physDev->dc_rect.top + y + extents.top;
1401 if(physDev->dc_rect.left + x + extents.right < w)
1402 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1404 image_w = w - image_x;
1405 if(physDev->dc_rect.top + y + extents.bottom < h)
1406 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1408 image_h = h - image_y;
1410 if(image_w <= 0 || image_h <= 0) goto no_image;
1412 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1413 image = XGetImage(gdi_display, physDev->drawable,
1414 image_x, image_y, image_w, image_h,
1415 AllPlanes, ZPixmap);
1416 X11DRV_check_error();
1418 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1419 gdi_display, (int)physDev->drawable, image_x, image_y,
1420 image_w, image_h, AllPlanes, ZPixmap,
1421 physDev->depth, image);
1423 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
1428 gcv.graphics_exposures = False;
1429 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1430 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1431 image_w, image_h, 0, 0);
1432 XFreeGC(gdi_display, gc);
1433 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1434 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1436 X11DRV_check_error();
1437 XFreePixmap(gdi_display, xpm);
1439 if(!image) goto no_image;
1441 image->red_mask = visual->red_mask;
1442 image->green_mask = visual->green_mask;
1443 image->blue_mask = visual->blue_mask;
1445 offset = xoff = yoff = 0;
1446 for(idx = 0; idx < count; idx++) {
1447 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1448 yoff + image_off_y - extents.top,
1449 formatEntry->bitmaps[wstr[idx]],
1450 &formatEntry->gis[wstr[idx]],
1451 physDev->textPixel);
1453 offset += lpDx[idx];
1454 xoff = offset * cosEsc;
1455 yoff = offset * -sinEsc;
1457 xoff += formatEntry->gis[wstr[idx]].xOff;
1458 yoff += formatEntry->gis[wstr[idx]].yOff;
1461 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1462 image_x, image_y, image_w, image_h);
1463 XDestroyImage(image);
1466 wine_tsx11_unlock();
1468 LeaveCriticalSection(&xrender_cs);
1470 if (flags & ETO_CLIPPED)
1472 /* restore the device region */
1473 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1474 DeleteObject( saved_region );
1480 X11DRV_UnlockDIBSection( physDev, TRUE );
1484 /******************************************************************************
1485 * AlphaBlend (x11drv.@)
1487 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1488 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1489 BLENDFUNCTION blendfn)
1491 XRenderPictureAttributes pa;
1492 XRenderPictFormat *src_format;
1493 XRenderPictFormat argb32_templ = {
1495 PictTypeDirect, /* type */
1498 16, /* direct.red */
1499 0xff, /* direct.redMask */
1500 8, /* direct.green */
1501 0xff, /* direct.greenMask */
1502 0, /* direct.blue */
1503 0xff, /* direct.blueMask */
1504 24, /* direct.alpha */
1505 0xff, /* direct.alphaMask */
1509 unsigned long argb32_templ_mask =
1515 PictFormatGreenMask |
1517 PictFormatBlueMask |
1519 PictFormatAlphaMask;
1521 Picture dst_pict, src_pict;
1527 DWORD *dstbits, *data;
1530 BOOL top_down = FALSE;
1532 enum drawable_depth_type dst_depth_type = (devDst->depth == 1) ? mono_drawable : color_drawable;
1534 if(!X11DRV_XRender_Installed) {
1535 FIXME("Unable to AlphaBlend without Xrender\n");
1540 pts[1].x = xDst + widthDst;
1541 pts[1].y = yDst + heightDst;
1542 LPtoDP(devDst->hdc, pts, 2);
1545 widthDst = pts[1].x - pts[0].x;
1546 heightDst = pts[1].y - pts[0].y;
1550 pts[1].x = xSrc + widthSrc;
1551 pts[1].y = ySrc + heightSrc;
1552 LPtoDP(devSrc->hdc, pts, 2);
1555 widthSrc = pts[1].x - pts[0].x;
1556 heightSrc = pts[1].y - pts[0].y;
1557 if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1559 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1560 if(widthDst != widthSrc || heightDst != heightSrc)
1562 if(!pXRenderSetPictureTransform)
1565 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1569 if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1571 FIXME("not a dibsection\n");
1575 if (xSrc < 0 || ySrc < 0 || widthSrc < 0 || heightSrc < 0 || xSrc + widthSrc > dib.dsBmih.biWidth
1576 || ySrc + heightSrc > abs(dib.dsBmih.biHeight))
1578 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc, ySrc, widthSrc, heightSrc);
1579 SetLastError(ERROR_INVALID_PARAMETER);
1583 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && blendfn.SourceConstantAlpha != 0xff)
1584 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn.SourceConstantAlpha);
1586 if(dib.dsBm.bmBitsPixel != 32) {
1587 FIXME("not a 32 bpp dibsection\n");
1590 dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1592 if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1594 dstbits += widthSrc * (heightSrc - 1);
1596 y = y2 + heightSrc - 1;
1600 y = dib.dsBmih.biHeight - ySrc - 1;
1601 y2 = y - heightSrc + 1;
1604 if (blendfn.AlphaFormat & AC_SRC_ALPHA)
1608 memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1610 dstbits += (top_down ? -1 : 1) * widthSrc;
1615 DWORD source_alpha = (DWORD)blendfn.SourceConstantAlpha << 24;
1620 DWORD *srcbits = (DWORD *)((char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes) + xSrc;
1621 for (x = 0; x < widthSrc; x++)
1623 DWORD argb = *srcbits++;
1624 argb = (argb & 0xffffff) | source_alpha;
1627 if (top_down) /* we traversed the row forward so we should go back by two rows */
1628 dstbits -= 2 * widthSrc;
1633 rgndata = X11DRV_GetRegionData( devDst->region, 0 );
1636 image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1637 (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1640 Avoid using XRenderFindStandardFormat as older libraries don't have it
1641 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1643 src_format = pXRenderFindFormat(gdi_display, argb32_templ_mask, &argb32_templ, 0);
1645 TRACE("src_format %p\n", src_format);
1647 pa.subwindow_mode = IncludeInferiors;
1649 /* FIXME use devDst->xrender->pict ? */
1650 dst_pict = pXRenderCreatePicture(gdi_display,
1652 pict_formats[dst_depth_type],
1653 CPSubwindowMode, &pa);
1654 TRACE("dst_pict %08lx\n", dst_pict);
1655 TRACE("src_drawable = %08lx\n", devSrc->drawable);
1656 xpm = XCreatePixmap(gdi_display,
1658 widthSrc, heightSrc, 32);
1659 gcv.graphics_exposures = False;
1660 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1661 TRACE("xpm = %08lx\n", xpm);
1662 XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1664 src_pict = pXRenderCreatePicture(gdi_display,
1666 CPSubwindowMode, &pa);
1667 TRACE("src_pict %08lx\n", src_pict);
1671 pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
1672 devDst->dc_rect.left, devDst->dc_rect.top,
1673 (XRectangle *)rgndata->Buffer,
1674 rgndata->rdh.nCount );
1675 HeapFree( GetProcessHeap(), 0, rgndata );
1678 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1679 if(widthDst != widthSrc || heightDst != heightSrc) {
1680 double xscale = widthSrc/(double)widthDst;
1681 double yscale = heightSrc/(double)heightDst;
1682 XTransform xform = {{
1683 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0) },
1684 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0) },
1685 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1687 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1690 pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
1692 xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
1695 pXRenderFreePicture(gdi_display, src_pict);
1696 XFreePixmap(gdi_display, xpm);
1697 XFreeGC(gdi_display, gc);
1698 pXRenderFreePicture(gdi_display, dst_pict);
1700 XDestroyImage(image);
1702 wine_tsx11_unlock();
1703 HeapFree(GetProcessHeap(), 0, data);
1707 #else /* SONAME_LIBXRENDER */
1709 void X11DRV_XRender_Init(void)
1711 TRACE("XRender support not compiled in.\n");
1715 void X11DRV_XRender_Finalize(void)
1719 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1725 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1731 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1732 const RECT *lprect, LPCWSTR wstr, UINT count,
1739 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1745 /******************************************************************************
1746 * AlphaBlend (x11drv.@)
1748 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1749 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1750 BLENDFUNCTION blendfn)
1752 FIXME("not supported - XRENDER headers were missing at compile time\n");
1756 #endif /* SONAME_LIBXRENDER */