winex11.drv: Support GdiAlphaBlend with blendfn.AlphaFormat == 0.
[wine] / dlls / winex11.drv / xrender.c
1 /*
2  * Functions to use the XRender extension
3  *
4  * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5  *
6  * Some parts also:
7  * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
8  *
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.
13  *
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.
18  *
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
22  */
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "x11drv.h"
34 #include "winternl.h"
35 #include "wine/library.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38
39 static BOOL X11DRV_XRender_Installed = FALSE;
40 int using_client_side_fonts = FALSE;
41
42 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
43
44 #ifdef SONAME_LIBXRENDER
45
46 #include <X11/Xlib.h>
47 #include <X11/extensions/Xrender.h>
48
49
50 enum drawable_depth_type {mono_drawable, color_drawable};
51 static XRenderPictFormat *pict_formats[2];
52
53 typedef struct
54 {
55     LOGFONTW lf;
56     SIZE     devsize;  /* size in device coords */
57     DWORD    hash;
58 } LFANDSIZE;
59
60 #define INITIAL_REALIZED_BUF_SIZE 128
61
62 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
63
64 typedef struct
65 {
66     GlyphSet glyphset;
67     XRenderPictFormat *font_format;
68     int nrealized;
69     BOOL *realized;
70     void **bitmaps;
71     XGlyphInfo *gis;
72 } gsCacheEntryFormat;
73
74 typedef struct
75 {
76     LFANDSIZE lfsz;
77     AA_Type aa_default;
78     gsCacheEntryFormat * format[AA_MAXVALUE];
79     INT count;
80     INT next;
81 } gsCacheEntry;
82
83 struct tagXRENDERINFO
84 {
85     int                cache_index;
86     Picture            pict;
87 };
88
89
90 static gsCacheEntry *glyphsetCache = NULL;
91 static DWORD glyphsetCacheSize = 0;
92 static INT lastfree = -1;
93 static INT mru = -1;
94
95 #define INIT_CACHE_SIZE 10
96
97 static int antialias = 1;
98
99 static void *xrender_handle;
100
101 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
102 MAKE_FUNCPTR(XRenderAddGlyphs)
103 MAKE_FUNCPTR(XRenderComposite)
104 MAKE_FUNCPTR(XRenderCompositeString8)
105 MAKE_FUNCPTR(XRenderCompositeString16)
106 MAKE_FUNCPTR(XRenderCompositeString32)
107 MAKE_FUNCPTR(XRenderCompositeText16)
108 MAKE_FUNCPTR(XRenderCreateGlyphSet)
109 MAKE_FUNCPTR(XRenderCreatePicture)
110 MAKE_FUNCPTR(XRenderFillRectangle)
111 MAKE_FUNCPTR(XRenderFindFormat)
112 MAKE_FUNCPTR(XRenderFindVisualFormat)
113 MAKE_FUNCPTR(XRenderFreeGlyphSet)
114 MAKE_FUNCPTR(XRenderFreePicture)
115 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
116 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
117 MAKE_FUNCPTR(XRenderSetPictureTransform)
118 #endif
119 MAKE_FUNCPTR(XRenderQueryExtension)
120 #undef MAKE_FUNCPTR
121
122 static CRITICAL_SECTION xrender_cs;
123 static CRITICAL_SECTION_DEBUG critsect_debug =
124 {
125     0, 0, &xrender_cs,
126     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
127       0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
128 };
129 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
130
131 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
132           ( ( (ULONG)_x4 << 24 ) |     \
133             ( (ULONG)_x3 << 16 ) |     \
134             ( (ULONG)_x2 <<  8 ) |     \
135               (ULONG)_x1         )
136
137 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
138
139 #define GASP_GRIDFIT 0x01
140 #define GASP_DOGRAY  0x02
141
142 #ifdef WORDS_BIGENDIAN
143 #define get_be_word(x) (x)
144 #else
145 #define get_be_word(x) RtlUshortByteSwap(x)
146 #endif
147
148 /***********************************************************************
149  *   X11DRV_XRender_Init
150  *
151  * Let's see if our XServer has the extension available
152  *
153  */
154 void X11DRV_XRender_Init(void)
155 {
156     int event_base, i;
157     XRenderPictFormat pf;
158
159     if (client_side_with_render &&
160         wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
161         wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) && 
162         (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
163     {
164
165 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
166 LOAD_FUNCPTR(XRenderAddGlyphs)
167 LOAD_FUNCPTR(XRenderComposite)
168 LOAD_FUNCPTR(XRenderCompositeString8)
169 LOAD_FUNCPTR(XRenderCompositeString16)
170 LOAD_FUNCPTR(XRenderCompositeString32)
171 LOAD_FUNCPTR(XRenderCompositeText16)
172 LOAD_FUNCPTR(XRenderCreateGlyphSet)
173 LOAD_FUNCPTR(XRenderCreatePicture)
174 LOAD_FUNCPTR(XRenderFillRectangle)
175 LOAD_FUNCPTR(XRenderFindFormat)
176 LOAD_FUNCPTR(XRenderFindVisualFormat)
177 LOAD_FUNCPTR(XRenderFreeGlyphSet)
178 LOAD_FUNCPTR(XRenderFreePicture)
179 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
180 LOAD_FUNCPTR(XRenderQueryExtension)
181 #undef LOAD_FUNCPTR
182 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
183 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
184 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
185 #undef LOAD_OPTIONAL_FUNCPTR
186 #endif
187
188
189         wine_tsx11_lock();
190         if(pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) {
191             X11DRV_XRender_Installed = TRUE;
192             TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
193             pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, visual);
194             if(!pict_formats[color_drawable])
195             {
196                 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
197                 if (visual->class == DirectColor)
198                 {
199                     XVisualInfo info;
200                     if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
201                                           screen_depth, TrueColor, &info ))
202                     {
203                         pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, info.visual);
204                         if (pict_formats[color_drawable]) visual = info.visual;
205                     }
206                 }
207             }
208             if(!pict_formats[color_drawable]) /* This fails in buggy versions of libXrender.so */
209             {
210                 wine_tsx11_unlock();
211                 WINE_MESSAGE(
212                     "Wine has detected that you probably have a buggy version\n"
213                     "of libXrender.so .  Because of this client side font rendering\n"
214                     "will be disabled.  Please upgrade this library.\n");
215                 X11DRV_XRender_Installed = FALSE;
216                 return;
217             }
218             pf.type = PictTypeDirect;
219             pf.depth = 1;
220             pf.direct.alpha = 0;
221             pf.direct.alphaMask = 1;
222             pict_formats[mono_drawable] = pXRenderFindFormat(gdi_display, PictFormatType |
223                                                              PictFormatDepth | PictFormatAlpha |
224                                                              PictFormatAlphaMask, &pf, 0);
225             if(!pict_formats[mono_drawable]) {
226                 ERR("mono_format == NULL?\n");
227                 X11DRV_XRender_Installed = FALSE;
228             }
229             if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
230                 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
231                 X11DRV_XRender_Installed = FALSE;
232             }
233         }
234         wine_tsx11_unlock();
235     }
236
237 sym_not_found:
238     if(X11DRV_XRender_Installed || client_side_with_core)
239     {
240         glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
241                                   sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
242
243         glyphsetCacheSize = INIT_CACHE_SIZE;
244         lastfree = 0;
245         for(i = 0; i < INIT_CACHE_SIZE; i++) {
246           glyphsetCache[i].next = i + 1;
247           glyphsetCache[i].count = -1;
248         }
249         glyphsetCache[i-1].next = -1;
250         using_client_side_fonts = 1;
251
252         if(!X11DRV_XRender_Installed) {
253             TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
254             if(screen_depth <= 8 || !client_side_antialias_with_core)
255                 antialias = 0;
256         } else {
257             if(screen_depth <= 8 || !client_side_antialias_with_render)
258                 antialias = 0;
259         }
260     }
261     else TRACE("Using X11 core fonts\n");
262 }
263
264 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
265 {
266   if(p1->hash != p2->hash) return TRUE;
267   if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
268   if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
269   return strcmpW(p1->lf.lfFaceName, p2->lf.lfFaceName);
270 }
271
272 #if 0
273 static void walk_cache(void)
274 {
275   int i;
276
277   EnterCriticalSection(&xrender_cs);
278   for(i=mru; i >= 0; i = glyphsetCache[i].next)
279     TRACE("item %d\n", i);
280   LeaveCriticalSection(&xrender_cs);
281 }
282 #endif
283
284 static int LookupEntry(LFANDSIZE *plfsz)
285 {
286   int i, prev_i = -1;
287
288   for(i = mru; i >= 0; i = glyphsetCache[i].next) {
289     TRACE("%d\n", i);
290     if(glyphsetCache[i].count == -1) { /* reached free list so stop */
291       i = -1;
292       break;
293     }
294
295     if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
296       glyphsetCache[i].count++;
297       if(prev_i >= 0) {
298         glyphsetCache[prev_i].next = glyphsetCache[i].next;
299         glyphsetCache[i].next = mru;
300         mru = i;
301       }
302       TRACE("found font in cache %d\n", i);
303       return i;
304     }
305     prev_i = i;
306   }
307   TRACE("font not in cache\n");
308   return -1;
309 }
310
311 static void FreeEntry(int entry)
312 {
313     int i, format;
314   
315     for(format = 0; format < AA_MAXVALUE; format++) {
316         gsCacheEntryFormat * formatEntry;
317
318         if( !glyphsetCache[entry].format[format] )
319             continue;
320
321         formatEntry = glyphsetCache[entry].format[format];
322
323         if(formatEntry->glyphset) {
324             wine_tsx11_lock();
325             pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
326             wine_tsx11_unlock();
327             formatEntry->glyphset = 0;
328         }
329         if(formatEntry->nrealized) {
330             HeapFree(GetProcessHeap(), 0, formatEntry->realized);
331             formatEntry->realized = NULL;
332             if(formatEntry->bitmaps) {
333                 for(i = 0; i < formatEntry->nrealized; i++)
334                     HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
335                 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
336                 formatEntry->bitmaps = NULL;
337             }
338             HeapFree(GetProcessHeap(), 0, formatEntry->gis);
339             formatEntry->gis = NULL;
340             formatEntry->nrealized = 0;
341         }
342
343         HeapFree(GetProcessHeap(), 0, formatEntry);
344         glyphsetCache[entry].format[format] = NULL;
345     }
346 }
347
348 static int AllocEntry(void)
349 {
350   int best = -1, prev_best = -1, i, prev_i = -1;
351
352   if(lastfree >= 0) {
353     assert(glyphsetCache[lastfree].count == -1);
354     glyphsetCache[lastfree].count = 1;
355     best = lastfree;
356     lastfree = glyphsetCache[lastfree].next;
357     assert(best != mru);
358     glyphsetCache[best].next = mru;
359     mru = best;
360
361     TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
362     return mru;
363   }
364
365   for(i = mru; i >= 0; i = glyphsetCache[i].next) {
366     if(glyphsetCache[i].count == 0) {
367       best = i;
368       prev_best = prev_i;
369     }
370     prev_i = i;
371   }
372
373   if(best >= 0) {
374     TRACE("freeing unused glyphset at cache %d\n", best);
375     FreeEntry(best);
376     glyphsetCache[best].count = 1;
377     if(prev_best >= 0) {
378       glyphsetCache[prev_best].next = glyphsetCache[best].next;
379       glyphsetCache[best].next = mru;
380       mru = best;
381     } else {
382       assert(mru == best);
383     }
384     return mru;
385   }
386
387   TRACE("Growing cache\n");
388   
389   if (glyphsetCache)
390     glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
391                               glyphsetCache,
392                               (glyphsetCacheSize + INIT_CACHE_SIZE)
393                               * sizeof(*glyphsetCache));
394   else
395     glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
396                               (glyphsetCacheSize + INIT_CACHE_SIZE)
397                               * sizeof(*glyphsetCache));
398
399   for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
400       i++) {
401     glyphsetCache[i].next = i + 1;
402     glyphsetCache[i].count = -1;
403   }
404   glyphsetCache[i-1].next = -1;
405   glyphsetCacheSize += INIT_CACHE_SIZE;
406
407   lastfree = glyphsetCache[best].next;
408   glyphsetCache[best].count = 1;
409   glyphsetCache[best].next = mru;
410   mru = best;
411   TRACE("new free cache slot at %d\n", mru);
412   return mru;
413 }
414
415 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
416 {
417     DWORD size;
418     WORD *gasp, *buffer;
419     WORD num_recs;
420     DWORD ppem;
421     TEXTMETRICW tm;
422
423     *flags = 0;
424
425     size = GetFontData(physDev->hdc, MS_GASP_TAG,  0, NULL, 0);
426     if(size == GDI_ERROR)
427         return FALSE;
428
429     gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
430     GetFontData(physDev->hdc, MS_GASP_TAG,  0, gasp, size);
431
432     GetTextMetricsW(physDev->hdc, &tm);
433     ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
434
435     gasp++;
436     num_recs = get_be_word(*gasp);
437     gasp++;
438     while(num_recs--)
439     {
440         *flags = get_be_word(*(gasp + 1));
441         if(ppem <= get_be_word(*gasp))
442             break;
443         gasp += 2;
444     }
445     TRACE("got flags %04x for ppem %d\n", *flags, ppem);
446
447     HeapFree(GetProcessHeap(), 0, buffer);
448     return TRUE;
449 }
450
451 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
452 {
453     int ret;
454     int format;
455     gsCacheEntry *entry;
456     WORD flags;
457     static int hinter = -1;
458
459     if((ret = LookupEntry(plfsz)) != -1) return ret;
460
461     ret = AllocEntry();
462     entry = glyphsetCache + ret;
463     entry->lfsz = *plfsz;
464     for( format = 0; format < AA_MAXVALUE; format++ ) {
465         assert( !entry->format[format] );
466     }
467
468     if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
469     {
470         if(hinter == -1)
471         {
472             RASTERIZER_STATUS status;
473             GetRasterizerCaps(&status, sizeof(status));
474             hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
475         }
476         if(!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
477             entry->aa_default = AA_Grey;
478         else
479             entry->aa_default = AA_None;
480     }
481     else
482         entry->aa_default = AA_None;
483
484     return ret;
485 }
486
487 static void dec_ref_cache(int index)
488 {
489     assert(index >= 0);
490     TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
491     assert(glyphsetCache[index].count > 0);
492     glyphsetCache[index].count--;
493 }
494
495 static void lfsz_calc_hash(LFANDSIZE *plfsz)
496 {
497   DWORD hash = 0, *ptr;
498   int i;
499
500   hash ^= plfsz->devsize.cx;
501   hash ^= plfsz->devsize.cy;
502   for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
503     hash ^= *ptr;
504   for(i = 0, ptr = (DWORD*)&plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
505     WCHAR *pwc = (WCHAR *)ptr;
506     if(!*pwc) break;
507     hash ^= *ptr;
508     pwc++;
509     if(!*pwc) break;
510   }
511   plfsz->hash = hash;
512   return;
513 }
514
515 /***********************************************************************
516  *   X11DRV_XRender_Finalize
517  */
518 void X11DRV_XRender_Finalize(void)
519 {
520     int i;
521
522     EnterCriticalSection(&xrender_cs);
523     for(i = mru; i >= 0; i = glyphsetCache[i].next)
524         FreeEntry(i);
525     LeaveCriticalSection(&xrender_cs);
526 }
527
528
529 /***********************************************************************
530  *   X11DRV_XRender_SelectFont
531  */
532 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
533 {
534     LFANDSIZE lfsz;
535
536     GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
537     TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
538           lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
539           lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
540     lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
541     lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
542     lfsz_calc_hash(&lfsz);
543
544     EnterCriticalSection(&xrender_cs);
545     if(!physDev->xrender) {
546         physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
547                                      sizeof(*physDev->xrender));
548         physDev->xrender->cache_index = -1;
549     }
550     else if(physDev->xrender->cache_index != -1)
551         dec_ref_cache(physDev->xrender->cache_index);
552     physDev->xrender->cache_index = GetCacheEntry(physDev, &lfsz);
553     LeaveCriticalSection(&xrender_cs);
554     return 0;
555 }
556
557 /***********************************************************************
558  *   X11DRV_XRender_DeleteDC
559  */
560 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
561 {
562     X11DRV_XRender_UpdateDrawable(physDev);
563
564     EnterCriticalSection(&xrender_cs);
565     if(physDev->xrender->cache_index != -1)
566         dec_ref_cache(physDev->xrender->cache_index);
567     LeaveCriticalSection(&xrender_cs);
568
569     HeapFree(GetProcessHeap(), 0, physDev->xrender);
570     physDev->xrender = NULL;
571     return;
572 }
573
574 /***********************************************************************
575  *   X11DRV_XRender_UpdateDrawable
576  *
577  * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
578  * It deletes the pict and tile when the drawable changes.
579  */
580 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
581 {
582     wine_tsx11_lock();
583
584     if(physDev->xrender->pict)
585     {
586         TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
587         XFlush(gdi_display);
588         pXRenderFreePicture(gdi_display, physDev->xrender->pict);
589         physDev->xrender->pict = 0;
590     }
591     wine_tsx11_unlock();
592
593     return;
594 }
595
596 /************************************************************************
597  *   UploadGlyph
598  *
599  * Helper to ExtTextOut.  Must be called inside xrender_cs
600  */
601 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
602 {
603     unsigned int buflen;
604     char *buf;
605     Glyph gid;
606     GLYPHMETRICS gm;
607     XGlyphInfo gi;
608     gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
609     gsCacheEntryFormat *formatEntry;
610     UINT ggo_format = GGO_GLYPH_INDEX;
611     XRenderPictFormat pf;
612     static const char zero[4];
613
614     switch(format) {
615     case AA_Grey:
616         ggo_format |= WINE_GGO_GRAY16_BITMAP;
617         break;
618
619     default:
620         ERR("aa = %d - not implemented\n", format);
621     case AA_None:
622         ggo_format |= GGO_BITMAP;
623         break;
624     }
625
626     buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
627                               NULL);
628     if(buflen == GDI_ERROR) {
629         if(format != AA_None) {
630             format = AA_None;
631             entry->aa_default = AA_None;
632             ggo_format &= ~WINE_GGO_GRAY16_BITMAP;
633             ggo_format |= GGO_BITMAP;
634             buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
635                                       NULL);
636         }
637         if(buflen == GDI_ERROR) {
638             WARN("GetGlyphOutlineW failed\n");
639             return FALSE;
640         }
641         TRACE("Turning off antialiasing for this monochrome font\n");
642     }
643
644     /* If there is nothing for the current type, we create the entry. */
645     if( !entry->format[format] ) {
646         entry->format[format] = HeapAlloc(GetProcessHeap(),
647                                           HEAP_ZERO_MEMORY,
648                                           sizeof(gsCacheEntryFormat));
649     }
650     formatEntry = entry->format[format];
651
652     if(formatEntry->nrealized <= glyph) {
653         formatEntry->nrealized = (glyph / 128 + 1) * 128;
654
655         if (formatEntry->realized)
656             formatEntry->realized = HeapReAlloc(GetProcessHeap(),
657                                       HEAP_ZERO_MEMORY,
658                                       formatEntry->realized,
659                                       formatEntry->nrealized * sizeof(BOOL));
660         else
661             formatEntry->realized = HeapAlloc(GetProcessHeap(),
662                                       HEAP_ZERO_MEMORY,
663                                       formatEntry->nrealized * sizeof(BOOL));
664
665         if(!X11DRV_XRender_Installed) {
666           if (formatEntry->bitmaps)
667             formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
668                                       HEAP_ZERO_MEMORY,
669                                       formatEntry->bitmaps,
670                                       formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
671           else
672             formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
673                                       HEAP_ZERO_MEMORY,
674                                       formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
675         }
676         if (formatEntry->gis)
677             formatEntry->gis = HeapReAlloc(GetProcessHeap(),
678                                    HEAP_ZERO_MEMORY,
679                                    formatEntry->gis,
680                                    formatEntry->nrealized * sizeof(formatEntry->gis[0]));
681         else
682             formatEntry->gis = HeapAlloc(GetProcessHeap(),
683                                    HEAP_ZERO_MEMORY,
684                                    formatEntry->nrealized * sizeof(formatEntry->gis[0]));
685     }
686
687
688     if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
689         switch(format) {
690         case AA_Grey:
691             pf.depth = 8;
692             pf.direct.alphaMask = 0xff;
693             break;
694
695         default:
696             ERR("aa = %d - not implemented\n", format);
697         case AA_None:
698             pf.depth = 1;
699             pf.direct.alphaMask = 1;
700             break;
701         }
702
703         pf.type = PictTypeDirect;
704         pf.direct.alpha = 0;
705
706         wine_tsx11_lock();
707         formatEntry->font_format = pXRenderFindFormat(gdi_display,
708                                                 PictFormatType |
709                                                 PictFormatDepth |
710                                                 PictFormatAlpha |
711                                                 PictFormatAlphaMask,
712                                                 &pf, 0);
713
714         formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
715         wine_tsx11_unlock();
716     }
717
718
719     buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
720     GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, NULL);
721     formatEntry->realized[glyph] = TRUE;
722
723     TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
724           buflen,
725           gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
726           gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
727
728     gi.width = gm.gmBlackBoxX;
729     gi.height = gm.gmBlackBoxY;
730     gi.x = -gm.gmptGlyphOrigin.x;
731     gi.y = gm.gmptGlyphOrigin.y;
732     gi.xOff = gm.gmCellIncX;
733     gi.yOff = gm.gmCellIncY;
734
735     if(TRACE_ON(xrender)) {
736         int pitch, i, j;
737         char output[300];
738         unsigned char *line;
739
740         if(format == AA_None) {
741             pitch = ((gi.width + 31) / 32) * 4;
742             for(i = 0; i < gi.height; i++) {
743                 line = (unsigned char*) buf + i * pitch;
744                 output[0] = '\0';
745                 for(j = 0; j < pitch * 8; j++) {
746                     strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
747                 }
748                 strcat(output, "\n");
749                 TRACE(output);
750             }
751         } else {
752             static const char blks[] = " .:;!o*#";
753             char str[2];
754
755             str[1] = '\0';
756             pitch = ((gi.width + 3) / 4) * 4;
757             for(i = 0; i < gi.height; i++) {
758                 line = (unsigned char*) buf + i * pitch;
759                 output[0] = '\0';
760                 for(j = 0; j < pitch; j++) {
761                     str[0] = blks[line[j] >> 5];
762                     strcat(output, str);
763                 }
764                 strcat(output, "\n");
765                 TRACE(output);
766             }
767         }
768     }
769
770
771     if(formatEntry->glyphset) {
772         if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
773             unsigned char *byte = (unsigned char*) buf, c;
774             int i = buflen;
775
776             while(i--) {
777                 c = *byte;
778
779                 /* magic to flip bit order */
780                 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
781                 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
782                 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
783
784                 *byte++ = c;
785             }
786         }
787         gid = glyph;
788
789         /*
790           XRenderCompositeText seems to ignore 0x0 glyphs when
791           AA_None, which means we lose the advance width of glyphs
792           like the space.  We'll pretend that such glyphs are 1x1
793           bitmaps.
794         */
795
796         if(buflen == 0)
797             gi.width = gi.height = 1;
798
799         wine_tsx11_lock();
800         pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
801                           buflen ? buf : zero, buflen ? buflen : sizeof(zero));
802         wine_tsx11_unlock();
803         HeapFree(GetProcessHeap(), 0, buf);
804     } else {
805         formatEntry->bitmaps[glyph] = buf;
806     }
807
808     memcpy(&formatEntry->gis[glyph], &gi, sizeof(gi));
809
810     return TRUE;
811 }
812
813 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
814                             void *bitmap, XGlyphInfo *gi)
815 {
816     unsigned char   *srcLine = bitmap, *src;
817     unsigned char   bits, bitsMask;
818     int             width = gi->width;
819     int             stride = ((width + 31) & ~31) >> 3;
820     int             height = gi->height;
821     int             w;
822     int             xspan, lenspan;
823
824     TRACE("%d, %d\n", x, y);
825     x -= gi->x;
826     y -= gi->y;
827     while (height--)
828     {
829         src = srcLine;
830         srcLine += stride;
831         w = width;
832         
833         bitsMask = 0x80;    /* FreeType is always MSB first */
834         bits = *src++;
835         
836         xspan = x;
837         while (w)
838         {
839             if (bits & bitsMask)
840             {
841                 lenspan = 0;
842                 do
843                 {
844                     lenspan++;
845                     if (lenspan == w)
846                         break;
847                     bitsMask = bitsMask >> 1;
848                     if (!bitsMask)
849                     {
850                         bits = *src++;
851                         bitsMask = 0x80;
852                     }
853                 } while (bits & bitsMask);
854                 XFillRectangle (gdi_display, physDev->drawable, 
855                                 physDev->gc, xspan, y, lenspan, 1);
856                 xspan += lenspan;
857                 w -= lenspan;
858             }
859             else
860             {
861                 do
862                 {
863                     w--;
864                     xspan++;
865                     if (!w)
866                         break;
867                     bitsMask = bitsMask >> 1;
868                     if (!bitsMask)
869                     {
870                         bits = *src++;
871                         bitsMask = 0x80;
872                     }
873                 } while (!(bits & bitsMask));
874             }
875         }
876         y++;
877     }
878 }
879
880 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
881                             void *bitmap, XGlyphInfo *gi)
882 {
883     unsigned char   *srcLine = bitmap, *src, bits;
884     int             width = gi->width;
885     int             stride = ((width + 3) & ~3);
886     int             height = gi->height;
887     int             w;
888     int             xspan, lenspan;
889
890     x -= gi->x;
891     y -= gi->y;
892     while (height--)
893     {
894         src = srcLine;
895         srcLine += stride;
896         w = width;
897         
898         bits = *src++;
899         xspan = x;
900         while (w)
901         {
902             if (bits >= 0x80)
903             {
904                 lenspan = 0;
905                 do
906                 {
907                     lenspan++;
908                     if (lenspan == w)
909                         break;
910                     bits = *src++;
911                 } while (bits >= 0x80);
912                 XFillRectangle (gdi_display, physDev->drawable, 
913                                 physDev->gc, xspan, y, lenspan, 1);
914                 xspan += lenspan;
915                 w -= lenspan;
916             }
917             else
918             {
919                 do
920                 {
921                     w--;
922                     xspan++;
923                     if (!w)
924                         break;
925                     bits = *src++;
926                 } while (bits < 0x80);
927             }
928         }
929         y++;
930     }
931 }
932
933
934 static void ExamineBitfield (DWORD mask, int *shift, int *len)
935 {
936     int s, l;
937
938     s = 0;
939     while ((mask & 1) == 0)
940     {
941         mask >>= 1;
942         s++;
943     }
944     l = 0;
945     while ((mask & 1) == 1)
946     {
947         mask >>= 1;
948         l++;
949     }
950     *shift = s;
951     *len = l;
952 }
953
954 static DWORD GetField (DWORD pixel, int shift, int len)
955 {
956     pixel = pixel & (((1 << (len)) - 1) << shift);
957     pixel = pixel << (32 - (shift + len)) >> 24;
958     while (len < 8)
959     {
960         pixel |= (pixel >> len);
961         len <<= 1;
962     }
963     return pixel;
964 }
965
966
967 static DWORD PutField (DWORD pixel, int shift, int len)
968 {
969     shift = shift - (8 - len);
970     if (len <= 8)
971         pixel &= (((1 << len) - 1) << (8 - len));
972     if (shift < 0)
973         pixel >>= -shift;
974     else
975         pixel <<= shift;
976     return pixel;
977 }
978
979 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
980                             int color)
981 {
982     int             r_shift, r_len;
983     int             g_shift, g_len;
984     int             b_shift, b_len;
985     BYTE            *maskLine, *mask, m;
986     int             maskStride;
987     DWORD           pixel;
988     int             width, height;
989     int             w, tx;
990     BYTE            src_r, src_g, src_b;
991
992     x -= gi->x;
993     y -= gi->y;
994     width = gi->width;
995     height = gi->height;
996
997     maskLine = (unsigned char *) bitmap;
998     maskStride = (width + 3) & ~3;
999
1000     ExamineBitfield (image->red_mask, &r_shift, &r_len);
1001     ExamineBitfield (image->green_mask, &g_shift, &g_len);
1002     ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1003
1004     src_r = GetField(color, r_shift, r_len);
1005     src_g = GetField(color, g_shift, g_len);
1006     src_b = GetField(color, b_shift, b_len);
1007     
1008     for(; height--; y++)
1009     {
1010         mask = maskLine;
1011         maskLine += maskStride;
1012         w = width;
1013         tx = x;
1014
1015         if(y < 0) continue;
1016         if(y >= image->height) break;
1017
1018         for(; w--; tx++)
1019         {
1020             if(tx >= image->width) break;
1021
1022             m = *mask++;
1023             if(tx < 0) continue;
1024
1025             if (m == 0xff)
1026                 XPutPixel (image, tx, y, color);
1027             else if (m)
1028             {
1029                 BYTE r, g, b;
1030
1031                 pixel = XGetPixel (image, tx, y);
1032
1033                 r = GetField(pixel, r_shift, r_len);
1034                 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1035                 g = GetField(pixel, g_shift, g_len);
1036                 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1037                 b = GetField(pixel, b_shift, b_len);
1038                 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1039
1040                 pixel = (PutField (r, r_shift, r_len) |
1041                          PutField (g, g_shift, g_len) |
1042                          PutField (b, b_shift, b_len));
1043                 XPutPixel (image, tx, y, pixel);
1044             }
1045         }
1046     }
1047 }
1048
1049 /*************************************************************
1050  *                 get_tile_pict
1051  *
1052  * Returns an appropiate Picture for tiling the text colour.
1053  * Call and use result within the xrender_cs
1054  */
1055 static Picture get_tile_pict(enum drawable_depth_type type, int text_pixel)
1056 {
1057     static struct
1058     {
1059         Pixmap xpm;
1060         Picture pict;
1061         int current_color;
1062     } tiles[2], *tile;
1063     XRenderColor col;
1064
1065     tile = &tiles[type];
1066
1067     if(!tile->xpm)
1068     {
1069         XRenderPictureAttributes pa;
1070
1071         wine_tsx11_lock();
1072         tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_formats[type]->depth);
1073
1074         pa.repeat = True;
1075         tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_formats[type], CPRepeat, &pa);
1076         wine_tsx11_unlock();
1077
1078         /* init current_color to something different from text_pixel */
1079         tile->current_color = ~text_pixel;
1080
1081         if(type == mono_drawable)
1082         {
1083             /* for a 1bpp bitmap we always need a 1 in the tile */
1084             col.red = col.green = col.blue = 0;
1085             col.alpha = 0xffff;
1086             wine_tsx11_lock();
1087             pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1088             wine_tsx11_unlock();
1089         }
1090     }
1091
1092     if(text_pixel != tile->current_color && type == color_drawable)
1093     {
1094         /* Map 0 -- 0xff onto 0 -- 0xffff */
1095         int r_shift, r_len;
1096         int g_shift, g_len;
1097         int b_shift, b_len;
1098
1099         ExamineBitfield (visual->red_mask, &r_shift, &r_len );
1100         ExamineBitfield (visual->green_mask, &g_shift, &g_len);
1101         ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
1102
1103         col.red = GetField(text_pixel, r_shift, r_len);
1104         col.red |= col.red << 8;
1105         col.green = GetField(text_pixel, g_shift, g_len);
1106         col.green |= col.green << 8;
1107         col.blue = GetField(text_pixel, b_shift, b_len);
1108         col.blue |= col.blue << 8;
1109         col.alpha = 0x0;
1110
1111         wine_tsx11_lock();
1112         pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1113         wine_tsx11_unlock();
1114         tile->current_color = text_pixel;
1115     }
1116     return tile->pict;
1117 }
1118
1119 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1120 {
1121     return 1;
1122 }
1123
1124 /***********************************************************************
1125  *   X11DRV_XRender_ExtTextOut
1126  */
1127 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1128                                 const RECT *lprect, LPCWSTR wstr, UINT count,
1129                                 const INT *lpDx )
1130 {
1131     RGNDATA *data;
1132     XGCValues xgcval;
1133     int render_op = PictOpOver;
1134     gsCacheEntry *entry;
1135     gsCacheEntryFormat *formatEntry;
1136     BOOL retv = FALSE;
1137     HDC hdc = physDev->hdc;
1138     int textPixel, backgroundPixel;
1139     HRGN saved_region = 0;
1140     BOOL disable_antialias = FALSE;
1141     AA_Type aa_type = AA_None;
1142     DIBSECTION bmp;
1143     unsigned int idx;
1144     double cosEsc, sinEsc;
1145     LOGFONTW lf;
1146     enum drawable_depth_type depth_type = (physDev->depth == 1) ? mono_drawable : color_drawable;
1147     Picture tile_pict = 0;
1148
1149     /* Do we need to disable antialiasing because of palette mode? */
1150     if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1151         TRACE("bitmap is not a DIB\n");
1152     }
1153     else if (bmp.dsBmih.biBitCount <= 8) {
1154         TRACE("Disabling antialiasing\n");
1155         disable_antialias = TRUE;
1156     }
1157
1158     xgcval.function = GXcopy;
1159     xgcval.background = physDev->backgroundPixel;
1160     xgcval.fill_style = FillSolid;
1161     wine_tsx11_lock();
1162     XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1163     wine_tsx11_unlock();
1164
1165     X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1166
1167     if(physDev->depth == 1) {
1168         if((physDev->textPixel & 0xffffff) == 0) {
1169             textPixel = 0;
1170             backgroundPixel = 1;
1171         } else {
1172             textPixel = 1;
1173             backgroundPixel = 0;
1174         }
1175     } else {
1176         textPixel = physDev->textPixel;
1177         backgroundPixel = physDev->backgroundPixel;
1178     }
1179
1180     if(flags & ETO_OPAQUE)
1181     {
1182         wine_tsx11_lock();
1183         XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1184         XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1185                         physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1186                         lprect->right - lprect->left, lprect->bottom - lprect->top );
1187         wine_tsx11_unlock();
1188     }
1189
1190     if(count == 0)
1191     {
1192         retv = TRUE;
1193         goto done_unlock;
1194     }
1195
1196     
1197     GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1198     if(lf.lfEscapement != 0) {
1199         cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1200         sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1201     } else {
1202         cosEsc = 1;
1203         sinEsc = 0;
1204     }
1205
1206     if (flags & ETO_CLIPPED)
1207     {
1208         HRGN clip_region;
1209
1210         clip_region = CreateRectRgnIndirect( lprect );
1211         /* make a copy of the current device region */
1212         saved_region = CreateRectRgn( 0, 0, 0, 0 );
1213         CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1214         X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1215         DeleteObject( clip_region );
1216     }
1217
1218     EnterCriticalSection(&xrender_cs);
1219
1220     if(X11DRV_XRender_Installed) {
1221         if(!physDev->xrender->pict) {
1222             XRenderPictureAttributes pa;
1223             pa.subwindow_mode = IncludeInferiors;
1224
1225             wine_tsx11_lock();
1226             physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1227                                                            physDev->drawable,
1228                                                            pict_formats[depth_type],
1229                                                            CPSubwindowMode, &pa);
1230             wine_tsx11_unlock();
1231
1232             TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1233                   physDev->xrender->pict, hdc, physDev->drawable);
1234         } else {
1235             TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1236                   physDev->xrender->pict, hdc, physDev->drawable);
1237         }
1238
1239         if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1240         {
1241             wine_tsx11_lock();
1242             pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1243                                               physDev->dc_rect.left, physDev->dc_rect.top,
1244                                               (XRectangle *)data->Buffer, data->rdh.nCount );
1245             wine_tsx11_unlock();
1246             HeapFree( GetProcessHeap(), 0, data );
1247         }
1248
1249         tile_pict = get_tile_pict(depth_type, physDev->textPixel);
1250
1251         /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1252          */
1253         if((depth_type == mono_drawable) && (textPixel == 0))
1254             render_op = PictOpOutReverse; /* This gives us 'black' text */
1255     }
1256
1257     entry = glyphsetCache + physDev->xrender->cache_index;
1258     if( disable_antialias == FALSE )
1259         aa_type = entry->aa_default;
1260     formatEntry = entry->format[aa_type];
1261
1262     for(idx = 0; idx < count; idx++) {
1263         if( !formatEntry ) {
1264             UploadGlyph(physDev, wstr[idx], aa_type);
1265             /* re-evaluate antialias since aa_default may have changed */
1266             if( disable_antialias == FALSE )
1267                 aa_type = entry->aa_default;
1268             formatEntry = entry->format[aa_type];
1269         } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1270             UploadGlyph(physDev, wstr[idx], aa_type);
1271         }
1272     }
1273     if (!formatEntry)
1274     {
1275         WARN("could not upload requested glyphs\n");
1276         LeaveCriticalSection(&xrender_cs);
1277         goto done_unlock;
1278     }
1279
1280     TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1281           physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1282
1283     if(X11DRV_XRender_Installed)
1284     {
1285         XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1286         INT offset = 0;
1287         POINT desired, current;
1288
1289         /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1290            So we pass zeros to the function and move to our starting position using the first
1291            element of the elts array. */
1292
1293         desired.x = physDev->dc_rect.left + x;
1294         desired.y = physDev->dc_rect.top + y;
1295         current.x = current.y = 0;
1296
1297         for(idx = 0; idx < count; idx++)
1298         {
1299             elts[idx].glyphset = formatEntry->glyphset;
1300             elts[idx].chars = wstr + idx;
1301             elts[idx].nchars = 1;
1302             elts[idx].xOff = desired.x - current.x;
1303             elts[idx].yOff = desired.y - current.y;
1304
1305             current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1306             current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1307
1308             if(!lpDx)
1309             {
1310                 desired.x += formatEntry->gis[wstr[idx]].xOff;
1311                 desired.y += formatEntry->gis[wstr[idx]].yOff;
1312             }
1313             else
1314             {
1315                 offset += lpDx[idx];
1316                 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1317                 desired.y = physDev->dc_rect.top  + y - offset * sinEsc;
1318             }
1319         }
1320         wine_tsx11_lock();
1321         pXRenderCompositeText16(gdi_display, render_op,
1322                                 tile_pict,
1323                                 physDev->xrender->pict,
1324                                 formatEntry->font_format,
1325                                 0, 0, 0, 0, elts, count);
1326         wine_tsx11_unlock();
1327         HeapFree(GetProcessHeap(), 0, elts);
1328     } else {
1329         INT offset = 0, xoff = 0, yoff = 0;
1330         wine_tsx11_lock();
1331         XSetForeground( gdi_display, physDev->gc, textPixel );
1332
1333         if(aa_type == AA_None || physDev->depth == 1)
1334         {
1335             void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1336
1337             if(aa_type == AA_None)
1338                 sharp_glyph_fn = SharpGlyphMono;
1339             else
1340                 sharp_glyph_fn = SharpGlyphGray;
1341
1342             for(idx = 0; idx < count; idx++) {
1343                 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1344                                physDev->dc_rect.top + y + yoff,
1345                                formatEntry->bitmaps[wstr[idx]],
1346                                &formatEntry->gis[wstr[idx]]);
1347                 if(lpDx) {
1348                     offset += lpDx[idx];
1349                     xoff = offset * cosEsc;
1350                     yoff = offset * -sinEsc;
1351                 } else {
1352                     xoff += formatEntry->gis[wstr[idx]].xOff;
1353                     yoff += formatEntry->gis[wstr[idx]].yOff;
1354                 }
1355             }
1356         } else {
1357             XImage *image;
1358             int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1359             RECT extents = {0, 0, 0, 0};
1360             POINT cur = {0, 0};
1361             int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1362             int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1363
1364             TRACE("drawable %dx%d\n", w, h);
1365
1366             for(idx = 0; idx < count; idx++) {
1367                 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1368                     extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1369                 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1370                     extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1371                 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1372                     extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1373                 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1374                     extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1375                 if(lpDx) {
1376                     offset += lpDx[idx];
1377                     cur.x = offset * cosEsc;
1378                     cur.y = offset * -sinEsc;
1379                 } else {
1380                     cur.x += formatEntry->gis[wstr[idx]].xOff;
1381                     cur.y += formatEntry->gis[wstr[idx]].yOff;
1382                 }
1383             }
1384             TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1385                   extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1386
1387             if(physDev->dc_rect.left + x + extents.left >= 0) {
1388                 image_x = physDev->dc_rect.left + x + extents.left;
1389                 image_off_x = 0;
1390             } else {
1391                 image_x = 0;
1392                 image_off_x = physDev->dc_rect.left + x + extents.left;
1393             }
1394             if(physDev->dc_rect.top + y + extents.top >= 0) {
1395                 image_y = physDev->dc_rect.top + y + extents.top;
1396                 image_off_y = 0;
1397             } else {
1398                 image_y = 0;
1399                 image_off_y = physDev->dc_rect.top + y + extents.top;
1400             }
1401             if(physDev->dc_rect.left + x + extents.right < w)
1402                 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1403             else
1404                 image_w = w - image_x;
1405             if(physDev->dc_rect.top + y + extents.bottom < h)
1406                 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1407             else
1408                 image_h = h - image_y;
1409
1410             if(image_w <= 0 || image_h <= 0) goto no_image;
1411
1412             X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1413             image = XGetImage(gdi_display, physDev->drawable,
1414                               image_x, image_y, image_w, image_h,
1415                               AllPlanes, ZPixmap);
1416             X11DRV_check_error();
1417
1418             TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1419                   gdi_display, (int)physDev->drawable, image_x, image_y,
1420                   image_w, image_h, AllPlanes, ZPixmap,
1421                   physDev->depth, image);
1422             if(!image) {
1423                 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
1424                                            physDev->depth);
1425                 GC gc;
1426                 XGCValues gcv;
1427
1428                 gcv.graphics_exposures = False;
1429                 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1430                 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1431                           image_w, image_h, 0, 0);
1432                 XFreeGC(gdi_display, gc);
1433                 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1434                 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1435                                   ZPixmap);
1436                 X11DRV_check_error();
1437                 XFreePixmap(gdi_display, xpm);
1438             }
1439             if(!image) goto no_image;
1440
1441             image->red_mask = visual->red_mask;
1442             image->green_mask = visual->green_mask;
1443             image->blue_mask = visual->blue_mask;
1444
1445             offset = xoff = yoff = 0;
1446             for(idx = 0; idx < count; idx++) {
1447                 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1448                                 yoff + image_off_y - extents.top,
1449                                 formatEntry->bitmaps[wstr[idx]],
1450                                 &formatEntry->gis[wstr[idx]],
1451                                 physDev->textPixel);
1452                 if(lpDx) {
1453                     offset += lpDx[idx];
1454                     xoff = offset * cosEsc;
1455                     yoff = offset * -sinEsc;
1456                 } else {
1457                     xoff += formatEntry->gis[wstr[idx]].xOff;
1458                     yoff += formatEntry->gis[wstr[idx]].yOff;
1459                 }
1460             }
1461             XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1462                       image_x, image_y, image_w, image_h);
1463             XDestroyImage(image);
1464         }
1465     no_image:
1466         wine_tsx11_unlock();
1467     }
1468     LeaveCriticalSection(&xrender_cs);
1469
1470     if (flags & ETO_CLIPPED)
1471     {
1472         /* restore the device region */
1473         X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1474         DeleteObject( saved_region );
1475     }
1476
1477     retv = TRUE;
1478
1479 done_unlock:
1480     X11DRV_UnlockDIBSection( physDev, TRUE );
1481     return retv;
1482 }
1483
1484 /******************************************************************************
1485  * AlphaBlend         (x11drv.@)
1486  */
1487 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1488                        X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1489                        BLENDFUNCTION blendfn)
1490 {
1491     XRenderPictureAttributes pa;
1492     XRenderPictFormat *src_format;
1493     XRenderPictFormat argb32_templ = {
1494         0,                          /* id */
1495         PictTypeDirect,             /* type */
1496         32,                         /* depth */
1497         {                           /* direct */
1498             16,                     /* direct.red */
1499             0xff,                   /* direct.redMask */
1500             8,                      /* direct.green */
1501             0xff,                   /* direct.greenMask */
1502             0,                      /* direct.blue */
1503             0xff,                   /* direct.blueMask */
1504             24,                     /* direct.alpha */
1505             0xff,                   /* direct.alphaMask */
1506         },
1507         0,                          /* colormap */
1508     };
1509     unsigned long argb32_templ_mask = 
1510         PictFormatType |
1511         PictFormatDepth |
1512         PictFormatRed |
1513         PictFormatRedMask |
1514         PictFormatGreen |
1515         PictFormatGreenMask |
1516         PictFormatBlue |
1517         PictFormatBlueMask |
1518         PictFormatAlpha |
1519         PictFormatAlphaMask;
1520
1521     Picture dst_pict, src_pict;
1522     Pixmap xpm;
1523     DIBSECTION dib;
1524     XImage *image;
1525     GC gc;
1526     XGCValues gcv;
1527     DWORD *dstbits, *data;
1528     int y, y2;
1529     POINT pts[2];
1530     BOOL top_down = FALSE;
1531     RGNDATA *rgndata;
1532     enum drawable_depth_type dst_depth_type = (devDst->depth == 1) ? mono_drawable : color_drawable;
1533
1534     if(!X11DRV_XRender_Installed) {
1535         FIXME("Unable to AlphaBlend without Xrender\n");
1536         return FALSE;
1537     }
1538     pts[0].x = xDst;
1539     pts[0].y = yDst;
1540     pts[1].x = xDst + widthDst;
1541     pts[1].y = yDst + heightDst;
1542     LPtoDP(devDst->hdc, pts, 2);
1543     xDst      = pts[0].x;
1544     yDst      = pts[0].y;
1545     widthDst  = pts[1].x - pts[0].x;
1546     heightDst = pts[1].y - pts[0].y;
1547
1548     pts[0].x = xSrc;
1549     pts[0].y = ySrc;
1550     pts[1].x = xSrc + widthSrc;
1551     pts[1].y = ySrc + heightSrc;
1552     LPtoDP(devSrc->hdc, pts, 2);
1553     xSrc      = pts[0].x;
1554     ySrc      = pts[0].y;
1555     widthSrc  = pts[1].x - pts[0].x;
1556     heightSrc = pts[1].y - pts[0].y;
1557     if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1558
1559 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1560     if(widthDst != widthSrc || heightDst != heightSrc)
1561 #else
1562     if(!pXRenderSetPictureTransform)
1563 #endif
1564     {
1565         FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1566         return FALSE;
1567     }
1568
1569     if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1570     {
1571         FIXME("not a dibsection\n");
1572         return FALSE;
1573     }
1574
1575     if (xSrc < 0 || ySrc < 0 || widthSrc < 0 || heightSrc < 0 || xSrc + widthSrc > dib.dsBmih.biWidth
1576         || ySrc + heightSrc > abs(dib.dsBmih.biHeight))
1577     {
1578         WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc, ySrc, widthSrc, heightSrc);
1579         SetLastError(ERROR_INVALID_PARAMETER);
1580         return FALSE;
1581     }
1582
1583     if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && blendfn.SourceConstantAlpha != 0xff)
1584         FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn.SourceConstantAlpha);
1585
1586     if(dib.dsBm.bmBitsPixel != 32) {
1587         FIXME("not a 32 bpp dibsection\n");
1588         return FALSE;
1589     }
1590     dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1591
1592     if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1593         top_down = TRUE;
1594         dstbits += widthSrc * (heightSrc - 1);
1595         y2 = ySrc;
1596         y = y2 + heightSrc - 1;
1597     }
1598     else
1599     {
1600         y = dib.dsBmih.biHeight - ySrc - 1;
1601         y2 = y - heightSrc + 1;
1602     }
1603
1604     if (blendfn.AlphaFormat & AC_SRC_ALPHA)
1605     {
1606         for(; y >= y2; y--)
1607         {
1608             memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1609                    widthSrc * 4);
1610             dstbits += (top_down ? -1 : 1) * widthSrc;
1611         }
1612     }
1613     else
1614     {
1615         DWORD source_alpha = (DWORD)blendfn.SourceConstantAlpha << 24;
1616         int x;
1617
1618         for(; y >= y2; y--)
1619         {
1620             DWORD *srcbits = (DWORD *)((char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes) + xSrc;
1621             for (x = 0; x < widthSrc; x++)
1622             {
1623                 DWORD argb = *srcbits++;
1624                 argb = (argb & 0xffffff) | source_alpha;
1625                 *dstbits++ = argb;
1626             }
1627             if (top_down)  /* we traversed the row forward so we should go back by two rows */
1628                 dstbits -= 2 * widthSrc;
1629         }
1630
1631     }
1632
1633     wine_tsx11_lock();
1634     image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1635                          (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1636
1637     /*
1638       Avoid using XRenderFindStandardFormat as older libraries don't have it
1639       src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1640     */
1641     src_format = pXRenderFindFormat(gdi_display, argb32_templ_mask, &argb32_templ, 0);
1642
1643     TRACE("src_format %p\n", src_format);
1644
1645     pa.subwindow_mode = IncludeInferiors;
1646
1647     /* FIXME use devDst->xrender->pict ? */
1648     dst_pict = pXRenderCreatePicture(gdi_display,
1649                                      devDst->drawable,
1650                                      pict_formats[dst_depth_type],
1651                                      CPSubwindowMode, &pa);
1652     TRACE("dst_pict %08lx\n", dst_pict);
1653     TRACE("src_drawable = %08lx\n", devSrc->drawable);
1654     xpm = XCreatePixmap(gdi_display,
1655                         root_window,
1656                         widthSrc, heightSrc, 32);
1657     gcv.graphics_exposures = False;
1658     gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1659     TRACE("xpm = %08lx\n", xpm);
1660     XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1661
1662     src_pict = pXRenderCreatePicture(gdi_display,
1663                                      xpm, src_format,
1664                                      CPSubwindowMode, &pa);
1665     TRACE("src_pict %08lx\n", src_pict);
1666
1667     if ((rgndata = X11DRV_GetRegionData( devDst->region, 0 )))
1668     {
1669         pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
1670                                           devDst->dc_rect.left, devDst->dc_rect.top,
1671                                           (XRectangle *)rgndata->Buffer, 
1672                                           rgndata->rdh.nCount );
1673         HeapFree( GetProcessHeap(), 0, rgndata );
1674     }
1675
1676 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1677     if(widthDst != widthSrc || heightDst != heightSrc) {
1678         double xscale = widthSrc/(double)widthDst;
1679         double yscale = heightSrc/(double)heightDst;
1680         XTransform xform = {{
1681             { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0) },
1682             { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0) },
1683             { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1684         }};
1685         pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1686     }
1687 #endif
1688     pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
1689                       0, 0, 0, 0,
1690                       xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
1691
1692
1693     pXRenderFreePicture(gdi_display, src_pict);
1694     XFreePixmap(gdi_display, xpm);
1695     XFreeGC(gdi_display, gc);
1696     pXRenderFreePicture(gdi_display, dst_pict);
1697     image->data = NULL;
1698     XDestroyImage(image);
1699
1700     wine_tsx11_unlock();
1701     HeapFree(GetProcessHeap(), 0, data);
1702     return TRUE;
1703 }
1704
1705 #else /* SONAME_LIBXRENDER */
1706
1707 void X11DRV_XRender_Init(void)
1708 {
1709     TRACE("XRender support not compiled in.\n");
1710     return;
1711 }
1712
1713 void X11DRV_XRender_Finalize(void)
1714 {
1715 }
1716
1717 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1718 {
1719   assert(0);
1720   return FALSE;
1721 }
1722
1723 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1724 {
1725   assert(0);
1726   return;
1727 }
1728
1729 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1730                                 const RECT *lprect, LPCWSTR wstr, UINT count,
1731                                 const INT *lpDx )
1732 {
1733   assert(0);
1734   return FALSE;
1735 }
1736
1737 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1738 {
1739   assert(0);
1740   return;
1741 }
1742
1743 /******************************************************************************
1744  * AlphaBlend         (x11drv.@)
1745  */
1746 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1747                        X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1748                        BLENDFUNCTION blendfn)
1749 {
1750   FIXME("not supported - XRENDER headers were missing at compile time\n");
1751   return FALSE;
1752 }
1753
1754 #endif /* SONAME_LIBXRENDER */