winex11: Get rid of the unnecessary opengl debug channel.
[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                 strcat(output, "\n");
750                 TRACE(output);
751             }
752         } else {
753             static const char blks[] = " .:;!o*#";
754             char str[2];
755
756             str[1] = '\0';
757             pitch = ((gi.width + 3) / 4) * 4;
758             for(i = 0; i < gi.height; i++) {
759                 line = (unsigned char*) buf + i * pitch;
760                 output[0] = '\0';
761                 for(j = 0; j < pitch; j++) {
762                     str[0] = blks[line[j] >> 5];
763                     strcat(output, str);
764                 }
765                 strcat(output, "\n");
766                 TRACE(output);
767             }
768         }
769     }
770
771
772     if(formatEntry->glyphset) {
773         if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
774             unsigned char *byte = (unsigned char*) buf, c;
775             int i = buflen;
776
777             while(i--) {
778                 c = *byte;
779
780                 /* magic to flip bit order */
781                 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
782                 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
783                 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
784
785                 *byte++ = c;
786             }
787         }
788         gid = glyph;
789
790         /*
791           XRenderCompositeText seems to ignore 0x0 glyphs when
792           AA_None, which means we lose the advance width of glyphs
793           like the space.  We'll pretend that such glyphs are 1x1
794           bitmaps.
795         */
796
797         if(buflen == 0)
798             gi.width = gi.height = 1;
799
800         wine_tsx11_lock();
801         pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
802                           buflen ? buf : zero, buflen ? buflen : sizeof(zero));
803         wine_tsx11_unlock();
804         HeapFree(GetProcessHeap(), 0, buf);
805     } else {
806         formatEntry->bitmaps[glyph] = buf;
807     }
808
809     formatEntry->gis[glyph] = gi;
810
811     return TRUE;
812 }
813
814 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
815                             void *bitmap, XGlyphInfo *gi)
816 {
817     unsigned char   *srcLine = bitmap, *src;
818     unsigned char   bits, bitsMask;
819     int             width = gi->width;
820     int             stride = ((width + 31) & ~31) >> 3;
821     int             height = gi->height;
822     int             w;
823     int             xspan, lenspan;
824
825     TRACE("%d, %d\n", x, y);
826     x -= gi->x;
827     y -= gi->y;
828     while (height--)
829     {
830         src = srcLine;
831         srcLine += stride;
832         w = width;
833         
834         bitsMask = 0x80;    /* FreeType is always MSB first */
835         bits = *src++;
836         
837         xspan = x;
838         while (w)
839         {
840             if (bits & bitsMask)
841             {
842                 lenspan = 0;
843                 do
844                 {
845                     lenspan++;
846                     if (lenspan == w)
847                         break;
848                     bitsMask = bitsMask >> 1;
849                     if (!bitsMask)
850                     {
851                         bits = *src++;
852                         bitsMask = 0x80;
853                     }
854                 } while (bits & bitsMask);
855                 XFillRectangle (gdi_display, physDev->drawable, 
856                                 physDev->gc, xspan, y, lenspan, 1);
857                 xspan += lenspan;
858                 w -= lenspan;
859             }
860             else
861             {
862                 do
863                 {
864                     w--;
865                     xspan++;
866                     if (!w)
867                         break;
868                     bitsMask = bitsMask >> 1;
869                     if (!bitsMask)
870                     {
871                         bits = *src++;
872                         bitsMask = 0x80;
873                     }
874                 } while (!(bits & bitsMask));
875             }
876         }
877         y++;
878     }
879 }
880
881 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
882                             void *bitmap, XGlyphInfo *gi)
883 {
884     unsigned char   *srcLine = bitmap, *src, bits;
885     int             width = gi->width;
886     int             stride = ((width + 3) & ~3);
887     int             height = gi->height;
888     int             w;
889     int             xspan, lenspan;
890
891     x -= gi->x;
892     y -= gi->y;
893     while (height--)
894     {
895         src = srcLine;
896         srcLine += stride;
897         w = width;
898         
899         bits = *src++;
900         xspan = x;
901         while (w)
902         {
903             if (bits >= 0x80)
904             {
905                 lenspan = 0;
906                 do
907                 {
908                     lenspan++;
909                     if (lenspan == w)
910                         break;
911                     bits = *src++;
912                 } while (bits >= 0x80);
913                 XFillRectangle (gdi_display, physDev->drawable, 
914                                 physDev->gc, xspan, y, lenspan, 1);
915                 xspan += lenspan;
916                 w -= lenspan;
917             }
918             else
919             {
920                 do
921                 {
922                     w--;
923                     xspan++;
924                     if (!w)
925                         break;
926                     bits = *src++;
927                 } while (bits < 0x80);
928             }
929         }
930         y++;
931     }
932 }
933
934
935 static void ExamineBitfield (DWORD mask, int *shift, int *len)
936 {
937     int s, l;
938
939     s = 0;
940     while ((mask & 1) == 0)
941     {
942         mask >>= 1;
943         s++;
944     }
945     l = 0;
946     while ((mask & 1) == 1)
947     {
948         mask >>= 1;
949         l++;
950     }
951     *shift = s;
952     *len = l;
953 }
954
955 static DWORD GetField (DWORD pixel, int shift, int len)
956 {
957     pixel = pixel & (((1 << (len)) - 1) << shift);
958     pixel = pixel << (32 - (shift + len)) >> 24;
959     while (len < 8)
960     {
961         pixel |= (pixel >> len);
962         len <<= 1;
963     }
964     return pixel;
965 }
966
967
968 static DWORD PutField (DWORD pixel, int shift, int len)
969 {
970     shift = shift - (8 - len);
971     if (len <= 8)
972         pixel &= (((1 << len) - 1) << (8 - len));
973     if (shift < 0)
974         pixel >>= -shift;
975     else
976         pixel <<= shift;
977     return pixel;
978 }
979
980 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
981                             int color)
982 {
983     int             r_shift, r_len;
984     int             g_shift, g_len;
985     int             b_shift, b_len;
986     BYTE            *maskLine, *mask, m;
987     int             maskStride;
988     DWORD           pixel;
989     int             width, height;
990     int             w, tx;
991     BYTE            src_r, src_g, src_b;
992
993     x -= gi->x;
994     y -= gi->y;
995     width = gi->width;
996     height = gi->height;
997
998     maskLine = (unsigned char *) bitmap;
999     maskStride = (width + 3) & ~3;
1000
1001     ExamineBitfield (image->red_mask, &r_shift, &r_len);
1002     ExamineBitfield (image->green_mask, &g_shift, &g_len);
1003     ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1004
1005     src_r = GetField(color, r_shift, r_len);
1006     src_g = GetField(color, g_shift, g_len);
1007     src_b = GetField(color, b_shift, b_len);
1008     
1009     for(; height--; y++)
1010     {
1011         mask = maskLine;
1012         maskLine += maskStride;
1013         w = width;
1014         tx = x;
1015
1016         if(y < 0) continue;
1017         if(y >= image->height) break;
1018
1019         for(; w--; tx++)
1020         {
1021             if(tx >= image->width) break;
1022
1023             m = *mask++;
1024             if(tx < 0) continue;
1025
1026             if (m == 0xff)
1027                 XPutPixel (image, tx, y, color);
1028             else if (m)
1029             {
1030                 BYTE r, g, b;
1031
1032                 pixel = XGetPixel (image, tx, y);
1033
1034                 r = GetField(pixel, r_shift, r_len);
1035                 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1036                 g = GetField(pixel, g_shift, g_len);
1037                 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1038                 b = GetField(pixel, b_shift, b_len);
1039                 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1040
1041                 pixel = (PutField (r, r_shift, r_len) |
1042                          PutField (g, g_shift, g_len) |
1043                          PutField (b, b_shift, b_len));
1044                 XPutPixel (image, tx, y, pixel);
1045             }
1046         }
1047     }
1048 }
1049
1050 /*************************************************************
1051  *                 get_tile_pict
1052  *
1053  * Returns an appropriate Picture for tiling the text colour.
1054  * Call and use result within the xrender_cs
1055  */
1056 static Picture get_tile_pict(enum drawable_depth_type type, int text_pixel)
1057 {
1058     static struct
1059     {
1060         Pixmap xpm;
1061         Picture pict;
1062         int current_color;
1063     } tiles[2], *tile;
1064     XRenderColor col;
1065
1066     tile = &tiles[type];
1067
1068     if(!tile->xpm)
1069     {
1070         XRenderPictureAttributes pa;
1071
1072         wine_tsx11_lock();
1073         tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_formats[type]->depth);
1074
1075         pa.repeat = True;
1076         tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_formats[type], CPRepeat, &pa);
1077         wine_tsx11_unlock();
1078
1079         /* init current_color to something different from text_pixel */
1080         tile->current_color = ~text_pixel;
1081
1082         if(type == mono_drawable)
1083         {
1084             /* for a 1bpp bitmap we always need a 1 in the tile */
1085             col.red = col.green = col.blue = 0;
1086             col.alpha = 0xffff;
1087             wine_tsx11_lock();
1088             pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1089             wine_tsx11_unlock();
1090         }
1091     }
1092
1093     if(text_pixel != tile->current_color && type == color_drawable)
1094     {
1095         /* Map 0 -- 0xff onto 0 -- 0xffff */
1096         int r_shift, r_len;
1097         int g_shift, g_len;
1098         int b_shift, b_len;
1099
1100         ExamineBitfield (visual->red_mask, &r_shift, &r_len );
1101         ExamineBitfield (visual->green_mask, &g_shift, &g_len);
1102         ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
1103
1104         col.red = GetField(text_pixel, r_shift, r_len);
1105         col.red |= col.red << 8;
1106         col.green = GetField(text_pixel, g_shift, g_len);
1107         col.green |= col.green << 8;
1108         col.blue = GetField(text_pixel, b_shift, b_len);
1109         col.blue |= col.blue << 8;
1110         col.alpha = 0xffff;
1111
1112         wine_tsx11_lock();
1113         pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1114         wine_tsx11_unlock();
1115         tile->current_color = text_pixel;
1116     }
1117     return tile->pict;
1118 }
1119
1120 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1121 {
1122     return 1;
1123 }
1124
1125 /***********************************************************************
1126  *   X11DRV_XRender_ExtTextOut
1127  */
1128 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1129                                 const RECT *lprect, LPCWSTR wstr, UINT count,
1130                                 const INT *lpDx )
1131 {
1132     RGNDATA *data;
1133     XGCValues xgcval;
1134     gsCacheEntry *entry;
1135     gsCacheEntryFormat *formatEntry;
1136     BOOL retv = FALSE;
1137     HDC hdc = physDev->hdc;
1138     int textPixel, backgroundPixel;
1139     HRGN saved_region = 0;
1140     BOOL disable_antialias = FALSE;
1141     AA_Type aa_type = AA_None;
1142     DIBSECTION bmp;
1143     unsigned int idx;
1144     double cosEsc, sinEsc;
1145     LOGFONTW lf;
1146     enum drawable_depth_type depth_type = (physDev->depth == 1) ? mono_drawable : color_drawable;
1147     Picture tile_pict = 0;
1148
1149     /* Do we need to disable antialiasing because of palette mode? */
1150     if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1151         TRACE("bitmap is not a DIB\n");
1152     }
1153     else if (bmp.dsBmih.biBitCount <= 8) {
1154         TRACE("Disabling antialiasing\n");
1155         disable_antialias = TRUE;
1156     }
1157
1158     xgcval.function = GXcopy;
1159     xgcval.background = physDev->backgroundPixel;
1160     xgcval.fill_style = FillSolid;
1161     wine_tsx11_lock();
1162     XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1163     wine_tsx11_unlock();
1164
1165     X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1166
1167     if(physDev->depth == 1) {
1168         if((physDev->textPixel & 0xffffff) == 0) {
1169             textPixel = 0;
1170             backgroundPixel = 1;
1171         } else {
1172             textPixel = 1;
1173             backgroundPixel = 0;
1174         }
1175     } else {
1176         textPixel = physDev->textPixel;
1177         backgroundPixel = physDev->backgroundPixel;
1178     }
1179
1180     if(flags & ETO_OPAQUE)
1181     {
1182         wine_tsx11_lock();
1183         XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1184         XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1185                         physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1186                         lprect->right - lprect->left, lprect->bottom - lprect->top );
1187         wine_tsx11_unlock();
1188     }
1189
1190     if(count == 0)
1191     {
1192         retv = TRUE;
1193         goto done_unlock;
1194     }
1195
1196     
1197     GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1198     if(lf.lfEscapement != 0) {
1199         cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1200         sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1201     } else {
1202         cosEsc = 1;
1203         sinEsc = 0;
1204     }
1205
1206     if (flags & ETO_CLIPPED)
1207     {
1208         HRGN clip_region;
1209
1210         clip_region = CreateRectRgnIndirect( lprect );
1211         /* make a copy of the current device region */
1212         saved_region = CreateRectRgn( 0, 0, 0, 0 );
1213         CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1214         X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1215         DeleteObject( clip_region );
1216     }
1217
1218     if(X11DRV_XRender_Installed) {
1219         if(!physDev->xrender->pict) {
1220             XRenderPictureAttributes pa;
1221             pa.subwindow_mode = IncludeInferiors;
1222
1223             wine_tsx11_lock();
1224             physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1225                                                            physDev->drawable,
1226                                                            pict_formats[depth_type],
1227                                                            CPSubwindowMode, &pa);
1228             wine_tsx11_unlock();
1229
1230             TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1231                   physDev->xrender->pict, hdc, physDev->drawable);
1232         } else {
1233             TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1234                   physDev->xrender->pict, hdc, physDev->drawable);
1235         }
1236
1237         if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1238         {
1239             wine_tsx11_lock();
1240             pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1241                                               physDev->dc_rect.left, physDev->dc_rect.top,
1242                                               (XRectangle *)data->Buffer, data->rdh.nCount );
1243             wine_tsx11_unlock();
1244             HeapFree( GetProcessHeap(), 0, data );
1245         }
1246     }
1247
1248     EnterCriticalSection(&xrender_cs);
1249
1250     entry = glyphsetCache + physDev->xrender->cache_index;
1251     if( disable_antialias == FALSE )
1252         aa_type = entry->aa_default;
1253     formatEntry = entry->format[aa_type];
1254
1255     for(idx = 0; idx < count; idx++) {
1256         if( !formatEntry ) {
1257             UploadGlyph(physDev, wstr[idx], aa_type);
1258             /* re-evaluate antialias since aa_default may have changed */
1259             if( disable_antialias == FALSE )
1260                 aa_type = entry->aa_default;
1261             formatEntry = entry->format[aa_type];
1262         } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1263             UploadGlyph(physDev, wstr[idx], aa_type);
1264         }
1265     }
1266     if (!formatEntry)
1267     {
1268         WARN("could not upload requested glyphs\n");
1269         LeaveCriticalSection(&xrender_cs);
1270         goto done_unlock;
1271     }
1272
1273     TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1274           physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1275
1276     if(X11DRV_XRender_Installed)
1277     {
1278         XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1279         INT offset = 0;
1280         POINT desired, current;
1281         int render_op = PictOpOver;
1282
1283         /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1284            So we pass zeros to the function and move to our starting position using the first
1285            element of the elts array. */
1286
1287         desired.x = physDev->dc_rect.left + x;
1288         desired.y = physDev->dc_rect.top + y;
1289         current.x = current.y = 0;
1290
1291         tile_pict = get_tile_pict(depth_type, physDev->textPixel);
1292
1293         /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1294          */
1295         if((depth_type == mono_drawable) && (textPixel == 0))
1296             render_op = PictOpOutReverse; /* This gives us 'black' text */
1297
1298         for(idx = 0; idx < count; idx++)
1299         {
1300             elts[idx].glyphset = formatEntry->glyphset;
1301             elts[idx].chars = wstr + idx;
1302             elts[idx].nchars = 1;
1303             elts[idx].xOff = desired.x - current.x;
1304             elts[idx].yOff = desired.y - current.y;
1305
1306             current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1307             current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1308
1309             if(!lpDx)
1310             {
1311                 desired.x += formatEntry->gis[wstr[idx]].xOff;
1312                 desired.y += formatEntry->gis[wstr[idx]].yOff;
1313             }
1314             else
1315             {
1316                 offset += lpDx[idx];
1317                 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1318                 desired.y = physDev->dc_rect.top  + y - offset * sinEsc;
1319             }
1320         }
1321         wine_tsx11_lock();
1322         pXRenderCompositeText16(gdi_display, render_op,
1323                                 tile_pict,
1324                                 physDev->xrender->pict,
1325                                 formatEntry->font_format,
1326                                 0, 0, 0, 0, elts, count);
1327         wine_tsx11_unlock();
1328         HeapFree(GetProcessHeap(), 0, elts);
1329     } else {
1330         INT offset = 0, xoff = 0, yoff = 0;
1331         wine_tsx11_lock();
1332         XSetForeground( gdi_display, physDev->gc, textPixel );
1333
1334         if(aa_type == AA_None || physDev->depth == 1)
1335         {
1336             void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1337
1338             if(aa_type == AA_None)
1339                 sharp_glyph_fn = SharpGlyphMono;
1340             else
1341                 sharp_glyph_fn = SharpGlyphGray;
1342
1343             for(idx = 0; idx < count; idx++) {
1344                 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1345                                physDev->dc_rect.top + y + yoff,
1346                                formatEntry->bitmaps[wstr[idx]],
1347                                &formatEntry->gis[wstr[idx]]);
1348                 if(lpDx) {
1349                     offset += lpDx[idx];
1350                     xoff = offset * cosEsc;
1351                     yoff = offset * -sinEsc;
1352                 } else {
1353                     xoff += formatEntry->gis[wstr[idx]].xOff;
1354                     yoff += formatEntry->gis[wstr[idx]].yOff;
1355                 }
1356             }
1357         } else {
1358             XImage *image;
1359             int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1360             RECT extents = {0, 0, 0, 0};
1361             POINT cur = {0, 0};
1362             int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1363             int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1364
1365             TRACE("drawable %dx%d\n", w, h);
1366
1367             for(idx = 0; idx < count; idx++) {
1368                 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1369                     extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1370                 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1371                     extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1372                 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1373                     extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1374                 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1375                     extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1376                 if(lpDx) {
1377                     offset += lpDx[idx];
1378                     cur.x = offset * cosEsc;
1379                     cur.y = offset * -sinEsc;
1380                 } else {
1381                     cur.x += formatEntry->gis[wstr[idx]].xOff;
1382                     cur.y += formatEntry->gis[wstr[idx]].yOff;
1383                 }
1384             }
1385             TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1386                   extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1387
1388             if(physDev->dc_rect.left + x + extents.left >= 0) {
1389                 image_x = physDev->dc_rect.left + x + extents.left;
1390                 image_off_x = 0;
1391             } else {
1392                 image_x = 0;
1393                 image_off_x = physDev->dc_rect.left + x + extents.left;
1394             }
1395             if(physDev->dc_rect.top + y + extents.top >= 0) {
1396                 image_y = physDev->dc_rect.top + y + extents.top;
1397                 image_off_y = 0;
1398             } else {
1399                 image_y = 0;
1400                 image_off_y = physDev->dc_rect.top + y + extents.top;
1401             }
1402             if(physDev->dc_rect.left + x + extents.right < w)
1403                 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1404             else
1405                 image_w = w - image_x;
1406             if(physDev->dc_rect.top + y + extents.bottom < h)
1407                 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1408             else
1409                 image_h = h - image_y;
1410
1411             if(image_w <= 0 || image_h <= 0) goto no_image;
1412
1413             X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1414             image = XGetImage(gdi_display, physDev->drawable,
1415                               image_x, image_y, image_w, image_h,
1416                               AllPlanes, ZPixmap);
1417             X11DRV_check_error();
1418
1419             TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1420                   gdi_display, (int)physDev->drawable, image_x, image_y,
1421                   image_w, image_h, AllPlanes, ZPixmap,
1422                   physDev->depth, image);
1423             if(!image) {
1424                 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
1425                                            physDev->depth);
1426                 GC gc;
1427                 XGCValues gcv;
1428
1429                 gcv.graphics_exposures = False;
1430                 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1431                 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1432                           image_w, image_h, 0, 0);
1433                 XFreeGC(gdi_display, gc);
1434                 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1435                 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1436                                   ZPixmap);
1437                 X11DRV_check_error();
1438                 XFreePixmap(gdi_display, xpm);
1439             }
1440             if(!image) goto no_image;
1441
1442             image->red_mask = visual->red_mask;
1443             image->green_mask = visual->green_mask;
1444             image->blue_mask = visual->blue_mask;
1445
1446             offset = xoff = yoff = 0;
1447             for(idx = 0; idx < count; idx++) {
1448                 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1449                                 yoff + image_off_y - extents.top,
1450                                 formatEntry->bitmaps[wstr[idx]],
1451                                 &formatEntry->gis[wstr[idx]],
1452                                 physDev->textPixel);
1453                 if(lpDx) {
1454                     offset += lpDx[idx];
1455                     xoff = offset * cosEsc;
1456                     yoff = offset * -sinEsc;
1457                 } else {
1458                     xoff += formatEntry->gis[wstr[idx]].xOff;
1459                     yoff += formatEntry->gis[wstr[idx]].yOff;
1460                 }
1461             }
1462             XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1463                       image_x, image_y, image_w, image_h);
1464             XDestroyImage(image);
1465         }
1466     no_image:
1467         wine_tsx11_unlock();
1468     }
1469     LeaveCriticalSection(&xrender_cs);
1470
1471     if (flags & ETO_CLIPPED)
1472     {
1473         /* restore the device region */
1474         X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1475         DeleteObject( saved_region );
1476     }
1477
1478     retv = TRUE;
1479
1480 done_unlock:
1481     X11DRV_UnlockDIBSection( physDev, TRUE );
1482     return retv;
1483 }
1484
1485 /******************************************************************************
1486  * AlphaBlend         (x11drv.@)
1487  */
1488 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1489                        X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1490                        BLENDFUNCTION blendfn)
1491 {
1492     XRenderPictureAttributes pa;
1493     XRenderPictFormat *src_format;
1494     XRenderPictFormat argb32_templ = {
1495         0,                          /* id */
1496         PictTypeDirect,             /* type */
1497         32,                         /* depth */
1498         {                           /* direct */
1499             16,                     /* direct.red */
1500             0xff,                   /* direct.redMask */
1501             8,                      /* direct.green */
1502             0xff,                   /* direct.greenMask */
1503             0,                      /* direct.blue */
1504             0xff,                   /* direct.blueMask */
1505             24,                     /* direct.alpha */
1506             0xff,                   /* direct.alphaMask */
1507         },
1508         0,                          /* colormap */
1509     };
1510     unsigned long argb32_templ_mask = 
1511         PictFormatType |
1512         PictFormatDepth |
1513         PictFormatRed |
1514         PictFormatRedMask |
1515         PictFormatGreen |
1516         PictFormatGreenMask |
1517         PictFormatBlue |
1518         PictFormatBlueMask |
1519         PictFormatAlpha |
1520         PictFormatAlphaMask;
1521
1522     Picture dst_pict, src_pict;
1523     Pixmap xpm;
1524     DIBSECTION dib;
1525     XImage *image;
1526     GC gc;
1527     XGCValues gcv;
1528     DWORD *dstbits, *data;
1529     int y, y2;
1530     POINT pts[2];
1531     BOOL top_down = FALSE;
1532     RGNDATA *rgndata;
1533     enum drawable_depth_type dst_depth_type = (devDst->depth == 1) ? mono_drawable : color_drawable;
1534
1535     if(!X11DRV_XRender_Installed) {
1536         FIXME("Unable to AlphaBlend without Xrender\n");
1537         return FALSE;
1538     }
1539     pts[0].x = xDst;
1540     pts[0].y = yDst;
1541     pts[1].x = xDst + widthDst;
1542     pts[1].y = yDst + heightDst;
1543     LPtoDP(devDst->hdc, pts, 2);
1544     xDst      = pts[0].x;
1545     yDst      = pts[0].y;
1546     widthDst  = pts[1].x - pts[0].x;
1547     heightDst = pts[1].y - pts[0].y;
1548
1549     pts[0].x = xSrc;
1550     pts[0].y = ySrc;
1551     pts[1].x = xSrc + widthSrc;
1552     pts[1].y = ySrc + heightSrc;
1553     LPtoDP(devSrc->hdc, pts, 2);
1554     xSrc      = pts[0].x;
1555     ySrc      = pts[0].y;
1556     widthSrc  = pts[1].x - pts[0].x;
1557     heightSrc = pts[1].y - pts[0].y;
1558     if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1559
1560 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1561     if(widthDst != widthSrc || heightDst != heightSrc)
1562 #else
1563     if(!pXRenderSetPictureTransform)
1564 #endif
1565     {
1566         FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1567         return FALSE;
1568     }
1569
1570     if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1571     {
1572         FIXME("not a dibsection\n");
1573         return FALSE;
1574     }
1575
1576     if (xSrc < 0 || ySrc < 0 || widthSrc < 0 || heightSrc < 0 || xSrc + widthSrc > dib.dsBmih.biWidth
1577         || ySrc + heightSrc > abs(dib.dsBmih.biHeight))
1578     {
1579         WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc, ySrc, widthSrc, heightSrc);
1580         SetLastError(ERROR_INVALID_PARAMETER);
1581         return FALSE;
1582     }
1583
1584     if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && blendfn.SourceConstantAlpha != 0xff)
1585         FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn.SourceConstantAlpha);
1586
1587     if(dib.dsBm.bmBitsPixel != 32) {
1588         FIXME("not a 32 bpp dibsection\n");
1589         return FALSE;
1590     }
1591     dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1592
1593     if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1594         top_down = TRUE;
1595         dstbits += widthSrc * (heightSrc - 1);
1596         y2 = ySrc;
1597         y = y2 + heightSrc - 1;
1598     }
1599     else
1600     {
1601         y = dib.dsBmih.biHeight - ySrc - 1;
1602         y2 = y - heightSrc + 1;
1603     }
1604
1605     if (blendfn.AlphaFormat & AC_SRC_ALPHA)
1606     {
1607         for(; y >= y2; y--)
1608         {
1609             memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1610                    widthSrc * 4);
1611             dstbits += (top_down ? -1 : 1) * widthSrc;
1612         }
1613     }
1614     else
1615     {
1616         DWORD source_alpha = (DWORD)blendfn.SourceConstantAlpha << 24;
1617         int x;
1618
1619         for(; y >= y2; y--)
1620         {
1621             DWORD *srcbits = (DWORD *)((char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes) + xSrc;
1622             for (x = 0; x < widthSrc; x++)
1623             {
1624                 DWORD argb = *srcbits++;
1625                 argb = (argb & 0xffffff) | source_alpha;
1626                 *dstbits++ = argb;
1627             }
1628             if (top_down)  /* we traversed the row forward so we should go back by two rows */
1629                 dstbits -= 2 * widthSrc;
1630         }
1631
1632     }
1633
1634     rgndata = X11DRV_GetRegionData( devDst->region, 0 );
1635
1636     wine_tsx11_lock();
1637     image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1638                          (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1639
1640     /*
1641       Avoid using XRenderFindStandardFormat as older libraries don't have it
1642       src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1643     */
1644     src_format = pXRenderFindFormat(gdi_display, argb32_templ_mask, &argb32_templ, 0);
1645
1646     TRACE("src_format %p\n", src_format);
1647
1648     pa.subwindow_mode = IncludeInferiors;
1649
1650     /* FIXME use devDst->xrender->pict ? */
1651     dst_pict = pXRenderCreatePicture(gdi_display,
1652                                      devDst->drawable,
1653                                      pict_formats[dst_depth_type],
1654                                      CPSubwindowMode, &pa);
1655     TRACE("dst_pict %08lx\n", dst_pict);
1656     TRACE("src_drawable = %08lx\n", devSrc->drawable);
1657     xpm = XCreatePixmap(gdi_display,
1658                         root_window,
1659                         widthSrc, heightSrc, 32);
1660     gcv.graphics_exposures = False;
1661     gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1662     TRACE("xpm = %08lx\n", xpm);
1663     XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1664
1665     src_pict = pXRenderCreatePicture(gdi_display,
1666                                      xpm, src_format,
1667                                      CPSubwindowMode, &pa);
1668     TRACE("src_pict %08lx\n", src_pict);
1669
1670     if (rgndata)
1671     {
1672         pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
1673                                           devDst->dc_rect.left, devDst->dc_rect.top,
1674                                           (XRectangle *)rgndata->Buffer, 
1675                                           rgndata->rdh.nCount );
1676         HeapFree( GetProcessHeap(), 0, rgndata );
1677     }
1678
1679 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1680     if(widthDst != widthSrc || heightDst != heightSrc) {
1681         double xscale = widthSrc/(double)widthDst;
1682         double yscale = heightSrc/(double)heightDst;
1683         XTransform xform = {{
1684             { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0) },
1685             { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0) },
1686             { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1687         }};
1688         pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1689     }
1690 #endif
1691     pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
1692                       0, 0, 0, 0,
1693                       xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
1694
1695
1696     pXRenderFreePicture(gdi_display, src_pict);
1697     XFreePixmap(gdi_display, xpm);
1698     XFreeGC(gdi_display, gc);
1699     pXRenderFreePicture(gdi_display, dst_pict);
1700     image->data = NULL;
1701     XDestroyImage(image);
1702
1703     wine_tsx11_unlock();
1704     HeapFree(GetProcessHeap(), 0, data);
1705     return TRUE;
1706 }
1707
1708 #else /* SONAME_LIBXRENDER */
1709
1710 void X11DRV_XRender_Init(void)
1711 {
1712     TRACE("XRender support not compiled in.\n");
1713     return;
1714 }
1715
1716 void X11DRV_XRender_Finalize(void)
1717 {
1718 }
1719
1720 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1721 {
1722   assert(0);
1723   return FALSE;
1724 }
1725
1726 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1727 {
1728   assert(0);
1729   return;
1730 }
1731
1732 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1733                                 const RECT *lprect, LPCWSTR wstr, UINT count,
1734                                 const INT *lpDx )
1735 {
1736   assert(0);
1737   return FALSE;
1738 }
1739
1740 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1741 {
1742   assert(0);
1743   return;
1744 }
1745
1746 /******************************************************************************
1747  * AlphaBlend         (x11drv.@)
1748  */
1749 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1750                        X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1751                        BLENDFUNCTION blendfn)
1752 {
1753   FIXME("not supported - XRENDER headers were missing at compile time\n");
1754   return FALSE;
1755 }
1756
1757 #endif /* SONAME_LIBXRENDER */