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