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