dsound: Enforce invariant about BlockAlign and nAvgBytesPerSec.
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blob076b6d4770d9b75c213c2f3f541d2f9d43964e94
1 /*
2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
7 * Some parts also:
8 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <assert.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <stdlib.h>
32 #include "windef.h"
33 #include "winbase.h"
34 #include "x11drv.h"
35 #include "winternl.h"
36 #include "wine/library.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
40 int using_client_side_fonts = FALSE;
42 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
44 #ifdef SONAME_LIBXRENDER
46 static BOOL X11DRV_XRender_Installed = FALSE;
48 #include <X11/Xlib.h>
49 #include <X11/extensions/Xrender.h>
51 #ifndef RepeatNone /* added in 0.10 */
52 #define RepeatNone 0
53 #define RepeatNormal 1
54 #define RepeatPad 2
55 #define RepeatReflect 3
56 #endif
58 #define MAX_FORMATS 10
59 typedef enum wine_xrformat
61 WXR_FORMAT_MONO,
62 WXR_FORMAT_GRAY,
63 WXR_FORMAT_X1R5G5B5,
64 WXR_FORMAT_X1B5G5R5,
65 WXR_FORMAT_R5G6B5,
66 WXR_FORMAT_B5G6R5,
67 WXR_FORMAT_R8G8B8,
68 WXR_FORMAT_B8G8R8,
69 WXR_FORMAT_A8R8G8B8,
70 WXR_FORMAT_X8R8G8B8,
71 } WXRFormat;
73 typedef struct wine_xrender_format_template
75 WXRFormat wxr_format;
76 unsigned int depth;
77 unsigned int alpha;
78 unsigned int alphaMask;
79 unsigned int red;
80 unsigned int redMask;
81 unsigned int green;
82 unsigned int greenMask;
83 unsigned int blue;
84 unsigned int blueMask;
85 } WineXRenderFormatTemplate;
87 static const WineXRenderFormatTemplate wxr_formats_template[] =
89 /* Format depth alpha mask red mask green mask blue mask*/
90 {WXR_FORMAT_MONO, 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
91 {WXR_FORMAT_GRAY, 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
92 {WXR_FORMAT_X1R5G5B5, 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
93 {WXR_FORMAT_X1B5G5R5, 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
94 {WXR_FORMAT_R5G6B5, 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
95 {WXR_FORMAT_B5G6R5, 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
96 {WXR_FORMAT_R8G8B8, 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
97 {WXR_FORMAT_B8G8R8, 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
98 {WXR_FORMAT_A8R8G8B8, 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
99 {WXR_FORMAT_X8R8G8B8, 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff }
102 typedef struct wine_xrender_format
104 WXRFormat format;
105 XRenderPictFormat *pict_format;
106 } WineXRenderFormat;
108 static WineXRenderFormat wxr_formats[MAX_FORMATS];
109 static int WineXRenderFormatsListSize = 0;
110 static WineXRenderFormat *default_format = NULL;
112 typedef struct
114 LOGFONTW lf;
115 XFORM xform;
116 SIZE devsize; /* size in device coords */
117 DWORD hash;
118 } LFANDSIZE;
120 #define INITIAL_REALIZED_BUF_SIZE 128
122 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
124 typedef struct
126 GlyphSet glyphset;
127 WineXRenderFormat *font_format;
128 int nrealized;
129 BOOL *realized;
130 void **bitmaps;
131 XGlyphInfo *gis;
132 } gsCacheEntryFormat;
134 typedef struct
136 LFANDSIZE lfsz;
137 AA_Type aa_default;
138 gsCacheEntryFormat * format[AA_MAXVALUE];
139 INT count;
140 INT next;
141 } gsCacheEntry;
143 struct tagXRENDERINFO
145 int cache_index;
146 Picture pict;
150 static gsCacheEntry *glyphsetCache = NULL;
151 static DWORD glyphsetCacheSize = 0;
152 static INT lastfree = -1;
153 static INT mru = -1;
155 #define INIT_CACHE_SIZE 10
157 static int antialias = 1;
159 static void *xrender_handle;
161 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
162 MAKE_FUNCPTR(XRenderAddGlyphs)
163 MAKE_FUNCPTR(XRenderComposite)
164 MAKE_FUNCPTR(XRenderCompositeString8)
165 MAKE_FUNCPTR(XRenderCompositeString16)
166 MAKE_FUNCPTR(XRenderCompositeString32)
167 MAKE_FUNCPTR(XRenderCompositeText16)
168 MAKE_FUNCPTR(XRenderCreateGlyphSet)
169 MAKE_FUNCPTR(XRenderCreatePicture)
170 MAKE_FUNCPTR(XRenderFillRectangle)
171 MAKE_FUNCPTR(XRenderFindFormat)
172 MAKE_FUNCPTR(XRenderFindVisualFormat)
173 MAKE_FUNCPTR(XRenderFreeGlyphSet)
174 MAKE_FUNCPTR(XRenderFreePicture)
175 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
176 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
177 MAKE_FUNCPTR(XRenderSetPictureTransform)
178 #endif
179 MAKE_FUNCPTR(XRenderQueryExtension)
180 #undef MAKE_FUNCPTR
182 static CRITICAL_SECTION xrender_cs;
183 static CRITICAL_SECTION_DEBUG critsect_debug =
185 0, 0, &xrender_cs,
186 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
187 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
189 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
191 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
192 ( ( (ULONG)_x4 << 24 ) | \
193 ( (ULONG)_x3 << 16 ) | \
194 ( (ULONG)_x2 << 8 ) | \
195 (ULONG)_x1 )
197 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
199 #define GASP_GRIDFIT 0x01
200 #define GASP_DOGRAY 0x02
202 #ifdef WORDS_BIGENDIAN
203 #define get_be_word(x) (x)
204 #define NATIVE_BYTE_ORDER MSBFirst
205 #else
206 #define get_be_word(x) RtlUshortByteSwap(x)
207 #define NATIVE_BYTE_ORDER LSBFirst
208 #endif
210 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
212 templ->id = 0;
213 templ->type = PictTypeDirect;
214 templ->depth = fmt->depth;
215 templ->direct.alpha = fmt->alpha;
216 templ->direct.alphaMask = fmt->alphaMask;
217 templ->direct.red = fmt->red;
218 templ->direct.redMask = fmt->redMask;
219 templ->direct.green = fmt->green;
220 templ->direct.greenMask = fmt->greenMask;
221 templ->direct.blue = fmt->blue;
222 templ->direct.blueMask = fmt->blueMask;
223 templ->colormap = 0;
225 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
227 return TRUE;
230 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
232 if(fmt->depth != screen_depth)
233 return FALSE;
234 if( (fmt->redMask << fmt->red) != visual->red_mask)
235 return FALSE;
236 if( (fmt->greenMask << fmt->green) != visual->green_mask)
237 return FALSE;
238 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
239 return FALSE;
241 /* We never select a default ARGB visual */
242 if(fmt->alphaMask)
243 return FALSE;
245 return TRUE;
248 static int load_xrender_formats(void)
250 unsigned int i;
251 for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
253 XRenderPictFormat templ, *pict_format;
255 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
257 wine_tsx11_lock();
258 pict_format = pXRenderFindVisualFormat(gdi_display, visual);
259 if(!pict_format)
261 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
262 if (visual->class == DirectColor)
264 XVisualInfo info;
265 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
266 screen_depth, TrueColor, &info ))
268 pict_format = pXRenderFindVisualFormat(gdi_display, info.visual);
269 if (pict_format) visual = info.visual;
273 wine_tsx11_unlock();
275 if(pict_format)
277 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
278 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
279 default_format = &wxr_formats[WineXRenderFormatsListSize];
280 WineXRenderFormatsListSize++;
281 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
284 else
286 unsigned long mask = 0;
287 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
289 wine_tsx11_lock();
290 pict_format = pXRenderFindFormat(gdi_display, mask, &templ, 0);
291 wine_tsx11_unlock();
293 if(pict_format)
295 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
296 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
297 WineXRenderFormatsListSize++;
298 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
302 return WineXRenderFormatsListSize;
305 /***********************************************************************
306 * X11DRV_XRender_Init
308 * Let's see if our XServer has the extension available
311 void X11DRV_XRender_Init(void)
313 int event_base, i;
315 if (client_side_with_render &&
316 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
317 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
318 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
321 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
322 LOAD_FUNCPTR(XRenderAddGlyphs)
323 LOAD_FUNCPTR(XRenderComposite)
324 LOAD_FUNCPTR(XRenderCompositeString8)
325 LOAD_FUNCPTR(XRenderCompositeString16)
326 LOAD_FUNCPTR(XRenderCompositeString32)
327 LOAD_FUNCPTR(XRenderCompositeText16)
328 LOAD_FUNCPTR(XRenderCreateGlyphSet)
329 LOAD_FUNCPTR(XRenderCreatePicture)
330 LOAD_FUNCPTR(XRenderFillRectangle)
331 LOAD_FUNCPTR(XRenderFindFormat)
332 LOAD_FUNCPTR(XRenderFindVisualFormat)
333 LOAD_FUNCPTR(XRenderFreeGlyphSet)
334 LOAD_FUNCPTR(XRenderFreePicture)
335 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
336 LOAD_FUNCPTR(XRenderQueryExtension)
337 #undef LOAD_FUNCPTR
338 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
339 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
340 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
341 #undef LOAD_OPTIONAL_FUNCPTR
342 #endif
344 wine_tsx11_lock();
345 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
346 wine_tsx11_unlock();
347 if(X11DRV_XRender_Installed) {
348 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
349 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
351 wine_tsx11_unlock();
352 WINE_MESSAGE(
353 "Wine has detected that you probably have a buggy version\n"
354 "of libXrender.so . Because of this client side font rendering\n"
355 "will be disabled. Please upgrade this library.\n");
356 X11DRV_XRender_Installed = FALSE;
357 return;
360 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
361 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
362 X11DRV_XRender_Installed = FALSE;
367 sym_not_found:
368 if(X11DRV_XRender_Installed || client_side_with_core)
370 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
371 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
373 glyphsetCacheSize = INIT_CACHE_SIZE;
374 lastfree = 0;
375 for(i = 0; i < INIT_CACHE_SIZE; i++) {
376 glyphsetCache[i].next = i + 1;
377 glyphsetCache[i].count = -1;
379 glyphsetCache[i-1].next = -1;
380 using_client_side_fonts = 1;
382 if(!X11DRV_XRender_Installed) {
383 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
384 if(screen_depth <= 8 || !client_side_antialias_with_core)
385 antialias = 0;
386 } else {
387 if(screen_depth <= 8 || !client_side_antialias_with_render)
388 antialias = 0;
391 else TRACE("Using X11 core fonts\n");
394 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
395 static void get_xrender_color(WineXRenderFormat *wxr_format, int src_color, XRenderColor *dst_color)
397 XRenderPictFormat *pf = wxr_format->pict_format;
399 if(pf->direct.redMask)
400 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
401 else
402 dst_color->red = 0;
404 if(pf->direct.greenMask)
405 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
406 else
407 dst_color->green = 0;
409 if(pf->direct.blueMask)
410 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
411 else
412 dst_color->blue = 0;
414 dst_color->alpha = 0xffff;
417 static WineXRenderFormat *get_xrender_format(WXRFormat format)
419 int i;
420 for(i=0; i<WineXRenderFormatsListSize; i++)
422 if(wxr_formats[i].format == format)
424 TRACE("Returning wxr_format=%#x\n", format);
425 return &wxr_formats[i];
428 return NULL;
431 static WineXRenderFormat *get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
433 int redMask, greenMask, blueMask;
434 unsigned int i;
436 if(depth == 1)
437 return get_xrender_format(WXR_FORMAT_MONO);
439 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
440 if(!shifts)
441 return default_format;
443 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
444 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
445 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
447 /* Try to locate a format which matches the specification of the dibsection. */
448 for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
450 if( depth == wxr_formats_template[i].depth &&
451 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
452 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
453 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
456 /* When we reach this stage the format was found in our template table but this doesn't mean that
457 * the Xserver also supports this format (e.g. its depth might be too low). The call below verifies that.
459 return get_xrender_format(wxr_formats_template[i].wxr_format);
463 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
464 ERR("No XRender format found!\n");
465 return NULL;
468 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
470 if(p1->hash != p2->hash) return TRUE;
471 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
472 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
473 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
474 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
477 #if 0
478 static void walk_cache(void)
480 int i;
482 EnterCriticalSection(&xrender_cs);
483 for(i=mru; i >= 0; i = glyphsetCache[i].next)
484 TRACE("item %d\n", i);
485 LeaveCriticalSection(&xrender_cs);
487 #endif
489 static int LookupEntry(LFANDSIZE *plfsz)
491 int i, prev_i = -1;
493 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
494 TRACE("%d\n", i);
495 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
496 i = -1;
497 break;
500 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
501 glyphsetCache[i].count++;
502 if(prev_i >= 0) {
503 glyphsetCache[prev_i].next = glyphsetCache[i].next;
504 glyphsetCache[i].next = mru;
505 mru = i;
507 TRACE("found font in cache %d\n", i);
508 return i;
510 prev_i = i;
512 TRACE("font not in cache\n");
513 return -1;
516 static void FreeEntry(int entry)
518 int i, format;
520 for(format = 0; format < AA_MAXVALUE; format++) {
521 gsCacheEntryFormat * formatEntry;
523 if( !glyphsetCache[entry].format[format] )
524 continue;
526 formatEntry = glyphsetCache[entry].format[format];
528 if(formatEntry->glyphset) {
529 wine_tsx11_lock();
530 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
531 wine_tsx11_unlock();
532 formatEntry->glyphset = 0;
534 if(formatEntry->nrealized) {
535 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
536 formatEntry->realized = NULL;
537 if(formatEntry->bitmaps) {
538 for(i = 0; i < formatEntry->nrealized; i++)
539 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
540 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
541 formatEntry->bitmaps = NULL;
543 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
544 formatEntry->gis = NULL;
545 formatEntry->nrealized = 0;
548 HeapFree(GetProcessHeap(), 0, formatEntry);
549 glyphsetCache[entry].format[format] = NULL;
553 static int AllocEntry(void)
555 int best = -1, prev_best = -1, i, prev_i = -1;
557 if(lastfree >= 0) {
558 assert(glyphsetCache[lastfree].count == -1);
559 glyphsetCache[lastfree].count = 1;
560 best = lastfree;
561 lastfree = glyphsetCache[lastfree].next;
562 assert(best != mru);
563 glyphsetCache[best].next = mru;
564 mru = best;
566 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
567 return mru;
570 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
571 if(glyphsetCache[i].count == 0) {
572 best = i;
573 prev_best = prev_i;
575 prev_i = i;
578 if(best >= 0) {
579 TRACE("freeing unused glyphset at cache %d\n", best);
580 FreeEntry(best);
581 glyphsetCache[best].count = 1;
582 if(prev_best >= 0) {
583 glyphsetCache[prev_best].next = glyphsetCache[best].next;
584 glyphsetCache[best].next = mru;
585 mru = best;
586 } else {
587 assert(mru == best);
589 return mru;
592 TRACE("Growing cache\n");
594 if (glyphsetCache)
595 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
596 glyphsetCache,
597 (glyphsetCacheSize + INIT_CACHE_SIZE)
598 * sizeof(*glyphsetCache));
599 else
600 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
601 (glyphsetCacheSize + INIT_CACHE_SIZE)
602 * sizeof(*glyphsetCache));
604 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
605 i++) {
606 glyphsetCache[i].next = i + 1;
607 glyphsetCache[i].count = -1;
609 glyphsetCache[i-1].next = -1;
610 glyphsetCacheSize += INIT_CACHE_SIZE;
612 lastfree = glyphsetCache[best].next;
613 glyphsetCache[best].count = 1;
614 glyphsetCache[best].next = mru;
615 mru = best;
616 TRACE("new free cache slot at %d\n", mru);
617 return mru;
620 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
622 DWORD size;
623 WORD *gasp, *buffer;
624 WORD num_recs;
625 DWORD ppem;
626 TEXTMETRICW tm;
628 *flags = 0;
630 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
631 if(size == GDI_ERROR)
632 return FALSE;
634 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
635 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
637 GetTextMetricsW(physDev->hdc, &tm);
638 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
640 gasp++;
641 num_recs = get_be_word(*gasp);
642 gasp++;
643 while(num_recs--)
645 *flags = get_be_word(*(gasp + 1));
646 if(ppem <= get_be_word(*gasp))
647 break;
648 gasp += 2;
650 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
652 HeapFree(GetProcessHeap(), 0, buffer);
653 return TRUE;
656 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
658 AA_Type ret;
659 WORD flags;
660 UINT font_smoothing_type, font_smoothing_orientation;
662 if (X11DRV_XRender_Installed && subpixel &&
663 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
664 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
666 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
667 &font_smoothing_orientation, 0) &&
668 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
670 ret = AA_BGR;
672 else
673 ret = AA_RGB;
674 /*FIXME
675 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
676 But, Wine's subpixel rendering can support the portrait mode.
679 else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
680 ret = AA_Grey;
681 else
682 ret = AA_None;
684 return ret;
687 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
689 int ret;
690 int format;
691 gsCacheEntry *entry;
692 static int hinter = -1;
693 static int subpixel = -1;
694 BOOL font_smoothing;
696 if((ret = LookupEntry(plfsz)) != -1) return ret;
698 ret = AllocEntry();
699 entry = glyphsetCache + ret;
700 entry->lfsz = *plfsz;
701 for( format = 0; format < AA_MAXVALUE; format++ ) {
702 assert( !entry->format[format] );
705 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
707 if(hinter == -1 || subpixel == -1)
709 RASTERIZER_STATUS status;
710 GetRasterizerCaps(&status, sizeof(status));
711 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
712 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
715 switch (plfsz->lf.lfQuality)
717 case ANTIALIASED_QUALITY:
718 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
719 break;
720 case CLEARTYPE_QUALITY:
721 case CLEARTYPE_NATURAL_QUALITY:
722 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
723 break;
724 case DEFAULT_QUALITY:
725 case DRAFT_QUALITY:
726 case PROOF_QUALITY:
727 default:
728 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
729 font_smoothing)
731 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
733 else
734 entry->aa_default = AA_None;
735 break;
738 else
739 entry->aa_default = AA_None;
741 return ret;
744 static void dec_ref_cache(int index)
746 assert(index >= 0);
747 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
748 assert(glyphsetCache[index].count > 0);
749 glyphsetCache[index].count--;
752 static void lfsz_calc_hash(LFANDSIZE *plfsz)
754 DWORD hash = 0, *ptr, two_chars;
755 WORD *pwc;
756 int i;
758 hash ^= plfsz->devsize.cx;
759 hash ^= plfsz->devsize.cy;
760 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
761 hash ^= *ptr;
762 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
763 hash ^= *ptr;
764 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
765 two_chars = *ptr;
766 pwc = (WCHAR *)&two_chars;
767 if(!*pwc) break;
768 *pwc = toupperW(*pwc);
769 pwc++;
770 *pwc = toupperW(*pwc);
771 hash ^= two_chars;
772 if(!*pwc) break;
774 plfsz->hash = hash;
775 return;
778 /***********************************************************************
779 * X11DRV_XRender_Finalize
781 void X11DRV_XRender_Finalize(void)
783 int i;
785 EnterCriticalSection(&xrender_cs);
786 for(i = mru; i >= 0; i = glyphsetCache[i].next)
787 FreeEntry(i);
788 LeaveCriticalSection(&xrender_cs);
792 /***********************************************************************
793 * X11DRV_XRender_SelectFont
795 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
797 LFANDSIZE lfsz;
799 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
800 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
801 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
802 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
803 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
804 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
805 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
806 GetWorldTransform( physDev->hdc, &lfsz.xform );
807 lfsz_calc_hash(&lfsz);
809 EnterCriticalSection(&xrender_cs);
810 if(!physDev->xrender) {
811 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
812 sizeof(*physDev->xrender));
813 physDev->xrender->cache_index = -1;
815 else if(physDev->xrender->cache_index != -1)
816 dec_ref_cache(physDev->xrender->cache_index);
817 physDev->xrender->cache_index = GetCacheEntry(physDev, &lfsz);
818 LeaveCriticalSection(&xrender_cs);
819 return 0;
822 /***********************************************************************
823 * X11DRV_XRender_DeleteDC
825 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
827 X11DRV_XRender_UpdateDrawable(physDev);
829 EnterCriticalSection(&xrender_cs);
830 if(physDev->xrender->cache_index != -1)
831 dec_ref_cache(physDev->xrender->cache_index);
832 LeaveCriticalSection(&xrender_cs);
834 HeapFree(GetProcessHeap(), 0, physDev->xrender);
835 physDev->xrender = NULL;
836 return;
839 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, const DIBSECTION *dib)
841 WineXRenderFormat *fmt;
842 ColorShifts shifts;
844 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
845 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
846 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
847 if(!X11DRV_XRender_Installed || dib->dsBm.bmBitsPixel <= 8)
848 return FALSE;
850 X11DRV_PALETTE_ComputeColorShifts(&shifts, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
852 /* Common formats should be in our picture format table. */
853 fmt = get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts);
854 if(fmt)
856 physBitmap->pixmap_depth = fmt->pict_format->depth;
857 physBitmap->trueColor = TRUE;
858 physBitmap->pixmap_color_shifts = shifts;
859 return TRUE;
861 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
862 dib->dsBm.bmBitsPixel, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
863 return FALSE;
866 /***********************************************************************
867 * X11DRV_XRender_UpdateDrawable
869 * Deletes the pict and tile when the drawable changes.
871 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
873 wine_tsx11_lock();
875 if(physDev->xrender->pict)
877 TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
878 XFlush(gdi_display);
879 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
880 physDev->xrender->pict = 0;
882 wine_tsx11_unlock();
884 return;
887 /************************************************************************
888 * UploadGlyph
890 * Helper to ExtTextOut. Must be called inside xrender_cs
892 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
894 unsigned int buflen;
895 char *buf;
896 Glyph gid;
897 GLYPHMETRICS gm;
898 XGlyphInfo gi;
899 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
900 gsCacheEntryFormat *formatEntry;
901 UINT ggo_format = GGO_GLYPH_INDEX;
902 WXRFormat wxr_format;
903 static const char zero[4];
904 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
906 switch(format) {
907 case AA_Grey:
908 ggo_format |= WINE_GGO_GRAY16_BITMAP;
909 break;
910 case AA_RGB:
911 ggo_format |= WINE_GGO_HRGB_BITMAP;
912 break;
913 case AA_BGR:
914 ggo_format |= WINE_GGO_HBGR_BITMAP;
915 break;
916 case AA_VRGB:
917 ggo_format |= WINE_GGO_VRGB_BITMAP;
918 break;
919 case AA_VBGR:
920 ggo_format |= WINE_GGO_VBGR_BITMAP;
921 break;
923 default:
924 ERR("aa = %d - not implemented\n", format);
925 case AA_None:
926 ggo_format |= GGO_BITMAP;
927 break;
930 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
931 if(buflen == GDI_ERROR) {
932 if(format != AA_None) {
933 format = AA_None;
934 entry->aa_default = AA_None;
935 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
936 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
938 if(buflen == GDI_ERROR) {
939 WARN("GetGlyphOutlineW failed\n");
940 return FALSE;
942 TRACE("Turning off antialiasing for this monochrome font\n");
945 /* If there is nothing for the current type, we create the entry. */
946 if( !entry->format[format] ) {
947 entry->format[format] = HeapAlloc(GetProcessHeap(),
948 HEAP_ZERO_MEMORY,
949 sizeof(gsCacheEntryFormat));
951 formatEntry = entry->format[format];
953 if(formatEntry->nrealized <= glyph) {
954 formatEntry->nrealized = (glyph / 128 + 1) * 128;
956 if (formatEntry->realized)
957 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
958 HEAP_ZERO_MEMORY,
959 formatEntry->realized,
960 formatEntry->nrealized * sizeof(BOOL));
961 else
962 formatEntry->realized = HeapAlloc(GetProcessHeap(),
963 HEAP_ZERO_MEMORY,
964 formatEntry->nrealized * sizeof(BOOL));
966 if(!X11DRV_XRender_Installed) {
967 if (formatEntry->bitmaps)
968 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
969 HEAP_ZERO_MEMORY,
970 formatEntry->bitmaps,
971 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
972 else
973 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
974 HEAP_ZERO_MEMORY,
975 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
977 if (formatEntry->gis)
978 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
979 HEAP_ZERO_MEMORY,
980 formatEntry->gis,
981 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
982 else
983 formatEntry->gis = HeapAlloc(GetProcessHeap(),
984 HEAP_ZERO_MEMORY,
985 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
989 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
990 switch(format) {
991 case AA_Grey:
992 wxr_format = WXR_FORMAT_GRAY;
993 break;
995 case AA_RGB:
996 case AA_BGR:
997 case AA_VRGB:
998 case AA_VBGR:
999 wxr_format = WXR_FORMAT_A8R8G8B8;
1000 break;
1002 default:
1003 ERR("aa = %d - not implemented\n", format);
1004 case AA_None:
1005 wxr_format = WXR_FORMAT_MONO;
1006 break;
1009 wine_tsx11_lock();
1010 formatEntry->font_format = get_xrender_format(wxr_format);
1011 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
1012 wine_tsx11_unlock();
1016 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1017 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1018 formatEntry->realized[glyph] = TRUE;
1020 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1021 buflen,
1022 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1023 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1025 gi.width = gm.gmBlackBoxX;
1026 gi.height = gm.gmBlackBoxY;
1027 gi.x = -gm.gmptGlyphOrigin.x;
1028 gi.y = gm.gmptGlyphOrigin.y;
1029 gi.xOff = gm.gmCellIncX;
1030 gi.yOff = gm.gmCellIncY;
1032 if(TRACE_ON(xrender)) {
1033 int pitch, i, j;
1034 char output[300];
1035 unsigned char *line;
1037 if(format == AA_None) {
1038 pitch = ((gi.width + 31) / 32) * 4;
1039 for(i = 0; i < gi.height; i++) {
1040 line = (unsigned char*) buf + i * pitch;
1041 output[0] = '\0';
1042 for(j = 0; j < pitch * 8; j++) {
1043 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1045 TRACE("%s\n", output);
1047 } else {
1048 static const char blks[] = " .:;!o*#";
1049 char str[2];
1051 str[1] = '\0';
1052 pitch = ((gi.width + 3) / 4) * 4;
1053 for(i = 0; i < gi.height; i++) {
1054 line = (unsigned char*) buf + i * pitch;
1055 output[0] = '\0';
1056 for(j = 0; j < pitch; j++) {
1057 str[0] = blks[line[j] >> 5];
1058 strcat(output, str);
1060 TRACE("%s\n", output);
1066 if(formatEntry->glyphset) {
1067 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1068 unsigned char *byte = (unsigned char*) buf, c;
1069 int i = buflen;
1071 while(i--) {
1072 c = *byte;
1074 /* magic to flip bit order */
1075 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1076 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1077 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1079 *byte++ = c;
1082 else if ( format != AA_Grey &&
1083 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1085 unsigned int i, *data = (unsigned int *)buf;
1086 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1088 gid = glyph;
1091 XRenderCompositeText seems to ignore 0x0 glyphs when
1092 AA_None, which means we lose the advance width of glyphs
1093 like the space. We'll pretend that such glyphs are 1x1
1094 bitmaps.
1097 if(buflen == 0)
1098 gi.width = gi.height = 1;
1100 wine_tsx11_lock();
1101 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1102 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1103 wine_tsx11_unlock();
1104 HeapFree(GetProcessHeap(), 0, buf);
1105 } else {
1106 formatEntry->bitmaps[glyph] = buf;
1109 formatEntry->gis[glyph] = gi;
1111 return TRUE;
1114 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
1115 void *bitmap, XGlyphInfo *gi)
1117 unsigned char *srcLine = bitmap, *src;
1118 unsigned char bits, bitsMask;
1119 int width = gi->width;
1120 int stride = ((width + 31) & ~31) >> 3;
1121 int height = gi->height;
1122 int w;
1123 int xspan, lenspan;
1125 TRACE("%d, %d\n", x, y);
1126 x -= gi->x;
1127 y -= gi->y;
1128 while (height--)
1130 src = srcLine;
1131 srcLine += stride;
1132 w = width;
1134 bitsMask = 0x80; /* FreeType is always MSB first */
1135 bits = *src++;
1137 xspan = x;
1138 while (w)
1140 if (bits & bitsMask)
1142 lenspan = 0;
1145 lenspan++;
1146 if (lenspan == w)
1147 break;
1148 bitsMask = bitsMask >> 1;
1149 if (!bitsMask)
1151 bits = *src++;
1152 bitsMask = 0x80;
1154 } while (bits & bitsMask);
1155 XFillRectangle (gdi_display, physDev->drawable,
1156 physDev->gc, xspan, y, lenspan, 1);
1157 xspan += lenspan;
1158 w -= lenspan;
1160 else
1164 w--;
1165 xspan++;
1166 if (!w)
1167 break;
1168 bitsMask = bitsMask >> 1;
1169 if (!bitsMask)
1171 bits = *src++;
1172 bitsMask = 0x80;
1174 } while (!(bits & bitsMask));
1177 y++;
1181 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
1182 void *bitmap, XGlyphInfo *gi)
1184 unsigned char *srcLine = bitmap, *src, bits;
1185 int width = gi->width;
1186 int stride = ((width + 3) & ~3);
1187 int height = gi->height;
1188 int w;
1189 int xspan, lenspan;
1191 x -= gi->x;
1192 y -= gi->y;
1193 while (height--)
1195 src = srcLine;
1196 srcLine += stride;
1197 w = width;
1199 bits = *src++;
1200 xspan = x;
1201 while (w)
1203 if (bits >= 0x80)
1205 lenspan = 0;
1208 lenspan++;
1209 if (lenspan == w)
1210 break;
1211 bits = *src++;
1212 } while (bits >= 0x80);
1213 XFillRectangle (gdi_display, physDev->drawable,
1214 physDev->gc, xspan, y, lenspan, 1);
1215 xspan += lenspan;
1216 w -= lenspan;
1218 else
1222 w--;
1223 xspan++;
1224 if (!w)
1225 break;
1226 bits = *src++;
1227 } while (bits < 0x80);
1230 y++;
1235 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1237 int s, l;
1239 s = 0;
1240 while ((mask & 1) == 0)
1242 mask >>= 1;
1243 s++;
1245 l = 0;
1246 while ((mask & 1) == 1)
1248 mask >>= 1;
1249 l++;
1251 *shift = s;
1252 *len = l;
1255 static DWORD GetField (DWORD pixel, int shift, int len)
1257 pixel = pixel & (((1 << (len)) - 1) << shift);
1258 pixel = pixel << (32 - (shift + len)) >> 24;
1259 while (len < 8)
1261 pixel |= (pixel >> len);
1262 len <<= 1;
1264 return pixel;
1268 static DWORD PutField (DWORD pixel, int shift, int len)
1270 shift = shift - (8 - len);
1271 if (len <= 8)
1272 pixel &= (((1 << len) - 1) << (8 - len));
1273 if (shift < 0)
1274 pixel >>= -shift;
1275 else
1276 pixel <<= shift;
1277 return pixel;
1280 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1281 int color)
1283 int r_shift, r_len;
1284 int g_shift, g_len;
1285 int b_shift, b_len;
1286 BYTE *maskLine, *mask, m;
1287 int maskStride;
1288 DWORD pixel;
1289 int width, height;
1290 int w, tx;
1291 BYTE src_r, src_g, src_b;
1293 x -= gi->x;
1294 y -= gi->y;
1295 width = gi->width;
1296 height = gi->height;
1298 maskLine = bitmap;
1299 maskStride = (width + 3) & ~3;
1301 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1302 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1303 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1305 src_r = GetField(color, r_shift, r_len);
1306 src_g = GetField(color, g_shift, g_len);
1307 src_b = GetField(color, b_shift, b_len);
1309 for(; height--; y++)
1311 mask = maskLine;
1312 maskLine += maskStride;
1313 w = width;
1314 tx = x;
1316 if(y < 0) continue;
1317 if(y >= image->height) break;
1319 for(; w--; tx++)
1321 if(tx >= image->width) break;
1323 m = *mask++;
1324 if(tx < 0) continue;
1326 if (m == 0xff)
1327 XPutPixel (image, tx, y, color);
1328 else if (m)
1330 BYTE r, g, b;
1332 pixel = XGetPixel (image, tx, y);
1334 r = GetField(pixel, r_shift, r_len);
1335 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1336 g = GetField(pixel, g_shift, g_len);
1337 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1338 b = GetField(pixel, b_shift, b_len);
1339 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1341 pixel = (PutField (r, r_shift, r_len) |
1342 PutField (g, g_shift, g_len) |
1343 PutField (b, b_shift, b_len));
1344 XPutPixel (image, tx, y, pixel);
1350 /*************************************************************
1351 * get_tile_pict
1353 * Returns an appropriate Picture for tiling the text colour.
1354 * Call and use result within the xrender_cs
1356 static Picture get_tile_pict(WineXRenderFormat *wxr_format, int text_pixel)
1358 static struct
1360 Pixmap xpm;
1361 Picture pict;
1362 int current_color;
1363 } tiles[MAX_FORMATS], *tile;
1364 XRenderColor col;
1366 tile = &tiles[wxr_format->format];
1368 if(!tile->xpm)
1370 XRenderPictureAttributes pa;
1372 wine_tsx11_lock();
1373 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1375 pa.repeat = RepeatNormal;
1376 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1377 wine_tsx11_unlock();
1379 /* init current_color to something different from text_pixel */
1380 tile->current_color = ~text_pixel;
1382 if(wxr_format->format == WXR_FORMAT_MONO)
1384 /* for a 1bpp bitmap we always need a 1 in the tile */
1385 col.red = col.green = col.blue = 0;
1386 col.alpha = 0xffff;
1387 wine_tsx11_lock();
1388 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1389 wine_tsx11_unlock();
1393 if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1395 get_xrender_color(wxr_format, text_pixel, &col);
1396 wine_tsx11_lock();
1397 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1398 wine_tsx11_unlock();
1399 tile->current_color = text_pixel;
1401 return tile->pict;
1404 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1406 return 1;
1409 /***********************************************************************
1410 * X11DRV_XRender_ExtTextOut
1412 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1413 const RECT *lprect, LPCWSTR wstr, UINT count,
1414 const INT *lpDx )
1416 RGNDATA *data;
1417 XGCValues xgcval;
1418 gsCacheEntry *entry;
1419 gsCacheEntryFormat *formatEntry;
1420 BOOL retv = FALSE;
1421 HDC hdc = physDev->hdc;
1422 int textPixel, backgroundPixel;
1423 HRGN saved_region = 0;
1424 BOOL disable_antialias = FALSE;
1425 AA_Type aa_type = AA_None;
1426 DIBSECTION bmp;
1427 unsigned int idx;
1428 double cosEsc, sinEsc;
1429 LOGFONTW lf;
1430 WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
1431 Picture tile_pict = 0;
1433 /* Do we need to disable antialiasing because of palette mode? */
1434 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1435 TRACE("bitmap is not a DIB\n");
1437 else if (bmp.dsBmih.biBitCount <= 8) {
1438 TRACE("Disabling antialiasing\n");
1439 disable_antialias = TRUE;
1442 xgcval.function = GXcopy;
1443 xgcval.background = physDev->backgroundPixel;
1444 xgcval.fill_style = FillSolid;
1445 wine_tsx11_lock();
1446 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1447 wine_tsx11_unlock();
1449 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1451 if(physDev->depth == 1) {
1452 if((physDev->textPixel & 0xffffff) == 0) {
1453 textPixel = 0;
1454 backgroundPixel = 1;
1455 } else {
1456 textPixel = 1;
1457 backgroundPixel = 0;
1459 } else {
1460 textPixel = physDev->textPixel;
1461 backgroundPixel = physDev->backgroundPixel;
1464 if(flags & ETO_OPAQUE)
1466 wine_tsx11_lock();
1467 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1468 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1469 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1470 lprect->right - lprect->left, lprect->bottom - lprect->top );
1471 wine_tsx11_unlock();
1474 if(count == 0)
1476 retv = TRUE;
1477 goto done_unlock;
1481 GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1482 if(lf.lfEscapement != 0) {
1483 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1484 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1485 } else {
1486 cosEsc = 1;
1487 sinEsc = 0;
1490 if (flags & ETO_CLIPPED)
1492 HRGN clip_region;
1494 clip_region = CreateRectRgnIndirect( lprect );
1495 /* make a copy of the current device region */
1496 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1497 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1498 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1499 DeleteObject( clip_region );
1502 if(X11DRV_XRender_Installed) {
1503 if(!physDev->xrender->pict) {
1504 XRenderPictureAttributes pa;
1505 pa.subwindow_mode = IncludeInferiors;
1507 wine_tsx11_lock();
1508 physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1509 physDev->drawable, dst_format->pict_format,
1510 CPSubwindowMode, &pa);
1511 wine_tsx11_unlock();
1513 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1514 physDev->xrender->pict, hdc, physDev->drawable);
1515 } else {
1516 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1517 physDev->xrender->pict, hdc, physDev->drawable);
1520 if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1522 wine_tsx11_lock();
1523 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1524 physDev->dc_rect.left, physDev->dc_rect.top,
1525 (XRectangle *)data->Buffer, data->rdh.nCount );
1526 wine_tsx11_unlock();
1527 HeapFree( GetProcessHeap(), 0, data );
1531 EnterCriticalSection(&xrender_cs);
1533 entry = glyphsetCache + physDev->xrender->cache_index;
1534 if( disable_antialias == FALSE )
1535 aa_type = entry->aa_default;
1536 formatEntry = entry->format[aa_type];
1538 for(idx = 0; idx < count; idx++) {
1539 if( !formatEntry ) {
1540 UploadGlyph(physDev, wstr[idx], aa_type);
1541 /* re-evaluate antialias since aa_default may have changed */
1542 if( disable_antialias == FALSE )
1543 aa_type = entry->aa_default;
1544 formatEntry = entry->format[aa_type];
1545 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1546 UploadGlyph(physDev, wstr[idx], aa_type);
1549 if (!formatEntry)
1551 WARN("could not upload requested glyphs\n");
1552 LeaveCriticalSection(&xrender_cs);
1553 goto done_unlock;
1556 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1557 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1559 if(X11DRV_XRender_Installed)
1561 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1562 INT offset = 0;
1563 POINT desired, current;
1564 int render_op = PictOpOver;
1566 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1567 So we pass zeros to the function and move to our starting position using the first
1568 element of the elts array. */
1570 desired.x = physDev->dc_rect.left + x;
1571 desired.y = physDev->dc_rect.top + y;
1572 current.x = current.y = 0;
1574 tile_pict = get_tile_pict(dst_format, physDev->textPixel);
1576 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1578 if((dst_format->format == WXR_FORMAT_MONO) && (textPixel == 0))
1579 render_op = PictOpOutReverse; /* This gives us 'black' text */
1581 for(idx = 0; idx < count; idx++)
1583 elts[idx].glyphset = formatEntry->glyphset;
1584 elts[idx].chars = wstr + idx;
1585 elts[idx].nchars = 1;
1586 elts[idx].xOff = desired.x - current.x;
1587 elts[idx].yOff = desired.y - current.y;
1589 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1590 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1592 if(!lpDx)
1594 desired.x += formatEntry->gis[wstr[idx]].xOff;
1595 desired.y += formatEntry->gis[wstr[idx]].yOff;
1597 else
1599 offset += lpDx[idx];
1600 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1601 desired.y = physDev->dc_rect.top + y - offset * sinEsc;
1604 wine_tsx11_lock();
1605 pXRenderCompositeText16(gdi_display, render_op,
1606 tile_pict,
1607 physDev->xrender->pict,
1608 formatEntry->font_format->pict_format,
1609 0, 0, 0, 0, elts, count);
1610 wine_tsx11_unlock();
1611 HeapFree(GetProcessHeap(), 0, elts);
1612 } else {
1613 INT offset = 0, xoff = 0, yoff = 0;
1614 wine_tsx11_lock();
1615 XSetForeground( gdi_display, physDev->gc, textPixel );
1617 if(aa_type == AA_None || physDev->depth == 1)
1619 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1621 if(aa_type == AA_None)
1622 sharp_glyph_fn = SharpGlyphMono;
1623 else
1624 sharp_glyph_fn = SharpGlyphGray;
1626 for(idx = 0; idx < count; idx++) {
1627 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1628 physDev->dc_rect.top + y + yoff,
1629 formatEntry->bitmaps[wstr[idx]],
1630 &formatEntry->gis[wstr[idx]]);
1631 if(lpDx) {
1632 offset += lpDx[idx];
1633 xoff = offset * cosEsc;
1634 yoff = offset * -sinEsc;
1635 } else {
1636 xoff += formatEntry->gis[wstr[idx]].xOff;
1637 yoff += formatEntry->gis[wstr[idx]].yOff;
1640 } else {
1641 XImage *image;
1642 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1643 RECT extents = {0, 0, 0, 0};
1644 POINT cur = {0, 0};
1645 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1646 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1648 TRACE("drawable %dx%d\n", w, h);
1650 for(idx = 0; idx < count; idx++) {
1651 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1652 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1653 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1654 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1655 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1656 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1657 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1658 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1659 if(lpDx) {
1660 offset += lpDx[idx];
1661 cur.x = offset * cosEsc;
1662 cur.y = offset * -sinEsc;
1663 } else {
1664 cur.x += formatEntry->gis[wstr[idx]].xOff;
1665 cur.y += formatEntry->gis[wstr[idx]].yOff;
1668 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1669 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1671 if(physDev->dc_rect.left + x + extents.left >= 0) {
1672 image_x = physDev->dc_rect.left + x + extents.left;
1673 image_off_x = 0;
1674 } else {
1675 image_x = 0;
1676 image_off_x = physDev->dc_rect.left + x + extents.left;
1678 if(physDev->dc_rect.top + y + extents.top >= 0) {
1679 image_y = physDev->dc_rect.top + y + extents.top;
1680 image_off_y = 0;
1681 } else {
1682 image_y = 0;
1683 image_off_y = physDev->dc_rect.top + y + extents.top;
1685 if(physDev->dc_rect.left + x + extents.right < w)
1686 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1687 else
1688 image_w = w - image_x;
1689 if(physDev->dc_rect.top + y + extents.bottom < h)
1690 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1691 else
1692 image_h = h - image_y;
1694 if(image_w <= 0 || image_h <= 0) goto no_image;
1696 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1697 image = XGetImage(gdi_display, physDev->drawable,
1698 image_x, image_y, image_w, image_h,
1699 AllPlanes, ZPixmap);
1700 X11DRV_check_error();
1702 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1703 gdi_display, (int)physDev->drawable, image_x, image_y,
1704 image_w, image_h, AllPlanes, ZPixmap,
1705 physDev->depth, image);
1706 if(!image) {
1707 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
1708 physDev->depth);
1709 GC gc;
1710 XGCValues gcv;
1712 gcv.graphics_exposures = False;
1713 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1714 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1715 image_w, image_h, 0, 0);
1716 XFreeGC(gdi_display, gc);
1717 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1718 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1719 ZPixmap);
1720 X11DRV_check_error();
1721 XFreePixmap(gdi_display, xpm);
1723 if(!image) goto no_image;
1725 image->red_mask = visual->red_mask;
1726 image->green_mask = visual->green_mask;
1727 image->blue_mask = visual->blue_mask;
1729 offset = xoff = yoff = 0;
1730 for(idx = 0; idx < count; idx++) {
1731 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1732 yoff + image_off_y - extents.top,
1733 formatEntry->bitmaps[wstr[idx]],
1734 &formatEntry->gis[wstr[idx]],
1735 physDev->textPixel);
1736 if(lpDx) {
1737 offset += lpDx[idx];
1738 xoff = offset * cosEsc;
1739 yoff = offset * -sinEsc;
1740 } else {
1741 xoff += formatEntry->gis[wstr[idx]].xOff;
1742 yoff += formatEntry->gis[wstr[idx]].yOff;
1745 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1746 image_x, image_y, image_w, image_h);
1747 XDestroyImage(image);
1749 no_image:
1750 wine_tsx11_unlock();
1752 LeaveCriticalSection(&xrender_cs);
1754 if (flags & ETO_CLIPPED)
1756 /* restore the device region */
1757 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1758 DeleteObject( saved_region );
1761 retv = TRUE;
1763 done_unlock:
1764 X11DRV_UnlockDIBSection( physDev, TRUE );
1765 return retv;
1768 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
1769 static void set_xrender_transformation(Picture src_pict, float xscale, float yscale, int xoffset, int yoffset)
1771 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1772 XTransform xform = {{
1773 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
1774 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
1775 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1778 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1779 #endif
1782 /* Helper function for (stretched) blitting using xrender */
1783 static void xrender_blit(Picture src_pict, Picture mask_pict, Picture dst_pict, int x_src, int y_src, float xscale, float yscale, int width, int height)
1785 /* Further down a transformation matrix is used for stretching and mirroring the source data.
1786 * xscale/yscale contain the scaling factors for the width and height. In case of mirroring
1787 * we also need a x- and y-offset because without the pixels will be in the wrong quadrant of the x-y plane.
1789 int x_offset = (xscale<0) ? width : 0;
1790 int y_offset = (yscale<0) ? height : 0;
1792 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1793 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1794 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1795 if(xscale != 1.0 || yscale != 1.0)
1797 /* When we are using a mask, 'src_pict' contains a 1x1 picture for tiling, the actual source data is in mask_pict */
1798 if(mask_pict)
1799 set_xrender_transformation(mask_pict, xscale, yscale, x_offset, y_offset);
1800 else
1801 set_xrender_transformation(src_pict, xscale, yscale, x_src + x_offset, y_src + y_offset);
1803 pXRenderComposite(gdi_display, PictOpSrc, src_pict, mask_pict, dst_pict, 0, 0, 0, 0, 0, 0, width, height);
1805 else
1807 /* When we are using a mask, 'src_pict' contains a 1x1 picture for tiling, the actual source data is in mask_pict */
1808 if(mask_pict)
1809 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
1810 else
1811 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1813 pXRenderComposite(gdi_display, PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, 0, 0, 0, 0, width, height);
1817 /******************************************************************************
1818 * AlphaBlend (x11drv.@)
1820 BOOL CDECL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1821 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1822 BLENDFUNCTION blendfn)
1824 XRenderPictureAttributes pa;
1825 Picture dst_pict, src_pict;
1826 Pixmap xpm;
1827 DIBSECTION dib;
1828 XImage *image;
1829 GC gc;
1830 XGCValues gcv;
1831 DWORD *dstbits, *data;
1832 int y, y2;
1833 POINT pts[2];
1834 BOOL top_down = FALSE;
1835 RGNDATA *rgndata;
1836 WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(devDst->depth, devDst->color_shifts);
1837 WineXRenderFormat *src_format;
1838 int repeat_src;
1840 if(!X11DRV_XRender_Installed) {
1841 FIXME("Unable to AlphaBlend without Xrender\n");
1842 return FALSE;
1844 pts[0].x = xDst;
1845 pts[0].y = yDst;
1846 pts[1].x = xDst + widthDst;
1847 pts[1].y = yDst + heightDst;
1848 LPtoDP(devDst->hdc, pts, 2);
1849 xDst = pts[0].x;
1850 yDst = pts[0].y;
1851 widthDst = pts[1].x - pts[0].x;
1852 heightDst = pts[1].y - pts[0].y;
1854 pts[0].x = xSrc;
1855 pts[0].y = ySrc;
1856 pts[1].x = xSrc + widthSrc;
1857 pts[1].y = ySrc + heightSrc;
1858 LPtoDP(devSrc->hdc, pts, 2);
1859 xSrc = pts[0].x;
1860 ySrc = pts[0].y;
1861 widthSrc = pts[1].x - pts[0].x;
1862 heightSrc = pts[1].y - pts[0].y;
1863 if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1865 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1866 if(widthDst != widthSrc || heightDst != heightSrc)
1867 #else
1868 if(!pXRenderSetPictureTransform)
1869 #endif
1871 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1872 return FALSE;
1875 if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1877 static BOOL out = FALSE;
1878 if (!out)
1880 FIXME("not a dibsection\n");
1881 out = TRUE;
1883 return FALSE;
1886 /* If the source is a 1x1 bitmap, tiling is equivalent to stretching, but
1887 tiling is much faster. Therefore, we do no stretching in this case. */
1888 repeat_src = dib.dsBmih.biWidth == 1 && abs(dib.dsBmih.biHeight) == 1;
1890 if (xSrc < 0 || ySrc < 0 || widthSrc < 0 || heightSrc < 0 || xSrc + widthSrc > dib.dsBmih.biWidth
1891 || ySrc + heightSrc > abs(dib.dsBmih.biHeight))
1893 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc, ySrc, widthSrc, heightSrc);
1894 SetLastError(ERROR_INVALID_PARAMETER);
1895 return FALSE;
1898 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && blendfn.SourceConstantAlpha != 0xff)
1899 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn.SourceConstantAlpha);
1901 if(dib.dsBm.bmBitsPixel != 32) {
1902 FIXME("not a 32 bpp dibsection\n");
1903 return FALSE;
1905 dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1907 if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1908 top_down = TRUE;
1909 dstbits += widthSrc * (heightSrc - 1);
1910 y2 = ySrc;
1911 y = y2 + heightSrc - 1;
1913 else
1915 y = dib.dsBmih.biHeight - ySrc - 1;
1916 y2 = y - heightSrc + 1;
1919 if (blendfn.AlphaFormat & AC_SRC_ALPHA)
1921 for(; y >= y2; y--)
1923 memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1924 widthSrc * 4);
1925 dstbits += (top_down ? -1 : 1) * widthSrc;
1928 else
1930 DWORD source_alpha = (DWORD)blendfn.SourceConstantAlpha << 24;
1931 int x;
1933 for(; y >= y2; y--)
1935 DWORD *srcbits = (DWORD *)((char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes) + xSrc;
1936 for (x = 0; x < widthSrc; x++)
1938 DWORD argb = *srcbits++;
1939 argb = (argb & 0xffffff) | source_alpha;
1940 *dstbits++ = argb;
1942 if (top_down) /* we traversed the row forward so we should go back by two rows */
1943 dstbits -= 2 * widthSrc;
1948 rgndata = X11DRV_GetRegionData( devDst->region, 0 );
1950 wine_tsx11_lock();
1951 image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1952 (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1954 src_format = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1955 TRACE("src_format %p\n", src_format);
1956 if(!src_format)
1958 WARN("Unable to find a picture format supporting alpha, make sure X is running at 24-bit\n");
1959 return FALSE;
1962 pa.subwindow_mode = IncludeInferiors;
1963 pa.repeat = repeat_src ? RepeatNormal : RepeatNone;
1965 /* FIXME use devDst->xrender->pict ? */
1966 dst_pict = pXRenderCreatePicture(gdi_display,
1967 devDst->drawable,
1968 dst_format->pict_format,
1969 CPSubwindowMode, &pa);
1970 TRACE("dst_pict %08lx\n", dst_pict);
1971 TRACE("src_drawable = %08lx\n", devSrc->drawable);
1972 xpm = XCreatePixmap(gdi_display,
1973 root_window,
1974 widthSrc, heightSrc, 32);
1975 gcv.graphics_exposures = False;
1976 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1977 TRACE("xpm = %08lx\n", xpm);
1978 XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1980 src_pict = pXRenderCreatePicture(gdi_display,
1981 xpm, src_format->pict_format,
1982 CPSubwindowMode|CPRepeat, &pa);
1983 TRACE("src_pict %08lx\n", src_pict);
1985 if (rgndata)
1987 pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
1988 devDst->dc_rect.left, devDst->dc_rect.top,
1989 (XRectangle *)rgndata->Buffer,
1990 rgndata->rdh.nCount );
1991 HeapFree( GetProcessHeap(), 0, rgndata );
1994 /* Make sure we ALWAYS set the transformation matrix even if we don't need to scale. The reason is
1995 * that later on we want to reuse pictures (it can bring a lot of extra performance) and each time
1996 * a different transformation matrix might have been used. */
1997 if (repeat_src)
1998 set_xrender_transformation(src_pict, 1.0, 1.0, 0, 0);
1999 else
2000 set_xrender_transformation(src_pict, widthSrc/(double)widthDst, heightSrc/(double)heightDst, 0, 0);
2001 pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
2002 0, 0, 0, 0,
2003 xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
2006 pXRenderFreePicture(gdi_display, src_pict);
2007 XFreePixmap(gdi_display, xpm);
2008 XFreeGC(gdi_display, gc);
2009 pXRenderFreePicture(gdi_display, dst_pict);
2010 image->data = NULL;
2011 XDestroyImage(image);
2013 wine_tsx11_unlock();
2014 HeapFree(GetProcessHeap(), 0, data);
2015 return TRUE;
2018 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2020 /* At depths >1, the depth of physBitmap and physDev might not be the same e.g. the physbitmap might be a 16-bit DIB while the physdev uses 24-bit */
2021 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2023 wine_tsx11_lock();
2024 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2026 /* Use XCopyArea when the physBitmap and brush.pixmap have the same depth. */
2027 if(physBitmap->pixmap_depth == 1 || physDev->depth == physBitmap->pixmap_depth)
2029 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2030 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2032 else /* We meed depth conversion */
2034 WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2035 WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2037 Picture src_pict, dst_pict;
2038 XRenderPictureAttributes pa;
2039 pa.subwindow_mode = IncludeInferiors;
2040 pa.repeat = RepeatNone;
2042 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2043 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2045 xrender_blit(src_pict, 0, dst_pict, 0, 0, 1.0, 1.0, width, height);
2046 pXRenderFreePicture(gdi_display, src_pict);
2047 pXRenderFreePicture(gdi_display, dst_pict);
2049 wine_tsx11_unlock();
2052 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2053 Pixmap pixmap, GC gc,
2054 INT widthSrc, INT heightSrc,
2055 INT widthDst, INT heightDst,
2056 RECT *visRectSrc, RECT *visRectDst )
2058 BOOL stretch = (widthSrc != widthDst) || (heightSrc != heightDst);
2059 int width = visRectDst->right - visRectDst->left;
2060 int height = visRectDst->bottom - visRectDst->top;
2061 int x_src = physDevSrc->dc_rect.left + visRectSrc->left;
2062 int y_src = physDevSrc->dc_rect.top + visRectSrc->top;
2063 WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physDevSrc->depth, physDevSrc->color_shifts);
2064 WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDevDst->depth, physDevDst->color_shifts);
2065 Picture src_pict=0, dst_pict=0, mask_pict=0;
2067 double xscale = widthSrc/(double)widthDst;
2068 double yscale = heightSrc/(double)heightDst;
2070 XRenderPictureAttributes pa;
2071 pa.subwindow_mode = IncludeInferiors;
2072 pa.repeat = RepeatNone;
2074 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n", physDevSrc->depth, widthSrc, heightSrc, x_src, y_src);
2075 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst->depth, widthDst, heightDst);
2077 if(!X11DRV_XRender_Installed)
2079 TRACE("Not using XRender since it is not available or disabled\n");
2080 return FALSE;
2083 /* XRender can't handle palettes, so abort */
2084 if(X11DRV_PALETTE_XPixelToPalette)
2085 return FALSE;
2087 /* XRender is of no use in this case */
2088 if((physDevDst->depth == 1) && (physDevSrc->depth > 1))
2089 return FALSE;
2091 /* Just use traditional X copy when the depths match and we don't need stretching */
2092 if((physDevSrc->depth == physDevDst->depth) && !stretch)
2094 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2095 wine_tsx11_lock();
2096 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
2097 wine_tsx11_unlock();
2098 return TRUE;
2101 /* mono -> color */
2102 if(physDevSrc->depth == 1)
2104 XRenderColor col;
2105 get_xrender_color(dst_format, physDevDst->textPixel, &col);
2107 /* We use the source drawable as a mask */
2108 wine_tsx11_lock();
2109 mask_pict = pXRenderCreatePicture(gdi_display, physDevSrc->drawable, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2111 /* Use backgroundPixel as the foreground color */
2112 src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
2114 /* Create a destination picture and fill it with textPixel color as the background color */
2115 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2116 pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height);
2118 xrender_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
2120 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2121 if(mask_pict) pXRenderFreePicture(gdi_display, mask_pict);
2122 wine_tsx11_unlock();
2124 else /* color -> color but with different depths */
2126 wine_tsx11_lock();
2127 src_pict = pXRenderCreatePicture(gdi_display,
2128 physDevSrc->drawable, src_format->pict_format,
2129 CPSubwindowMode|CPRepeat, &pa);
2131 dst_pict = pXRenderCreatePicture(gdi_display,
2132 pixmap, dst_format->pict_format,
2133 CPSubwindowMode|CPRepeat, &pa);
2135 xrender_blit(src_pict, 0, dst_pict, x_src, y_src, xscale, yscale, width, height);
2137 if(src_pict) pXRenderFreePicture(gdi_display, src_pict);
2138 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2139 wine_tsx11_unlock();
2141 return TRUE;
2144 #else /* SONAME_LIBXRENDER */
2146 void X11DRV_XRender_Init(void)
2148 TRACE("XRender support not compiled in.\n");
2149 return;
2152 void X11DRV_XRender_Finalize(void)
2156 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
2158 assert(0);
2159 return FALSE;
2162 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
2164 assert(0);
2165 return;
2168 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
2169 const RECT *lprect, LPCWSTR wstr, UINT count,
2170 const INT *lpDx )
2172 assert(0);
2173 return FALSE;
2176 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
2178 assert(0);
2179 return;
2182 /******************************************************************************
2183 * AlphaBlend (x11drv.@)
2185 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
2186 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
2187 BLENDFUNCTION blendfn)
2189 FIXME("not supported - XRENDER headers were missing at compile time\n");
2190 return FALSE;
2193 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2195 wine_tsx11_lock();
2196 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
2198 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2199 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2200 wine_tsx11_unlock();
2203 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, const DIBSECTION *dib)
2205 return FALSE;
2208 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2209 Pixmap pixmap, GC gc,
2210 INT widthSrc, INT heightSrc,
2211 INT widthDst, INT heightDst,
2212 RECT *visRectSrc, RECT *visRectDst )
2214 return FALSE;
2216 #endif /* SONAME_LIBXRENDER */