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