Implementation of underline and strikeout text in xrender.
[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 "ts_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   glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
338                               glyphsetCache,
339                               (glyphsetCacheSize + INIT_CACHE_SIZE)
340                               * sizeof(*glyphsetCache));
341   for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
342       i++) {
343     glyphsetCache[i].next = i + 1;
344     glyphsetCache[i].count = -1;
345   }
346   glyphsetCache[i-1].next = -1;
347   glyphsetCacheSize += INIT_CACHE_SIZE;
348
349   lastfree = glyphsetCache[best].next;
350   glyphsetCache[best].count = 1;
351   glyphsetCache[best].next = mru;
352   mru = best;
353   TRACE("new free cache slot at %d\n", mru);
354   return mru;
355 }
356
357 static int GetCacheEntry(LFANDSIZE *plfsz)
358 {
359     XRenderPictFormat pf;
360     int ret;
361     gsCacheEntry *entry;
362
363     if((ret = LookupEntry(plfsz)) != -1) return ret;
364
365     ret = AllocEntry();
366     entry = glyphsetCache + ret;
367     entry->lfsz = *plfsz;
368     assert(entry->nrealized == 0);
369
370     if(antialias)
371         entry->aa = AA_Grey;
372     else
373         entry->aa = AA_None;
374
375     if(X11DRV_XRender_Installed) {
376         switch(entry->aa) {
377         case AA_Grey:
378             pf.depth = 8;
379             pf.direct.alphaMask = 0xff;
380             break;
381
382         default:
383             ERR("aa = %d - not implemented\n", entry->aa);
384         case AA_None:
385             pf.depth = 1;
386             pf.direct.alphaMask = 1;
387             break;
388         }
389
390         pf.type = PictTypeDirect;
391         pf.direct.alpha = 0;
392
393         wine_tsx11_lock();
394         entry->font_format = pXRenderFindFormat(gdi_display,
395                                                 PictFormatType |
396                                                 PictFormatDepth |
397                                                 PictFormatAlpha |
398                                                 PictFormatAlphaMask,
399                                                 &pf, 0);
400
401         entry->glyphset = pXRenderCreateGlyphSet(gdi_display, entry->font_format);
402         wine_tsx11_unlock();
403     }
404     return ret;
405 }
406
407 static void dec_ref_cache(int index)
408 {
409     assert(index >= 0);
410     TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
411     assert(glyphsetCache[index].count > 0);
412     glyphsetCache[index].count--;
413 }
414
415 static void lfsz_calc_hash(LFANDSIZE *plfsz)
416 {
417   DWORD hash = 0, *ptr;
418   int i;
419
420   for(ptr = (DWORD*)&plfsz->xform; ptr < (DWORD*)(&plfsz->xform + 1); ptr++)
421     hash ^= *ptr;
422   for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
423     hash ^= *ptr;
424   for(i = 0, ptr = (DWORD*)&plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
425     WCHAR *pwc = (WCHAR *)ptr;
426     if(!*pwc) break;
427     hash ^= *ptr;
428     pwc++;
429     if(!*pwc) break;
430   }
431   plfsz->hash = hash;
432   return;
433 }
434
435 /***********************************************************************
436  *   X11DRV_XRender_Finalize
437  */
438 void X11DRV_XRender_Finalize(void)
439 {
440     int i;
441
442     EnterCriticalSection(&xrender_cs);
443     for(i = mru; i >= 0; i = glyphsetCache[i].next)
444         FreeEntry(i);
445     LeaveCriticalSection(&xrender_cs);
446 }
447
448
449 /***********************************************************************
450  *   X11DRV_XRender_SelectFont
451  */
452 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
453 {
454     LFANDSIZE lfsz;
455
456     GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
457     TRACE("h=%ld w=%ld weight=%ld it=%d charset=%d name=%s\n",
458           lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
459           lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
460     lfsz.xform = physDev->dc->xformWorld2Vport;
461     lfsz_calc_hash(&lfsz);
462
463     EnterCriticalSection(&xrender_cs);
464     if(!physDev->xrender) {
465         physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
466                                      sizeof(*physDev->xrender));
467         physDev->xrender->cache_index = -1;
468     }
469     else if(physDev->xrender->cache_index != -1)
470         dec_ref_cache(physDev->xrender->cache_index);
471     physDev->xrender->cache_index = GetCacheEntry(&lfsz);
472     LeaveCriticalSection(&xrender_cs);
473     return 0;
474 }
475
476 /***********************************************************************
477  *   X11DRV_XRender_DeleteDC
478  */
479 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
480 {
481     wine_tsx11_lock();
482     if(physDev->xrender->tile_pict)
483         pXRenderFreePicture(gdi_display, physDev->xrender->tile_pict);
484
485     if(physDev->xrender->tile_xpm)
486         XFreePixmap(gdi_display, physDev->xrender->tile_xpm);
487
488     if(physDev->xrender->pict) {
489         TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->dc);
490         pXRenderFreePicture(gdi_display, physDev->xrender->pict);
491     }
492     wine_tsx11_unlock();
493
494     EnterCriticalSection(&xrender_cs);
495     if(physDev->xrender->cache_index != -1)
496         dec_ref_cache(physDev->xrender->cache_index);
497     LeaveCriticalSection(&xrender_cs);
498
499     HeapFree(GetProcessHeap(), 0, physDev->xrender);
500     physDev->xrender = NULL;
501     return;
502 }
503
504 /***********************************************************************
505  *   X11DRV_XRender_UpdateDrawable
506  *
507  * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
508  * It deletes the pict when the drawable changes.
509  */
510 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
511 {
512     if(physDev->xrender->pict) {
513         TRACE("freeing pict %08lx from dc %p drawable %08lx\n", physDev->xrender->pict,
514               physDev->dc, physDev->drawable);
515         wine_tsx11_lock();
516         XFlush(gdi_display);
517         pXRenderFreePicture(gdi_display, physDev->xrender->pict);
518         wine_tsx11_unlock();
519     }
520     physDev->xrender->pict = 0;
521     return;
522 }
523
524 /************************************************************************
525  *   UploadGlyph
526  *
527  * Helper to ExtTextOut.  Must be called inside xrender_cs
528  */
529 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph)
530 {
531     int buflen;
532     char *buf;
533     Glyph gid;
534     GLYPHMETRICS gm;
535     XGlyphInfo gi;
536     gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
537     UINT ggo_format = GGO_GLYPH_INDEX;
538
539     if(entry->nrealized <= glyph) {
540         entry->nrealized = (glyph / 128 + 1) * 128;
541         entry->realized = HeapReAlloc(GetProcessHeap(),
542                                       HEAP_ZERO_MEMORY,
543                                       entry->realized,
544                                       entry->nrealized * sizeof(BOOL));
545         if(entry->glyphset == 0) {
546           entry->bitmaps = HeapReAlloc(GetProcessHeap(),
547                                       HEAP_ZERO_MEMORY,
548                                       entry->bitmaps,
549                                       entry->nrealized * sizeof(entry->bitmaps[0]));
550           entry->gis = HeapReAlloc(GetProcessHeap(),
551                                    HEAP_ZERO_MEMORY,
552                                    entry->gis,
553                                    entry->nrealized * sizeof(entry->gis[0]));
554         }
555     }
556
557     switch(entry->aa) {
558     case AA_Grey:
559         ggo_format |= WINE_GGO_GRAY16_BITMAP;
560         break;
561
562     default:
563         ERR("aa = %d - not implemented\n", entry->aa);
564     case AA_None:
565         ggo_format |= GGO_BITMAP;
566         break;
567     }
568
569     buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
570                               NULL);
571     if(buflen == GDI_ERROR) {
572         LeaveCriticalSection(&xrender_cs);
573         return FALSE;
574     }
575
576     entry->realized[glyph] = TRUE;
577
578     buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
579     GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, NULL);
580
581     TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%ld,%ld\n",
582           buflen,
583           gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
584           gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
585
586     gi.width = gm.gmBlackBoxX;
587     gi.height = gm.gmBlackBoxY;
588     gi.x = -gm.gmptGlyphOrigin.x;
589     gi.y = gm.gmptGlyphOrigin.y;
590     gi.xOff = gm.gmCellIncX;
591     gi.yOff = gm.gmCellIncY;
592
593     if(TRACE_ON(xrender)) {
594         int pitch, i, j;
595         char output[300];
596         unsigned char *line;
597
598         if(entry->aa == AA_None) {
599             pitch = ((gi.width + 31) / 32) * 4;
600             for(i = 0; i < gi.height; i++) {
601                 line = buf + i * pitch;
602                 output[0] = '\0';
603                 for(j = 0; j < pitch * 8; j++) {
604                     strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
605                 }
606                 strcat(output, "\n");
607                 TRACE(output);
608             }
609         } else {
610             char blks[] = " .:;!o*#";
611             char str[2];
612
613             str[1] = '\0';
614             pitch = ((gi.width + 3) / 4) * 4;
615             for(i = 0; i < gi.height; i++) {
616                 line = buf + i * pitch;
617                 output[0] = '\0';
618                 for(j = 0; j < pitch; j++) {
619                     str[0] = blks[line[j] >> 5];
620                     strcat(output, str);
621                 }
622                 strcat(output, "\n");
623                 TRACE(output);
624             }
625         }
626     }
627
628     if(entry->glyphset) {
629         if(entry->aa == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
630             unsigned char *byte = buf, c;
631             int i = buflen;
632
633             while(i--) {
634                 c = *byte;
635
636                 /* magic to flip bit order */
637                 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
638                 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
639                 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
640
641                 *byte++ = c;
642             }
643         }
644         gid = glyph;
645         wine_tsx11_lock();
646         pXRenderAddGlyphs(gdi_display, entry->glyphset, &gid, &gi, 1,
647                           buf, buflen);
648         wine_tsx11_unlock();
649         HeapFree(GetProcessHeap(), 0, buf);
650     } else {
651         entry->bitmaps[glyph] = buf;
652         memcpy(&entry->gis[glyph], &gi, sizeof(gi));
653     }
654     return TRUE;
655 }
656
657 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
658                             void *bitmap, XGlyphInfo *gi)
659 {
660     unsigned char   *srcLine = bitmap, *src;
661     unsigned char   bits, bitsMask;
662     int             width = gi->width;
663     int             stride = ((width + 31) & ~31) >> 3;
664     int             height = gi->height;
665     int             w;
666     int             xspan, lenspan;
667
668     TRACE("%d, %d\n", x, y);
669     x -= gi->x;
670     y -= gi->y;
671     while (height--)
672     {
673         src = srcLine;
674         srcLine += stride;
675         w = width;
676         
677         bitsMask = 0x80;    /* FreeType is always MSB first */
678         bits = *src++;
679         
680         xspan = x;
681         while (w)
682         {
683             if (bits & bitsMask)
684             {
685                 lenspan = 0;
686                 do
687                 {
688                     lenspan++;
689                     if (lenspan == w)
690                         break;
691                     bitsMask = bitsMask >> 1;
692                     if (!bitsMask)
693                     {
694                         bits = *src++;
695                         bitsMask = 0x80;
696                     }
697                 } while (bits & bitsMask);
698                 XFillRectangle (gdi_display, physDev->drawable, 
699                                 physDev->gc, xspan, y, lenspan, 1);
700                 xspan += lenspan;
701                 w -= lenspan;
702             }
703             else
704             {
705                 do
706                 {
707                     w--;
708                     xspan++;
709                     if (!w)
710                         break;
711                     bitsMask = bitsMask >> 1;
712                     if (!bitsMask)
713                     {
714                         bits = *src++;
715                         bitsMask = 0x80;
716                     }
717                 } while (!(bits & bitsMask));
718             }
719         }
720         y++;
721     }
722 }
723
724 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
725                             void *bitmap, XGlyphInfo *gi)
726 {
727     unsigned char   *srcLine = bitmap, *src, bits;
728     int             width = gi->width;
729     int             stride = ((width + 3) & ~3);
730     int             height = gi->height;
731     int             w;
732     int             xspan, lenspan;
733
734     x -= gi->x;
735     y -= gi->y;
736     while (height--)
737     {
738         src = srcLine;
739         srcLine += stride;
740         w = width;
741         
742         bits = *src++;
743         xspan = x;
744         while (w)
745         {
746             if (bits >= 0x80)
747             {
748                 lenspan = 0;
749                 do
750                 {
751                     lenspan++;
752                     if (lenspan == w)
753                         break;
754                     bits = *src++;
755                 } while (bits >= 0x80);
756                 XFillRectangle (gdi_display, physDev->drawable, 
757                                 physDev->gc, xspan, y, lenspan, 1);
758                 xspan += lenspan;
759                 w -= lenspan;
760             }
761             else
762             {
763                 do
764                 {
765                     w--;
766                     xspan++;
767                     if (!w)
768                         break;
769                     bits = *src++;
770                 } while (bits < 0x80);
771             }
772         }
773         y++;
774     }
775 }
776
777
778 static void ExamineBitfield (DWORD mask, int *shift, int *len)
779 {
780     int s, l;
781
782     s = 0;
783     while ((mask & 1) == 0)
784     {
785         mask >>= 1;
786         s++;
787     }
788     l = 0;
789     while ((mask & 1) == 1)
790     {
791         mask >>= 1;
792         l++;
793     }
794     *shift = s;
795     *len = l;
796 }
797
798 static DWORD GetField (DWORD pixel, int shift, int len)
799 {
800     pixel = pixel & (((1 << (len)) - 1) << shift);
801     pixel = pixel << (32 - (shift + len)) >> 24;
802     while (len < 8)
803     {
804         pixel |= (pixel >> len);
805         len <<= 1;
806     }
807     return pixel;
808 }
809
810
811 static DWORD PutField (DWORD pixel, int shift, int len)
812 {
813     shift = shift - (8 - len);
814     if (len <= 8)
815         pixel &= (((1 << len) - 1) << (8 - len));
816     if (shift < 0)
817         pixel >>= -shift;
818     else
819         pixel <<= shift;
820     return pixel;
821 }
822
823 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
824                             COLORREF color)
825 {
826     int             r_shift, r_len;
827     int             g_shift, g_len;
828     int             b_shift, b_len;
829     BYTE            *maskLine, *mask, m;
830     int             maskStride;
831     DWORD           pixel;
832     int             width, height;
833     int             w, tx;
834     BYTE            src_r, src_g, src_b;
835
836     src_r = GetRValue(color);
837     src_g = GetGValue(color);
838     src_b = GetBValue(color);
839
840     x -= gi->x;
841     y -= gi->y;
842     width = gi->width;
843     height = gi->height;
844
845     maskLine = (unsigned char *) bitmap;
846     maskStride = (width + 3) & ~3;
847
848     ExamineBitfield (image->red_mask, &r_shift, &r_len);
849     ExamineBitfield (image->green_mask, &g_shift, &g_len);
850     ExamineBitfield (image->blue_mask, &b_shift, &b_len);
851     for(; height--; y++)
852     {
853         mask = maskLine;
854         maskLine += maskStride;
855         w = width;
856         tx = x;
857
858         if(y < 0) continue;
859         if(y >= image->height) break;
860
861         for(; w--; tx++)
862         {
863             if(tx >= image->width) break;
864
865             m = *mask++;
866             if(tx < 0) continue;
867
868             if (m == 0xff)
869             {
870                 pixel = (PutField ((src_r), r_shift, r_len) |
871                          PutField ((src_g), g_shift, g_len) |
872                          PutField ((src_b), b_shift, b_len));
873                 XPutPixel (image, tx, y, pixel);
874             }
875             else if (m)
876             {
877                 BYTE r, g, b;
878
879                 pixel = XGetPixel (image, tx, y);
880
881                 r = GetField(pixel, r_shift, r_len);
882                 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
883                 g = GetField(pixel, g_shift, g_len);
884                 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
885                 b = GetField(pixel, b_shift, b_len);
886                 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
887
888                 pixel = (PutField (r, r_shift, r_len) |
889                          PutField (g, g_shift, g_len) |
890                          PutField (b, b_shift, b_len));
891                 XPutPixel (image, tx, y, pixel);
892             }
893         }
894     }
895 }
896
897 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
898 {
899     return 1;
900 }
901
902 /***********************************************************************
903  *   X11DRV_XRender_ExtTextOut
904  */
905 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
906                                 const RECT *lprect, LPCWSTR wstr, UINT count,
907                                 const INT *lpDx )
908 {
909     XRenderColor col;
910     int idx;
911     TEXTMETRICW tm;
912     RGNDATA *data;
913     SIZE sz;
914     RECT rc;
915     BOOL done_extents = FALSE;
916     INT width, xwidth, ywidth;
917     double cosEsc, sinEsc;
918     XGCValues xgcval;
919     LOGFONTW lf;
920     int render_op = PictOpOver;
921     WORD *glyphs;
922     POINT pt;
923     gsCacheEntry *entry;
924     BOOL retv = FALSE;
925     HDC hdc = physDev->hdc;
926     DC *dc = physDev->dc;
927     int textPixel, backgroundPixel;
928     INT *deltas = NULL;
929     INT char_extra;
930
931     TRACE("%p, %d, %d, %08x, %p, %s, %d, %p)\n", hdc, x, y, flags,
932           lprect, debugstr_wn(wstr, count), count, lpDx);
933
934     if(flags & ETO_GLYPH_INDEX)
935         glyphs = (LPWORD)wstr;
936     else {
937         glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
938         GetGlyphIndicesW(hdc, wstr, count, glyphs, 0);
939     }
940
941     if(lprect)
942       TRACE("rect: %ld,%ld - %ld,%ld\n", lprect->left, lprect->top, lprect->right,
943             lprect->bottom);
944     TRACE("align = %x bkmode = %x mapmode = %x\n", dc->textAlign, GetBkMode(hdc), dc->MapMode);
945
946     if(dc->textAlign & TA_UPDATECP) {
947         x = dc->CursPosX;
948         y = dc->CursPosY;
949     }
950
951     GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
952     if(lf.lfEscapement != 0) {
953         cosEsc = cos(lf.lfEscapement * M_PI / 1800);
954         sinEsc = sin(lf.lfEscapement * M_PI / 1800);
955     } else {
956         cosEsc = 1;
957         sinEsc = 0;
958     }
959
960     if(flags & (ETO_CLIPPED | ETO_OPAQUE)) {
961         if(!lprect) {
962             if(flags & ETO_CLIPPED) return FALSE;
963                 GetTextExtentPointI(hdc, glyphs, count, &sz);
964                 done_extents = TRUE;
965                 rc.left = x;
966                 rc.top = y;
967                 rc.right = x + sz.cx;
968                 rc.bottom = y + sz.cy;
969         } else {
970             rc = *lprect;
971         }
972
973         LPtoDP(physDev->hdc, (POINT*)&rc, 2);
974
975         if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
976         if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
977     }
978
979     xgcval.function = GXcopy;
980     xgcval.background = physDev->backgroundPixel;
981     xgcval.fill_style = FillSolid;
982     TSXChangeGC( gdi_display, physDev->gc,
983                  GCFunction | GCBackground | GCFillStyle, &xgcval );
984
985     X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
986
987     if(dc->bitsPerPixel == 1) {
988         if((dc->textColor & 0xffffff) == 0) {
989             textPixel = 0;
990             backgroundPixel = 1;
991         } else {
992             textPixel = 1;
993             backgroundPixel = 0;
994         }
995     } else {
996         textPixel = physDev->textPixel;
997         backgroundPixel = physDev->backgroundPixel;
998     }
999
1000     if(flags & ETO_OPAQUE) {
1001         TSXSetForeground( gdi_display, physDev->gc, backgroundPixel );
1002         TSXFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1003                           physDev->org.x + rc.left, physDev->org.y + rc.top,
1004                           rc.right - rc.left, rc.bottom - rc.top );
1005     }
1006
1007     if(count == 0) {
1008         retv =  TRUE;
1009         goto done;
1010     }
1011
1012     pt.x = x;
1013     pt.y = y;
1014     LPtoDP(physDev->hdc, &pt, 1);
1015     x = pt.x;
1016     y = pt.y;
1017
1018     TRACE("real x,y %d,%d\n", x, y);
1019
1020     if((char_extra = GetTextCharacterExtra(physDev->hdc)) != 0) {
1021         INT i;
1022         SIZE tmpsz;
1023         deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
1024         for(i = 0; i < count; i++) {
1025             deltas[i] = char_extra;
1026             if(lpDx)
1027                 deltas[i] += lpDx[i];
1028             else {
1029                 GetTextExtentPointI(hdc, glyphs + i, 1, &tmpsz);
1030                 deltas[i] += tmpsz.cx;
1031             }
1032         }
1033     } else if(lpDx)
1034         deltas = (INT*)lpDx;
1035
1036     if(deltas) {
1037         width = 0;
1038         for(idx = 0; idx < count; idx++)
1039             width += deltas[idx];
1040     } else {
1041         if(!done_extents) {
1042             GetTextExtentPointI(hdc, glyphs, count, &sz);
1043             done_extents = TRUE;
1044         }
1045         width = sz.cx;
1046     }
1047     width = INTERNAL_XWSTODS(dc, width);
1048     xwidth = width * cosEsc;
1049     ywidth = width * sinEsc;
1050
1051     GetTextMetricsW(hdc, &tm);
1052
1053     tm.tmAscent = INTERNAL_YWSTODS(dc, tm.tmAscent);
1054     tm.tmDescent = INTERNAL_YWSTODS(dc, tm.tmDescent);
1055     switch( dc->textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER) ) {
1056     case TA_LEFT:
1057         if (dc->textAlign & TA_UPDATECP) {
1058             pt.x = x + xwidth;
1059             pt.y = y - ywidth;
1060             DPtoLP(physDev->hdc, &pt, 1);
1061             dc->CursPosX = pt.x;
1062             dc->CursPosY = pt.y;
1063         }
1064         break;
1065
1066     case TA_CENTER:
1067         x -= xwidth / 2;
1068         y += ywidth / 2;
1069         break;
1070
1071     case TA_RIGHT:
1072         x -= xwidth;
1073         y += ywidth;
1074         if (dc->textAlign & TA_UPDATECP) {
1075             pt.x = x;
1076             pt.y = y;
1077             DPtoLP(physDev->hdc, &pt, 1);
1078             dc->CursPosX = pt.x;
1079             dc->CursPosY = pt.y;
1080         }
1081         break;
1082     }
1083
1084     switch( dc->textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE) ) {
1085     case TA_TOP:
1086         y += tm.tmAscent * cosEsc;
1087         x += tm.tmAscent * sinEsc;
1088         break;
1089
1090     case TA_BOTTOM:
1091         y -= tm.tmDescent * cosEsc;
1092         x -= tm.tmDescent * sinEsc;
1093         break;
1094
1095     case TA_BASELINE:
1096         break;
1097     }
1098
1099     if (flags & ETO_CLIPPED)
1100     {
1101         SaveVisRgn16( HDC_16(hdc) );
1102         IntersectVisRect16( HDC_16(dc->hSelf), lprect->left, lprect->top, lprect->right, lprect->bottom );
1103     }
1104
1105     if(X11DRV_XRender_Installed) {
1106         if(!physDev->xrender->pict) {
1107             XRenderPictureAttributes pa;
1108             pa.subwindow_mode = IncludeInferiors;
1109
1110             wine_tsx11_lock();
1111             physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1112                                                            physDev->drawable,
1113                                                            (dc->bitsPerPixel == 1) ?
1114                                                            mono_format : screen_format,
1115                                                            CPSubwindowMode, &pa);
1116             wine_tsx11_unlock();
1117
1118             TRACE("allocing pict = %lx dc = %p drawable = %08lx\n", physDev->xrender->pict, dc, physDev->drawable);
1119         } else {
1120             TRACE("using existing pict = %lx dc = %p drawable = %08lx\n", physDev->xrender->pict, dc, physDev->drawable);
1121         }
1122
1123         if ((data = X11DRV_GetRegionData( dc->hGCClipRgn, 0 )))
1124         {
1125             wine_tsx11_lock();
1126             pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1127                                               physDev->org.x, physDev->org.y,
1128                                               (XRectangle *)data->Buffer, data->rdh.nCount );
1129             wine_tsx11_unlock();
1130             HeapFree( GetProcessHeap(), 0, data );
1131         }
1132     }
1133
1134     if(GetBkMode(hdc) != TRANSPARENT) {
1135         if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE))) {
1136             if(!(flags & ETO_OPAQUE) || x < rc.left || x + width >= rc.right ||
1137                y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom) {
1138                 TSXSetForeground( gdi_display, physDev->gc, backgroundPixel );
1139                 TSXFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1140                                   physDev->org.x + x, physDev->org.y + y - tm.tmAscent,
1141                                   width, tm.tmAscent + tm.tmDescent );
1142             }
1143         }
1144     }
1145
1146     if(X11DRV_XRender_Installed) {
1147         /* Create a 1x1 pixmap to tile over the font mask */
1148         if(!physDev->xrender->tile_xpm) {
1149             XRenderPictureAttributes pa;
1150
1151             XRenderPictFormat *format = (dc->bitsPerPixel == 1) ? mono_format : screen_format;
1152             wine_tsx11_lock();
1153             physDev->xrender->tile_xpm = XCreatePixmap(gdi_display,
1154                                                        physDev->drawable,
1155                                                        1, 1,
1156                                                        format->depth);
1157             pa.repeat = True;
1158             physDev->xrender->tile_pict = pXRenderCreatePicture(gdi_display,
1159                                                                 physDev->xrender->tile_xpm,
1160                                                                 format,
1161                                                                 CPRepeat, &pa);
1162             wine_tsx11_unlock();
1163             TRACE("Created pixmap of depth %d\n", format->depth);
1164             /* init lastTextColor to something different from dc->textColor */
1165             physDev->xrender->lastTextColor = ~dc->textColor;
1166
1167         }
1168
1169         if(dc->textColor != physDev->xrender->lastTextColor) {
1170             if(dc->bitsPerPixel != 1) {
1171               /* Map 0 -- 0xff onto 0 -- 0xffff */
1172                 col.red = GetRValue(dc->textColor);
1173                 col.red |= col.red << 8;
1174                 col.green = GetGValue(dc->textColor);
1175                 col.green |= col.green << 8;
1176                 col.blue = GetBValue(dc->textColor);
1177                 col.blue |= col.blue << 8;
1178                 col.alpha = 0x0;
1179             } else { /* for a 1bpp bitmap we always need a 1 in the tile */
1180                 col.red = col.green = col.blue = 0;
1181                 col.alpha = 0xffff;
1182             }
1183             wine_tsx11_lock();
1184             pXRenderFillRectangle(gdi_display, PictOpSrc,
1185                                   physDev->xrender->tile_pict,
1186                                   &col, 0, 0, 1, 1);
1187             wine_tsx11_unlock();
1188             physDev->xrender->lastTextColor = dc->textColor;
1189         }
1190
1191         /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1192          */
1193         if((dc->bitsPerPixel == 1) && (textPixel == 0))
1194             render_op = PictOpOutReverse; /* This gives us 'black' text */
1195     }
1196
1197     EnterCriticalSection(&xrender_cs);
1198     entry = glyphsetCache + physDev->xrender->cache_index;
1199
1200     for(idx = 0; idx < count; idx++) {
1201         if(glyphs[idx] >= entry->nrealized || entry->realized[glyphs[idx]] == FALSE) {
1202             UploadGlyph(physDev, glyphs[idx]);
1203         }
1204     }
1205
1206
1207     TRACE("Writing %s at %ld,%ld\n", debugstr_wn(wstr,count),
1208           physDev->org.x + x, physDev->org.y + y);
1209
1210     if(X11DRV_XRender_Installed) {
1211         wine_tsx11_lock();
1212         if(!deltas)
1213             pXRenderCompositeString16(gdi_display, render_op,
1214                                       physDev->xrender->tile_pict,
1215                                       physDev->xrender->pict,
1216                                       entry->font_format, entry->glyphset,
1217                                       0, 0, physDev->org.x + x, physDev->org.y + y,
1218                                       glyphs, count);
1219
1220         else {
1221             INT offset = 0, xoff = 0, yoff = 0;
1222             for(idx = 0; idx < count; idx++) {
1223                 pXRenderCompositeString16(gdi_display, render_op,
1224                                           physDev->xrender->tile_pict,
1225                                           physDev->xrender->pict,
1226                                           entry->font_format, entry->glyphset,
1227                                           0, 0, physDev->org.x + x + xoff,
1228                                           physDev->org.y + y + yoff,
1229                                           glyphs + idx, 1);
1230                 offset += INTERNAL_XWSTODS(dc, deltas[idx]);
1231                 xoff = offset * cosEsc;
1232                 yoff = offset * -sinEsc;
1233             }
1234         }
1235         wine_tsx11_unlock();
1236
1237         if (lf.lfUnderline || lf.lfStrikeOut) {
1238             int linePos;
1239             unsigned int lineWidth;
1240             UINT nMetricsSize = GetOutlineTextMetricsW(hdc, 0, NULL);
1241             OUTLINETEXTMETRICW* otm = HeapAlloc(GetProcessHeap(), 0, nMetricsSize);
1242             if (!otm) goto done;
1243
1244             GetOutlineTextMetricsW(hdc, nMetricsSize, otm);
1245
1246             wine_tsx11_lock();
1247             XSetForeground( gdi_display, physDev->gc, physDev->textPixel );
1248
1249             if (lf.lfUnderline) {
1250                 linePos = INTERNAL_YWSTODS(dc, otm->otmsUnderscorePosition);
1251                 lineWidth = INTERNAL_YWSTODS(dc, otm->otmsUnderscoreSize);
1252
1253                 XSetLineAttributes( gdi_display, physDev->gc, lineWidth,
1254                                     LineSolid, CapProjecting, JoinBevel );
1255                 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1256                            physDev->org.x + x, physDev->org.y + y - linePos,
1257                            physDev->org.x + x + width, physDev->org.y + y - linePos );
1258             }
1259
1260             if (lf.lfStrikeOut) { 
1261                 linePos = INTERNAL_YWSTODS(dc, otm->otmsStrikeoutPosition);
1262                 lineWidth = INTERNAL_YWSTODS(dc, otm->otmsStrikeoutSize);
1263
1264                 XSetLineAttributes( gdi_display, physDev->gc, lineWidth,
1265                                     LineSolid, CapProjecting, JoinBevel );
1266                 XDrawLine( gdi_display, physDev->drawable, physDev->gc,
1267                            physDev->org.x + x, physDev->org.y + y - linePos,
1268                            physDev->org.x + x + width, physDev->org.y + y - linePos );
1269             } 
1270             wine_tsx11_unlock();
1271             HeapFree(GetProcessHeap(), 0, otm);
1272         }
1273
1274     } else {
1275         INT offset = 0, xoff = 0, yoff = 0;
1276         wine_tsx11_lock();
1277         XSetForeground( gdi_display, physDev->gc, textPixel );
1278
1279         if(entry->aa == AA_None) {
1280             for(idx = 0; idx < count; idx++) {
1281                 SharpGlyphMono(physDev, physDev->org.x + x + xoff,
1282                                physDev->org.y + y + yoff,
1283                                entry->bitmaps[glyphs[idx]],
1284                                &entry->gis[glyphs[idx]]);
1285                 if(deltas) {
1286                     offset += INTERNAL_XWSTODS(dc, deltas[idx]);
1287                     xoff = offset * cosEsc;
1288                     yoff = offset * -sinEsc;
1289
1290                 } else {
1291                     xoff += entry->gis[glyphs[idx]].xOff;
1292                     yoff += entry->gis[glyphs[idx]].yOff;
1293                 }
1294             }
1295         } else if(dc->bitsPerPixel == 1) {
1296             for(idx = 0; idx < count; idx++) {
1297                 SharpGlyphGray(physDev, physDev->org.x + x + xoff,
1298                                physDev->org.y + y + yoff,
1299                                entry->bitmaps[glyphs[idx]],
1300                                &entry->gis[glyphs[idx]]);
1301                 if(deltas) {
1302                     offset += INTERNAL_XWSTODS(dc, deltas[idx]);
1303                     xoff = offset * cosEsc;
1304                     yoff = offset * -sinEsc;
1305
1306                 } else {
1307                     xoff += entry->gis[glyphs[idx]].xOff;
1308                     yoff += entry->gis[glyphs[idx]].yOff;
1309                 }
1310                     
1311             }
1312         } else {
1313             XImage *image;
1314             unsigned int w, h, dummy_uint;
1315             Window dummy_window;
1316             int dummy_int;
1317             int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1318             RECT extents = {0, 0, 0, 0};
1319             POINT cur = {0, 0};
1320             
1321             
1322             XGetGeometry(gdi_display, physDev->drawable, &dummy_window, &dummy_int, &dummy_int,
1323                          &w, &h, &dummy_uint, &dummy_uint);
1324             TRACE("drawable %dx%d\n", w, h);
1325
1326             for(idx = 0; idx < count; idx++) {
1327                 if(extents.left > cur.x - entry->gis[glyphs[idx]].x)
1328                     extents.left = cur.x - entry->gis[glyphs[idx]].x;
1329                 if(extents.top > cur.y - entry->gis[glyphs[idx]].y)
1330                     extents.top = cur.y - entry->gis[glyphs[idx]].y;
1331                 if(extents.right < cur.x - entry->gis[glyphs[idx]].x + entry->gis[glyphs[idx]].width)
1332                     extents.right = cur.x - entry->gis[glyphs[idx]].x + entry->gis[glyphs[idx]].width;
1333                 if(extents.bottom < cur.y - entry->gis[glyphs[idx]].y + entry->gis[glyphs[idx]].height)
1334                     extents.bottom = cur.y - entry->gis[glyphs[idx]].y + entry->gis[glyphs[idx]].height;
1335                 if(deltas) {
1336                     offset += INTERNAL_XWSTODS(dc, deltas[idx]);
1337                     cur.x = offset * cosEsc;
1338                     cur.y = offset * -sinEsc;
1339                 } else {
1340                     cur.x += entry->gis[glyphs[idx]].xOff;
1341                     cur.y += entry->gis[glyphs[idx]].yOff;
1342                 }
1343             }
1344             TRACE("glyph extents %ld,%ld - %ld,%ld drawable x,y %ld,%ld\n", extents.left, extents.top,
1345                   extents.right, extents.bottom, physDev->org.x + x, physDev->org.y + y);
1346
1347             if(physDev->org.x + x + extents.left >= 0) {
1348                 image_x = physDev->org.x + x + extents.left;
1349                 image_off_x = 0;
1350             } else {
1351                 image_x = 0;
1352                 image_off_x = physDev->org.x + x + extents.left;
1353             }
1354             if(physDev->org.y + y + extents.top >= 0) {
1355                 image_y = physDev->org.y + y + extents.top;
1356                 image_off_y = 0;
1357             } else {
1358                 image_y = 0;
1359                 image_off_y = physDev->org.y + y + extents.top;
1360             }
1361             if(physDev->org.x + x + extents.right < w)
1362                 image_w = physDev->org.x + x + extents.right - image_x;
1363             else
1364                 image_w = w - image_x;
1365             if(physDev->org.y + y + extents.bottom < h)
1366                 image_h = physDev->org.y + y + extents.bottom - image_y;
1367             else
1368                 image_h = h - image_y;
1369
1370             if(image_w <= 0 || image_h <= 0) goto no_image;
1371
1372             X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1373             image = XGetImage(gdi_display, physDev->drawable,
1374                               image_x, image_y, image_w, image_h,
1375                               AllPlanes, ZPixmap);
1376             X11DRV_check_error();
1377
1378             TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1379                   gdi_display, (int)physDev->drawable, image_x, image_y,
1380                   image_w, image_h, AllPlanes, ZPixmap,
1381                   dc->bitsPerPixel, image);
1382             if(!image) {
1383                 Pixmap xpm = XCreatePixmap(gdi_display, physDev->drawable, image_w, image_h,
1384                                            dc->bitsPerPixel);
1385                 GC gc;
1386                 XGCValues gcv;
1387
1388                 gcv.graphics_exposures = False;
1389                 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1390                 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1391                           image_w, image_h, 0, 0);
1392                 XFreeGC(gdi_display, gc);
1393                 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1394                 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1395                                   ZPixmap);
1396                 X11DRV_check_error();
1397                 XFreePixmap(gdi_display, xpm);
1398             }
1399             if(!image) goto no_image;
1400
1401             image->red_mask = visual->red_mask;
1402             image->green_mask = visual->green_mask;
1403             image->blue_mask = visual->blue_mask;
1404
1405             offset = xoff = yoff = 0;
1406             for(idx = 0; idx < count; idx++) {
1407                 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1408                                 yoff + image_off_y - extents.top,
1409                                 entry->bitmaps[glyphs[idx]],
1410                                 &entry->gis[glyphs[idx]],
1411                                 dc->textColor);
1412                 if(deltas) {
1413                     offset += INTERNAL_XWSTODS(dc, deltas[idx]);
1414                     xoff = offset * cosEsc;
1415                     yoff = offset * -sinEsc;
1416                 } else {
1417                     xoff += entry->gis[glyphs[idx]].xOff;
1418                     yoff += entry->gis[glyphs[idx]].yOff;
1419                 }
1420                     
1421             }
1422             XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1423                       image_x, image_y, image_w, image_h);
1424             XDestroyImage(image);
1425         }
1426     no_image:
1427         wine_tsx11_unlock();
1428     }
1429     LeaveCriticalSection(&xrender_cs);
1430
1431     if(deltas && deltas != lpDx)
1432         HeapFree(GetProcessHeap(), 0, deltas);
1433
1434     if (flags & ETO_CLIPPED)
1435         RestoreVisRgn16( HDC_16(hdc) );
1436
1437     retv = TRUE;
1438
1439 done:
1440     X11DRV_UnlockDIBSection( physDev, TRUE );
1441     if(glyphs != wstr) HeapFree(GetProcessHeap(), 0, glyphs);
1442     return retv;
1443 }
1444
1445 #else /* HAVE_X11_EXTENSIONS_XRENDER_H */
1446
1447 void X11DRV_XRender_Init(void)
1448 {
1449     TRACE("XRender support not compiled in.\n");
1450     return;
1451 }
1452
1453 void X11DRV_XRender_Finalize(void)
1454 {
1455 }
1456
1457 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1458 {
1459   assert(0);
1460   return FALSE;
1461 }
1462
1463 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1464 {
1465   assert(0);
1466   return;
1467 }
1468
1469 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1470                                 const RECT *lprect, LPCWSTR wstr, UINT count,
1471                                 const INT *lpDx )
1472 {
1473   assert(0);
1474   return FALSE;
1475 }
1476
1477 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1478 {
1479   assert(0);
1480   return;
1481 }
1482
1483 #endif /* HAVE_X11_EXTENSIONS_XRENDER_H */