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