dsound: Request that WinMM perform audio conversion if the hardware doesn't support...
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blobdc603af237fc92774580bce77ecba460f139b378
1 /*
2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
7 * Some parts also:
8 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <assert.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <stdlib.h>
32 #include "windef.h"
33 #include "winbase.h"
34 #include "x11drv.h"
35 #include "winternl.h"
36 #include "wine/library.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
40 int using_client_side_fonts = FALSE;
42 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
44 #ifdef SONAME_LIBXRENDER
46 static BOOL X11DRV_XRender_Installed = FALSE;
48 #include <X11/Xlib.h>
49 #include <X11/extensions/Xrender.h>
51 #ifndef RepeatNone /* added in 0.10 */
52 #define RepeatNone 0
53 #define RepeatNormal 1
54 #define RepeatPad 2
55 #define RepeatReflect 3
56 #endif
58 typedef enum wine_xrformat
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_B8G8R8A8,
70 WXR_FORMAT_X8R8G8B8,
71 WXR_FORMAT_B8G8R8X8,
72 WXR_NB_FORMATS
73 } WXRFormat;
75 typedef struct wine_xrender_format_template
77 WXRFormat wxr_format;
78 unsigned int depth;
79 unsigned int alpha;
80 unsigned int alphaMask;
81 unsigned int red;
82 unsigned int redMask;
83 unsigned int green;
84 unsigned int greenMask;
85 unsigned int blue;
86 unsigned int blueMask;
87 } WineXRenderFormatTemplate;
89 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
91 /* Format depth alpha mask red mask green mask blue mask*/
92 {WXR_FORMAT_MONO, 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
93 {WXR_FORMAT_GRAY, 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
94 {WXR_FORMAT_X1R5G5B5, 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
95 {WXR_FORMAT_X1B5G5R5, 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
96 {WXR_FORMAT_R5G6B5, 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
97 {WXR_FORMAT_B5G6R5, 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
98 {WXR_FORMAT_R8G8B8, 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
99 {WXR_FORMAT_B8G8R8, 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
100 {WXR_FORMAT_A8R8G8B8, 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
101 {WXR_FORMAT_B8G8R8A8, 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
102 {WXR_FORMAT_X8R8G8B8, 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
103 {WXR_FORMAT_B8G8R8X8, 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
106 typedef struct wine_xrender_format
108 WXRFormat format;
109 XRenderPictFormat *pict_format;
110 } WineXRenderFormat;
112 static WineXRenderFormat wxr_formats[WXR_NB_FORMATS];
113 static int WineXRenderFormatsListSize = 0;
114 static WineXRenderFormat *default_format = NULL;
116 typedef struct
118 LOGFONTW lf;
119 XFORM xform;
120 SIZE devsize; /* size in device coords */
121 DWORD hash;
122 } LFANDSIZE;
124 #define INITIAL_REALIZED_BUF_SIZE 128
126 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
128 typedef struct
130 GlyphSet glyphset;
131 const WineXRenderFormat *font_format;
132 int nrealized;
133 BOOL *realized;
134 void **bitmaps;
135 XGlyphInfo *gis;
136 } gsCacheEntryFormat;
138 typedef struct
140 LFANDSIZE lfsz;
141 AA_Type aa_default;
142 gsCacheEntryFormat * format[AA_MAXVALUE];
143 INT count;
144 INT next;
145 } gsCacheEntry;
147 struct xrender_info
149 int cache_index;
150 Picture pict;
151 Picture pict_src;
152 const WineXRenderFormat *format;
155 static gsCacheEntry *glyphsetCache = NULL;
156 static DWORD glyphsetCacheSize = 0;
157 static INT lastfree = -1;
158 static INT mru = -1;
160 #define INIT_CACHE_SIZE 10
162 static int antialias = 1;
164 static void *xrender_handle;
166 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
167 MAKE_FUNCPTR(XRenderAddGlyphs)
168 MAKE_FUNCPTR(XRenderComposite)
169 MAKE_FUNCPTR(XRenderCompositeString8)
170 MAKE_FUNCPTR(XRenderCompositeString16)
171 MAKE_FUNCPTR(XRenderCompositeString32)
172 MAKE_FUNCPTR(XRenderCompositeText16)
173 MAKE_FUNCPTR(XRenderCreateGlyphSet)
174 MAKE_FUNCPTR(XRenderCreatePicture)
175 MAKE_FUNCPTR(XRenderFillRectangle)
176 MAKE_FUNCPTR(XRenderFindFormat)
177 MAKE_FUNCPTR(XRenderFindVisualFormat)
178 MAKE_FUNCPTR(XRenderFreeGlyphSet)
179 MAKE_FUNCPTR(XRenderFreePicture)
180 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
181 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
182 MAKE_FUNCPTR(XRenderSetPictureTransform)
183 #endif
184 MAKE_FUNCPTR(XRenderQueryExtension)
186 #ifdef SONAME_LIBFONTCONFIG
187 #include <fontconfig/fontconfig.h>
188 MAKE_FUNCPTR(FcConfigSubstitute)
189 MAKE_FUNCPTR(FcDefaultSubstitute)
190 MAKE_FUNCPTR(FcFontMatch)
191 MAKE_FUNCPTR(FcInit)
192 MAKE_FUNCPTR(FcPatternCreate)
193 MAKE_FUNCPTR(FcPatternDestroy)
194 MAKE_FUNCPTR(FcPatternAddInteger)
195 MAKE_FUNCPTR(FcPatternAddString)
196 MAKE_FUNCPTR(FcPatternGetBool)
197 MAKE_FUNCPTR(FcPatternGetInteger)
198 MAKE_FUNCPTR(FcPatternGetString)
199 static void *fontconfig_handle;
200 static BOOL fontconfig_installed;
201 #endif
203 #undef MAKE_FUNCPTR
205 static CRITICAL_SECTION xrender_cs;
206 static CRITICAL_SECTION_DEBUG critsect_debug =
208 0, 0, &xrender_cs,
209 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
210 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
212 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
214 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
215 ( ( (ULONG)_x4 << 24 ) | \
216 ( (ULONG)_x3 << 16 ) | \
217 ( (ULONG)_x2 << 8 ) | \
218 (ULONG)_x1 )
220 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
222 #define GASP_GRIDFIT 0x01
223 #define GASP_DOGRAY 0x02
225 #ifdef WORDS_BIGENDIAN
226 #define get_be_word(x) (x)
227 #define NATIVE_BYTE_ORDER MSBFirst
228 #else
229 #define get_be_word(x) RtlUshortByteSwap(x)
230 #define NATIVE_BYTE_ORDER LSBFirst
231 #endif
233 static WXRFormat get_format_without_alpha( WXRFormat format )
235 switch (format)
237 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
238 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
239 default: return format;
243 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
245 templ->id = 0;
246 templ->type = PictTypeDirect;
247 templ->depth = fmt->depth;
248 templ->direct.alpha = fmt->alpha;
249 templ->direct.alphaMask = fmt->alphaMask;
250 templ->direct.red = fmt->red;
251 templ->direct.redMask = fmt->redMask;
252 templ->direct.green = fmt->green;
253 templ->direct.greenMask = fmt->greenMask;
254 templ->direct.blue = fmt->blue;
255 templ->direct.blueMask = fmt->blueMask;
256 templ->colormap = 0;
258 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
260 return TRUE;
263 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
265 if(fmt->depth != screen_depth)
266 return FALSE;
267 if( (fmt->redMask << fmt->red) != visual->red_mask)
268 return FALSE;
269 if( (fmt->greenMask << fmt->green) != visual->green_mask)
270 return FALSE;
271 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
272 return FALSE;
274 /* We never select a default ARGB visual */
275 if(fmt->alphaMask)
276 return FALSE;
278 return TRUE;
281 static int load_xrender_formats(void)
283 unsigned int i;
284 for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
286 XRenderPictFormat templ, *pict_format;
288 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
290 wine_tsx11_lock();
291 pict_format = pXRenderFindVisualFormat(gdi_display, visual);
292 if(!pict_format)
294 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
295 if (visual->class == DirectColor)
297 XVisualInfo info;
298 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
299 screen_depth, TrueColor, &info ))
301 pict_format = pXRenderFindVisualFormat(gdi_display, info.visual);
302 if (pict_format) visual = info.visual;
306 wine_tsx11_unlock();
308 if(pict_format)
310 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
311 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
312 default_format = &wxr_formats[WineXRenderFormatsListSize];
313 WineXRenderFormatsListSize++;
314 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
317 else
319 unsigned long mask = 0;
320 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
322 wine_tsx11_lock();
323 pict_format = pXRenderFindFormat(gdi_display, mask, &templ, 0);
324 wine_tsx11_unlock();
326 if(pict_format)
328 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
329 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
330 WineXRenderFormatsListSize++;
331 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
335 return WineXRenderFormatsListSize;
338 /***********************************************************************
339 * X11DRV_XRender_Init
341 * Let's see if our XServer has the extension available
344 void X11DRV_XRender_Init(void)
346 int event_base, i;
348 if (client_side_with_render &&
349 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
352 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
353 LOAD_FUNCPTR(XRenderAddGlyphs)
354 LOAD_FUNCPTR(XRenderComposite)
355 LOAD_FUNCPTR(XRenderCompositeString8)
356 LOAD_FUNCPTR(XRenderCompositeString16)
357 LOAD_FUNCPTR(XRenderCompositeString32)
358 LOAD_FUNCPTR(XRenderCompositeText16)
359 LOAD_FUNCPTR(XRenderCreateGlyphSet)
360 LOAD_FUNCPTR(XRenderCreatePicture)
361 LOAD_FUNCPTR(XRenderFillRectangle)
362 LOAD_FUNCPTR(XRenderFindFormat)
363 LOAD_FUNCPTR(XRenderFindVisualFormat)
364 LOAD_FUNCPTR(XRenderFreeGlyphSet)
365 LOAD_FUNCPTR(XRenderFreePicture)
366 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
367 LOAD_FUNCPTR(XRenderQueryExtension)
368 #undef LOAD_FUNCPTR
369 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
370 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
371 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
372 #undef LOAD_OPTIONAL_FUNCPTR
373 #endif
375 wine_tsx11_lock();
376 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
377 wine_tsx11_unlock();
378 if(X11DRV_XRender_Installed) {
379 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
380 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
382 wine_tsx11_unlock();
383 WINE_MESSAGE(
384 "Wine has detected that you probably have a buggy version\n"
385 "of libXrender.so . Because of this client side font rendering\n"
386 "will be disabled. Please upgrade this library.\n");
387 X11DRV_XRender_Installed = FALSE;
388 return;
391 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
392 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
393 X11DRV_XRender_Installed = FALSE;
398 #ifdef SONAME_LIBFONTCONFIG
399 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
401 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fontconfig_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
402 LOAD_FUNCPTR(FcConfigSubstitute);
403 LOAD_FUNCPTR(FcDefaultSubstitute);
404 LOAD_FUNCPTR(FcFontMatch);
405 LOAD_FUNCPTR(FcInit);
406 LOAD_FUNCPTR(FcPatternCreate);
407 LOAD_FUNCPTR(FcPatternDestroy);
408 LOAD_FUNCPTR(FcPatternAddInteger);
409 LOAD_FUNCPTR(FcPatternAddString);
410 LOAD_FUNCPTR(FcPatternGetBool);
411 LOAD_FUNCPTR(FcPatternGetInteger);
412 LOAD_FUNCPTR(FcPatternGetString);
413 #undef LOAD_FUNCPTR
414 fontconfig_installed = pFcInit();
416 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
417 #endif
419 sym_not_found:
420 if(X11DRV_XRender_Installed || client_side_with_core)
422 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
423 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
425 glyphsetCacheSize = INIT_CACHE_SIZE;
426 lastfree = 0;
427 for(i = 0; i < INIT_CACHE_SIZE; i++) {
428 glyphsetCache[i].next = i + 1;
429 glyphsetCache[i].count = -1;
431 glyphsetCache[i-1].next = -1;
432 using_client_side_fonts = 1;
434 if(!X11DRV_XRender_Installed) {
435 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
436 if(screen_depth <= 8 || !client_side_antialias_with_core)
437 antialias = 0;
438 } else {
439 if(screen_depth <= 8 || !client_side_antialias_with_render)
440 antialias = 0;
443 else TRACE("Using X11 core fonts\n");
446 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
447 static void get_xrender_color(const WineXRenderFormat *wxr_format, int src_color, XRenderColor *dst_color)
449 XRenderPictFormat *pf = wxr_format->pict_format;
451 if(pf->direct.redMask)
452 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
453 else
454 dst_color->red = 0;
456 if(pf->direct.greenMask)
457 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
458 else
459 dst_color->green = 0;
461 if(pf->direct.blueMask)
462 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
463 else
464 dst_color->blue = 0;
466 dst_color->alpha = 0xffff;
469 static const WineXRenderFormat *get_xrender_format(WXRFormat format)
471 int i;
472 for(i=0; i<WineXRenderFormatsListSize; i++)
474 if(wxr_formats[i].format == format)
476 TRACE("Returning wxr_format=%#x\n", format);
477 return &wxr_formats[i];
480 return NULL;
483 static const WineXRenderFormat *get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
485 int redMask, greenMask, blueMask;
486 unsigned int i;
488 if(depth == 1)
489 return get_xrender_format(WXR_FORMAT_MONO);
491 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
492 if(!shifts)
493 return default_format;
495 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
496 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
497 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
499 /* Try to locate a format which matches the specification of the dibsection. */
500 for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
502 if( depth == wxr_formats_template[i].depth &&
503 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
504 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
505 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
508 /* When we reach this stage the format was found in our template table but this doesn't mean that
509 * the Xserver also supports this format (e.g. its depth might be too low). The call below verifies that.
511 return get_xrender_format(wxr_formats_template[i].wxr_format);
515 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
516 ERR("No XRender format found!\n");
517 return NULL;
520 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
521 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
523 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
524 XTransform xform = {{
525 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
526 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
527 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
530 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
531 #endif
534 /* check if we can use repeating instead of scaling for the specified source DC */
535 static BOOL use_source_repeat( X11DRV_PDEVICE *physDev )
537 return (physDev->bitmap &&
538 physDev->drawable_rect.right - physDev->drawable_rect.left == 1 &&
539 physDev->drawable_rect.bottom - physDev->drawable_rect.top == 1);
542 static struct xrender_info *get_xrender_info(X11DRV_PDEVICE *physDev)
544 if(!physDev->xrender)
546 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physDev->xrender));
548 if(!physDev->xrender)
550 ERR("Unable to allocate XRENDERINFO!\n");
551 return NULL;
553 physDev->xrender->cache_index = -1;
555 if (!physDev->xrender->format)
556 physDev->xrender->format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
558 return physDev->xrender;
561 static Picture get_xrender_picture(X11DRV_PDEVICE *physDev)
563 struct xrender_info *info = get_xrender_info(physDev);
564 if (!info) return 0;
566 if (!info->pict && info->format)
568 XRenderPictureAttributes pa;
569 RGNDATA *clip = X11DRV_GetRegionData( physDev->region, 0 );
571 wine_tsx11_lock();
572 pa.subwindow_mode = IncludeInferiors;
573 info->pict = pXRenderCreatePicture(gdi_display, physDev->drawable, info->format->pict_format,
574 CPSubwindowMode, &pa);
575 if (info->pict && clip)
576 pXRenderSetPictureClipRectangles( gdi_display, info->pict,
577 physDev->dc_rect.left, physDev->dc_rect.top,
578 (XRectangle *)clip->Buffer, clip->rdh.nCount );
579 wine_tsx11_unlock();
580 TRACE("Allocing pict=%lx dc=%p drawable=%08lx\n", info->pict, physDev->dev.hdc, physDev->drawable);
581 HeapFree( GetProcessHeap(), 0, clip );
584 return info->pict;
587 static Picture get_xrender_picture_source(X11DRV_PDEVICE *physDev, BOOL repeat)
589 struct xrender_info *info = get_xrender_info(physDev);
590 if (!info) return 0;
592 if (!info->pict_src && info->format)
594 XRenderPictureAttributes pa;
596 wine_tsx11_lock();
597 pa.subwindow_mode = IncludeInferiors;
598 pa.repeat = repeat ? RepeatNormal : RepeatNone;
599 info->pict_src = pXRenderCreatePicture(gdi_display, physDev->drawable, info->format->pict_format,
600 CPSubwindowMode|CPRepeat, &pa);
601 wine_tsx11_unlock();
603 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
604 info->pict_src, physDev->dev.hdc, physDev->drawable, pa.repeat);
607 return info->pict_src;
610 /* return a mask picture used to force alpha to 0 */
611 static Picture get_no_alpha_mask(void)
613 static Pixmap pixmap;
614 static Picture pict;
616 wine_tsx11_lock();
617 if (!pict)
619 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
620 XRenderPictureAttributes pa;
621 XRenderColor col;
623 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
624 pa.repeat = RepeatNormal;
625 pa.component_alpha = True;
626 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format,
627 CPRepeat|CPComponentAlpha, &pa );
628 col.red = col.green = col.blue = 0xffff;
629 col.alpha = 0;
630 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
632 wine_tsx11_unlock();
633 return pict;
636 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
638 if(p1->hash != p2->hash) return TRUE;
639 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
640 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
641 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
642 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
645 #if 0
646 static void walk_cache(void)
648 int i;
650 EnterCriticalSection(&xrender_cs);
651 for(i=mru; i >= 0; i = glyphsetCache[i].next)
652 TRACE("item %d\n", i);
653 LeaveCriticalSection(&xrender_cs);
655 #endif
657 static int LookupEntry(LFANDSIZE *plfsz)
659 int i, prev_i = -1;
661 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
662 TRACE("%d\n", i);
663 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
665 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
666 glyphsetCache[i].count++;
667 if(prev_i >= 0) {
668 glyphsetCache[prev_i].next = glyphsetCache[i].next;
669 glyphsetCache[i].next = mru;
670 mru = i;
672 TRACE("found font in cache %d\n", i);
673 return i;
675 prev_i = i;
677 TRACE("font not in cache\n");
678 return -1;
681 static void FreeEntry(int entry)
683 int i, format;
685 for(format = 0; format < AA_MAXVALUE; format++) {
686 gsCacheEntryFormat * formatEntry;
688 if( !glyphsetCache[entry].format[format] )
689 continue;
691 formatEntry = glyphsetCache[entry].format[format];
693 if(formatEntry->glyphset) {
694 wine_tsx11_lock();
695 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
696 wine_tsx11_unlock();
697 formatEntry->glyphset = 0;
699 if(formatEntry->nrealized) {
700 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
701 formatEntry->realized = NULL;
702 if(formatEntry->bitmaps) {
703 for(i = 0; i < formatEntry->nrealized; i++)
704 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
705 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
706 formatEntry->bitmaps = NULL;
708 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
709 formatEntry->gis = NULL;
710 formatEntry->nrealized = 0;
713 HeapFree(GetProcessHeap(), 0, formatEntry);
714 glyphsetCache[entry].format[format] = NULL;
718 static int AllocEntry(void)
720 int best = -1, prev_best = -1, i, prev_i = -1;
722 if(lastfree >= 0) {
723 assert(glyphsetCache[lastfree].count == -1);
724 glyphsetCache[lastfree].count = 1;
725 best = lastfree;
726 lastfree = glyphsetCache[lastfree].next;
727 assert(best != mru);
728 glyphsetCache[best].next = mru;
729 mru = best;
731 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
732 return mru;
735 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
736 if(glyphsetCache[i].count == 0) {
737 best = i;
738 prev_best = prev_i;
740 prev_i = i;
743 if(best >= 0) {
744 TRACE("freeing unused glyphset at cache %d\n", best);
745 FreeEntry(best);
746 glyphsetCache[best].count = 1;
747 if(prev_best >= 0) {
748 glyphsetCache[prev_best].next = glyphsetCache[best].next;
749 glyphsetCache[best].next = mru;
750 mru = best;
751 } else {
752 assert(mru == best);
754 return mru;
757 TRACE("Growing cache\n");
759 if (glyphsetCache)
760 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
761 glyphsetCache,
762 (glyphsetCacheSize + INIT_CACHE_SIZE)
763 * sizeof(*glyphsetCache));
764 else
765 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
766 (glyphsetCacheSize + INIT_CACHE_SIZE)
767 * sizeof(*glyphsetCache));
769 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
770 i++) {
771 glyphsetCache[i].next = i + 1;
772 glyphsetCache[i].count = -1;
774 glyphsetCache[i-1].next = -1;
775 glyphsetCacheSize += INIT_CACHE_SIZE;
777 lastfree = glyphsetCache[best].next;
778 glyphsetCache[best].count = 1;
779 glyphsetCache[best].next = mru;
780 mru = best;
781 TRACE("new free cache slot at %d\n", mru);
782 return mru;
785 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
787 DWORD size;
788 WORD *gasp, *buffer;
789 WORD num_recs;
790 DWORD ppem;
791 TEXTMETRICW tm;
793 *flags = 0;
795 size = GetFontData(physDev->dev.hdc, MS_GASP_TAG, 0, NULL, 0);
796 if(size == GDI_ERROR)
797 return FALSE;
799 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
800 GetFontData(physDev->dev.hdc, MS_GASP_TAG, 0, gasp, size);
802 GetTextMetricsW(physDev->dev.hdc, &tm);
803 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
805 gasp++;
806 num_recs = get_be_word(*gasp);
807 gasp++;
808 while(num_recs--)
810 *flags = get_be_word(*(gasp + 1));
811 if(ppem <= get_be_word(*gasp))
812 break;
813 gasp += 2;
815 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
817 HeapFree(GetProcessHeap(), 0, buffer);
818 return TRUE;
821 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
823 AA_Type ret;
824 WORD flags;
825 UINT font_smoothing_type, font_smoothing_orientation;
827 if (X11DRV_XRender_Installed && subpixel &&
828 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
829 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
831 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
832 &font_smoothing_orientation, 0) &&
833 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
835 ret = AA_BGR;
837 else
838 ret = AA_RGB;
839 /*FIXME
840 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
841 But, Wine's subpixel rendering can support the portrait mode.
844 else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
845 ret = AA_Grey;
846 else
847 ret = AA_None;
849 return ret;
852 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
854 int ret;
855 int format;
856 gsCacheEntry *entry;
857 static int hinter = -1;
858 static int subpixel = -1;
859 BOOL font_smoothing;
861 if((ret = LookupEntry(plfsz)) != -1) return ret;
863 ret = AllocEntry();
864 entry = glyphsetCache + ret;
865 entry->lfsz = *plfsz;
866 for( format = 0; format < AA_MAXVALUE; format++ ) {
867 assert( !entry->format[format] );
870 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
872 if(hinter == -1 || subpixel == -1)
874 RASTERIZER_STATUS status;
875 GetRasterizerCaps(&status, sizeof(status));
876 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
877 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
880 switch (plfsz->lf.lfQuality)
882 case ANTIALIASED_QUALITY:
883 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
884 return ret; /* ignore further configuration */
885 case CLEARTYPE_QUALITY:
886 case CLEARTYPE_NATURAL_QUALITY:
887 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
888 break;
889 case DEFAULT_QUALITY:
890 case DRAFT_QUALITY:
891 case PROOF_QUALITY:
892 default:
893 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
894 font_smoothing)
896 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
898 else
899 entry->aa_default = AA_None;
900 break;
903 font_smoothing = TRUE; /* default to enabled */
904 #ifdef SONAME_LIBFONTCONFIG
905 if (fontconfig_installed)
907 FcPattern *match, *pattern = pFcPatternCreate();
908 FcResult result;
909 char family[LF_FACESIZE * 4];
911 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
912 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
913 if (plfsz->lf.lfWeight != FW_DONTCARE)
915 int weight;
916 switch (plfsz->lf.lfWeight)
918 case FW_THIN: weight = FC_WEIGHT_THIN; break;
919 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
920 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
921 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
922 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
923 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
924 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
925 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
926 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
927 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
929 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
931 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
932 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
933 pFcDefaultSubstitute( pattern );
934 if ((match = pFcFontMatch( NULL, pattern, &result )))
936 int rgba;
937 FcBool antialias;
939 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
940 antialias = TRUE;
941 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
943 FcChar8 *file;
944 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
946 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
947 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
949 switch (rgba)
951 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
952 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
953 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
954 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
955 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
958 if (!antialias) font_smoothing = FALSE;
959 pFcPatternDestroy( match );
961 pFcPatternDestroy( pattern );
963 #endif /* SONAME_LIBFONTCONFIG */
965 /* now check Xft resources */
967 char *value;
968 BOOL antialias = TRUE;
970 wine_tsx11_lock();
971 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
973 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
974 value[0] == '0' || !strcasecmp( value, "off" ))
975 antialias = FALSE;
977 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
979 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
980 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
981 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
982 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
983 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
984 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
986 wine_tsx11_unlock();
987 if (!antialias) font_smoothing = FALSE;
990 if (!font_smoothing) entry->aa_default = AA_None;
992 /* we can't support subpixel without xrender */
993 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
995 else
996 entry->aa_default = AA_None;
998 return ret;
1001 static void dec_ref_cache(int index)
1003 assert(index >= 0);
1004 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1005 assert(glyphsetCache[index].count > 0);
1006 glyphsetCache[index].count--;
1009 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1011 DWORD hash = 0, *ptr, two_chars;
1012 WORD *pwc;
1013 int i;
1015 hash ^= plfsz->devsize.cx;
1016 hash ^= plfsz->devsize.cy;
1017 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1018 hash ^= *ptr;
1019 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1020 hash ^= *ptr;
1021 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1022 two_chars = *ptr;
1023 pwc = (WCHAR *)&two_chars;
1024 if(!*pwc) break;
1025 *pwc = toupperW(*pwc);
1026 pwc++;
1027 *pwc = toupperW(*pwc);
1028 hash ^= two_chars;
1029 if(!*pwc) break;
1031 plfsz->hash = hash;
1032 return;
1035 /***********************************************************************
1036 * X11DRV_XRender_Finalize
1038 void X11DRV_XRender_Finalize(void)
1040 int i;
1042 EnterCriticalSection(&xrender_cs);
1043 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1044 FreeEntry(i);
1045 LeaveCriticalSection(&xrender_cs);
1049 /***********************************************************************
1050 * X11DRV_XRender_SelectFont
1052 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1054 LFANDSIZE lfsz;
1055 struct xrender_info *info;
1057 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
1058 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1059 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1060 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1061 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1062 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
1063 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
1065 GetTransform( physDev->dev.hdc, 0x204, &lfsz.xform );
1066 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1067 lfsz.xform.eM21, lfsz.xform.eM22);
1069 /* Not used fields, would break hashing */
1070 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1072 lfsz_calc_hash(&lfsz);
1074 info = get_xrender_info(physDev);
1075 if (!info) return 0;
1077 EnterCriticalSection(&xrender_cs);
1078 if(info->cache_index != -1)
1079 dec_ref_cache(info->cache_index);
1080 info->cache_index = GetCacheEntry(physDev, &lfsz);
1081 LeaveCriticalSection(&xrender_cs);
1082 return 0;
1085 /***********************************************************************
1086 * X11DRV_XRender_SetDeviceClipping
1088 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
1090 if (physDev->xrender->pict)
1092 wine_tsx11_lock();
1093 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1094 physDev->dc_rect.left, physDev->dc_rect.top,
1095 (XRectangle *)data->Buffer, data->rdh.nCount );
1096 wine_tsx11_unlock();
1100 /***********************************************************************
1101 * X11DRV_XRender_DeleteDC
1103 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1105 X11DRV_XRender_UpdateDrawable(physDev);
1107 EnterCriticalSection(&xrender_cs);
1108 if(physDev->xrender->cache_index != -1)
1109 dec_ref_cache(physDev->xrender->cache_index);
1110 LeaveCriticalSection(&xrender_cs);
1112 HeapFree(GetProcessHeap(), 0, physDev->xrender);
1113 physDev->xrender = NULL;
1114 return;
1117 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1119 const WineXRenderFormat *fmt;
1120 ColorShifts shifts;
1122 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1123 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1124 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1125 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1126 return FALSE;
1128 if (dib)
1130 const DWORD *bitfields;
1131 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1132 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1134 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1135 bitfields = dib->dsBitfields;
1136 else if(bits_pixel == 24 || bits_pixel == 32)
1137 bitfields = bitfields_32;
1138 else
1139 bitfields = bitfields_16;
1141 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1142 fmt = get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts);
1144 /* Common formats should be in our picture format table. */
1145 if (!fmt)
1147 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1148 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1149 return FALSE;
1152 else
1154 int red_mask, green_mask, blue_mask;
1156 /* We are dealing with a DDB */
1157 switch (bits_pixel)
1159 case 16:
1160 fmt = get_xrender_format(WXR_FORMAT_R5G6B5);
1161 break;
1162 case 24:
1163 fmt = get_xrender_format(WXR_FORMAT_R8G8B8);
1164 break;
1165 case 32:
1166 fmt = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1167 break;
1168 default:
1169 fmt = NULL;
1172 if (!fmt)
1174 TRACE("Unhandled DDB bits_pixel=%d\n", bits_pixel);
1175 return FALSE;
1178 red_mask = fmt->pict_format->direct.redMask << fmt->pict_format->direct.red;
1179 green_mask = fmt->pict_format->direct.greenMask << fmt->pict_format->direct.green;
1180 blue_mask = fmt->pict_format->direct.blueMask << fmt->pict_format->direct.blue;
1181 X11DRV_PALETTE_ComputeColorShifts(&shifts, red_mask, green_mask, blue_mask);
1184 physBitmap->pixmap_depth = fmt->pict_format->depth;
1185 physBitmap->trueColor = TRUE;
1186 physBitmap->pixmap_color_shifts = shifts;
1187 return TRUE;
1190 /***********************************************************************
1191 * X11DRV_XRender_UpdateDrawable
1193 * Deletes the pict and tile when the drawable changes.
1195 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1197 struct xrender_info *info = physDev->xrender;
1199 if (info->pict || info->pict_src)
1201 wine_tsx11_lock();
1202 XFlush( gdi_display );
1203 if (info->pict)
1205 TRACE("freeing pict = %lx dc = %p\n", info->pict, physDev->dev.hdc);
1206 pXRenderFreePicture(gdi_display, info->pict);
1207 info->pict = 0;
1209 if(info->pict_src)
1211 TRACE("freeing pict = %lx dc = %p\n", info->pict_src, physDev->dev.hdc);
1212 pXRenderFreePicture(gdi_display, info->pict_src);
1213 info->pict_src = 0;
1215 wine_tsx11_unlock();
1218 info->format = NULL;
1221 /************************************************************************
1222 * UploadGlyph
1224 * Helper to ExtTextOut. Must be called inside xrender_cs
1226 static void UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
1228 unsigned int buflen;
1229 char *buf;
1230 Glyph gid;
1231 GLYPHMETRICS gm;
1232 XGlyphInfo gi;
1233 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
1234 gsCacheEntryFormat *formatEntry;
1235 UINT ggo_format = GGO_GLYPH_INDEX;
1236 WXRFormat wxr_format;
1237 static const char zero[4];
1238 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1240 switch(format) {
1241 case AA_Grey:
1242 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1243 break;
1244 case AA_RGB:
1245 ggo_format |= WINE_GGO_HRGB_BITMAP;
1246 break;
1247 case AA_BGR:
1248 ggo_format |= WINE_GGO_HBGR_BITMAP;
1249 break;
1250 case AA_VRGB:
1251 ggo_format |= WINE_GGO_VRGB_BITMAP;
1252 break;
1253 case AA_VBGR:
1254 ggo_format |= WINE_GGO_VBGR_BITMAP;
1255 break;
1257 default:
1258 ERR("aa = %d - not implemented\n", format);
1259 case AA_None:
1260 ggo_format |= GGO_BITMAP;
1261 break;
1264 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1265 if(buflen == GDI_ERROR) {
1266 if(format != AA_None) {
1267 format = AA_None;
1268 entry->aa_default = AA_None;
1269 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1270 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1272 if(buflen == GDI_ERROR) {
1273 WARN("GetGlyphOutlineW failed using default glyph\n");
1274 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1275 if(buflen == GDI_ERROR) {
1276 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1277 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1278 if(buflen == GDI_ERROR) {
1279 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1280 return;
1284 TRACE("Turning off antialiasing for this monochrome font\n");
1287 /* If there is nothing for the current type, we create the entry. */
1288 if( !entry->format[format] ) {
1289 entry->format[format] = HeapAlloc(GetProcessHeap(),
1290 HEAP_ZERO_MEMORY,
1291 sizeof(gsCacheEntryFormat));
1293 formatEntry = entry->format[format];
1295 if(formatEntry->nrealized <= glyph) {
1296 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1298 if (formatEntry->realized)
1299 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1300 HEAP_ZERO_MEMORY,
1301 formatEntry->realized,
1302 formatEntry->nrealized * sizeof(BOOL));
1303 else
1304 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1305 HEAP_ZERO_MEMORY,
1306 formatEntry->nrealized * sizeof(BOOL));
1308 if(!X11DRV_XRender_Installed) {
1309 if (formatEntry->bitmaps)
1310 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1311 HEAP_ZERO_MEMORY,
1312 formatEntry->bitmaps,
1313 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1314 else
1315 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1316 HEAP_ZERO_MEMORY,
1317 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1319 if (formatEntry->gis)
1320 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1321 HEAP_ZERO_MEMORY,
1322 formatEntry->gis,
1323 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1324 else
1325 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1326 HEAP_ZERO_MEMORY,
1327 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1331 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1332 switch(format) {
1333 case AA_Grey:
1334 wxr_format = WXR_FORMAT_GRAY;
1335 break;
1337 case AA_RGB:
1338 case AA_BGR:
1339 case AA_VRGB:
1340 case AA_VBGR:
1341 wxr_format = WXR_FORMAT_A8R8G8B8;
1342 break;
1344 default:
1345 ERR("aa = %d - not implemented\n", format);
1346 case AA_None:
1347 wxr_format = WXR_FORMAT_MONO;
1348 break;
1351 wine_tsx11_lock();
1352 formatEntry->font_format = get_xrender_format(wxr_format);
1353 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
1354 wine_tsx11_unlock();
1358 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1359 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1360 formatEntry->realized[glyph] = TRUE;
1362 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1363 buflen,
1364 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1365 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1367 gi.width = gm.gmBlackBoxX;
1368 gi.height = gm.gmBlackBoxY;
1369 gi.x = -gm.gmptGlyphOrigin.x;
1370 gi.y = gm.gmptGlyphOrigin.y;
1371 gi.xOff = gm.gmCellIncX;
1372 gi.yOff = gm.gmCellIncY;
1374 if(TRACE_ON(xrender)) {
1375 int pitch, i, j;
1376 char output[300];
1377 unsigned char *line;
1379 if(format == AA_None) {
1380 pitch = ((gi.width + 31) / 32) * 4;
1381 for(i = 0; i < gi.height; i++) {
1382 line = (unsigned char*) buf + i * pitch;
1383 output[0] = '\0';
1384 for(j = 0; j < pitch * 8; j++) {
1385 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1387 TRACE("%s\n", output);
1389 } else {
1390 static const char blks[] = " .:;!o*#";
1391 char str[2];
1393 str[1] = '\0';
1394 pitch = ((gi.width + 3) / 4) * 4;
1395 for(i = 0; i < gi.height; i++) {
1396 line = (unsigned char*) buf + i * pitch;
1397 output[0] = '\0';
1398 for(j = 0; j < pitch; j++) {
1399 str[0] = blks[line[j] >> 5];
1400 strcat(output, str);
1402 TRACE("%s\n", output);
1408 if(formatEntry->glyphset) {
1409 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1410 unsigned char *byte = (unsigned char*) buf, c;
1411 int i = buflen;
1413 while(i--) {
1414 c = *byte;
1416 /* magic to flip bit order */
1417 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1418 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1419 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1421 *byte++ = c;
1424 else if ( format != AA_Grey &&
1425 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1427 unsigned int i, *data = (unsigned int *)buf;
1428 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1430 gid = glyph;
1433 XRenderCompositeText seems to ignore 0x0 glyphs when
1434 AA_None, which means we lose the advance width of glyphs
1435 like the space. We'll pretend that such glyphs are 1x1
1436 bitmaps.
1439 if(buflen == 0)
1440 gi.width = gi.height = 1;
1442 wine_tsx11_lock();
1443 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1444 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1445 wine_tsx11_unlock();
1446 HeapFree(GetProcessHeap(), 0, buf);
1447 } else {
1448 formatEntry->bitmaps[glyph] = buf;
1451 formatEntry->gis[glyph] = gi;
1454 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
1455 void *bitmap, XGlyphInfo *gi)
1457 unsigned char *srcLine = bitmap, *src;
1458 unsigned char bits, bitsMask;
1459 int width = gi->width;
1460 int stride = ((width + 31) & ~31) >> 3;
1461 int height = gi->height;
1462 int w;
1463 int xspan, lenspan;
1465 TRACE("%d, %d\n", x, y);
1466 x -= gi->x;
1467 y -= gi->y;
1468 while (height--)
1470 src = srcLine;
1471 srcLine += stride;
1472 w = width;
1474 bitsMask = 0x80; /* FreeType is always MSB first */
1475 bits = *src++;
1477 xspan = x;
1478 while (w)
1480 if (bits & bitsMask)
1482 lenspan = 0;
1485 lenspan++;
1486 if (lenspan == w)
1487 break;
1488 bitsMask = bitsMask >> 1;
1489 if (!bitsMask)
1491 bits = *src++;
1492 bitsMask = 0x80;
1494 } while (bits & bitsMask);
1495 XFillRectangle (gdi_display, physDev->drawable,
1496 physDev->gc, xspan, y, lenspan, 1);
1497 xspan += lenspan;
1498 w -= lenspan;
1500 else
1504 w--;
1505 xspan++;
1506 if (!w)
1507 break;
1508 bitsMask = bitsMask >> 1;
1509 if (!bitsMask)
1511 bits = *src++;
1512 bitsMask = 0x80;
1514 } while (!(bits & bitsMask));
1517 y++;
1521 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
1522 void *bitmap, XGlyphInfo *gi)
1524 unsigned char *srcLine = bitmap, *src, bits;
1525 int width = gi->width;
1526 int stride = ((width + 3) & ~3);
1527 int height = gi->height;
1528 int w;
1529 int xspan, lenspan;
1531 x -= gi->x;
1532 y -= gi->y;
1533 while (height--)
1535 src = srcLine;
1536 srcLine += stride;
1537 w = width;
1539 bits = *src++;
1540 xspan = x;
1541 while (w)
1543 if (bits >= 0x80)
1545 lenspan = 0;
1548 lenspan++;
1549 if (lenspan == w)
1550 break;
1551 bits = *src++;
1552 } while (bits >= 0x80);
1553 XFillRectangle (gdi_display, physDev->drawable,
1554 physDev->gc, xspan, y, lenspan, 1);
1555 xspan += lenspan;
1556 w -= lenspan;
1558 else
1562 w--;
1563 xspan++;
1564 if (!w)
1565 break;
1566 bits = *src++;
1567 } while (bits < 0x80);
1570 y++;
1575 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1577 int s, l;
1579 s = 0;
1580 while ((mask & 1) == 0)
1582 mask >>= 1;
1583 s++;
1585 l = 0;
1586 while ((mask & 1) == 1)
1588 mask >>= 1;
1589 l++;
1591 *shift = s;
1592 *len = l;
1595 static DWORD GetField (DWORD pixel, int shift, int len)
1597 pixel = pixel & (((1 << (len)) - 1) << shift);
1598 pixel = pixel << (32 - (shift + len)) >> 24;
1599 while (len < 8)
1601 pixel |= (pixel >> len);
1602 len <<= 1;
1604 return pixel;
1608 static DWORD PutField (DWORD pixel, int shift, int len)
1610 shift = shift - (8 - len);
1611 if (len <= 8)
1612 pixel &= (((1 << len) - 1) << (8 - len));
1613 if (shift < 0)
1614 pixel >>= -shift;
1615 else
1616 pixel <<= shift;
1617 return pixel;
1620 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1621 int color)
1623 int r_shift, r_len;
1624 int g_shift, g_len;
1625 int b_shift, b_len;
1626 BYTE *maskLine, *mask, m;
1627 int maskStride;
1628 DWORD pixel;
1629 int width, height;
1630 int w, tx;
1631 BYTE src_r, src_g, src_b;
1633 x -= gi->x;
1634 y -= gi->y;
1635 width = gi->width;
1636 height = gi->height;
1638 maskLine = bitmap;
1639 maskStride = (width + 3) & ~3;
1641 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1642 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1643 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1645 src_r = GetField(color, r_shift, r_len);
1646 src_g = GetField(color, g_shift, g_len);
1647 src_b = GetField(color, b_shift, b_len);
1649 for(; height--; y++)
1651 mask = maskLine;
1652 maskLine += maskStride;
1653 w = width;
1654 tx = x;
1656 if(y < 0) continue;
1657 if(y >= image->height) break;
1659 for(; w--; tx++)
1661 if(tx >= image->width) break;
1663 m = *mask++;
1664 if(tx < 0) continue;
1666 if (m == 0xff)
1667 XPutPixel (image, tx, y, color);
1668 else if (m)
1670 BYTE r, g, b;
1672 pixel = XGetPixel (image, tx, y);
1674 r = GetField(pixel, r_shift, r_len);
1675 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1676 g = GetField(pixel, g_shift, g_len);
1677 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1678 b = GetField(pixel, b_shift, b_len);
1679 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1681 pixel = (PutField (r, r_shift, r_len) |
1682 PutField (g, g_shift, g_len) |
1683 PutField (b, b_shift, b_len));
1684 XPutPixel (image, tx, y, pixel);
1690 /*************************************************************
1691 * get_tile_pict
1693 * Returns an appropriate Picture for tiling the text colour.
1694 * Call and use result within the xrender_cs
1696 static Picture get_tile_pict(const WineXRenderFormat *wxr_format, int text_pixel)
1698 static struct
1700 Pixmap xpm;
1701 Picture pict;
1702 int current_color;
1703 } tiles[WXR_NB_FORMATS], *tile;
1704 XRenderColor col;
1706 tile = &tiles[wxr_format->format];
1708 if(!tile->xpm)
1710 XRenderPictureAttributes pa;
1712 wine_tsx11_lock();
1713 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1715 pa.repeat = RepeatNormal;
1716 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1717 wine_tsx11_unlock();
1719 /* init current_color to something different from text_pixel */
1720 tile->current_color = ~text_pixel;
1722 if(wxr_format->format == WXR_FORMAT_MONO)
1724 /* for a 1bpp bitmap we always need a 1 in the tile */
1725 col.red = col.green = col.blue = 0;
1726 col.alpha = 0xffff;
1727 wine_tsx11_lock();
1728 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1729 wine_tsx11_unlock();
1733 if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1735 get_xrender_color(wxr_format, text_pixel, &col);
1736 wine_tsx11_lock();
1737 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1738 wine_tsx11_unlock();
1739 tile->current_color = text_pixel;
1741 return tile->pict;
1744 /*************************************************************
1745 * get_mask_pict
1747 * Returns an appropriate Picture for masking with the specified alpha.
1748 * Call and use result within the xrender_cs
1750 static Picture get_mask_pict( int alpha )
1752 static Pixmap pixmap;
1753 static Picture pict;
1754 static int current_alpha;
1756 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1758 if (!pixmap)
1760 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
1761 XRenderPictureAttributes pa;
1763 wine_tsx11_lock();
1764 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1765 pa.repeat = RepeatNormal;
1766 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format, CPRepeat, &pa );
1767 wine_tsx11_unlock();
1768 current_alpha = -1;
1771 if (alpha != current_alpha)
1773 XRenderColor col;
1774 col.red = col.green = col.blue = 0;
1775 col.alpha = current_alpha = alpha;
1776 wine_tsx11_lock();
1777 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1778 wine_tsx11_unlock();
1780 return pict;
1783 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1785 return 1;
1788 /********************************************************************
1789 * is_dib_with_colortable
1791 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1793 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1795 DIBSECTION dib;
1797 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1798 dib.dsBmih.biBitCount <= 8 )
1799 return TRUE;
1801 return FALSE;
1804 /***********************************************************************
1805 * X11DRV_XRender_ExtTextOut
1807 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1808 const RECT *lprect, LPCWSTR wstr, UINT count,
1809 const INT *lpDx )
1811 XGCValues xgcval;
1812 gsCacheEntry *entry;
1813 gsCacheEntryFormat *formatEntry;
1814 BOOL retv = FALSE;
1815 int textPixel, backgroundPixel;
1816 HRGN saved_region = 0;
1817 BOOL disable_antialias = FALSE;
1818 AA_Type aa_type = AA_None;
1819 unsigned int idx;
1820 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
1821 Picture tile_pict = 0;
1823 if(is_dib_with_colortable( physDev ))
1825 TRACE("Disabling antialiasing\n");
1826 disable_antialias = TRUE;
1829 xgcval.function = GXcopy;
1830 xgcval.background = physDev->backgroundPixel;
1831 xgcval.fill_style = FillSolid;
1832 wine_tsx11_lock();
1833 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1834 wine_tsx11_unlock();
1836 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1838 if(physDev->depth == 1) {
1839 if((physDev->textPixel & 0xffffff) == 0) {
1840 textPixel = 0;
1841 backgroundPixel = 1;
1842 } else {
1843 textPixel = 1;
1844 backgroundPixel = 0;
1846 } else {
1847 textPixel = physDev->textPixel;
1848 backgroundPixel = physDev->backgroundPixel;
1851 if(flags & ETO_OPAQUE)
1853 wine_tsx11_lock();
1854 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1855 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1856 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1857 lprect->right - lprect->left, lprect->bottom - lprect->top );
1858 wine_tsx11_unlock();
1861 if(count == 0)
1863 retv = TRUE;
1864 goto done_unlock;
1867 if (flags & ETO_CLIPPED)
1869 HRGN clip_region;
1871 clip_region = CreateRectRgnIndirect( lprect );
1872 /* make a copy of the current device region */
1873 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1874 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1875 X11DRV_SetDeviceClipping( &physDev->dev, saved_region, clip_region );
1876 DeleteObject( clip_region );
1879 EnterCriticalSection(&xrender_cs);
1881 entry = glyphsetCache + physDev->xrender->cache_index;
1882 if( disable_antialias == FALSE )
1883 aa_type = entry->aa_default;
1884 formatEntry = entry->format[aa_type];
1886 for(idx = 0; idx < count; idx++) {
1887 if( !formatEntry ) {
1888 UploadGlyph(physDev, wstr[idx], aa_type);
1889 /* re-evaluate antialias since aa_default may have changed */
1890 if( disable_antialias == FALSE )
1891 aa_type = entry->aa_default;
1892 formatEntry = entry->format[aa_type];
1893 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1894 UploadGlyph(physDev, wstr[idx], aa_type);
1897 if (!formatEntry)
1899 WARN("could not upload requested glyphs\n");
1900 LeaveCriticalSection(&xrender_cs);
1901 goto done_unlock;
1904 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1905 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1907 if(X11DRV_XRender_Installed)
1909 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1910 POINT offset = {0, 0};
1911 POINT desired, current;
1912 int render_op = PictOpOver;
1913 Picture pict = get_xrender_picture(physDev);
1915 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1916 So we pass zeros to the function and move to our starting position using the first
1917 element of the elts array. */
1919 desired.x = physDev->dc_rect.left + x;
1920 desired.y = physDev->dc_rect.top + y;
1921 current.x = current.y = 0;
1923 tile_pict = get_tile_pict(dst_format, physDev->textPixel);
1925 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1927 if((dst_format->format == WXR_FORMAT_MONO) && (textPixel == 0))
1928 render_op = PictOpOutReverse; /* This gives us 'black' text */
1930 for(idx = 0; idx < count; idx++)
1932 elts[idx].glyphset = formatEntry->glyphset;
1933 elts[idx].chars = wstr + idx;
1934 elts[idx].nchars = 1;
1935 elts[idx].xOff = desired.x - current.x;
1936 elts[idx].yOff = desired.y - current.y;
1938 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1939 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1941 if(!lpDx)
1943 desired.x += formatEntry->gis[wstr[idx]].xOff;
1944 desired.y += formatEntry->gis[wstr[idx]].yOff;
1946 else
1948 if(flags & ETO_PDY)
1950 offset.x += lpDx[idx * 2];
1951 offset.y += lpDx[idx * 2 + 1];
1953 else
1954 offset.x += lpDx[idx];
1955 desired.x = physDev->dc_rect.left + x + offset.x;
1956 desired.y = physDev->dc_rect.top + y + offset.y;
1959 wine_tsx11_lock();
1960 /* Make sure we don't have any transforms set from a previous call */
1961 set_xrender_transformation(pict, 1, 1, 0, 0);
1962 pXRenderCompositeText16(gdi_display, render_op,
1963 tile_pict,
1964 pict,
1965 formatEntry->font_format->pict_format,
1966 0, 0, 0, 0, elts, count);
1967 wine_tsx11_unlock();
1968 HeapFree(GetProcessHeap(), 0, elts);
1969 } else {
1970 POINT offset = {0, 0};
1971 wine_tsx11_lock();
1972 XSetForeground( gdi_display, physDev->gc, textPixel );
1974 if(aa_type == AA_None || physDev->depth == 1)
1976 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1978 if(aa_type == AA_None)
1979 sharp_glyph_fn = SharpGlyphMono;
1980 else
1981 sharp_glyph_fn = SharpGlyphGray;
1983 for(idx = 0; idx < count; idx++) {
1984 sharp_glyph_fn(physDev,
1985 physDev->dc_rect.left + x + offset.x,
1986 physDev->dc_rect.top + y + offset.y,
1987 formatEntry->bitmaps[wstr[idx]],
1988 &formatEntry->gis[wstr[idx]]);
1989 if(lpDx)
1991 if(flags & ETO_PDY)
1993 offset.x += lpDx[idx * 2];
1994 offset.y += lpDx[idx * 2 + 1];
1996 else
1997 offset.x += lpDx[idx];
1999 else
2001 offset.x += formatEntry->gis[wstr[idx]].xOff;
2002 offset.y += formatEntry->gis[wstr[idx]].yOff;
2005 } else {
2006 XImage *image;
2007 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2008 RECT extents = {0, 0, 0, 0};
2009 POINT cur = {0, 0};
2010 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
2011 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
2013 TRACE("drawable %dx%d\n", w, h);
2015 for(idx = 0; idx < count; idx++) {
2016 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2017 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2018 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2019 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2020 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2021 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2022 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2023 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2025 if(lpDx)
2027 if(flags & ETO_PDY)
2029 cur.x += lpDx[idx * 2];
2030 cur.y += lpDx[idx * 2 + 1];
2032 else
2033 cur.x += lpDx[idx];
2035 else
2037 cur.x += formatEntry->gis[wstr[idx]].xOff;
2038 cur.y += formatEntry->gis[wstr[idx]].yOff;
2041 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2042 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
2044 if(physDev->dc_rect.left + x + extents.left >= 0) {
2045 image_x = physDev->dc_rect.left + x + extents.left;
2046 image_off_x = 0;
2047 } else {
2048 image_x = 0;
2049 image_off_x = physDev->dc_rect.left + x + extents.left;
2051 if(physDev->dc_rect.top + y + extents.top >= 0) {
2052 image_y = physDev->dc_rect.top + y + extents.top;
2053 image_off_y = 0;
2054 } else {
2055 image_y = 0;
2056 image_off_y = physDev->dc_rect.top + y + extents.top;
2058 if(physDev->dc_rect.left + x + extents.right < w)
2059 image_w = physDev->dc_rect.left + x + extents.right - image_x;
2060 else
2061 image_w = w - image_x;
2062 if(physDev->dc_rect.top + y + extents.bottom < h)
2063 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
2064 else
2065 image_h = h - image_y;
2067 if(image_w <= 0 || image_h <= 0) goto no_image;
2069 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2070 image = XGetImage(gdi_display, physDev->drawable,
2071 image_x, image_y, image_w, image_h,
2072 AllPlanes, ZPixmap);
2073 X11DRV_check_error();
2075 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2076 gdi_display, (int)physDev->drawable, image_x, image_y,
2077 image_w, image_h, AllPlanes, ZPixmap,
2078 physDev->depth, image);
2079 if(!image) {
2080 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2081 physDev->depth);
2082 GC gc;
2083 XGCValues gcv;
2085 gcv.graphics_exposures = False;
2086 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2087 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
2088 image_w, image_h, 0, 0);
2089 XFreeGC(gdi_display, gc);
2090 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2091 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2092 ZPixmap);
2093 X11DRV_check_error();
2094 XFreePixmap(gdi_display, xpm);
2096 if(!image) goto no_image;
2098 image->red_mask = visual->red_mask;
2099 image->green_mask = visual->green_mask;
2100 image->blue_mask = visual->blue_mask;
2102 for(idx = 0; idx < count; idx++) {
2103 SmoothGlyphGray(image,
2104 offset.x + image_off_x - extents.left,
2105 offset.y + image_off_y - extents.top,
2106 formatEntry->bitmaps[wstr[idx]],
2107 &formatEntry->gis[wstr[idx]],
2108 physDev->textPixel);
2109 if(lpDx)
2111 if(flags & ETO_PDY)
2113 offset.x += lpDx[idx * 2];
2114 offset.y += lpDx[idx * 2 + 1];
2116 else
2117 offset.x += lpDx[idx];
2119 else
2121 offset.x += formatEntry->gis[wstr[idx]].xOff;
2122 offset.y += formatEntry->gis[wstr[idx]].yOff;
2125 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
2126 image_x, image_y, image_w, image_h);
2127 XDestroyImage(image);
2129 no_image:
2130 wine_tsx11_unlock();
2132 LeaveCriticalSection(&xrender_cs);
2134 if (flags & ETO_CLIPPED)
2136 /* restore the device region */
2137 X11DRV_SetDeviceClipping( &physDev->dev, saved_region, 0 );
2138 DeleteObject( saved_region );
2141 retv = TRUE;
2143 done_unlock:
2144 X11DRV_UnlockDIBSection( physDev, TRUE );
2145 return retv;
2148 /* Helper function for (stretched) blitting using xrender */
2149 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2150 int x_src, int y_src, int x_dst, int y_dst,
2151 double xscale, double yscale, int width, int height )
2153 int x_offset, y_offset;
2155 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2156 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2157 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2158 if(xscale != 1.0 || yscale != 1.0)
2160 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2161 * in the wrong quadrant of the x-y plane.
2163 x_offset = (xscale < 0) ? -width : 0;
2164 y_offset = (yscale < 0) ? -height : 0;
2165 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2167 else
2169 x_offset = x_src;
2170 y_offset = y_src;
2171 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2173 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2174 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2177 /* Helper function for (stretched) mono->color blitting using xrender */
2178 static void xrender_mono_blit( Picture src_pict, Picture mask_pict, Picture dst_pict,
2179 int x_src, int y_src, double xscale, double yscale, int width, int height )
2181 int x_offset, y_offset;
2183 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2184 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
2185 * tile data. We need PictOpOver for correct rendering.
2186 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2187 * mask_x / mask_y
2189 if (xscale != 1.0 || yscale != 1.0)
2191 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2192 * in the wrong quadrant of the x-y plane.
2194 x_offset = (xscale < 0) ? -width : 0;
2195 y_offset = (yscale < 0) ? -height : 0;
2196 set_xrender_transformation(mask_pict, xscale, yscale, x_src, y_src);
2198 else
2200 x_offset = x_src;
2201 y_offset = y_src;
2202 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
2204 pXRenderComposite(gdi_display, PictOpOver, src_pict, mask_pict, dst_pict,
2205 0, 0, x_offset, y_offset, 0, 0, width, height);
2208 /******************************************************************************
2209 * AlphaBlend
2211 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, struct bitblt_coords *dst,
2212 X11DRV_PDEVICE *devSrc, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2214 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2215 struct xrender_info *src_info = get_xrender_info( devSrc );
2216 double xscale, yscale;
2217 BOOL use_repeat;
2219 if(!X11DRV_XRender_Installed) {
2220 FIXME("Unable to AlphaBlend without Xrender\n");
2221 return FALSE;
2224 if (devSrc != devDst) X11DRV_LockDIBSection( devSrc, DIB_Status_GdiMod );
2225 X11DRV_LockDIBSection( devDst, DIB_Status_GdiMod );
2227 dst_pict = get_xrender_picture( devDst );
2229 use_repeat = use_source_repeat( devSrc );
2230 if (!use_repeat)
2232 xscale = src->width / (double)dst->width;
2233 yscale = src->height / (double)dst->height;
2235 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2237 if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && src_info->format)
2239 /* we need a source picture with no alpha */
2240 WXRFormat format = get_format_without_alpha( src_info->format->format );
2241 if (format != src_info->format->format)
2243 XRenderPictureAttributes pa;
2244 const WineXRenderFormat *fmt = get_xrender_format( format );
2246 wine_tsx11_lock();
2247 pa.subwindow_mode = IncludeInferiors;
2248 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2249 tmp_pict = pXRenderCreatePicture( gdi_display, devSrc->drawable, fmt->pict_format,
2250 CPSubwindowMode|CPRepeat, &pa );
2251 wine_tsx11_unlock();
2252 src_pict = tmp_pict;
2256 if (!src_pict) src_pict = get_xrender_picture_source( devSrc, use_repeat );
2258 EnterCriticalSection( &xrender_cs );
2259 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2261 wine_tsx11_lock();
2262 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2263 devSrc->dc_rect.left + src->visrect.left, devSrc->dc_rect.top + src->visrect.top,
2264 devDst->dc_rect.left + dst->visrect.left, devDst->dc_rect.top + dst->visrect.top,
2265 xscale, yscale,
2266 dst->visrect.right - dst->visrect.left, dst->visrect.bottom - dst->visrect.top );
2267 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2268 wine_tsx11_unlock();
2270 LeaveCriticalSection( &xrender_cs );
2271 if (devSrc != devDst) X11DRV_UnlockDIBSection( devSrc, FALSE );
2272 X11DRV_UnlockDIBSection( devDst, TRUE );
2273 return TRUE;
2277 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2279 /* At depths >1, the depth of physBitmap and physDev might not be the same e.g. the physbitmap might be a 16-bit DIB while the physdev uses 24-bit */
2280 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2281 const WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2282 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2284 wine_tsx11_lock();
2285 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2287 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2288 if( (physBitmap->pixmap_depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->pixmap_depth) ||
2289 (src_format->format == dst_format->format) )
2291 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2292 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2294 else /* We need depth conversion */
2296 Picture src_pict, dst_pict;
2297 XRenderPictureAttributes pa;
2298 pa.subwindow_mode = IncludeInferiors;
2299 pa.repeat = RepeatNone;
2301 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2302 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2304 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2305 pXRenderFreePicture(gdi_display, src_pict);
2306 pXRenderFreePicture(gdi_display, dst_pict);
2308 wine_tsx11_unlock();
2311 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2312 Pixmap pixmap, GC gc,
2313 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2315 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2316 int width = dst->visrect.right - dst->visrect.left;
2317 int height = dst->visrect.bottom - dst->visrect.top;
2318 int x_src = physDevSrc->dc_rect.left + src->visrect.left;
2319 int y_src = physDevSrc->dc_rect.top + src->visrect.top;
2320 struct xrender_info *src_info = get_xrender_info(physDevSrc);
2321 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDevDst->depth, physDevDst->color_shifts);
2322 Picture src_pict=0, dst_pict=0, mask_pict=0;
2323 BOOL use_repeat;
2324 double xscale, yscale;
2326 XRenderPictureAttributes pa;
2327 pa.subwindow_mode = IncludeInferiors;
2328 pa.repeat = RepeatNone;
2330 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2331 physDevSrc->depth, src->width, src->height, x_src, y_src);
2332 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst->depth, dst->width, dst->height);
2334 if(!X11DRV_XRender_Installed)
2336 TRACE("Not using XRender since it is not available or disabled\n");
2337 return FALSE;
2340 /* XRender can't handle palettes, so abort */
2341 if(X11DRV_PALETTE_XPixelToPalette)
2342 return FALSE;
2344 /* XRender is of no use in this case */
2345 if((physDevDst->depth == 1) && (physDevSrc->depth > 1))
2346 return FALSE;
2348 /* Just use traditional X copy when the formats match and we don't need stretching */
2349 if((src_info->format->format == dst_format->format) && !stretch)
2351 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2352 wine_tsx11_lock();
2353 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
2354 wine_tsx11_unlock();
2355 return TRUE;
2358 use_repeat = use_source_repeat( physDevSrc );
2359 if (!use_repeat)
2361 xscale = src->width / (double)dst->width;
2362 yscale = src->height / (double)dst->height;
2364 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2366 /* mono -> color */
2367 if(physDevSrc->depth == 1 && physDevDst->depth > 1)
2369 XRenderColor col;
2370 get_xrender_color(dst_format, physDevDst->textPixel, &col);
2372 /* We use the source drawable as a mask */
2373 mask_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2375 /* Use backgroundPixel as the foreground color */
2376 EnterCriticalSection( &xrender_cs );
2377 src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
2379 /* Create a destination picture and fill it with textPixel color as the background color */
2380 wine_tsx11_lock();
2381 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2382 pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height);
2384 xrender_mono_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
2386 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2387 wine_tsx11_unlock();
2388 LeaveCriticalSection( &xrender_cs );
2390 else /* color -> color (can be at different depths) or mono -> mono */
2392 if (physDevDst->depth == 32 && physDevSrc->depth < 32) mask_pict = get_no_alpha_mask();
2393 src_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2395 wine_tsx11_lock();
2396 dst_pict = pXRenderCreatePicture(gdi_display,
2397 pixmap, dst_format->pict_format,
2398 CPSubwindowMode|CPRepeat, &pa);
2400 xrender_blit(PictOpSrc, src_pict, mask_pict, dst_pict,
2401 x_src, y_src, 0, 0, xscale, yscale, width, height);
2403 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2404 wine_tsx11_unlock();
2406 return TRUE;
2409 #else /* SONAME_LIBXRENDER */
2411 void X11DRV_XRender_Init(void)
2413 TRACE("XRender support not compiled in.\n");
2414 return;
2417 void X11DRV_XRender_Finalize(void)
2421 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
2423 assert(0);
2424 return FALSE;
2427 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
2429 assert(0);
2430 return;
2433 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
2435 assert(0);
2436 return;
2439 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
2440 const RECT *lprect, LPCWSTR wstr, UINT count,
2441 const INT *lpDx )
2443 assert(0);
2444 return FALSE;
2447 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
2449 assert(0);
2450 return;
2453 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2454 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2456 FIXME("not supported - XRENDER headers were missing at compile time\n");
2457 return FALSE;
2460 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2462 wine_tsx11_lock();
2463 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
2465 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2466 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2467 wine_tsx11_unlock();
2470 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2472 return FALSE;
2475 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2476 Pixmap pixmap, GC gc,
2477 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2479 return FALSE;
2481 #endif /* SONAME_LIBXRENDER */