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)
145 #define NATIVE_BYTE_ORDER MSBFirst
147 #define get_be_word(x) RtlUshortByteSwap(x)
148 #define NATIVE_BYTE_ORDER LSBFirst
151 /***********************************************************************
152 * X11DRV_XRender_Init
154 * Let's see if our XServer has the extension available
157 void X11DRV_XRender_Init(void)
160 XRenderPictFormat pf;
162 if (client_side_with_render &&
163 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
164 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
165 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
168 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
169 LOAD_FUNCPTR(XRenderAddGlyphs)
170 LOAD_FUNCPTR(XRenderComposite)
171 LOAD_FUNCPTR(XRenderCompositeString8)
172 LOAD_FUNCPTR(XRenderCompositeString16)
173 LOAD_FUNCPTR(XRenderCompositeString32)
174 LOAD_FUNCPTR(XRenderCompositeText16)
175 LOAD_FUNCPTR(XRenderCreateGlyphSet)
176 LOAD_FUNCPTR(XRenderCreatePicture)
177 LOAD_FUNCPTR(XRenderFillRectangle)
178 LOAD_FUNCPTR(XRenderFindFormat)
179 LOAD_FUNCPTR(XRenderFindVisualFormat)
180 LOAD_FUNCPTR(XRenderFreeGlyphSet)
181 LOAD_FUNCPTR(XRenderFreePicture)
182 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
183 LOAD_FUNCPTR(XRenderQueryExtension)
185 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
186 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
187 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
188 #undef LOAD_OPTIONAL_FUNCPTR
193 if(pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) {
194 X11DRV_XRender_Installed = TRUE;
195 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
196 pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, visual);
197 if(!pict_formats[color_drawable])
199 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
200 if (visual->class == DirectColor)
203 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
204 screen_depth, TrueColor, &info ))
206 pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, info.visual);
207 if (pict_formats[color_drawable]) visual = info.visual;
211 if(!pict_formats[color_drawable]) /* This fails in buggy versions of libXrender.so */
215 "Wine has detected that you probably have a buggy version\n"
216 "of libXrender.so . Because of this client side font rendering\n"
217 "will be disabled. Please upgrade this library.\n");
218 X11DRV_XRender_Installed = FALSE;
221 pf.type = PictTypeDirect;
224 pf.direct.alphaMask = 1;
225 pict_formats[mono_drawable] = pXRenderFindFormat(gdi_display, PictFormatType |
226 PictFormatDepth | PictFormatAlpha |
227 PictFormatAlphaMask, &pf, 0);
228 if(!pict_formats[mono_drawable]) {
229 ERR("mono_format == NULL?\n");
230 X11DRV_XRender_Installed = FALSE;
232 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
233 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
234 X11DRV_XRender_Installed = FALSE;
241 if(X11DRV_XRender_Installed || client_side_with_core)
243 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
244 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
246 glyphsetCacheSize = INIT_CACHE_SIZE;
248 for(i = 0; i < INIT_CACHE_SIZE; i++) {
249 glyphsetCache[i].next = i + 1;
250 glyphsetCache[i].count = -1;
252 glyphsetCache[i-1].next = -1;
253 using_client_side_fonts = 1;
255 if(!X11DRV_XRender_Installed) {
256 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
257 if(screen_depth <= 8 || !client_side_antialias_with_core)
260 if(screen_depth <= 8 || !client_side_antialias_with_render)
264 else TRACE("Using X11 core fonts\n");
267 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
269 if(p1->hash != p2->hash) return TRUE;
270 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
271 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
272 return strcmpW(p1->lf.lfFaceName, p2->lf.lfFaceName);
276 static void walk_cache(void)
280 EnterCriticalSection(&xrender_cs);
281 for(i=mru; i >= 0; i = glyphsetCache[i].next)
282 TRACE("item %d\n", i);
283 LeaveCriticalSection(&xrender_cs);
287 static int LookupEntry(LFANDSIZE *plfsz)
291 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
293 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
298 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
299 glyphsetCache[i].count++;
301 glyphsetCache[prev_i].next = glyphsetCache[i].next;
302 glyphsetCache[i].next = mru;
305 TRACE("found font in cache %d\n", i);
310 TRACE("font not in cache\n");
314 static void FreeEntry(int entry)
318 for(format = 0; format < AA_MAXVALUE; format++) {
319 gsCacheEntryFormat * formatEntry;
321 if( !glyphsetCache[entry].format[format] )
324 formatEntry = glyphsetCache[entry].format[format];
326 if(formatEntry->glyphset) {
328 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
330 formatEntry->glyphset = 0;
332 if(formatEntry->nrealized) {
333 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
334 formatEntry->realized = NULL;
335 if(formatEntry->bitmaps) {
336 for(i = 0; i < formatEntry->nrealized; i++)
337 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
338 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
339 formatEntry->bitmaps = NULL;
341 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
342 formatEntry->gis = NULL;
343 formatEntry->nrealized = 0;
346 HeapFree(GetProcessHeap(), 0, formatEntry);
347 glyphsetCache[entry].format[format] = NULL;
351 static int AllocEntry(void)
353 int best = -1, prev_best = -1, i, prev_i = -1;
356 assert(glyphsetCache[lastfree].count == -1);
357 glyphsetCache[lastfree].count = 1;
359 lastfree = glyphsetCache[lastfree].next;
361 glyphsetCache[best].next = mru;
364 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
368 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
369 if(glyphsetCache[i].count == 0) {
377 TRACE("freeing unused glyphset at cache %d\n", best);
379 glyphsetCache[best].count = 1;
381 glyphsetCache[prev_best].next = glyphsetCache[best].next;
382 glyphsetCache[best].next = mru;
390 TRACE("Growing cache\n");
393 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
395 (glyphsetCacheSize + INIT_CACHE_SIZE)
396 * sizeof(*glyphsetCache));
398 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
399 (glyphsetCacheSize + INIT_CACHE_SIZE)
400 * sizeof(*glyphsetCache));
402 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
404 glyphsetCache[i].next = i + 1;
405 glyphsetCache[i].count = -1;
407 glyphsetCache[i-1].next = -1;
408 glyphsetCacheSize += INIT_CACHE_SIZE;
410 lastfree = glyphsetCache[best].next;
411 glyphsetCache[best].count = 1;
412 glyphsetCache[best].next = mru;
414 TRACE("new free cache slot at %d\n", mru);
418 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
428 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
429 if(size == GDI_ERROR)
432 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
433 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
435 GetTextMetricsW(physDev->hdc, &tm);
436 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
439 num_recs = get_be_word(*gasp);
443 *flags = get_be_word(*(gasp + 1));
444 if(ppem <= get_be_word(*gasp))
448 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
450 HeapFree(GetProcessHeap(), 0, buffer);
454 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
458 UINT font_smoothing_type, font_smoothing_orientation;
460 if (X11DRV_XRender_Installed && subpixel &&
461 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
462 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
464 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
465 &font_smoothing_orientation, 0) &&
466 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
473 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
474 But, Wine's subpixel rendering can support the portrait mode.
477 else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
485 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
490 static int hinter = -1;
491 static int subpixel = -1;
494 if((ret = LookupEntry(plfsz)) != -1) return ret;
497 entry = glyphsetCache + ret;
498 entry->lfsz = *plfsz;
499 for( format = 0; format < AA_MAXVALUE; format++ ) {
500 assert( !entry->format[format] );
503 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
505 if(hinter == -1 || subpixel == -1)
507 RASTERIZER_STATUS status;
508 GetRasterizerCaps(&status, sizeof(status));
509 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
510 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
513 switch (plfsz->lf.lfQuality)
515 case ANTIALIASED_QUALITY:
516 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
518 case CLEARTYPE_QUALITY:
519 case CLEARTYPE_NATURAL_QUALITY:
520 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
522 case DEFAULT_QUALITY:
526 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
529 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
532 entry->aa_default = AA_None;
537 entry->aa_default = AA_None;
542 static void dec_ref_cache(int index)
545 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
546 assert(glyphsetCache[index].count > 0);
547 glyphsetCache[index].count--;
550 static void lfsz_calc_hash(LFANDSIZE *plfsz)
552 DWORD hash = 0, *ptr;
555 hash ^= plfsz->devsize.cx;
556 hash ^= plfsz->devsize.cy;
557 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
559 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
560 WCHAR *pwc = (WCHAR *)ptr;
570 /***********************************************************************
571 * X11DRV_XRender_Finalize
573 void X11DRV_XRender_Finalize(void)
577 EnterCriticalSection(&xrender_cs);
578 for(i = mru; i >= 0; i = glyphsetCache[i].next)
580 LeaveCriticalSection(&xrender_cs);
584 /***********************************************************************
585 * X11DRV_XRender_SelectFont
587 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
591 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
592 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
593 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
594 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
595 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
596 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
597 lfsz_calc_hash(&lfsz);
599 EnterCriticalSection(&xrender_cs);
600 if(!physDev->xrender) {
601 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
602 sizeof(*physDev->xrender));
603 physDev->xrender->cache_index = -1;
605 else if(physDev->xrender->cache_index != -1)
606 dec_ref_cache(physDev->xrender->cache_index);
607 physDev->xrender->cache_index = GetCacheEntry(physDev, &lfsz);
608 LeaveCriticalSection(&xrender_cs);
612 /***********************************************************************
613 * X11DRV_XRender_DeleteDC
615 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
617 X11DRV_XRender_UpdateDrawable(physDev);
619 EnterCriticalSection(&xrender_cs);
620 if(physDev->xrender->cache_index != -1)
621 dec_ref_cache(physDev->xrender->cache_index);
622 LeaveCriticalSection(&xrender_cs);
624 HeapFree(GetProcessHeap(), 0, physDev->xrender);
625 physDev->xrender = NULL;
629 /***********************************************************************
630 * X11DRV_XRender_UpdateDrawable
632 * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
633 * It deletes the pict and tile when the drawable changes.
635 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
639 if(physDev->xrender->pict)
641 TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
643 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
644 physDev->xrender->pict = 0;
651 /************************************************************************
654 * Helper to ExtTextOut. Must be called inside xrender_cs
656 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
663 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
664 gsCacheEntryFormat *formatEntry;
665 UINT ggo_format = GGO_GLYPH_INDEX;
666 XRenderPictFormat pf;
667 unsigned long pf_mask;
668 static const char zero[4];
672 ggo_format |= WINE_GGO_GRAY16_BITMAP;
675 ggo_format |= WINE_GGO_HRGB_BITMAP;
678 ggo_format |= WINE_GGO_HBGR_BITMAP;
681 ggo_format |= WINE_GGO_VRGB_BITMAP;
684 ggo_format |= WINE_GGO_VBGR_BITMAP;
688 ERR("aa = %d - not implemented\n", format);
690 ggo_format |= GGO_BITMAP;
694 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
696 if(buflen == GDI_ERROR) {
697 if(format != AA_None) {
699 entry->aa_default = AA_None;
700 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
701 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
704 if(buflen == GDI_ERROR) {
705 WARN("GetGlyphOutlineW failed\n");
708 TRACE("Turning off antialiasing for this monochrome font\n");
711 /* If there is nothing for the current type, we create the entry. */
712 if( !entry->format[format] ) {
713 entry->format[format] = HeapAlloc(GetProcessHeap(),
715 sizeof(gsCacheEntryFormat));
717 formatEntry = entry->format[format];
719 if(formatEntry->nrealized <= glyph) {
720 formatEntry->nrealized = (glyph / 128 + 1) * 128;
722 if (formatEntry->realized)
723 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
725 formatEntry->realized,
726 formatEntry->nrealized * sizeof(BOOL));
728 formatEntry->realized = HeapAlloc(GetProcessHeap(),
730 formatEntry->nrealized * sizeof(BOOL));
732 if(!X11DRV_XRender_Installed) {
733 if (formatEntry->bitmaps)
734 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
736 formatEntry->bitmaps,
737 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
739 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
741 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
743 if (formatEntry->gis)
744 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
747 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
749 formatEntry->gis = HeapAlloc(GetProcessHeap(),
751 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
755 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
758 pf_mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask,
759 pf.type = PictTypeDirect;
762 pf.direct.alphaMask = 0xff;
769 pf_mask = PictFormatType | PictFormatDepth | PictFormatRed | PictFormatRedMask |
770 PictFormatGreen | PictFormatGreenMask | PictFormatBlue |
771 PictFormatBlueMask | PictFormatAlpha | PictFormatAlphaMask;
772 pf.type = PictTypeDirect;
775 pf.direct.redMask = 0xff;
777 pf.direct.greenMask = 0xff;
779 pf.direct.blueMask = 0xff;
780 pf.direct.alpha = 24;
781 pf.direct.alphaMask = 0xff;
785 ERR("aa = %d - not implemented\n", format);
787 pf_mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask,
788 pf.type = PictTypeDirect;
791 pf.direct.alphaMask = 1;
796 formatEntry->font_format = pXRenderFindFormat(gdi_display, pf_mask, &pf, 0);
797 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
802 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
803 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, NULL);
804 formatEntry->realized[glyph] = TRUE;
806 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
808 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
809 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
811 gi.width = gm.gmBlackBoxX;
812 gi.height = gm.gmBlackBoxY;
813 gi.x = -gm.gmptGlyphOrigin.x;
814 gi.y = gm.gmptGlyphOrigin.y;
815 gi.xOff = gm.gmCellIncX;
816 gi.yOff = gm.gmCellIncY;
818 if(TRACE_ON(xrender)) {
823 if(format == AA_None) {
824 pitch = ((gi.width + 31) / 32) * 4;
825 for(i = 0; i < gi.height; i++) {
826 line = (unsigned char*) buf + i * pitch;
828 for(j = 0; j < pitch * 8; j++) {
829 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
831 TRACE("%s\n", output);
834 static const char blks[] = " .:;!o*#";
838 pitch = ((gi.width + 3) / 4) * 4;
839 for(i = 0; i < gi.height; i++) {
840 line = (unsigned char*) buf + i * pitch;
842 for(j = 0; j < pitch; j++) {
843 str[0] = blks[line[j] >> 5];
846 TRACE("%s\n", output);
852 if(formatEntry->glyphset) {
853 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
854 unsigned char *byte = (unsigned char*) buf, c;
860 /* magic to flip bit order */
861 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
862 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
863 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
868 else if ( format != AA_Grey &&
869 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
871 unsigned int i, *data = (unsigned int *)buf;
872 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
877 XRenderCompositeText seems to ignore 0x0 glyphs when
878 AA_None, which means we lose the advance width of glyphs
879 like the space. We'll pretend that such glyphs are 1x1
884 gi.width = gi.height = 1;
887 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
888 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
890 HeapFree(GetProcessHeap(), 0, buf);
892 formatEntry->bitmaps[glyph] = buf;
895 formatEntry->gis[glyph] = gi;
900 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
901 void *bitmap, XGlyphInfo *gi)
903 unsigned char *srcLine = bitmap, *src;
904 unsigned char bits, bitsMask;
905 int width = gi->width;
906 int stride = ((width + 31) & ~31) >> 3;
907 int height = gi->height;
911 TRACE("%d, %d\n", x, y);
920 bitsMask = 0x80; /* FreeType is always MSB first */
934 bitsMask = bitsMask >> 1;
940 } while (bits & bitsMask);
941 XFillRectangle (gdi_display, physDev->drawable,
942 physDev->gc, xspan, y, lenspan, 1);
954 bitsMask = bitsMask >> 1;
960 } while (!(bits & bitsMask));
967 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
968 void *bitmap, XGlyphInfo *gi)
970 unsigned char *srcLine = bitmap, *src, bits;
971 int width = gi->width;
972 int stride = ((width + 3) & ~3);
973 int height = gi->height;
998 } while (bits >= 0x80);
999 XFillRectangle (gdi_display, physDev->drawable,
1000 physDev->gc, xspan, y, lenspan, 1);
1013 } while (bits < 0x80);
1021 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1026 while ((mask & 1) == 0)
1032 while ((mask & 1) == 1)
1041 static DWORD GetField (DWORD pixel, int shift, int len)
1043 pixel = pixel & (((1 << (len)) - 1) << shift);
1044 pixel = pixel << (32 - (shift + len)) >> 24;
1047 pixel |= (pixel >> len);
1054 static DWORD PutField (DWORD pixel, int shift, int len)
1056 shift = shift - (8 - len);
1058 pixel &= (((1 << len) - 1) << (8 - len));
1066 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1072 BYTE *maskLine, *mask, m;
1077 BYTE src_r, src_g, src_b;
1082 height = gi->height;
1085 maskStride = (width + 3) & ~3;
1087 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1088 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1089 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1091 src_r = GetField(color, r_shift, r_len);
1092 src_g = GetField(color, g_shift, g_len);
1093 src_b = GetField(color, b_shift, b_len);
1095 for(; height--; y++)
1098 maskLine += maskStride;
1103 if(y >= image->height) break;
1107 if(tx >= image->width) break;
1110 if(tx < 0) continue;
1113 XPutPixel (image, tx, y, color);
1118 pixel = XGetPixel (image, tx, y);
1120 r = GetField(pixel, r_shift, r_len);
1121 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1122 g = GetField(pixel, g_shift, g_len);
1123 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1124 b = GetField(pixel, b_shift, b_len);
1125 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1127 pixel = (PutField (r, r_shift, r_len) |
1128 PutField (g, g_shift, g_len) |
1129 PutField (b, b_shift, b_len));
1130 XPutPixel (image, tx, y, pixel);
1136 /*************************************************************
1139 * Returns an appropriate Picture for tiling the text colour.
1140 * Call and use result within the xrender_cs
1142 static Picture get_tile_pict(enum drawable_depth_type type, int text_pixel)
1152 tile = &tiles[type];
1156 XRenderPictureAttributes pa;
1159 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_formats[type]->depth);
1162 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_formats[type], CPRepeat, &pa);
1163 wine_tsx11_unlock();
1165 /* init current_color to something different from text_pixel */
1166 tile->current_color = ~text_pixel;
1168 if(type == mono_drawable)
1170 /* for a 1bpp bitmap we always need a 1 in the tile */
1171 col.red = col.green = col.blue = 0;
1174 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1175 wine_tsx11_unlock();
1179 if(text_pixel != tile->current_color && type == color_drawable)
1181 /* Map 0 -- 0xff onto 0 -- 0xffff */
1186 ExamineBitfield (visual->red_mask, &r_shift, &r_len );
1187 ExamineBitfield (visual->green_mask, &g_shift, &g_len);
1188 ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
1190 col.red = GetField(text_pixel, r_shift, r_len);
1191 col.red |= col.red << 8;
1192 col.green = GetField(text_pixel, g_shift, g_len);
1193 col.green |= col.green << 8;
1194 col.blue = GetField(text_pixel, b_shift, b_len);
1195 col.blue |= col.blue << 8;
1199 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1200 wine_tsx11_unlock();
1201 tile->current_color = text_pixel;
1206 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1211 /***********************************************************************
1212 * X11DRV_XRender_ExtTextOut
1214 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1215 const RECT *lprect, LPCWSTR wstr, UINT count,
1220 gsCacheEntry *entry;
1221 gsCacheEntryFormat *formatEntry;
1223 HDC hdc = physDev->hdc;
1224 int textPixel, backgroundPixel;
1225 HRGN saved_region = 0;
1226 BOOL disable_antialias = FALSE;
1227 AA_Type aa_type = AA_None;
1230 double cosEsc, sinEsc;
1232 enum drawable_depth_type depth_type = (physDev->depth == 1) ? mono_drawable : color_drawable;
1233 Picture tile_pict = 0;
1235 /* Do we need to disable antialiasing because of palette mode? */
1236 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1237 TRACE("bitmap is not a DIB\n");
1239 else if (bmp.dsBmih.biBitCount <= 8) {
1240 TRACE("Disabling antialiasing\n");
1241 disable_antialias = TRUE;
1244 xgcval.function = GXcopy;
1245 xgcval.background = physDev->backgroundPixel;
1246 xgcval.fill_style = FillSolid;
1248 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1249 wine_tsx11_unlock();
1251 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1253 if(physDev->depth == 1) {
1254 if((physDev->textPixel & 0xffffff) == 0) {
1256 backgroundPixel = 1;
1259 backgroundPixel = 0;
1262 textPixel = physDev->textPixel;
1263 backgroundPixel = physDev->backgroundPixel;
1266 if(flags & ETO_OPAQUE)
1269 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1270 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1271 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1272 lprect->right - lprect->left, lprect->bottom - lprect->top );
1273 wine_tsx11_unlock();
1283 GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1284 if(lf.lfEscapement != 0) {
1285 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1286 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1292 if (flags & ETO_CLIPPED)
1296 clip_region = CreateRectRgnIndirect( lprect );
1297 /* make a copy of the current device region */
1298 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1299 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1300 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1301 DeleteObject( clip_region );
1304 if(X11DRV_XRender_Installed) {
1305 if(!physDev->xrender->pict) {
1306 XRenderPictureAttributes pa;
1307 pa.subwindow_mode = IncludeInferiors;
1310 physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1312 pict_formats[depth_type],
1313 CPSubwindowMode, &pa);
1314 wine_tsx11_unlock();
1316 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1317 physDev->xrender->pict, hdc, physDev->drawable);
1319 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1320 physDev->xrender->pict, hdc, physDev->drawable);
1323 if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1326 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1327 physDev->dc_rect.left, physDev->dc_rect.top,
1328 (XRectangle *)data->Buffer, data->rdh.nCount );
1329 wine_tsx11_unlock();
1330 HeapFree( GetProcessHeap(), 0, data );
1334 EnterCriticalSection(&xrender_cs);
1336 entry = glyphsetCache + physDev->xrender->cache_index;
1337 if( disable_antialias == FALSE )
1338 aa_type = entry->aa_default;
1339 formatEntry = entry->format[aa_type];
1341 for(idx = 0; idx < count; idx++) {
1342 if( !formatEntry ) {
1343 UploadGlyph(physDev, wstr[idx], aa_type);
1344 /* re-evaluate antialias since aa_default may have changed */
1345 if( disable_antialias == FALSE )
1346 aa_type = entry->aa_default;
1347 formatEntry = entry->format[aa_type];
1348 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1349 UploadGlyph(physDev, wstr[idx], aa_type);
1354 WARN("could not upload requested glyphs\n");
1355 LeaveCriticalSection(&xrender_cs);
1359 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1360 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1362 if(X11DRV_XRender_Installed)
1364 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1366 POINT desired, current;
1367 int render_op = PictOpOver;
1369 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1370 So we pass zeros to the function and move to our starting position using the first
1371 element of the elts array. */
1373 desired.x = physDev->dc_rect.left + x;
1374 desired.y = physDev->dc_rect.top + y;
1375 current.x = current.y = 0;
1377 tile_pict = get_tile_pict(depth_type, physDev->textPixel);
1379 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1381 if((depth_type == mono_drawable) && (textPixel == 0))
1382 render_op = PictOpOutReverse; /* This gives us 'black' text */
1384 for(idx = 0; idx < count; idx++)
1386 elts[idx].glyphset = formatEntry->glyphset;
1387 elts[idx].chars = wstr + idx;
1388 elts[idx].nchars = 1;
1389 elts[idx].xOff = desired.x - current.x;
1390 elts[idx].yOff = desired.y - current.y;
1392 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1393 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1397 desired.x += formatEntry->gis[wstr[idx]].xOff;
1398 desired.y += formatEntry->gis[wstr[idx]].yOff;
1402 offset += lpDx[idx];
1403 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1404 desired.y = physDev->dc_rect.top + y - offset * sinEsc;
1408 pXRenderCompositeText16(gdi_display, render_op,
1410 physDev->xrender->pict,
1411 formatEntry->font_format,
1412 0, 0, 0, 0, elts, count);
1413 wine_tsx11_unlock();
1414 HeapFree(GetProcessHeap(), 0, elts);
1416 INT offset = 0, xoff = 0, yoff = 0;
1418 XSetForeground( gdi_display, physDev->gc, textPixel );
1420 if(aa_type == AA_None || physDev->depth == 1)
1422 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1424 if(aa_type == AA_None)
1425 sharp_glyph_fn = SharpGlyphMono;
1427 sharp_glyph_fn = SharpGlyphGray;
1429 for(idx = 0; idx < count; idx++) {
1430 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1431 physDev->dc_rect.top + y + yoff,
1432 formatEntry->bitmaps[wstr[idx]],
1433 &formatEntry->gis[wstr[idx]]);
1435 offset += lpDx[idx];
1436 xoff = offset * cosEsc;
1437 yoff = offset * -sinEsc;
1439 xoff += formatEntry->gis[wstr[idx]].xOff;
1440 yoff += formatEntry->gis[wstr[idx]].yOff;
1445 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1446 RECT extents = {0, 0, 0, 0};
1448 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1449 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1451 TRACE("drawable %dx%d\n", w, h);
1453 for(idx = 0; idx < count; idx++) {
1454 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1455 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1456 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1457 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1458 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1459 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1460 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1461 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1463 offset += lpDx[idx];
1464 cur.x = offset * cosEsc;
1465 cur.y = offset * -sinEsc;
1467 cur.x += formatEntry->gis[wstr[idx]].xOff;
1468 cur.y += formatEntry->gis[wstr[idx]].yOff;
1471 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1472 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1474 if(physDev->dc_rect.left + x + extents.left >= 0) {
1475 image_x = physDev->dc_rect.left + x + extents.left;
1479 image_off_x = physDev->dc_rect.left + x + extents.left;
1481 if(physDev->dc_rect.top + y + extents.top >= 0) {
1482 image_y = physDev->dc_rect.top + y + extents.top;
1486 image_off_y = physDev->dc_rect.top + y + extents.top;
1488 if(physDev->dc_rect.left + x + extents.right < w)
1489 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1491 image_w = w - image_x;
1492 if(physDev->dc_rect.top + y + extents.bottom < h)
1493 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1495 image_h = h - image_y;
1497 if(image_w <= 0 || image_h <= 0) goto no_image;
1499 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1500 image = XGetImage(gdi_display, physDev->drawable,
1501 image_x, image_y, image_w, image_h,
1502 AllPlanes, ZPixmap);
1503 X11DRV_check_error();
1505 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1506 gdi_display, (int)physDev->drawable, image_x, image_y,
1507 image_w, image_h, AllPlanes, ZPixmap,
1508 physDev->depth, image);
1510 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
1515 gcv.graphics_exposures = False;
1516 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1517 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1518 image_w, image_h, 0, 0);
1519 XFreeGC(gdi_display, gc);
1520 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1521 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1523 X11DRV_check_error();
1524 XFreePixmap(gdi_display, xpm);
1526 if(!image) goto no_image;
1528 image->red_mask = visual->red_mask;
1529 image->green_mask = visual->green_mask;
1530 image->blue_mask = visual->blue_mask;
1532 offset = xoff = yoff = 0;
1533 for(idx = 0; idx < count; idx++) {
1534 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1535 yoff + image_off_y - extents.top,
1536 formatEntry->bitmaps[wstr[idx]],
1537 &formatEntry->gis[wstr[idx]],
1538 physDev->textPixel);
1540 offset += lpDx[idx];
1541 xoff = offset * cosEsc;
1542 yoff = offset * -sinEsc;
1544 xoff += formatEntry->gis[wstr[idx]].xOff;
1545 yoff += formatEntry->gis[wstr[idx]].yOff;
1548 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1549 image_x, image_y, image_w, image_h);
1550 XDestroyImage(image);
1553 wine_tsx11_unlock();
1555 LeaveCriticalSection(&xrender_cs);
1557 if (flags & ETO_CLIPPED)
1559 /* restore the device region */
1560 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1561 DeleteObject( saved_region );
1567 X11DRV_UnlockDIBSection( physDev, TRUE );
1571 /******************************************************************************
1572 * AlphaBlend (x11drv.@)
1574 BOOL CDECL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1575 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1576 BLENDFUNCTION blendfn)
1578 XRenderPictureAttributes pa;
1579 XRenderPictFormat *src_format;
1580 XRenderPictFormat argb32_templ = {
1582 PictTypeDirect, /* type */
1585 16, /* direct.red */
1586 0xff, /* direct.redMask */
1587 8, /* direct.green */
1588 0xff, /* direct.greenMask */
1589 0, /* direct.blue */
1590 0xff, /* direct.blueMask */
1591 24, /* direct.alpha */
1592 0xff, /* direct.alphaMask */
1596 unsigned long argb32_templ_mask =
1602 PictFormatGreenMask |
1604 PictFormatBlueMask |
1606 PictFormatAlphaMask;
1608 Picture dst_pict, src_pict;
1614 DWORD *dstbits, *data;
1617 BOOL top_down = FALSE;
1619 enum drawable_depth_type dst_depth_type = (devDst->depth == 1) ? mono_drawable : color_drawable;
1621 if(!X11DRV_XRender_Installed) {
1622 FIXME("Unable to AlphaBlend without Xrender\n");
1627 pts[1].x = xDst + widthDst;
1628 pts[1].y = yDst + heightDst;
1629 LPtoDP(devDst->hdc, pts, 2);
1632 widthDst = pts[1].x - pts[0].x;
1633 heightDst = pts[1].y - pts[0].y;
1637 pts[1].x = xSrc + widthSrc;
1638 pts[1].y = ySrc + heightSrc;
1639 LPtoDP(devSrc->hdc, pts, 2);
1642 widthSrc = pts[1].x - pts[0].x;
1643 heightSrc = pts[1].y - pts[0].y;
1644 if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1646 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1647 if(widthDst != widthSrc || heightDst != heightSrc)
1649 if(!pXRenderSetPictureTransform)
1652 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1656 if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1658 static BOOL out = FALSE;
1661 FIXME("not a dibsection\n");
1667 if (xSrc < 0 || ySrc < 0 || widthSrc < 0 || heightSrc < 0 || xSrc + widthSrc > dib.dsBmih.biWidth
1668 || ySrc + heightSrc > abs(dib.dsBmih.biHeight))
1670 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc, ySrc, widthSrc, heightSrc);
1671 SetLastError(ERROR_INVALID_PARAMETER);
1675 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && blendfn.SourceConstantAlpha != 0xff)
1676 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn.SourceConstantAlpha);
1678 if(dib.dsBm.bmBitsPixel != 32) {
1679 FIXME("not a 32 bpp dibsection\n");
1682 dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1684 if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1686 dstbits += widthSrc * (heightSrc - 1);
1688 y = y2 + heightSrc - 1;
1692 y = dib.dsBmih.biHeight - ySrc - 1;
1693 y2 = y - heightSrc + 1;
1696 if (blendfn.AlphaFormat & AC_SRC_ALPHA)
1700 memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1702 dstbits += (top_down ? -1 : 1) * widthSrc;
1707 DWORD source_alpha = (DWORD)blendfn.SourceConstantAlpha << 24;
1712 DWORD *srcbits = (DWORD *)((char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes) + xSrc;
1713 for (x = 0; x < widthSrc; x++)
1715 DWORD argb = *srcbits++;
1716 argb = (argb & 0xffffff) | source_alpha;
1719 if (top_down) /* we traversed the row forward so we should go back by two rows */
1720 dstbits -= 2 * widthSrc;
1725 rgndata = X11DRV_GetRegionData( devDst->region, 0 );
1728 image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1729 (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1732 Avoid using XRenderFindStandardFormat as older libraries don't have it
1733 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1735 src_format = pXRenderFindFormat(gdi_display, argb32_templ_mask, &argb32_templ, 0);
1737 TRACE("src_format %p\n", src_format);
1739 pa.subwindow_mode = IncludeInferiors;
1741 /* FIXME use devDst->xrender->pict ? */
1742 dst_pict = pXRenderCreatePicture(gdi_display,
1744 pict_formats[dst_depth_type],
1745 CPSubwindowMode, &pa);
1746 TRACE("dst_pict %08lx\n", dst_pict);
1747 TRACE("src_drawable = %08lx\n", devSrc->drawable);
1748 xpm = XCreatePixmap(gdi_display,
1750 widthSrc, heightSrc, 32);
1751 gcv.graphics_exposures = False;
1752 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1753 TRACE("xpm = %08lx\n", xpm);
1754 XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1756 src_pict = pXRenderCreatePicture(gdi_display,
1758 CPSubwindowMode, &pa);
1759 TRACE("src_pict %08lx\n", src_pict);
1763 pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
1764 devDst->dc_rect.left, devDst->dc_rect.top,
1765 (XRectangle *)rgndata->Buffer,
1766 rgndata->rdh.nCount );
1767 HeapFree( GetProcessHeap(), 0, rgndata );
1770 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1771 if(widthDst != widthSrc || heightDst != heightSrc) {
1772 double xscale = widthSrc/(double)widthDst;
1773 double yscale = heightSrc/(double)heightDst;
1774 XTransform xform = {{
1775 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0) },
1776 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0) },
1777 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1779 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1782 pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
1784 xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
1787 pXRenderFreePicture(gdi_display, src_pict);
1788 XFreePixmap(gdi_display, xpm);
1789 XFreeGC(gdi_display, gc);
1790 pXRenderFreePicture(gdi_display, dst_pict);
1792 XDestroyImage(image);
1794 wine_tsx11_unlock();
1795 HeapFree(GetProcessHeap(), 0, data);
1799 #else /* SONAME_LIBXRENDER */
1801 void X11DRV_XRender_Init(void)
1803 TRACE("XRender support not compiled in.\n");
1807 void X11DRV_XRender_Finalize(void)
1811 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1817 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1823 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1824 const RECT *lprect, LPCWSTR wstr, UINT count,
1831 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1837 /******************************************************************************
1838 * AlphaBlend (x11drv.@)
1840 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1841 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1842 BLENDFUNCTION blendfn)
1844 FIXME("not supported - XRENDER headers were missing at compile time\n");
1848 #endif /* SONAME_LIBXRENDER */