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