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