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