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];
58 SIZE devsize; /* size in device coords */
62 #define INITIAL_REALIZED_BUF_SIZE 128
64 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
69 XRenderPictFormat *font_format;
80 gsCacheEntryFormat * format[AA_MAXVALUE];
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 static void *xrender_handle;
103 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
104 MAKE_FUNCPTR(XRenderAddGlyphs)
105 MAKE_FUNCPTR(XRenderComposite)
106 MAKE_FUNCPTR(XRenderCompositeString8)
107 MAKE_FUNCPTR(XRenderCompositeString16)
108 MAKE_FUNCPTR(XRenderCompositeString32)
109 MAKE_FUNCPTR(XRenderCompositeText16)
110 MAKE_FUNCPTR(XRenderCreateGlyphSet)
111 MAKE_FUNCPTR(XRenderCreatePicture)
112 MAKE_FUNCPTR(XRenderFillRectangle)
113 MAKE_FUNCPTR(XRenderFindFormat)
114 MAKE_FUNCPTR(XRenderFindVisualFormat)
115 MAKE_FUNCPTR(XRenderFreeGlyphSet)
116 MAKE_FUNCPTR(XRenderFreePicture)
117 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
118 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
119 MAKE_FUNCPTR(XRenderSetPictureTransform)
121 MAKE_FUNCPTR(XRenderQueryExtension)
124 static CRITICAL_SECTION xrender_cs;
125 static CRITICAL_SECTION_DEBUG critsect_debug =
128 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
129 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
131 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
133 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
134 ( ( (ULONG)_x4 << 24 ) | \
135 ( (ULONG)_x3 << 16 ) | \
136 ( (ULONG)_x2 << 8 ) | \
139 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
141 #define GASP_GRIDFIT 0x01
142 #define GASP_DOGRAY 0x02
144 #ifdef WORDS_BIGENDIAN
145 #define get_be_word(x) (x)
146 #define NATIVE_BYTE_ORDER MSBFirst
148 #define get_be_word(x) RtlUshortByteSwap(x)
149 #define NATIVE_BYTE_ORDER LSBFirst
152 /***********************************************************************
153 * X11DRV_XRender_Init
155 * Let's see if our XServer has the extension available
158 void X11DRV_XRender_Init(void)
161 XRenderPictFormat pf;
163 if (client_side_with_render &&
164 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
165 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
166 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
169 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
170 LOAD_FUNCPTR(XRenderAddGlyphs)
171 LOAD_FUNCPTR(XRenderComposite)
172 LOAD_FUNCPTR(XRenderCompositeString8)
173 LOAD_FUNCPTR(XRenderCompositeString16)
174 LOAD_FUNCPTR(XRenderCompositeString32)
175 LOAD_FUNCPTR(XRenderCompositeText16)
176 LOAD_FUNCPTR(XRenderCreateGlyphSet)
177 LOAD_FUNCPTR(XRenderCreatePicture)
178 LOAD_FUNCPTR(XRenderFillRectangle)
179 LOAD_FUNCPTR(XRenderFindFormat)
180 LOAD_FUNCPTR(XRenderFindVisualFormat)
181 LOAD_FUNCPTR(XRenderFreeGlyphSet)
182 LOAD_FUNCPTR(XRenderFreePicture)
183 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
184 LOAD_FUNCPTR(XRenderQueryExtension)
186 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
187 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
188 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
189 #undef LOAD_OPTIONAL_FUNCPTR
194 if(pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) {
195 X11DRV_XRender_Installed = TRUE;
196 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
197 pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, visual);
198 if(!pict_formats[color_drawable])
200 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
201 if (visual->class == DirectColor)
204 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
205 screen_depth, TrueColor, &info ))
207 pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, info.visual);
208 if (pict_formats[color_drawable]) visual = info.visual;
212 if(!pict_formats[color_drawable]) /* This fails in buggy versions of libXrender.so */
216 "Wine has detected that you probably have a buggy version\n"
217 "of libXrender.so . Because of this client side font rendering\n"
218 "will be disabled. Please upgrade this library.\n");
219 X11DRV_XRender_Installed = FALSE;
222 pf.type = PictTypeDirect;
225 pf.direct.alphaMask = 1;
226 pict_formats[mono_drawable] = pXRenderFindFormat(gdi_display, PictFormatType |
227 PictFormatDepth | PictFormatAlpha |
228 PictFormatAlphaMask, &pf, 0);
229 if(!pict_formats[mono_drawable]) {
230 ERR("mono_format == NULL?\n");
231 X11DRV_XRender_Installed = FALSE;
233 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
234 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
235 X11DRV_XRender_Installed = FALSE;
242 if(X11DRV_XRender_Installed || client_side_with_core)
244 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
245 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
247 glyphsetCacheSize = INIT_CACHE_SIZE;
249 for(i = 0; i < INIT_CACHE_SIZE; i++) {
250 glyphsetCache[i].next = i + 1;
251 glyphsetCache[i].count = -1;
253 glyphsetCache[i-1].next = -1;
254 using_client_side_fonts = 1;
256 if(!X11DRV_XRender_Installed) {
257 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
258 if(screen_depth <= 8 || !client_side_antialias_with_core)
261 if(screen_depth <= 8 || !client_side_antialias_with_render)
265 else TRACE("Using X11 core fonts\n");
268 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
270 if(p1->hash != p2->hash) return TRUE;
271 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
272 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
273 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
274 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
278 static void walk_cache(void)
282 EnterCriticalSection(&xrender_cs);
283 for(i=mru; i >= 0; i = glyphsetCache[i].next)
284 TRACE("item %d\n", i);
285 LeaveCriticalSection(&xrender_cs);
289 static int LookupEntry(LFANDSIZE *plfsz)
293 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
295 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
300 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
301 glyphsetCache[i].count++;
303 glyphsetCache[prev_i].next = glyphsetCache[i].next;
304 glyphsetCache[i].next = mru;
307 TRACE("found font in cache %d\n", i);
312 TRACE("font not in cache\n");
316 static void FreeEntry(int entry)
320 for(format = 0; format < AA_MAXVALUE; format++) {
321 gsCacheEntryFormat * formatEntry;
323 if( !glyphsetCache[entry].format[format] )
326 formatEntry = glyphsetCache[entry].format[format];
328 if(formatEntry->glyphset) {
330 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
332 formatEntry->glyphset = 0;
334 if(formatEntry->nrealized) {
335 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
336 formatEntry->realized = NULL;
337 if(formatEntry->bitmaps) {
338 for(i = 0; i < formatEntry->nrealized; i++)
339 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
340 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
341 formatEntry->bitmaps = NULL;
343 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
344 formatEntry->gis = NULL;
345 formatEntry->nrealized = 0;
348 HeapFree(GetProcessHeap(), 0, formatEntry);
349 glyphsetCache[entry].format[format] = NULL;
353 static int AllocEntry(void)
355 int best = -1, prev_best = -1, i, prev_i = -1;
358 assert(glyphsetCache[lastfree].count == -1);
359 glyphsetCache[lastfree].count = 1;
361 lastfree = glyphsetCache[lastfree].next;
363 glyphsetCache[best].next = mru;
366 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
370 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
371 if(glyphsetCache[i].count == 0) {
379 TRACE("freeing unused glyphset at cache %d\n", best);
381 glyphsetCache[best].count = 1;
383 glyphsetCache[prev_best].next = glyphsetCache[best].next;
384 glyphsetCache[best].next = mru;
392 TRACE("Growing cache\n");
395 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
397 (glyphsetCacheSize + INIT_CACHE_SIZE)
398 * sizeof(*glyphsetCache));
400 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
401 (glyphsetCacheSize + INIT_CACHE_SIZE)
402 * sizeof(*glyphsetCache));
404 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
406 glyphsetCache[i].next = i + 1;
407 glyphsetCache[i].count = -1;
409 glyphsetCache[i-1].next = -1;
410 glyphsetCacheSize += INIT_CACHE_SIZE;
412 lastfree = glyphsetCache[best].next;
413 glyphsetCache[best].count = 1;
414 glyphsetCache[best].next = mru;
416 TRACE("new free cache slot at %d\n", mru);
420 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
430 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
431 if(size == GDI_ERROR)
434 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
435 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
437 GetTextMetricsW(physDev->hdc, &tm);
438 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
441 num_recs = get_be_word(*gasp);
445 *flags = get_be_word(*(gasp + 1));
446 if(ppem <= get_be_word(*gasp))
450 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
452 HeapFree(GetProcessHeap(), 0, buffer);
456 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
460 UINT font_smoothing_type, font_smoothing_orientation;
462 if (X11DRV_XRender_Installed && subpixel &&
463 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
464 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
466 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
467 &font_smoothing_orientation, 0) &&
468 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
475 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
476 But, Wine's subpixel rendering can support the portrait mode.
479 else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
487 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
492 static int hinter = -1;
493 static int subpixel = -1;
496 if((ret = LookupEntry(plfsz)) != -1) return ret;
499 entry = glyphsetCache + ret;
500 entry->lfsz = *plfsz;
501 for( format = 0; format < AA_MAXVALUE; format++ ) {
502 assert( !entry->format[format] );
505 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
507 if(hinter == -1 || subpixel == -1)
509 RASTERIZER_STATUS status;
510 GetRasterizerCaps(&status, sizeof(status));
511 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
512 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
515 switch (plfsz->lf.lfQuality)
517 case ANTIALIASED_QUALITY:
518 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
520 case CLEARTYPE_QUALITY:
521 case CLEARTYPE_NATURAL_QUALITY:
522 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
524 case DEFAULT_QUALITY:
528 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
531 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
534 entry->aa_default = AA_None;
539 entry->aa_default = AA_None;
544 static void dec_ref_cache(int index)
547 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
548 assert(glyphsetCache[index].count > 0);
549 glyphsetCache[index].count--;
552 static void lfsz_calc_hash(LFANDSIZE *plfsz)
554 DWORD hash = 0, *ptr, two_chars;
558 hash ^= plfsz->devsize.cx;
559 hash ^= plfsz->devsize.cy;
560 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
562 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
564 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
566 pwc = (WCHAR *)&two_chars;
568 *pwc = toupperW(*pwc);
570 *pwc = toupperW(*pwc);
578 /***********************************************************************
579 * X11DRV_XRender_Finalize
581 void X11DRV_XRender_Finalize(void)
585 EnterCriticalSection(&xrender_cs);
586 for(i = mru; i >= 0; i = glyphsetCache[i].next)
588 LeaveCriticalSection(&xrender_cs);
592 /***********************************************************************
593 * X11DRV_XRender_SelectFont
595 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
599 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
600 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
601 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
602 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
603 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
604 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
605 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
606 GetWorldTransform( physDev->hdc, &lfsz.xform );
607 lfsz_calc_hash(&lfsz);
609 EnterCriticalSection(&xrender_cs);
610 if(!physDev->xrender) {
611 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
612 sizeof(*physDev->xrender));
613 physDev->xrender->cache_index = -1;
615 else if(physDev->xrender->cache_index != -1)
616 dec_ref_cache(physDev->xrender->cache_index);
617 physDev->xrender->cache_index = GetCacheEntry(physDev, &lfsz);
618 LeaveCriticalSection(&xrender_cs);
622 /***********************************************************************
623 * X11DRV_XRender_DeleteDC
625 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
627 X11DRV_XRender_UpdateDrawable(physDev);
629 EnterCriticalSection(&xrender_cs);
630 if(physDev->xrender->cache_index != -1)
631 dec_ref_cache(physDev->xrender->cache_index);
632 LeaveCriticalSection(&xrender_cs);
634 HeapFree(GetProcessHeap(), 0, physDev->xrender);
635 physDev->xrender = NULL;
639 /***********************************************************************
640 * X11DRV_XRender_UpdateDrawable
642 * Deletes the pict and tile when the drawable changes.
644 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
648 if(physDev->xrender->pict)
650 TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
652 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
653 physDev->xrender->pict = 0;
660 /************************************************************************
663 * Helper to ExtTextOut. Must be called inside xrender_cs
665 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
672 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
673 gsCacheEntryFormat *formatEntry;
674 UINT ggo_format = GGO_GLYPH_INDEX;
675 XRenderPictFormat pf;
676 unsigned long pf_mask;
677 static const char zero[4];
678 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
682 ggo_format |= WINE_GGO_GRAY16_BITMAP;
685 ggo_format |= WINE_GGO_HRGB_BITMAP;
688 ggo_format |= WINE_GGO_HBGR_BITMAP;
691 ggo_format |= WINE_GGO_VRGB_BITMAP;
694 ggo_format |= WINE_GGO_VBGR_BITMAP;
698 ERR("aa = %d - not implemented\n", format);
700 ggo_format |= GGO_BITMAP;
704 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
705 if(buflen == GDI_ERROR) {
706 if(format != AA_None) {
708 entry->aa_default = AA_None;
709 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
710 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
712 if(buflen == GDI_ERROR) {
713 WARN("GetGlyphOutlineW failed\n");
716 TRACE("Turning off antialiasing for this monochrome font\n");
719 /* If there is nothing for the current type, we create the entry. */
720 if( !entry->format[format] ) {
721 entry->format[format] = HeapAlloc(GetProcessHeap(),
723 sizeof(gsCacheEntryFormat));
725 formatEntry = entry->format[format];
727 if(formatEntry->nrealized <= glyph) {
728 formatEntry->nrealized = (glyph / 128 + 1) * 128;
730 if (formatEntry->realized)
731 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
733 formatEntry->realized,
734 formatEntry->nrealized * sizeof(BOOL));
736 formatEntry->realized = HeapAlloc(GetProcessHeap(),
738 formatEntry->nrealized * sizeof(BOOL));
740 if(!X11DRV_XRender_Installed) {
741 if (formatEntry->bitmaps)
742 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
744 formatEntry->bitmaps,
745 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
747 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
749 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
751 if (formatEntry->gis)
752 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
755 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
757 formatEntry->gis = HeapAlloc(GetProcessHeap(),
759 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
763 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
766 pf_mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask,
767 pf.type = PictTypeDirect;
770 pf.direct.alphaMask = 0xff;
777 pf_mask = PictFormatType | PictFormatDepth | PictFormatRed | PictFormatRedMask |
778 PictFormatGreen | PictFormatGreenMask | PictFormatBlue |
779 PictFormatBlueMask | PictFormatAlpha | PictFormatAlphaMask;
780 pf.type = PictTypeDirect;
783 pf.direct.redMask = 0xff;
785 pf.direct.greenMask = 0xff;
787 pf.direct.blueMask = 0xff;
788 pf.direct.alpha = 24;
789 pf.direct.alphaMask = 0xff;
793 ERR("aa = %d - not implemented\n", format);
795 pf_mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask,
796 pf.type = PictTypeDirect;
799 pf.direct.alphaMask = 1;
804 formatEntry->font_format = pXRenderFindFormat(gdi_display, pf_mask, &pf, 0);
805 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
810 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
811 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
812 formatEntry->realized[glyph] = TRUE;
814 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
816 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
817 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
819 gi.width = gm.gmBlackBoxX;
820 gi.height = gm.gmBlackBoxY;
821 gi.x = -gm.gmptGlyphOrigin.x;
822 gi.y = gm.gmptGlyphOrigin.y;
823 gi.xOff = gm.gmCellIncX;
824 gi.yOff = gm.gmCellIncY;
826 if(TRACE_ON(xrender)) {
831 if(format == AA_None) {
832 pitch = ((gi.width + 31) / 32) * 4;
833 for(i = 0; i < gi.height; i++) {
834 line = (unsigned char*) buf + i * pitch;
836 for(j = 0; j < pitch * 8; j++) {
837 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
839 TRACE("%s\n", output);
842 static const char blks[] = " .:;!o*#";
846 pitch = ((gi.width + 3) / 4) * 4;
847 for(i = 0; i < gi.height; i++) {
848 line = (unsigned char*) buf + i * pitch;
850 for(j = 0; j < pitch; j++) {
851 str[0] = blks[line[j] >> 5];
854 TRACE("%s\n", output);
860 if(formatEntry->glyphset) {
861 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
862 unsigned char *byte = (unsigned char*) buf, c;
868 /* magic to flip bit order */
869 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
870 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
871 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
876 else if ( format != AA_Grey &&
877 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
879 unsigned int i, *data = (unsigned int *)buf;
880 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
885 XRenderCompositeText seems to ignore 0x0 glyphs when
886 AA_None, which means we lose the advance width of glyphs
887 like the space. We'll pretend that such glyphs are 1x1
892 gi.width = gi.height = 1;
895 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
896 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
898 HeapFree(GetProcessHeap(), 0, buf);
900 formatEntry->bitmaps[glyph] = buf;
903 formatEntry->gis[glyph] = gi;
908 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
909 void *bitmap, XGlyphInfo *gi)
911 unsigned char *srcLine = bitmap, *src;
912 unsigned char bits, bitsMask;
913 int width = gi->width;
914 int stride = ((width + 31) & ~31) >> 3;
915 int height = gi->height;
919 TRACE("%d, %d\n", x, y);
928 bitsMask = 0x80; /* FreeType is always MSB first */
942 bitsMask = bitsMask >> 1;
948 } while (bits & bitsMask);
949 XFillRectangle (gdi_display, physDev->drawable,
950 physDev->gc, xspan, y, lenspan, 1);
962 bitsMask = bitsMask >> 1;
968 } while (!(bits & bitsMask));
975 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
976 void *bitmap, XGlyphInfo *gi)
978 unsigned char *srcLine = bitmap, *src, bits;
979 int width = gi->width;
980 int stride = ((width + 3) & ~3);
981 int height = gi->height;
1006 } while (bits >= 0x80);
1007 XFillRectangle (gdi_display, physDev->drawable,
1008 physDev->gc, xspan, y, lenspan, 1);
1021 } while (bits < 0x80);
1029 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1034 while ((mask & 1) == 0)
1040 while ((mask & 1) == 1)
1049 static DWORD GetField (DWORD pixel, int shift, int len)
1051 pixel = pixel & (((1 << (len)) - 1) << shift);
1052 pixel = pixel << (32 - (shift + len)) >> 24;
1055 pixel |= (pixel >> len);
1062 static DWORD PutField (DWORD pixel, int shift, int len)
1064 shift = shift - (8 - len);
1066 pixel &= (((1 << len) - 1) << (8 - len));
1074 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1080 BYTE *maskLine, *mask, m;
1085 BYTE src_r, src_g, src_b;
1090 height = gi->height;
1093 maskStride = (width + 3) & ~3;
1095 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1096 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1097 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1099 src_r = GetField(color, r_shift, r_len);
1100 src_g = GetField(color, g_shift, g_len);
1101 src_b = GetField(color, b_shift, b_len);
1103 for(; height--; y++)
1106 maskLine += maskStride;
1111 if(y >= image->height) break;
1115 if(tx >= image->width) break;
1118 if(tx < 0) continue;
1121 XPutPixel (image, tx, y, color);
1126 pixel = XGetPixel (image, tx, y);
1128 r = GetField(pixel, r_shift, r_len);
1129 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1130 g = GetField(pixel, g_shift, g_len);
1131 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1132 b = GetField(pixel, b_shift, b_len);
1133 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1135 pixel = (PutField (r, r_shift, r_len) |
1136 PutField (g, g_shift, g_len) |
1137 PutField (b, b_shift, b_len));
1138 XPutPixel (image, tx, y, pixel);
1144 /*************************************************************
1147 * Returns an appropriate Picture for tiling the text colour.
1148 * Call and use result within the xrender_cs
1150 static Picture get_tile_pict(enum drawable_depth_type type, int text_pixel)
1160 tile = &tiles[type];
1164 XRenderPictureAttributes pa;
1167 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_formats[type]->depth);
1170 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_formats[type], CPRepeat, &pa);
1171 wine_tsx11_unlock();
1173 /* init current_color to something different from text_pixel */
1174 tile->current_color = ~text_pixel;
1176 if(type == mono_drawable)
1178 /* for a 1bpp bitmap we always need a 1 in the tile */
1179 col.red = col.green = col.blue = 0;
1182 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1183 wine_tsx11_unlock();
1187 if(text_pixel != tile->current_color && type == color_drawable)
1189 /* Map 0 -- 0xff onto 0 -- 0xffff */
1194 ExamineBitfield (visual->red_mask, &r_shift, &r_len );
1195 ExamineBitfield (visual->green_mask, &g_shift, &g_len);
1196 ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
1198 col.red = GetField(text_pixel, r_shift, r_len);
1199 col.red |= col.red << 8;
1200 col.green = GetField(text_pixel, g_shift, g_len);
1201 col.green |= col.green << 8;
1202 col.blue = GetField(text_pixel, b_shift, b_len);
1203 col.blue |= col.blue << 8;
1207 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1208 wine_tsx11_unlock();
1209 tile->current_color = text_pixel;
1214 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1219 /***********************************************************************
1220 * X11DRV_XRender_ExtTextOut
1222 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1223 const RECT *lprect, LPCWSTR wstr, UINT count,
1228 gsCacheEntry *entry;
1229 gsCacheEntryFormat *formatEntry;
1231 HDC hdc = physDev->hdc;
1232 int textPixel, backgroundPixel;
1233 HRGN saved_region = 0;
1234 BOOL disable_antialias = FALSE;
1235 AA_Type aa_type = AA_None;
1238 double cosEsc, sinEsc;
1240 enum drawable_depth_type depth_type = (physDev->depth == 1) ? mono_drawable : color_drawable;
1241 Picture tile_pict = 0;
1243 /* Do we need to disable antialiasing because of palette mode? */
1244 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1245 TRACE("bitmap is not a DIB\n");
1247 else if (bmp.dsBmih.biBitCount <= 8) {
1248 TRACE("Disabling antialiasing\n");
1249 disable_antialias = TRUE;
1252 xgcval.function = GXcopy;
1253 xgcval.background = physDev->backgroundPixel;
1254 xgcval.fill_style = FillSolid;
1256 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1257 wine_tsx11_unlock();
1259 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1261 if(physDev->depth == 1) {
1262 if((physDev->textPixel & 0xffffff) == 0) {
1264 backgroundPixel = 1;
1267 backgroundPixel = 0;
1270 textPixel = physDev->textPixel;
1271 backgroundPixel = physDev->backgroundPixel;
1274 if(flags & ETO_OPAQUE)
1277 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1278 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1279 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1280 lprect->right - lprect->left, lprect->bottom - lprect->top );
1281 wine_tsx11_unlock();
1291 GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1292 if(lf.lfEscapement != 0) {
1293 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1294 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1300 if (flags & ETO_CLIPPED)
1304 clip_region = CreateRectRgnIndirect( lprect );
1305 /* make a copy of the current device region */
1306 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1307 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1308 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1309 DeleteObject( clip_region );
1312 if(X11DRV_XRender_Installed) {
1313 if(!physDev->xrender->pict) {
1314 XRenderPictureAttributes pa;
1315 pa.subwindow_mode = IncludeInferiors;
1318 physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1320 pict_formats[depth_type],
1321 CPSubwindowMode, &pa);
1322 wine_tsx11_unlock();
1324 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1325 physDev->xrender->pict, hdc, physDev->drawable);
1327 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1328 physDev->xrender->pict, hdc, physDev->drawable);
1331 if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1334 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1335 physDev->dc_rect.left, physDev->dc_rect.top,
1336 (XRectangle *)data->Buffer, data->rdh.nCount );
1337 wine_tsx11_unlock();
1338 HeapFree( GetProcessHeap(), 0, data );
1342 EnterCriticalSection(&xrender_cs);
1344 entry = glyphsetCache + physDev->xrender->cache_index;
1345 if( disable_antialias == FALSE )
1346 aa_type = entry->aa_default;
1347 formatEntry = entry->format[aa_type];
1349 for(idx = 0; idx < count; idx++) {
1350 if( !formatEntry ) {
1351 UploadGlyph(physDev, wstr[idx], aa_type);
1352 /* re-evaluate antialias since aa_default may have changed */
1353 if( disable_antialias == FALSE )
1354 aa_type = entry->aa_default;
1355 formatEntry = entry->format[aa_type];
1356 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1357 UploadGlyph(physDev, wstr[idx], aa_type);
1362 WARN("could not upload requested glyphs\n");
1363 LeaveCriticalSection(&xrender_cs);
1367 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1368 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1370 if(X11DRV_XRender_Installed)
1372 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1374 POINT desired, current;
1375 int render_op = PictOpOver;
1377 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1378 So we pass zeros to the function and move to our starting position using the first
1379 element of the elts array. */
1381 desired.x = physDev->dc_rect.left + x;
1382 desired.y = physDev->dc_rect.top + y;
1383 current.x = current.y = 0;
1385 tile_pict = get_tile_pict(depth_type, physDev->textPixel);
1387 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1389 if((depth_type == mono_drawable) && (textPixel == 0))
1390 render_op = PictOpOutReverse; /* This gives us 'black' text */
1392 for(idx = 0; idx < count; idx++)
1394 elts[idx].glyphset = formatEntry->glyphset;
1395 elts[idx].chars = wstr + idx;
1396 elts[idx].nchars = 1;
1397 elts[idx].xOff = desired.x - current.x;
1398 elts[idx].yOff = desired.y - current.y;
1400 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1401 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1405 desired.x += formatEntry->gis[wstr[idx]].xOff;
1406 desired.y += formatEntry->gis[wstr[idx]].yOff;
1410 offset += lpDx[idx];
1411 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1412 desired.y = physDev->dc_rect.top + y - offset * sinEsc;
1416 pXRenderCompositeText16(gdi_display, render_op,
1418 physDev->xrender->pict,
1419 formatEntry->font_format,
1420 0, 0, 0, 0, elts, count);
1421 wine_tsx11_unlock();
1422 HeapFree(GetProcessHeap(), 0, elts);
1424 INT offset = 0, xoff = 0, yoff = 0;
1426 XSetForeground( gdi_display, physDev->gc, textPixel );
1428 if(aa_type == AA_None || physDev->depth == 1)
1430 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1432 if(aa_type == AA_None)
1433 sharp_glyph_fn = SharpGlyphMono;
1435 sharp_glyph_fn = SharpGlyphGray;
1437 for(idx = 0; idx < count; idx++) {
1438 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1439 physDev->dc_rect.top + y + yoff,
1440 formatEntry->bitmaps[wstr[idx]],
1441 &formatEntry->gis[wstr[idx]]);
1443 offset += lpDx[idx];
1444 xoff = offset * cosEsc;
1445 yoff = offset * -sinEsc;
1447 xoff += formatEntry->gis[wstr[idx]].xOff;
1448 yoff += formatEntry->gis[wstr[idx]].yOff;
1453 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1454 RECT extents = {0, 0, 0, 0};
1456 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1457 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1459 TRACE("drawable %dx%d\n", w, h);
1461 for(idx = 0; idx < count; idx++) {
1462 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1463 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1464 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1465 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1466 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1467 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1468 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1469 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1471 offset += lpDx[idx];
1472 cur.x = offset * cosEsc;
1473 cur.y = offset * -sinEsc;
1475 cur.x += formatEntry->gis[wstr[idx]].xOff;
1476 cur.y += formatEntry->gis[wstr[idx]].yOff;
1479 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1480 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1482 if(physDev->dc_rect.left + x + extents.left >= 0) {
1483 image_x = physDev->dc_rect.left + x + extents.left;
1487 image_off_x = physDev->dc_rect.left + x + extents.left;
1489 if(physDev->dc_rect.top + y + extents.top >= 0) {
1490 image_y = physDev->dc_rect.top + y + extents.top;
1494 image_off_y = physDev->dc_rect.top + y + extents.top;
1496 if(physDev->dc_rect.left + x + extents.right < w)
1497 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1499 image_w = w - image_x;
1500 if(physDev->dc_rect.top + y + extents.bottom < h)
1501 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1503 image_h = h - image_y;
1505 if(image_w <= 0 || image_h <= 0) goto no_image;
1507 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1508 image = XGetImage(gdi_display, physDev->drawable,
1509 image_x, image_y, image_w, image_h,
1510 AllPlanes, ZPixmap);
1511 X11DRV_check_error();
1513 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1514 gdi_display, (int)physDev->drawable, image_x, image_y,
1515 image_w, image_h, AllPlanes, ZPixmap,
1516 physDev->depth, image);
1518 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
1523 gcv.graphics_exposures = False;
1524 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1525 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1526 image_w, image_h, 0, 0);
1527 XFreeGC(gdi_display, gc);
1528 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1529 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1531 X11DRV_check_error();
1532 XFreePixmap(gdi_display, xpm);
1534 if(!image) goto no_image;
1536 image->red_mask = visual->red_mask;
1537 image->green_mask = visual->green_mask;
1538 image->blue_mask = visual->blue_mask;
1540 offset = xoff = yoff = 0;
1541 for(idx = 0; idx < count; idx++) {
1542 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1543 yoff + image_off_y - extents.top,
1544 formatEntry->bitmaps[wstr[idx]],
1545 &formatEntry->gis[wstr[idx]],
1546 physDev->textPixel);
1548 offset += lpDx[idx];
1549 xoff = offset * cosEsc;
1550 yoff = offset * -sinEsc;
1552 xoff += formatEntry->gis[wstr[idx]].xOff;
1553 yoff += formatEntry->gis[wstr[idx]].yOff;
1556 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1557 image_x, image_y, image_w, image_h);
1558 XDestroyImage(image);
1561 wine_tsx11_unlock();
1563 LeaveCriticalSection(&xrender_cs);
1565 if (flags & ETO_CLIPPED)
1567 /* restore the device region */
1568 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1569 DeleteObject( saved_region );
1575 X11DRV_UnlockDIBSection( physDev, TRUE );
1579 /******************************************************************************
1580 * AlphaBlend (x11drv.@)
1582 BOOL CDECL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1583 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1584 BLENDFUNCTION blendfn)
1586 XRenderPictureAttributes pa;
1587 XRenderPictFormat *src_format;
1588 XRenderPictFormat argb32_templ = {
1590 PictTypeDirect, /* type */
1593 16, /* direct.red */
1594 0xff, /* direct.redMask */
1595 8, /* direct.green */
1596 0xff, /* direct.greenMask */
1597 0, /* direct.blue */
1598 0xff, /* direct.blueMask */
1599 24, /* direct.alpha */
1600 0xff, /* direct.alphaMask */
1604 unsigned long argb32_templ_mask =
1610 PictFormatGreenMask |
1612 PictFormatBlueMask |
1614 PictFormatAlphaMask;
1616 Picture dst_pict, src_pict;
1622 DWORD *dstbits, *data;
1625 BOOL top_down = FALSE;
1627 enum drawable_depth_type dst_depth_type = (devDst->depth == 1) ? mono_drawable : color_drawable;
1629 if(!X11DRV_XRender_Installed) {
1630 FIXME("Unable to AlphaBlend without Xrender\n");
1635 pts[1].x = xDst + widthDst;
1636 pts[1].y = yDst + heightDst;
1637 LPtoDP(devDst->hdc, pts, 2);
1640 widthDst = pts[1].x - pts[0].x;
1641 heightDst = pts[1].y - pts[0].y;
1645 pts[1].x = xSrc + widthSrc;
1646 pts[1].y = ySrc + heightSrc;
1647 LPtoDP(devSrc->hdc, pts, 2);
1650 widthSrc = pts[1].x - pts[0].x;
1651 heightSrc = pts[1].y - pts[0].y;
1652 if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1654 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1655 if(widthDst != widthSrc || heightDst != heightSrc)
1657 if(!pXRenderSetPictureTransform)
1660 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1664 if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1666 static BOOL out = FALSE;
1669 FIXME("not a dibsection\n");
1675 if (xSrc < 0 || ySrc < 0 || widthSrc < 0 || heightSrc < 0 || xSrc + widthSrc > dib.dsBmih.biWidth
1676 || ySrc + heightSrc > abs(dib.dsBmih.biHeight))
1678 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc, ySrc, widthSrc, heightSrc);
1679 SetLastError(ERROR_INVALID_PARAMETER);
1683 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && blendfn.SourceConstantAlpha != 0xff)
1684 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn.SourceConstantAlpha);
1686 if(dib.dsBm.bmBitsPixel != 32) {
1687 FIXME("not a 32 bpp dibsection\n");
1690 dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1692 if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1694 dstbits += widthSrc * (heightSrc - 1);
1696 y = y2 + heightSrc - 1;
1700 y = dib.dsBmih.biHeight - ySrc - 1;
1701 y2 = y - heightSrc + 1;
1704 if (blendfn.AlphaFormat & AC_SRC_ALPHA)
1708 memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1710 dstbits += (top_down ? -1 : 1) * widthSrc;
1715 DWORD source_alpha = (DWORD)blendfn.SourceConstantAlpha << 24;
1720 DWORD *srcbits = (DWORD *)((char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes) + xSrc;
1721 for (x = 0; x < widthSrc; x++)
1723 DWORD argb = *srcbits++;
1724 argb = (argb & 0xffffff) | source_alpha;
1727 if (top_down) /* we traversed the row forward so we should go back by two rows */
1728 dstbits -= 2 * widthSrc;
1733 rgndata = X11DRV_GetRegionData( devDst->region, 0 );
1736 image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1737 (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1740 Avoid using XRenderFindStandardFormat as older libraries don't have it
1741 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1743 src_format = pXRenderFindFormat(gdi_display, argb32_templ_mask, &argb32_templ, 0);
1745 TRACE("src_format %p\n", src_format);
1747 pa.subwindow_mode = IncludeInferiors;
1749 /* FIXME use devDst->xrender->pict ? */
1750 dst_pict = pXRenderCreatePicture(gdi_display,
1752 pict_formats[dst_depth_type],
1753 CPSubwindowMode, &pa);
1754 TRACE("dst_pict %08lx\n", dst_pict);
1755 TRACE("src_drawable = %08lx\n", devSrc->drawable);
1756 xpm = XCreatePixmap(gdi_display,
1758 widthSrc, heightSrc, 32);
1759 gcv.graphics_exposures = False;
1760 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1761 TRACE("xpm = %08lx\n", xpm);
1762 XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1764 src_pict = pXRenderCreatePicture(gdi_display,
1766 CPSubwindowMode, &pa);
1767 TRACE("src_pict %08lx\n", src_pict);
1771 pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
1772 devDst->dc_rect.left, devDst->dc_rect.top,
1773 (XRectangle *)rgndata->Buffer,
1774 rgndata->rdh.nCount );
1775 HeapFree( GetProcessHeap(), 0, rgndata );
1778 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1779 if(widthDst != widthSrc || heightDst != heightSrc) {
1780 double xscale = widthSrc/(double)widthDst;
1781 double yscale = heightSrc/(double)heightDst;
1782 XTransform xform = {{
1783 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0) },
1784 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0) },
1785 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1787 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1790 pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
1792 xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
1795 pXRenderFreePicture(gdi_display, src_pict);
1796 XFreePixmap(gdi_display, xpm);
1797 XFreeGC(gdi_display, gc);
1798 pXRenderFreePicture(gdi_display, dst_pict);
1800 XDestroyImage(image);
1802 wine_tsx11_unlock();
1803 HeapFree(GetProcessHeap(), 0, data);
1807 #else /* SONAME_LIBXRENDER */
1809 void X11DRV_XRender_Init(void)
1811 TRACE("XRender support not compiled in.\n");
1815 void X11DRV_XRender_Finalize(void)
1819 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1825 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1831 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1832 const RECT *lprect, LPCWSTR wstr, UINT count,
1839 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1845 /******************************************************************************
1846 * AlphaBlend (x11drv.@)
1848 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1849 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1850 BLENDFUNCTION blendfn)
1852 FIXME("not supported - XRENDER headers were missing at compile time\n");
1856 #endif /* SONAME_LIBXRENDER */