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