INT21_GetFreeDiskSpace(): The drive parameter is found in the DL
[wine] / dlls / x11drv / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "wownt32.h"
34 #include "x11drv.h"
35 #include "bitmap.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 HAVE_X11_EXTENSIONS_XRENDER_H
45
46 #include <X11/Xlib.h>
47 #include <X11/extensions/Xrender.h>
48
49 static XRenderPictFormat *screen_format; /* format of screen */
50 static XRenderPictFormat *mono_format; /* format of mono bitmap */
51
52 typedef struct
53 {
54     LOGFONTW lf;
55     XFORM  xform; /* this is dum as we don't care about offsets */
56     DWORD hash;
57 } LFANDSIZE;
58
59 #define INITIAL_REALIZED_BUF_SIZE 128
60
61 typedef enum { AA_None, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR } AA_Type;
62
63 typedef struct
64 {
65     LFANDSIZE lfsz;
66     AA_Type aa;
67     GlyphSet glyphset;
68     XRenderPictFormat *font_format;
69     int nrealized;
70     BOOL *realized;
71     void **bitmaps;
72     XGlyphInfo *gis;
73     UINT count;
74     INT next;
75 } gsCacheEntry;
76
77 struct tagXRENDERINFO
78 {
79     int                cache_index;
80     Picture            pict;
81     Picture            tile_pict;
82     Pixmap             tile_xpm;
83     COLORREF           lastTextColor;
84 };
85
86
87 static gsCacheEntry *glyphsetCache = NULL;
88 static DWORD glyphsetCacheSize = 0;
89 static INT lastfree = -1;
90 static INT mru = -1;
91
92 #define INIT_CACHE_SIZE 10
93
94 static int antialias = 1;
95
96 /* some default values just in case */
97 #ifndef SONAME_LIBX11
98 #define SONAME_LIBX11 "libX11.so"
99 #endif
100 #ifndef SONAME_LIBXEXT
101 #define SONAME_LIBXEXT "libXext.so"
102 #endif
103 #ifndef SONAME_LIBXRENDER
104 #define SONAME_LIBXRENDER "libXrender.so"
105 #endif
106
107 static void *xrender_handle;
108
109 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
110 MAKE_FUNCPTR(XRenderAddGlyphs)
111 MAKE_FUNCPTR(XRenderCompositeString8)
112 MAKE_FUNCPTR(XRenderCompositeString16)
113 MAKE_FUNCPTR(XRenderCompositeString32)
114 MAKE_FUNCPTR(XRenderCreateGlyphSet)
115 MAKE_FUNCPTR(XRenderCreatePicture)
116 MAKE_FUNCPTR(XRenderFillRectangle)
117 MAKE_FUNCPTR(XRenderFindFormat)
118 MAKE_FUNCPTR(XRenderFindVisualFormat)
119 MAKE_FUNCPTR(XRenderFreeGlyphSet)
120 MAKE_FUNCPTR(XRenderFreePicture)
121 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
122 MAKE_FUNCPTR(XRenderQueryExtension)
123 #undef MAKE_FUNCPTR
124
125 static CRITICAL_SECTION xrender_cs;
126 static CRITICAL_SECTION_DEBUG critsect_debug =
127 {
128     0, 0, &xrender_cs,
129     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
130       0, 0, { 0, (DWORD)(__FILE__ ": xrender_cs") }
131 };
132 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
133
134
135 /***********************************************************************
136  *   X11DRV_XRender_Init
137  *
138  * Let's see if our XServer has the extension available
139  *
140  */
141 void X11DRV_XRender_Init(void)
142 {
143     int error_base, event_base, i;
144     XRenderPictFormat pf;
145
146     if (client_side_with_render &&
147         wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
148         wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) && 
149         (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
150     {
151
152 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
153 LOAD_FUNCPTR(XRenderAddGlyphs)
154 LOAD_FUNCPTR(XRenderCompositeString8)
155 LOAD_FUNCPTR(XRenderCompositeString16)
156 LOAD_FUNCPTR(XRenderCompositeString32)
157 LOAD_FUNCPTR(XRenderCreateGlyphSet)
158 LOAD_FUNCPTR(XRenderCreatePicture)
159 LOAD_FUNCPTR(XRenderFillRectangle)
160 LOAD_FUNCPTR(XRenderFindFormat)
161 LOAD_FUNCPTR(XRenderFindVisualFormat)
162 LOAD_FUNCPTR(XRenderFreeGlyphSet)
163 LOAD_FUNCPTR(XRenderFreePicture)
164 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
165 LOAD_FUNCPTR(XRenderQueryExtension)
166 #undef LOAD_FUNCPTR
167
168         wine_tsx11_lock();
169         if(pXRenderQueryExtension(gdi_display, &event_base, &error_base)) {
170             X11DRV_XRender_Installed = TRUE;
171             TRACE("Xrender is up and running error_base = %d\n", error_base);
172             screen_format = pXRenderFindVisualFormat(gdi_display, visual);
173             if(!screen_format) { /* This fails in buggy versions of libXrender.so */
174                 wine_tsx11_unlock();
175                 WINE_MESSAGE(
176                     "Wine has detected that you probably have a buggy version\n"
177                     "of libXrender.so .  Because of this client side font rendering\n"
178                     "will be disabled.  Please upgrade this library.\n");
179                 X11DRV_XRender_Installed = FALSE;
180                 return;
181             }
182             pf.type = PictTypeDirect;
183             pf.depth = 1;
184             pf.direct.alpha = 0;
185             pf.direct.alphaMask = 1;
186             mono_format = pXRenderFindFormat(gdi_display, PictFormatType |
187                                              PictFormatDepth | PictFormatAlpha |
188                                              PictFormatAlphaMask, &pf, 0);
189             if(!mono_format) {
190                 ERR("mono_format == NULL?\n");
191                 X11DRV_XRender_Installed = FALSE;
192             }
193         }
194         wine_tsx11_unlock();
195     }
196
197 sym_not_found:
198     if(X11DRV_XRender_Installed || client_side_with_core)
199     {
200         glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
201                                   sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
202
203         glyphsetCacheSize = INIT_CACHE_SIZE;
204         lastfree = 0;
205         for(i = 0; i < INIT_CACHE_SIZE; i++) {
206           glyphsetCache[i].next = i + 1;
207           glyphsetCache[i].count = -1;
208         }
209         glyphsetCache[i-1].next = -1;
210         using_client_side_fonts = 1;
211
212         if(!X11DRV_XRender_Installed) {
213             TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
214             if(screen_depth <= 8 || !client_side_antialias_with_core)
215                 antialias = 0;
216         } else {
217             if(screen_depth <= 8 || !client_side_antialias_with_render)
218                 antialias = 0;
219         }
220     }
221     else TRACE("Using X11 core fonts\n");
222 }
223
224 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
225 {
226   if(p1->hash != p2->hash) return TRUE;
227   if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
228   if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
229   return strcmpW(p1->lf.lfFaceName, p2->lf.lfFaceName);
230 }
231
232 #if 0
233 static void walk_cache(void)
234 {
235   int i;
236
237   EnterCriticalSection(&xrender_cs);
238   for(i=mru; i >= 0; i = glyphsetCache[i].next)
239     TRACE("item %d\n", i);
240   LeaveCriticalSection(&xrender_cs);
241 }
242 #endif
243
244 static int LookupEntry(LFANDSIZE *plfsz)
245 {
246   int i, prev_i = -1;
247
248   for(i = mru; i >= 0; i = glyphsetCache[i].next) {
249     TRACE("%d\n", i);
250     if(glyphsetCache[i].count == -1) { /* reached free list so stop */
251       i = -1;
252       break;
253     }
254
255     if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
256       glyphsetCache[i].count++;
257       if(prev_i >= 0) {
258         glyphsetCache[prev_i].next = glyphsetCache[i].next;
259         glyphsetCache[i].next = mru;
260         mru = i;
261       }
262       TRACE("found font in cache %d\n", i);
263       return i;
264     }
265     prev_i = i;
266   }
267   TRACE("font not in cache\n");
268   return -1;
269 }
270
271 static void FreeEntry(int entry)
272 {
273     int i;
274
275     if(glyphsetCache[entry].glyphset) {
276         wine_tsx11_lock();
277         pXRenderFreeGlyphSet(gdi_display, glyphsetCache[entry].glyphset);
278         wine_tsx11_unlock();
279         glyphsetCache[entry].glyphset = 0;
280     }
281     if(glyphsetCache[entry].nrealized) {
282         HeapFree(GetProcessHeap(), 0, glyphsetCache[entry].realized);
283         glyphsetCache[entry].realized = NULL;
284         if(glyphsetCache[entry].bitmaps) {
285             for(i = 0; i < glyphsetCache[entry].nrealized; i++)
286                 if(glyphsetCache[entry].bitmaps[i])
287                     HeapFree(GetProcessHeap(), 0, glyphsetCache[entry].bitmaps[i]);
288             HeapFree(GetProcessHeap(), 0, glyphsetCache[entry].bitmaps);
289             glyphsetCache[entry].bitmaps = NULL;
290             HeapFree(GetProcessHeap(), 0, glyphsetCache[entry].gis);
291             glyphsetCache[entry].gis = NULL;
292         }
293         glyphsetCache[entry].nrealized = 0;
294     }
295 }
296
297 static int AllocEntry(void)
298 {
299   int best = -1, prev_best = -1, i, prev_i = -1;
300
301   if(lastfree >= 0) {
302     assert(glyphsetCache[lastfree].count == -1);
303     glyphsetCache[lastfree].count = 1;
304     best = lastfree;
305     lastfree = glyphsetCache[lastfree].next;
306     assert(best != mru);
307     glyphsetCache[best].next = mru;
308     mru = best;
309
310     TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
311     return mru;
312   }
313
314   for(i = mru; i >= 0; i = glyphsetCache[i].next) {
315     if(glyphsetCache[i].count == 0) {
316       best = i;
317       prev_best = prev_i;
318     }
319     prev_i = i;
320   }
321
322   if(best >= 0) {
323     TRACE("freeing unused glyphset at cache %d\n", best);
324     FreeEntry(best);
325     glyphsetCache[best].count = 1;
326     if(prev_best >= 0) {
327       glyphsetCache[prev_best].next = glyphsetCache[best].next;
328       glyphsetCache[best].next = mru;
329       mru = best;
330     } else {
331       assert(mru == best);
332     }
333     return mru;
334   }
335
336   TRACE("Growing cache\n");
337   
338   if (glyphsetCache)
339     glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
340                               glyphsetCache,
341                               (glyphsetCacheSize + INIT_CACHE_SIZE)
342                               * sizeof(*glyphsetCache));
343   else
344     glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
345                               (glyphsetCacheSize + INIT_CACHE_SIZE)
346                               * sizeof(*glyphsetCache));
347
348   for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
349       i++) {
350     glyphsetCache[i].next = i + 1;
351     glyphsetCache[i].count = -1;
352   }
353   glyphsetCache[i-1].next = -1;
354   glyphsetCacheSize += INIT_CACHE_SIZE;
355
356   lastfree = glyphsetCache[best].next;
357   glyphsetCache[best].count = 1;
358   glyphsetCache[best].next = mru;
359   mru = best;
360   TRACE("new free cache slot at %d\n", mru);
361   return mru;
362 }
363
364 static int GetCacheEntry(LFANDSIZE *plfsz)
365 {
366     XRenderPictFormat pf;
367     int ret;
368     gsCacheEntry *entry;
369
370     if((ret = LookupEntry(plfsz)) != -1) return ret;
371
372     ret = AllocEntry();
373     entry = glyphsetCache + ret;
374     entry->lfsz = *plfsz;
375     assert(entry->nrealized == 0);
376
377     if(antialias)
378         entry->aa = AA_Grey;
379     else
380         entry->aa = AA_None;
381
382     if(X11DRV_XRender_Installed) {
383         switch(entry->aa) {
384         case AA_Grey:
385             pf.depth = 8;
386             pf.direct.alphaMask = 0xff;
387             break;
388
389         default:
390             ERR("aa = %d - not implemented\n", entry->aa);
391         case AA_None:
392             pf.depth = 1;
393             pf.direct.alphaMask = 1;
394             break;
395         }
396
397         pf.type = PictTypeDirect;
398         pf.direct.alpha = 0;
399
400         wine_tsx11_lock();
401         entry->font_format = pXRenderFindFormat(gdi_display,
402                                                 PictFormatType |
403                                                 PictFormatDepth |
404                                                 PictFormatAlpha |
405                                                 PictFormatAlphaMask,
406                                                 &pf, 0);
407
408         entry->glyphset = pXRenderCreateGlyphSet(gdi_display, entry->font_format);
409         wine_tsx11_unlock();
410     }
411     return ret;
412 }
413
414 static void dec_ref_cache(int index)
415 {
416     assert(index >= 0);
417     TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
418     assert(glyphsetCache[index].count > 0);
419     glyphsetCache[index].count--;
420 }
421
422 static void lfsz_calc_hash(LFANDSIZE *plfsz)
423 {
424   DWORD hash = 0, *ptr;
425   int i;
426
427   for(ptr = (DWORD*)&plfsz->xform; ptr < (DWORD*)(&plfsz->xform + 1); ptr++)
428     hash ^= *ptr;
429   for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
430     hash ^= *ptr;
431   for(i = 0, ptr = (DWORD*)&plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
432     WCHAR *pwc = (WCHAR *)ptr;
433     if(!*pwc) break;
434     hash ^= *ptr;
435     pwc++;
436     if(!*pwc) break;
437   }
438   plfsz->hash = hash;
439   return;
440 }
441
442 /***********************************************************************
443  *   X11DRV_XRender_Finalize
444  */
445 void X11DRV_XRender_Finalize(void)
446 {
447     int i;
448
449     EnterCriticalSection(&xrender_cs);
450     for(i = mru; i >= 0; i = glyphsetCache[i].next)
451         FreeEntry(i);
452     LeaveCriticalSection(&xrender_cs);
453 }
454
455
456 /***********************************************************************
457  *   X11DRV_XRender_SelectFont
458  */
459 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
460 {
461     LFANDSIZE lfsz;
462
463     GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
464     TRACE("h=%ld w=%ld weight=%ld it=%d charset=%d name=%s\n",
465           lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
466           lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
467     lfsz.xform = physDev->dc->xformWorld2Vport;
468     lfsz_calc_hash(&lfsz);
469
470     EnterCriticalSection(&xrender_cs);
471     if(!physDev->xrender) {
472         physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
473                                      sizeof(*physDev->xrender));
474         physDev->xrender->cache_index = -1;
475     }
476     else if(physDev->xrender->cache_index != -1)
477         dec_ref_cache(physDev->xrender->cache_index);
478     physDev->xrender->cache_index = GetCacheEntry(&lfsz);
479     LeaveCriticalSection(&xrender_cs);
480     return 0;
481 }
482
483 /***********************************************************************
484  *   X11DRV_XRender_DeleteDC
485  */
486 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
487 {
488     wine_tsx11_lock();
489     if(physDev->xrender->tile_pict)
490         pXRenderFreePicture(gdi_display, physDev->xrender->tile_pict);
491
492     if(physDev->xrender->tile_xpm)
493         XFreePixmap(gdi_display, physDev->xrender->tile_xpm);
494
495     if(physDev->xrender->pict) {
496         TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->dc);
497         pXRenderFreePicture(gdi_display, physDev->xrender->pict);
498     }
499     wine_tsx11_unlock();
500
501     EnterCriticalSection(&xrender_cs);
502     if(physDev->xrender->cache_index != -1)
503         dec_ref_cache(physDev->xrender->cache_index);
504     LeaveCriticalSection(&xrender_cs);
505
506     HeapFree(GetProcessHeap(), 0, physDev->xrender);
507     physDev->xrender = NULL;
508     return;
509 }
510
511 /***********************************************************************
512  *   X11DRV_XRender_UpdateDrawable
513  *
514  * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
515  * It deletes the pict when the drawable changes.
516  */
517 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
518 {
519     if(physDev->xrender->pict) {
520         TRACE("freeing pict %08lx from dc %p drawable %08lx\n", physDev->xrender->pict,
521               physDev->dc, physDev->drawable);
522         wine_tsx11_lock();
523         XFlush(gdi_display);
524         pXRenderFreePicture(gdi_display, physDev->xrender->pict);
525         wine_tsx11_unlock();
526     }
527     physDev->xrender->pict = 0;
528     return;
529 }
530
531 /************************************************************************
532  *   UploadGlyph
533  *
534  * Helper to ExtTextOut.  Must be called inside xrender_cs
535  */
536 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph)
537 {
538     int buflen;
539     char *buf;
540     Glyph gid;
541     GLYPHMETRICS gm;
542     XGlyphInfo gi;
543     gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
544     UINT ggo_format = GGO_GLYPH_INDEX;
545
546     if(entry->nrealized <= glyph) {
547         entry->nrealized = (glyph / 128 + 1) * 128;
548
549         if (entry->realized)
550             entry->realized = HeapReAlloc(GetProcessHeap(),
551                                       HEAP_ZERO_MEMORY,
552                                       entry->realized,
553                                       entry->nrealized * sizeof(BOOL));
554         else
555             entry->realized = HeapAlloc(GetProcessHeap(),
556                                       HEAP_ZERO_MEMORY,
557                                       entry->nrealized * sizeof(BOOL));
558
559         if(entry->glyphset == 0) {
560           if (entry->bitmaps)
561             entry->bitmaps = HeapReAlloc(GetProcessHeap(),
562                                       HEAP_ZERO_MEMORY,
563                                       entry->bitmaps,
564                                       entry->nrealized * sizeof(entry->bitmaps[0]));
565           else
566             entry->bitmaps = HeapAlloc(GetProcessHeap(),
567                                       HEAP_ZERO_MEMORY,
568                                       entry->nrealized * sizeof(entry->bitmaps[0]));
569
570           if (entry->gis)
571             entry->gis = HeapReAlloc(GetProcessHeap(),
572                                    HEAP_ZERO_MEMORY,
573                                    entry->gis,
574                                    entry->nrealized * sizeof(entry->gis[0]));
575           else
576             entry->gis = HeapAlloc(GetProcessHeap(),
577                                    HEAP_ZERO_MEMORY,
578                                    entry->nrealized * sizeof(entry->gis[0]));
579         }
580     }
581
582     switch(entry->aa) {
583     case AA_Grey:
584         ggo_format |= WINE_GGO_GRAY16_BITMAP;
585         break;
586
587     default:
588         ERR("aa = %d - not implemented\n", entry->aa);
589     case AA_None:
590         ggo_format |= GGO_BITMAP;
591         break;
592     }
593
594     buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
595                               NULL);
596     if(buflen == GDI_ERROR) {
597         LeaveCriticalSection(&xrender_cs);
598         return FALSE;
599     }
600
601     entry->realized[glyph] = TRUE;
602
603     buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
604     GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, NULL);
605
606     TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%ld,%ld\n",
607           buflen,
608           gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
609           gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
610
611     gi.width = gm.gmBlackBoxX;
612     gi.height = gm.gmBlackBoxY;
613     gi.x = -gm.gmptGlyphOrigin.x;
614     gi.y = gm.gmptGlyphOrigin.y;
615     gi.xOff = gm.gmCellIncX;
616     gi.yOff = gm.gmCellIncY;
617
618     if(TRACE_ON(xrender)) {
619         int pitch, i, j;
620         char output[300];
621         unsigned char *line;
622
623         if(entry->aa == AA_None) {
624             pitch = ((gi.width + 31) / 32) * 4;
625             for(i = 0; i < gi.height; i++) {
626                 line = buf + i * pitch;
627                 output[0] = '\0';
628                 for(j = 0; j < pitch * 8; j++) {
629                     strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
630                 }
631                 strcat(output, "\n");
632                 TRACE(output);
633             }
634         } else {
635             char blks[] = " .:;!o*#";
636             char str[2];
637
638             str[1] = '\0';
639             pitch = ((gi.width + 3) / 4) * 4;
640             for(i = 0; i < gi.height; i++) {
641                 line = buf + i * pitch;
642                 output[0] = '\0';
643                 for(j = 0; j < pitch; j++) {
644                     str[0] = blks[line[j] >> 5];
645                     strcat(output, str);
646                 }
647                 strcat(output, "\n");
648                 TRACE(output);
649             }
650         }
651     }
652
653     if(entry->glyphset) {
654         if(entry->aa == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
655             unsigned char *byte = buf, c;
656             int i = buflen;
657
658             while(i--) {
659                 c = *byte;
660
661                 /* magic to flip bit order */
662                 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
663                 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
664                 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
665
666                 *byte++ = c;
667             }
668         }
669         gid = glyph;
670         wine_tsx11_lock();
671         pXRenderAddGlyphs(gdi_display, entry->glyphset, &gid, &gi, 1,
672                           buf, buflen);
673         wine_tsx11_unlock();
674         HeapFree(GetProcessHeap(), 0, buf);
675     } else {
676         entry->bitmaps[glyph] = buf;
677         memcpy(&entry->gis[glyph], &gi, sizeof(gi));
678     }
679     return TRUE;
680 }
681
682 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
683                             void *bitmap, XGlyphInfo *gi)
684 {
685     unsigned char   *srcLine = bitmap, *src;
686     unsigned char   bits, bitsMask;
687     int             width = gi->width;
688     int             stride = ((width + 31) & ~31) >> 3;
689     int             height = gi->height;
690     int             w;
691     int             xspan, lenspan;
692
693     TRACE("%d, %d\n", x, y);
694     x -= gi->x;
695     y -= gi->y;
696     while (height--)
697     {
698         src = srcLine;
699         srcLine += stride;
700         w = width;
701         
702         bitsMask = 0x80;    /* FreeType is always MSB first */
703         bits = *src++;
704         
705         xspan = x;
706         while (w)
707         {
708             if (bits & bitsMask)
709             {
710                 lenspan = 0;
711                 do
712                 {
713                     lenspan++;
714                     if (lenspan == w)
715                         break;
716                     bitsMask = bitsMask >> 1;
717                     if (!bitsMask)
718                     {
719                         bits = *src++;
720                         bitsMask = 0x80;
721                     }
722                 } while (bits & bitsMask);
723                 XFillRectangle (gdi_display, physDev->drawable, 
724                                 physDev->gc, xspan, y, lenspan, 1);
725                 xspan += lenspan;
726                 w -= lenspan;
727             }
728             else
729             {
730                 do
731                 {
732                     w--;
733                     xspan++;
734                     if (!w)
735                         break;
736                     bitsMask = bitsMask >> 1;
737                     if (!bitsMask)
738                     {
739                         bits = *src++;
740                         bitsMask = 0x80;
741                     }
742                 } while (!(bits & bitsMask));
743             }
744         }
745         y++;
746     }
747 }
748
749 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
750                             void *bitmap, XGlyphInfo *gi)
751 {
752     unsigned char   *srcLine = bitmap, *src, bits;
753     int             width = gi->width;
754     int             stride = ((width + 3) & ~3);
755     int             height = gi->height;
756     int             w;
757     int             xspan, lenspan;
758
759     x -= gi->x;
760     y -= gi->y;
761     while (height--)
762     {
763         src = srcLine;
764         srcLine += stride;
765         w = width;
766         
767         bits = *src++;
768         xspan = x;
769         while (w)
770         {
771             if (bits >= 0x80)
772             {
773                 lenspan = 0;
774                 do
775                 {
776                     lenspan++;
777                     if (lenspan == w)
778                         break;
779                     bits = *src++;
780                 } while (bits >= 0x80);
781                 XFillRectangle (gdi_display, physDev->drawable, 
782                                 physDev->gc, xspan, y, lenspan, 1);
783                 xspan += lenspan;
784                 w -= lenspan;
785             }
786             else
787             {
788                 do
789                 {
790                     w--;
791                     xspan++;
792                     if (!w)
793                         break;
794                     bits = *src++;
795                 } while (bits < 0x80);
796             }
797         }
798         y++;
799     }
800 }
801
802
803 static void ExamineBitfield (DWORD mask, int *shift, int *len)
804 {
805     int s, l;
806
807     s = 0;
808     while ((mask & 1) == 0)
809     {
810         mask >>= 1;
811         s++;
812     }
813     l = 0;
814     while ((mask & 1) == 1)
815     {
816         mask >>= 1;
817         l++;
818     }
819     *shift = s;
820     *len = l;
821 }
822
823 static DWORD GetField (DWORD pixel, int shift, int len)
824 {
825     pixel = pixel & (((1 << (len)) - 1) << shift);
826     pixel = pixel << (32 - (shift + len)) >> 24;
827     while (len < 8)
828     {
829         pixel |= (pixel >> len);
830         len <<= 1;
831     }
832     return pixel;
833 }
834
835
836 static DWORD PutField (DWORD pixel, int shift, int len)
837 {
838     shift = shift - (8 - len);
839     if (len <= 8)
840         pixel &= (((1 << len) - 1) << (8 - len));
841     if (shift < 0)
842         pixel >>= -shift;
843     else
844         pixel <<= shift;
845     return pixel;
846 }
847
848 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
849                             COLORREF color)
850 {
851     int             r_shift, r_len;
852     int             g_shift, g_len;
853     int             b_shift, b_len;
854     BYTE            *maskLine, *mask, m;
855     int             maskStride;
856     DWORD           pixel;
857     int             width, height;
858     int             w, tx;
859     BYTE            src_r, src_g, src_b;
860
861     src_r = GetRValue(color);
862     src_g = GetGValue(color);
863     src_b = GetBValue(color);
864
865     x -= gi->x;
866     y -= gi->y;
867     width = gi->width;
868     height = gi->height;
869
870     maskLine = (unsigned char *) bitmap;
871     maskStride = (width + 3) & ~3;
872
873     ExamineBitfield (image->red_mask, &r_shift, &r_len);
874     ExamineBitfield (image->green_mask, &g_shift, &g_len);
875     ExamineBitfield (image->blue_mask, &b_shift, &b_len);
876     for(; height--; y++)
877     {
878         mask = maskLine;
879         maskLine += maskStride;
880         w = width;
881         tx = x;
882
883         if(y < 0) continue;
884         if(y >= image->height) break;
885
886         for(; w--; tx++)
887         {
888             if(tx >= image->width) break;
889
890             m = *mask++;
891             if(tx < 0) continue;
892
893             if (m == 0xff)
894             {
895                 pixel = (PutField ((src_r), r_shift, r_len) |
896                          PutField ((src_g), g_shift, g_len) |
897                          PutField ((src_b), b_shift, b_len));
898                 XPutPixel (image, tx, y, pixel);
899             }
900             else if (m)
901             {
902                 BYTE r, g, b;
903
904                 pixel = XGetPixel (image, tx, y);
905
906                 r = GetField(pixel, r_shift, r_len);
907                 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
908                 g = GetField(pixel, g_shift, g_len);
909                 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
910                 b = GetField(pixel, b_shift, b_len);
911                 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
912
913                 pixel = (PutField (r, r_shift, r_len) |
914                          PutField (g, g_shift, g_len) |
915                          PutField (b, b_shift, b_len));
916                 XPutPixel (image, tx, y, pixel);
917             }
918         }
919     }
920 }
921
922 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
923 {
924     return 1;
925 }
926
927 /***********************************************************************
928  *   X11DRV_XRender_ExtTextOut
929  */
930 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
931                                 const RECT *lprect, LPCWSTR wstr, UINT count,
932                                 const INT *lpDx )
933 {
934     XRenderColor col;
935     int idx;
936     TEXTMETRICW tm;
937     RGNDATA *data;
938     SIZE sz;
939     RECT rc;
940     BOOL done_extents = FALSE;
941     INT width, xwidth, ywidth;
942     double cosEsc, sinEsc;
943     XGCValues xgcval;
944     LOGFONTW lf;
945     int render_op = PictOpOver;
946     WORD *glyphs;
947     POINT pt;
948     gsCacheEntry *entry;
949     BOOL retv = FALSE;
950     HDC hdc = physDev->hdc;
951     DC *dc = physDev->dc;
952     int textPixel, backgroundPixel;
953     INT *deltas = NULL;
954     INT char_extra;
955
956     TRACE("%p, %d, %d, %08x, %p, %s, %d, %p)\n", hdc, x, y, flags,
957           lprect, debugstr_wn(wstr, count), count, lpDx);
958
959     if(flags & ETO_GLYPH_INDEX)
960         glyphs = (LPWORD)wstr;
961     else {
962         glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
963         GetGlyphIndicesW(hdc, wstr, count, glyphs, 0);
964     }
965
966     if(lprect)
967       TRACE("rect: %ld,%ld - %ld,%ld\n", lprect->left, lprect->top, lprect->right,
968             lprect->bottom);
969     TRACE("align = %x bkmode = %x mapmode = %x\n", dc->textAlign, GetBkMode(hdc), dc->MapMode);
970
971     if(dc->textAlign & TA_UPDATECP) {
972         x = dc->CursPosX;
973         y = dc->CursPosY;
974     }
975
976     GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
977     if(lf.lfEscapement != 0) {
978         cosEsc = cos(lf.lfEscapement * M_PI / 1800);
979         sinEsc = sin(lf.lfEscapement * M_PI / 1800);
980     } else {
981         cosEsc = 1;
982         sinEsc = 0;
983     }
984
985     if(flags & (ETO_CLIPPED | ETO_OPAQUE)) {
986         if(!lprect) {
987             if(flags & ETO_CLIPPED) return FALSE;
988                 GetTextExtentPointI(hdc, glyphs, count, &sz);
989                 done_extents = TRUE;
990                 rc.left = x;
991                 rc.top = y;
992                 rc.right = x + sz.cx;
993                 rc.bottom = y + sz.cy;
994         } else {
995             rc = *lprect;
996         }
997
998         LPtoDP(physDev->hdc, (POINT*)&rc, 2);
999
1000         if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
1001         if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
1002     }
1003
1004     xgcval.function = GXcopy;
1005     xgcval.background = physDev->backgroundPixel;
1006     xgcval.fill_style = FillSolid;
1007     wine_tsx11_lock();
1008     XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1009     wine_tsx11_unlock();
1010
1011     X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1012
1013     if(dc->bitsPerPixel == 1) {
1014         if((dc->textColor & 0xffffff) == 0) {
1015             textPixel = 0;
1016             backgroundPixel = 1;
1017         } else {
1018             textPixel = 1;
1019             backgroundPixel = 0;
1020         }
1021     } else {
1022         textPixel = physDev->textPixel;
1023         backgroundPixel = physDev->backgroundPixel;
1024     }
1025
1026     if(flags & ETO_OPAQUE) {
1027         wine_tsx11_lock();
1028         XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1029         XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1030                         physDev->org.x + rc.left, physDev->org.y + rc.top,
1031                         rc.right - rc.left, rc.bottom - rc.top );
1032         wine_tsx11_unlock();
1033     }
1034
1035     if(count == 0) {
1036         retv =  TRUE;
1037         goto done;
1038     }
1039
1040     pt.x = x;
1041     pt.y = y;
1042     LPtoDP(physDev->hdc, &pt, 1);
1043     x = pt.x;
1044     y = pt.y;
1045
1046     TRACE("real x,y %d,%d\n", x, y);
1047
1048     if((char_extra = GetTextCharacterExtra(physDev->hdc)) != 0) {
1049         INT i;
1050         SIZE tmpsz;
1051         deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
1052         for(i = 0; i < count; i++) {
1053             if(lpDx)
1054                 deltas[i] = lpDx[i] + char_extra;
1055             else {
1056                 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
1057                 deltas[i] = tmpsz.cx;
1058             }
1059         }
1060     } else if(lpDx)
1061         deltas = (INT*)lpDx;
1062
1063     if(deltas) {
1064         width = 0;
1065         for(idx = 0; idx < count; idx++)
1066             width += deltas[idx];
1067     } else {
1068         if(!done_extents) {
1069             GetTextExtentPointI(hdc, glyphs, count, &sz);
1070             done_extents = TRUE;
1071         }
1072         width = sz.cx;
1073     }
1074     width = INTERNAL_XWSTODS(dc, width);
1075     xwidth = width * cosEsc;
1076     ywidth = width * sinEsc;
1077
1078     GetTextMetricsW(hdc, &tm);
1079
1080     tm.tmAscent = INTERNAL_YWSTODS(dc, tm.tmAscent);
1081     tm.tmDescent = INTERNAL_YWSTODS(dc, tm.tmDescent);
1082     switch( dc->textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER) ) {
1083     case TA_LEFT:
1084         if (dc->textAlign & TA_UPDATECP) {
1085             pt.x = x + xwidth;
1086             pt.y = y - ywidth;
1087             DPtoLP(physDev->hdc, &pt, 1);
1088             dc->CursPosX = pt.x;
1089             dc->CursPosY = pt.y;
1090         }
1091         break;
1092
1093     case TA_CENTER:
1094         x -= xwidth / 2;
1095         y += ywidth / 2;
1096         break;
1097
1098     case TA_RIGHT:
1099         x -= xwidth;
1100         y += ywidth;
1101         if (dc->textAlign & TA_UPDATECP) {
1102             pt.x = x;
1103             pt.y = y;
1104             DPtoLP(physDev->hdc, &pt, 1);
1105             dc->CursPosX = pt.x;
1106             dc->CursPosY = pt.y;
1107         }
1108         break;
1109     }
1110
1111     switch( dc->textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE) ) {
1112     case TA_TOP:
1113         y += tm.tmAscent * cosEsc;
1114         x += tm.tmAscent * sinEsc;
1115         break;
1116
1117     case TA_BOTTOM:
1118         y -= tm.tmDescent * cosEsc;
1119         x -= tm.tmDescent * sinEsc;
1120         break;
1121
1122     case TA_BASELINE:
1123         break;
1124     }
1125
1126     if (flags & ETO_CLIPPED)
1127     {
1128         SaveVisRgn16( HDC_16(hdc) );
1129         IntersectVisRect16( HDC_16(dc->hSelf), lprect->left, lprect->top, lprect->right, lprect->bottom );
1130     }
1131
1132     if(X11DRV_XRender_Installed) {
1133         if(!physDev->xrender->pict) {
1134             XRenderPictureAttributes pa;
1135             pa.subwindow_mode = IncludeInferiors;
1136
1137             wine_tsx11_lock();
1138             physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1139                                                            physDev->drawable,
1140                                                            (dc->bitsPerPixel == 1) ?
1141                                                            mono_format : screen_format,
1142                                                            CPSubwindowMode, &pa);
1143             wine_tsx11_unlock();
1144
1145             TRACE("allocing pict = %lx dc = %p drawable = %08lx\n", physDev->xrender->pict, dc, physDev->drawable);
1146         } else {
1147             TRACE("using existing pict = %lx dc = %p drawable = %08lx\n", physDev->xrender->pict, dc, physDev->drawable);
1148         }
1149
1150         if ((data = X11DRV_GetRegionData( dc->hGCClipRgn, 0 )))
1151         {
1152             wine_tsx11_lock();
1153             pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1154                                               physDev->org.x, physDev->org.y,
1155                                               (XRectangle *)data->Buffer, data->rdh.nCount );
1156             wine_tsx11_unlock();
1157             HeapFree( GetProcessHeap(), 0, data );
1158         }
1159     }
1160
1161     if(GetBkMode(hdc) != TRANSPARENT) {
1162         if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE))) {
1163             if(!(flags & ETO_OPAQUE) || x < rc.left || x + width >= rc.right ||
1164                y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom) {
1165                 wine_tsx11_lock();
1166                 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1167                 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1168                                 physDev->org.x + x, physDev->org.y + y - tm.tmAscent,
1169                                 width, tm.tmAscent + tm.tmDescent );
1170                 wine_tsx11_unlock();
1171             }
1172         }
1173     }
1174
1175     if(X11DRV_XRender_Installed) {
1176         /* Create a 1x1 pixmap to tile over the font mask */
1177         if(!physDev->xrender->tile_xpm) {
1178             XRenderPictureAttributes pa;
1179
1180             XRenderPictFormat *format = (dc->bitsPerPixel == 1) ? mono_format : screen_format;
1181             wine_tsx11_lock();
1182             physDev->xrender->tile_xpm = XCreatePixmap(gdi_display,
1183                                                        physDev->drawable,
1184                                                        1, 1,
1185                                                        format->depth);
1186             pa.repeat = True;
1187             physDev->xrender->tile_pict = pXRenderCreatePicture(gdi_display,
1188                                                                 physDev->xrender->tile_xpm,
1189                                                                 format,
1190                                                                 CPRepeat, &pa);
1191             wine_tsx11_unlock();
1192             TRACE("Created pixmap of depth %d\n", format->depth);
1193             /* init lastTextColor to something different from dc->textColor */
1194             physDev->xrender->lastTextColor = ~dc->textColor;
1195
1196         }
1197
1198         if(dc->textColor != physDev->xrender->lastTextColor) {
1199             if(dc->bitsPerPixel != 1) {
1200               /* Map 0 -- 0xff onto 0 -- 0xffff */
1201                 col.red = GetRValue(dc->textColor);
1202                 col.red |= col.red << 8;
1203                 col.green = GetGValue(dc->textColor);
1204                 col.green |= col.green << 8;
1205                 col.blue = GetBValue(dc->textColor);
1206                 col.blue |= col.blue << 8;
1207                 col.alpha = 0x0;
1208             } else { /* for a 1bpp bitmap we always need a 1 in the tile */
1209                 col.red = col.green = col.blue = 0;
1210                 col.alpha = 0xffff;
1211             }
1212             wine_tsx11_lock();
1213             pXRenderFillRectangle(gdi_display, PictOpSrc,
1214                                   physDev->xrender->tile_pict,
1215                                   &col, 0, 0, 1, 1);
1216             wine_tsx11_unlock();
1217             physDev->xrender->lastTextColor = dc->textColor;
1218         }
1219
1220         /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1221          */
1222         if((dc->bitsPerPixel == 1) && (textPixel == 0))
1223             render_op = PictOpOutReverse; /* This gives us 'black' text */
1224     }
1225
1226     EnterCriticalSection(&xrender_cs);
1227     entry = glyphsetCache + physDev->xrender->cache_index;
1228
1229     for(idx = 0; idx < count; idx++) {
1230         if(glyphs[idx] >= entry->nrealized || entry->realized[glyphs[idx]] == FALSE) {
1231             UploadGlyph(physDev, glyphs[idx]);
1232         }
1233     }
1234
1235
1236     TRACE("Writing %s at %ld,%ld\n", debugstr_wn(wstr,count),
1237           physDev->org.x + x, physDev->org.y + y);
1238
1239     if(X11DRV_XRender_Installed) {
1240         wine_tsx11_lock();
1241         if(!deltas)
1242             pXRenderCompositeString16(gdi_display, render_op,
1243                                       physDev->xrender->tile_pict,
1244                                       physDev->xrender->pict,
1245                                       entry->font_format, entry->glyphset,
1246                                       0, 0, physDev->org.x + x, physDev->org.y + y,
1247                                       glyphs, count);
1248
1249         else {
1250             INT offset = 0, xoff = 0, yoff = 0;
1251             for(idx = 0; idx < count; idx++) {
1252                 pXRenderCompositeString16(gdi_display, render_op,
1253                                           physDev->xrender->tile_pict,
1254                                           physDev->xrender->pict,
1255                                           entry->font_format, entry->glyphset,
1256                                           0, 0, physDev->org.x + x + xoff,
1257                                           physDev->org.y + y + yoff,
1258                                           glyphs + idx, 1);
1259                 offset += INTERNAL_XWSTODS(dc, deltas[idx]);
1260                 xoff = offset * cosEsc;
1261                 yoff = offset * -sinEsc;
1262             }
1263         }
1264         wine_tsx11_unlock();
1265
1266         if (lf.lfUnderline || lf.lfStrikeOut) {
1267             int linePos;
1268             unsigned int lineWidth;
1269             UINT nMetricsSize = GetOutlineTextMetricsW(hdc, 0, NULL);
1270             OUTLINETEXTMETRICW* otm = HeapAlloc(GetProcessHeap(), 0, nMetricsSize);
1271             if (!otm) goto done;
1272
1273             GetOutlineTextMetricsW(hdc, nMetricsSize, otm);
1274
1275             wine_tsx11_lock();
1276             XSetForeground( gdi_display, physDev->gc, physDev->textPixel );
1277
1278             if (lf.lfUnderline) {
1279                 linePos = INTERNAL_YWSTODS(dc, otm->otmsUnderscorePosition);
1280                 lineWidth = INTERNAL_YWSTODS(dc, otm->otmsUnderscoreSize);
1281
1282                 XSetLineAttributes( gdi_display, physDev->gc, lineWidth,
1283                                     LineSolid, CapProjecting, JoinBevel );
1284                 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1285                            physDev->org.x + x, physDev->org.y + y - linePos,
1286                            physDev->org.x + x + width, physDev->org.y + y - linePos );
1287             }
1288
1289             if (lf.lfStrikeOut) { 
1290                 linePos = INTERNAL_YWSTODS(dc, otm->otmsStrikeoutPosition);
1291                 lineWidth = INTERNAL_YWSTODS(dc, otm->otmsStrikeoutSize);
1292
1293                 XSetLineAttributes( gdi_display, physDev->gc, lineWidth,
1294                                     LineSolid, CapProjecting, JoinBevel );
1295                 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1296                            physDev->org.x + x, physDev->org.y + y - linePos,
1297                            physDev->org.x + x + width, physDev->org.y + y - linePos );
1298             } 
1299             wine_tsx11_unlock();
1300             HeapFree(GetProcessHeap(), 0, otm);
1301         }
1302
1303     } else {
1304         INT offset = 0, xoff = 0, yoff = 0;
1305         wine_tsx11_lock();
1306         XSetForeground( gdi_display, physDev->gc, textPixel );
1307
1308         if(entry->aa == AA_None) {
1309             for(idx = 0; idx < count; idx++) {
1310                 SharpGlyphMono(physDev, physDev->org.x + x + xoff,
1311                                physDev->org.y + y + yoff,
1312                                entry->bitmaps[glyphs[idx]],
1313                                &entry->gis[glyphs[idx]]);
1314                 if(deltas) {
1315                     offset += INTERNAL_XWSTODS(dc, deltas[idx]);
1316                     xoff = offset * cosEsc;
1317                     yoff = offset * -sinEsc;
1318
1319                 } else {
1320                     xoff += entry->gis[glyphs[idx]].xOff;
1321                     yoff += entry->gis[glyphs[idx]].yOff;
1322                 }
1323             }
1324         } else if(dc->bitsPerPixel == 1) {
1325             for(idx = 0; idx < count; idx++) {
1326                 SharpGlyphGray(physDev, physDev->org.x + x + xoff,
1327                                physDev->org.y + y + yoff,
1328                                entry->bitmaps[glyphs[idx]],
1329                                &entry->gis[glyphs[idx]]);
1330                 if(deltas) {
1331                     offset += INTERNAL_XWSTODS(dc, deltas[idx]);
1332                     xoff = offset * cosEsc;
1333                     yoff = offset * -sinEsc;
1334
1335                 } else {
1336                     xoff += entry->gis[glyphs[idx]].xOff;
1337                     yoff += entry->gis[glyphs[idx]].yOff;
1338                 }
1339                     
1340             }
1341         } else {
1342             XImage *image;
1343             unsigned int w, h, dummy_uint;
1344             Window dummy_window;
1345             int dummy_int;
1346             int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1347             RECT extents = {0, 0, 0, 0};
1348             POINT cur = {0, 0};
1349             
1350             
1351             XGetGeometry(gdi_display, physDev->drawable, &dummy_window, &dummy_int, &dummy_int,
1352                          &w, &h, &dummy_uint, &dummy_uint);
1353             TRACE("drawable %dx%d\n", w, h);
1354
1355             for(idx = 0; idx < count; idx++) {
1356                 if(extents.left > cur.x - entry->gis[glyphs[idx]].x)
1357                     extents.left = cur.x - entry->gis[glyphs[idx]].x;
1358                 if(extents.top > cur.y - entry->gis[glyphs[idx]].y)
1359                     extents.top = cur.y - entry->gis[glyphs[idx]].y;
1360                 if(extents.right < cur.x - entry->gis[glyphs[idx]].x + entry->gis[glyphs[idx]].width)
1361                     extents.right = cur.x - entry->gis[glyphs[idx]].x + entry->gis[glyphs[idx]].width;
1362                 if(extents.bottom < cur.y - entry->gis[glyphs[idx]].y + entry->gis[glyphs[idx]].height)
1363                     extents.bottom = cur.y - entry->gis[glyphs[idx]].y + entry->gis[glyphs[idx]].height;
1364                 if(deltas) {
1365                     offset += INTERNAL_XWSTODS(dc, deltas[idx]);
1366                     cur.x = offset * cosEsc;
1367                     cur.y = offset * -sinEsc;
1368                 } else {
1369                     cur.x += entry->gis[glyphs[idx]].xOff;
1370                     cur.y += entry->gis[glyphs[idx]].yOff;
1371                 }
1372             }
1373             TRACE("glyph extents %ld,%ld - %ld,%ld drawable x,y %ld,%ld\n", extents.left, extents.top,
1374                   extents.right, extents.bottom, physDev->org.x + x, physDev->org.y + y);
1375
1376             if(physDev->org.x + x + extents.left >= 0) {
1377                 image_x = physDev->org.x + x + extents.left;
1378                 image_off_x = 0;
1379             } else {
1380                 image_x = 0;
1381                 image_off_x = physDev->org.x + x + extents.left;
1382             }
1383             if(physDev->org.y + y + extents.top >= 0) {
1384                 image_y = physDev->org.y + y + extents.top;
1385                 image_off_y = 0;
1386             } else {
1387                 image_y = 0;
1388                 image_off_y = physDev->org.y + y + extents.top;
1389             }
1390             if(physDev->org.x + x + extents.right < w)
1391                 image_w = physDev->org.x + x + extents.right - image_x;
1392             else
1393                 image_w = w - image_x;
1394             if(physDev->org.y + y + extents.bottom < h)
1395                 image_h = physDev->org.y + y + extents.bottom - image_y;
1396             else
1397                 image_h = h - image_y;
1398
1399             if(image_w <= 0 || image_h <= 0) goto no_image;
1400
1401             X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1402             image = XGetImage(gdi_display, physDev->drawable,
1403                               image_x, image_y, image_w, image_h,
1404                               AllPlanes, ZPixmap);
1405             X11DRV_check_error();
1406
1407             TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1408                   gdi_display, (int)physDev->drawable, image_x, image_y,
1409                   image_w, image_h, AllPlanes, ZPixmap,
1410                   dc->bitsPerPixel, image);
1411             if(!image) {
1412                 Pixmap xpm = XCreatePixmap(gdi_display, physDev->drawable, image_w, image_h,
1413                                            dc->bitsPerPixel);
1414                 GC gc;
1415                 XGCValues gcv;
1416
1417                 gcv.graphics_exposures = False;
1418                 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1419                 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1420                           image_w, image_h, 0, 0);
1421                 XFreeGC(gdi_display, gc);
1422                 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1423                 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1424                                   ZPixmap);
1425                 X11DRV_check_error();
1426                 XFreePixmap(gdi_display, xpm);
1427             }
1428             if(!image) goto no_image;
1429
1430             image->red_mask = visual->red_mask;
1431             image->green_mask = visual->green_mask;
1432             image->blue_mask = visual->blue_mask;
1433
1434             offset = xoff = yoff = 0;
1435             for(idx = 0; idx < count; idx++) {
1436                 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1437                                 yoff + image_off_y - extents.top,
1438                                 entry->bitmaps[glyphs[idx]],
1439                                 &entry->gis[glyphs[idx]],
1440                                 dc->textColor);
1441                 if(deltas) {
1442                     offset += INTERNAL_XWSTODS(dc, deltas[idx]);
1443                     xoff = offset * cosEsc;
1444                     yoff = offset * -sinEsc;
1445                 } else {
1446                     xoff += entry->gis[glyphs[idx]].xOff;
1447                     yoff += entry->gis[glyphs[idx]].yOff;
1448                 }
1449                     
1450             }
1451             XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1452                       image_x, image_y, image_w, image_h);
1453             XDestroyImage(image);
1454         }
1455     no_image:
1456         wine_tsx11_unlock();
1457     }
1458     LeaveCriticalSection(&xrender_cs);
1459
1460     if(deltas && deltas != lpDx)
1461         HeapFree(GetProcessHeap(), 0, deltas);
1462
1463     if (flags & ETO_CLIPPED)
1464         RestoreVisRgn16( HDC_16(hdc) );
1465
1466     retv = TRUE;
1467
1468 done:
1469     X11DRV_UnlockDIBSection( physDev, TRUE );
1470     if(glyphs != wstr) HeapFree(GetProcessHeap(), 0, glyphs);
1471     return retv;
1472 }
1473
1474 #else /* HAVE_X11_EXTENSIONS_XRENDER_H */
1475
1476 void X11DRV_XRender_Init(void)
1477 {
1478     TRACE("XRender support not compiled in.\n");
1479     return;
1480 }
1481
1482 void X11DRV_XRender_Finalize(void)
1483 {
1484 }
1485
1486 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1487 {
1488   assert(0);
1489   return FALSE;
1490 }
1491
1492 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1493 {
1494   assert(0);
1495   return;
1496 }
1497
1498 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1499                                 const RECT *lprect, LPCWSTR wstr, UINT count,
1500                                 const INT *lpDx )
1501 {
1502   assert(0);
1503   return FALSE;
1504 }
1505
1506 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1507 {
1508   assert(0);
1509   return;
1510 }
1511
1512 #endif /* HAVE_X11_EXTENSIONS_XRENDER_H */