comctl32/monthcal: Remove unused variable (Clang).
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blob48ecd226915b8be2619280b496992c2f34198503
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->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->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) { /* reached free list so stop */
664 i = -1;
665 break;
668 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
669 glyphsetCache[i].count++;
670 if(prev_i >= 0) {
671 glyphsetCache[prev_i].next = glyphsetCache[i].next;
672 glyphsetCache[i].next = mru;
673 mru = i;
675 TRACE("found font in cache %d\n", i);
676 return i;
678 prev_i = i;
680 TRACE("font not in cache\n");
681 return -1;
684 static void FreeEntry(int entry)
686 int i, format;
688 for(format = 0; format < AA_MAXVALUE; format++) {
689 gsCacheEntryFormat * formatEntry;
691 if( !glyphsetCache[entry].format[format] )
692 continue;
694 formatEntry = glyphsetCache[entry].format[format];
696 if(formatEntry->glyphset) {
697 wine_tsx11_lock();
698 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
699 wine_tsx11_unlock();
700 formatEntry->glyphset = 0;
702 if(formatEntry->nrealized) {
703 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
704 formatEntry->realized = NULL;
705 if(formatEntry->bitmaps) {
706 for(i = 0; i < formatEntry->nrealized; i++)
707 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
708 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
709 formatEntry->bitmaps = NULL;
711 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
712 formatEntry->gis = NULL;
713 formatEntry->nrealized = 0;
716 HeapFree(GetProcessHeap(), 0, formatEntry);
717 glyphsetCache[entry].format[format] = NULL;
721 static int AllocEntry(void)
723 int best = -1, prev_best = -1, i, prev_i = -1;
725 if(lastfree >= 0) {
726 assert(glyphsetCache[lastfree].count == -1);
727 glyphsetCache[lastfree].count = 1;
728 best = lastfree;
729 lastfree = glyphsetCache[lastfree].next;
730 assert(best != mru);
731 glyphsetCache[best].next = mru;
732 mru = best;
734 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
735 return mru;
738 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
739 if(glyphsetCache[i].count == 0) {
740 best = i;
741 prev_best = prev_i;
743 prev_i = i;
746 if(best >= 0) {
747 TRACE("freeing unused glyphset at cache %d\n", best);
748 FreeEntry(best);
749 glyphsetCache[best].count = 1;
750 if(prev_best >= 0) {
751 glyphsetCache[prev_best].next = glyphsetCache[best].next;
752 glyphsetCache[best].next = mru;
753 mru = best;
754 } else {
755 assert(mru == best);
757 return mru;
760 TRACE("Growing cache\n");
762 if (glyphsetCache)
763 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
764 glyphsetCache,
765 (glyphsetCacheSize + INIT_CACHE_SIZE)
766 * sizeof(*glyphsetCache));
767 else
768 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
769 (glyphsetCacheSize + INIT_CACHE_SIZE)
770 * sizeof(*glyphsetCache));
772 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
773 i++) {
774 glyphsetCache[i].next = i + 1;
775 glyphsetCache[i].count = -1;
777 glyphsetCache[i-1].next = -1;
778 glyphsetCacheSize += INIT_CACHE_SIZE;
780 lastfree = glyphsetCache[best].next;
781 glyphsetCache[best].count = 1;
782 glyphsetCache[best].next = mru;
783 mru = best;
784 TRACE("new free cache slot at %d\n", mru);
785 return mru;
788 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
790 DWORD size;
791 WORD *gasp, *buffer;
792 WORD num_recs;
793 DWORD ppem;
794 TEXTMETRICW tm;
796 *flags = 0;
798 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
799 if(size == GDI_ERROR)
800 return FALSE;
802 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
803 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
805 GetTextMetricsW(physDev->hdc, &tm);
806 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
808 gasp++;
809 num_recs = get_be_word(*gasp);
810 gasp++;
811 while(num_recs--)
813 *flags = get_be_word(*(gasp + 1));
814 if(ppem <= get_be_word(*gasp))
815 break;
816 gasp += 2;
818 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
820 HeapFree(GetProcessHeap(), 0, buffer);
821 return TRUE;
824 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
826 AA_Type ret;
827 WORD flags;
828 UINT font_smoothing_type, font_smoothing_orientation;
830 if (X11DRV_XRender_Installed && subpixel &&
831 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
832 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
834 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
835 &font_smoothing_orientation, 0) &&
836 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
838 ret = AA_BGR;
840 else
841 ret = AA_RGB;
842 /*FIXME
843 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
844 But, Wine's subpixel rendering can support the portrait mode.
847 else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
848 ret = AA_Grey;
849 else
850 ret = AA_None;
852 return ret;
855 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
857 int ret;
858 int format;
859 gsCacheEntry *entry;
860 static int hinter = -1;
861 static int subpixel = -1;
862 BOOL font_smoothing;
864 if((ret = LookupEntry(plfsz)) != -1) return ret;
866 ret = AllocEntry();
867 entry = glyphsetCache + ret;
868 entry->lfsz = *plfsz;
869 for( format = 0; format < AA_MAXVALUE; format++ ) {
870 assert( !entry->format[format] );
873 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
875 if(hinter == -1 || subpixel == -1)
877 RASTERIZER_STATUS status;
878 GetRasterizerCaps(&status, sizeof(status));
879 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
880 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
883 switch (plfsz->lf.lfQuality)
885 case ANTIALIASED_QUALITY:
886 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
887 return ret; /* ignore further configuration */
888 case CLEARTYPE_QUALITY:
889 case CLEARTYPE_NATURAL_QUALITY:
890 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
891 break;
892 case DEFAULT_QUALITY:
893 case DRAFT_QUALITY:
894 case PROOF_QUALITY:
895 default:
896 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
897 font_smoothing)
899 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
901 else
902 entry->aa_default = AA_None;
903 break;
906 font_smoothing = TRUE; /* default to enabled */
907 #ifdef SONAME_LIBFONTCONFIG
908 if (fontconfig_installed)
910 FcPattern *match, *pattern = pFcPatternCreate();
911 FcResult result;
912 char family[LF_FACESIZE * 4];
914 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
915 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
916 if (plfsz->lf.lfWeight != FW_DONTCARE)
918 int weight;
919 switch (plfsz->lf.lfWeight)
921 case FW_THIN: weight = FC_WEIGHT_THIN; break;
922 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
923 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
924 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
925 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
926 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
927 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
928 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
929 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
930 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
932 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
934 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
935 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
936 pFcDefaultSubstitute( pattern );
937 if ((match = pFcFontMatch( NULL, pattern, &result )))
939 int rgba;
940 FcBool antialias;
942 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
943 antialias = TRUE;
944 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
946 FcChar8 *file;
947 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
949 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
950 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
952 switch (rgba)
954 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
955 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
956 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
957 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
958 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
961 if (!antialias) font_smoothing = FALSE;
962 pFcPatternDestroy( match );
964 pFcPatternDestroy( pattern );
966 #endif /* SONAME_LIBFONTCONFIG */
968 /* now check Xft resources */
970 char *value;
971 BOOL antialias = TRUE;
973 wine_tsx11_lock();
974 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
976 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
977 value[0] == '0' || !strcasecmp( value, "off" ))
978 antialias = FALSE;
980 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
982 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
983 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
984 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
985 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
986 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
987 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
989 wine_tsx11_unlock();
990 if (!antialias) font_smoothing = FALSE;
993 if (!font_smoothing) entry->aa_default = AA_None;
995 /* we can't support subpixel without xrender */
996 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
998 else
999 entry->aa_default = AA_None;
1001 return ret;
1004 static void dec_ref_cache(int index)
1006 assert(index >= 0);
1007 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1008 assert(glyphsetCache[index].count > 0);
1009 glyphsetCache[index].count--;
1012 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1014 DWORD hash = 0, *ptr, two_chars;
1015 WORD *pwc;
1016 int i;
1018 hash ^= plfsz->devsize.cx;
1019 hash ^= plfsz->devsize.cy;
1020 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1021 hash ^= *ptr;
1022 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1023 hash ^= *ptr;
1024 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1025 two_chars = *ptr;
1026 pwc = (WCHAR *)&two_chars;
1027 if(!*pwc) break;
1028 *pwc = toupperW(*pwc);
1029 pwc++;
1030 *pwc = toupperW(*pwc);
1031 hash ^= two_chars;
1032 if(!*pwc) break;
1034 plfsz->hash = hash;
1035 return;
1038 /***********************************************************************
1039 * X11DRV_XRender_Finalize
1041 void X11DRV_XRender_Finalize(void)
1043 int i;
1045 EnterCriticalSection(&xrender_cs);
1046 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1047 FreeEntry(i);
1048 LeaveCriticalSection(&xrender_cs);
1052 /***********************************************************************
1053 * X11DRV_XRender_SelectFont
1055 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1057 LFANDSIZE lfsz;
1058 struct xrender_info *info;
1060 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
1061 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1062 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1063 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1064 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1065 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
1066 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
1068 GetTransform( physDev->hdc, 0x204, &lfsz.xform );
1069 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1070 lfsz.xform.eM21, lfsz.xform.eM22);
1072 /* Not used fields, would break hashing */
1073 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1075 lfsz_calc_hash(&lfsz);
1077 info = get_xrender_info(physDev);
1078 if (!info) return 0;
1080 EnterCriticalSection(&xrender_cs);
1081 if(info->cache_index != -1)
1082 dec_ref_cache(info->cache_index);
1083 info->cache_index = GetCacheEntry(physDev, &lfsz);
1084 LeaveCriticalSection(&xrender_cs);
1085 return 0;
1088 /***********************************************************************
1089 * X11DRV_XRender_SetDeviceClipping
1091 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
1093 if (physDev->xrender->pict)
1095 wine_tsx11_lock();
1096 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1097 physDev->dc_rect.left, physDev->dc_rect.top,
1098 (XRectangle *)data->Buffer, data->rdh.nCount );
1099 wine_tsx11_unlock();
1103 /***********************************************************************
1104 * X11DRV_XRender_DeleteDC
1106 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1108 X11DRV_XRender_UpdateDrawable(physDev);
1110 EnterCriticalSection(&xrender_cs);
1111 if(physDev->xrender->cache_index != -1)
1112 dec_ref_cache(physDev->xrender->cache_index);
1113 LeaveCriticalSection(&xrender_cs);
1115 HeapFree(GetProcessHeap(), 0, physDev->xrender);
1116 physDev->xrender = NULL;
1117 return;
1120 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1122 const WineXRenderFormat *fmt;
1123 ColorShifts shifts;
1125 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1126 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1127 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1128 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1129 return FALSE;
1131 if (dib)
1133 const DWORD *bitfields;
1134 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1135 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1137 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1138 bitfields = dib->dsBitfields;
1139 else if(bits_pixel == 24 || bits_pixel == 32)
1140 bitfields = bitfields_32;
1141 else
1142 bitfields = bitfields_16;
1144 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1145 fmt = get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts);
1147 /* Common formats should be in our picture format table. */
1148 if (!fmt)
1150 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1151 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1152 return FALSE;
1155 else
1157 int red_mask, green_mask, blue_mask;
1159 /* We are dealing with a DDB */
1160 switch (bits_pixel)
1162 case 16:
1163 fmt = get_xrender_format(WXR_FORMAT_R5G6B5);
1164 break;
1165 case 24:
1166 fmt = get_xrender_format(WXR_FORMAT_R8G8B8);
1167 break;
1168 case 32:
1169 fmt = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1170 break;
1171 default:
1172 fmt = NULL;
1175 if (!fmt)
1177 TRACE("Unhandled DDB bits_pixel=%d\n", bits_pixel);
1178 return FALSE;
1181 red_mask = fmt->pict_format->direct.redMask << fmt->pict_format->direct.red;
1182 green_mask = fmt->pict_format->direct.greenMask << fmt->pict_format->direct.green;
1183 blue_mask = fmt->pict_format->direct.blueMask << fmt->pict_format->direct.blue;
1184 X11DRV_PALETTE_ComputeColorShifts(&shifts, red_mask, green_mask, blue_mask);
1187 physBitmap->pixmap_depth = fmt->pict_format->depth;
1188 physBitmap->trueColor = TRUE;
1189 physBitmap->pixmap_color_shifts = shifts;
1190 return TRUE;
1193 /***********************************************************************
1194 * X11DRV_XRender_UpdateDrawable
1196 * Deletes the pict and tile when the drawable changes.
1198 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1200 struct xrender_info *info = physDev->xrender;
1202 if (info->pict || info->pict_src)
1204 wine_tsx11_lock();
1205 XFlush( gdi_display );
1206 if (info->pict)
1208 TRACE("freeing pict = %lx dc = %p\n", info->pict, physDev->hdc);
1209 pXRenderFreePicture(gdi_display, info->pict);
1210 info->pict = 0;
1212 if(info->pict_src)
1214 TRACE("freeing pict = %lx dc = %p\n", info->pict_src, physDev->hdc);
1215 pXRenderFreePicture(gdi_display, info->pict_src);
1216 info->pict_src = 0;
1218 wine_tsx11_unlock();
1221 info->format = NULL;
1224 /************************************************************************
1225 * UploadGlyph
1227 * Helper to ExtTextOut. Must be called inside xrender_cs
1229 static void UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
1231 unsigned int buflen;
1232 char *buf;
1233 Glyph gid;
1234 GLYPHMETRICS gm;
1235 XGlyphInfo gi;
1236 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
1237 gsCacheEntryFormat *formatEntry;
1238 UINT ggo_format = GGO_GLYPH_INDEX;
1239 WXRFormat wxr_format;
1240 static const char zero[4];
1241 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1243 switch(format) {
1244 case AA_Grey:
1245 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1246 break;
1247 case AA_RGB:
1248 ggo_format |= WINE_GGO_HRGB_BITMAP;
1249 break;
1250 case AA_BGR:
1251 ggo_format |= WINE_GGO_HBGR_BITMAP;
1252 break;
1253 case AA_VRGB:
1254 ggo_format |= WINE_GGO_VRGB_BITMAP;
1255 break;
1256 case AA_VBGR:
1257 ggo_format |= WINE_GGO_VBGR_BITMAP;
1258 break;
1260 default:
1261 ERR("aa = %d - not implemented\n", format);
1262 case AA_None:
1263 ggo_format |= GGO_BITMAP;
1264 break;
1267 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1268 if(buflen == GDI_ERROR) {
1269 if(format != AA_None) {
1270 format = AA_None;
1271 entry->aa_default = AA_None;
1272 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1273 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1275 if(buflen == GDI_ERROR) {
1276 WARN("GetGlyphOutlineW failed using default glyph\n");
1277 buflen = GetGlyphOutlineW(physDev->hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1278 if(buflen == GDI_ERROR) {
1279 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1280 buflen = GetGlyphOutlineW(physDev->hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1281 if(buflen == GDI_ERROR) {
1282 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1283 return;
1287 TRACE("Turning off antialiasing for this monochrome font\n");
1290 /* If there is nothing for the current type, we create the entry. */
1291 if( !entry->format[format] ) {
1292 entry->format[format] = HeapAlloc(GetProcessHeap(),
1293 HEAP_ZERO_MEMORY,
1294 sizeof(gsCacheEntryFormat));
1296 formatEntry = entry->format[format];
1298 if(formatEntry->nrealized <= glyph) {
1299 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1301 if (formatEntry->realized)
1302 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1303 HEAP_ZERO_MEMORY,
1304 formatEntry->realized,
1305 formatEntry->nrealized * sizeof(BOOL));
1306 else
1307 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1308 HEAP_ZERO_MEMORY,
1309 formatEntry->nrealized * sizeof(BOOL));
1311 if(!X11DRV_XRender_Installed) {
1312 if (formatEntry->bitmaps)
1313 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1314 HEAP_ZERO_MEMORY,
1315 formatEntry->bitmaps,
1316 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1317 else
1318 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1319 HEAP_ZERO_MEMORY,
1320 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1322 if (formatEntry->gis)
1323 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1324 HEAP_ZERO_MEMORY,
1325 formatEntry->gis,
1326 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1327 else
1328 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1329 HEAP_ZERO_MEMORY,
1330 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1334 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1335 switch(format) {
1336 case AA_Grey:
1337 wxr_format = WXR_FORMAT_GRAY;
1338 break;
1340 case AA_RGB:
1341 case AA_BGR:
1342 case AA_VRGB:
1343 case AA_VBGR:
1344 wxr_format = WXR_FORMAT_A8R8G8B8;
1345 break;
1347 default:
1348 ERR("aa = %d - not implemented\n", format);
1349 case AA_None:
1350 wxr_format = WXR_FORMAT_MONO;
1351 break;
1354 wine_tsx11_lock();
1355 formatEntry->font_format = get_xrender_format(wxr_format);
1356 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
1357 wine_tsx11_unlock();
1361 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1362 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1363 formatEntry->realized[glyph] = TRUE;
1365 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1366 buflen,
1367 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1368 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1370 gi.width = gm.gmBlackBoxX;
1371 gi.height = gm.gmBlackBoxY;
1372 gi.x = -gm.gmptGlyphOrigin.x;
1373 gi.y = gm.gmptGlyphOrigin.y;
1374 gi.xOff = gm.gmCellIncX;
1375 gi.yOff = gm.gmCellIncY;
1377 if(TRACE_ON(xrender)) {
1378 int pitch, i, j;
1379 char output[300];
1380 unsigned char *line;
1382 if(format == AA_None) {
1383 pitch = ((gi.width + 31) / 32) * 4;
1384 for(i = 0; i < gi.height; i++) {
1385 line = (unsigned char*) buf + i * pitch;
1386 output[0] = '\0';
1387 for(j = 0; j < pitch * 8; j++) {
1388 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1390 TRACE("%s\n", output);
1392 } else {
1393 static const char blks[] = " .:;!o*#";
1394 char str[2];
1396 str[1] = '\0';
1397 pitch = ((gi.width + 3) / 4) * 4;
1398 for(i = 0; i < gi.height; i++) {
1399 line = (unsigned char*) buf + i * pitch;
1400 output[0] = '\0';
1401 for(j = 0; j < pitch; j++) {
1402 str[0] = blks[line[j] >> 5];
1403 strcat(output, str);
1405 TRACE("%s\n", output);
1411 if(formatEntry->glyphset) {
1412 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1413 unsigned char *byte = (unsigned char*) buf, c;
1414 int i = buflen;
1416 while(i--) {
1417 c = *byte;
1419 /* magic to flip bit order */
1420 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1421 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1422 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1424 *byte++ = c;
1427 else if ( format != AA_Grey &&
1428 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1430 unsigned int i, *data = (unsigned int *)buf;
1431 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1433 gid = glyph;
1436 XRenderCompositeText seems to ignore 0x0 glyphs when
1437 AA_None, which means we lose the advance width of glyphs
1438 like the space. We'll pretend that such glyphs are 1x1
1439 bitmaps.
1442 if(buflen == 0)
1443 gi.width = gi.height = 1;
1445 wine_tsx11_lock();
1446 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1447 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1448 wine_tsx11_unlock();
1449 HeapFree(GetProcessHeap(), 0, buf);
1450 } else {
1451 formatEntry->bitmaps[glyph] = buf;
1454 formatEntry->gis[glyph] = gi;
1457 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
1458 void *bitmap, XGlyphInfo *gi)
1460 unsigned char *srcLine = bitmap, *src;
1461 unsigned char bits, bitsMask;
1462 int width = gi->width;
1463 int stride = ((width + 31) & ~31) >> 3;
1464 int height = gi->height;
1465 int w;
1466 int xspan, lenspan;
1468 TRACE("%d, %d\n", x, y);
1469 x -= gi->x;
1470 y -= gi->y;
1471 while (height--)
1473 src = srcLine;
1474 srcLine += stride;
1475 w = width;
1477 bitsMask = 0x80; /* FreeType is always MSB first */
1478 bits = *src++;
1480 xspan = x;
1481 while (w)
1483 if (bits & bitsMask)
1485 lenspan = 0;
1488 lenspan++;
1489 if (lenspan == w)
1490 break;
1491 bitsMask = bitsMask >> 1;
1492 if (!bitsMask)
1494 bits = *src++;
1495 bitsMask = 0x80;
1497 } while (bits & bitsMask);
1498 XFillRectangle (gdi_display, physDev->drawable,
1499 physDev->gc, xspan, y, lenspan, 1);
1500 xspan += lenspan;
1501 w -= lenspan;
1503 else
1507 w--;
1508 xspan++;
1509 if (!w)
1510 break;
1511 bitsMask = bitsMask >> 1;
1512 if (!bitsMask)
1514 bits = *src++;
1515 bitsMask = 0x80;
1517 } while (!(bits & bitsMask));
1520 y++;
1524 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
1525 void *bitmap, XGlyphInfo *gi)
1527 unsigned char *srcLine = bitmap, *src, bits;
1528 int width = gi->width;
1529 int stride = ((width + 3) & ~3);
1530 int height = gi->height;
1531 int w;
1532 int xspan, lenspan;
1534 x -= gi->x;
1535 y -= gi->y;
1536 while (height--)
1538 src = srcLine;
1539 srcLine += stride;
1540 w = width;
1542 bits = *src++;
1543 xspan = x;
1544 while (w)
1546 if (bits >= 0x80)
1548 lenspan = 0;
1551 lenspan++;
1552 if (lenspan == w)
1553 break;
1554 bits = *src++;
1555 } while (bits >= 0x80);
1556 XFillRectangle (gdi_display, physDev->drawable,
1557 physDev->gc, xspan, y, lenspan, 1);
1558 xspan += lenspan;
1559 w -= lenspan;
1561 else
1565 w--;
1566 xspan++;
1567 if (!w)
1568 break;
1569 bits = *src++;
1570 } while (bits < 0x80);
1573 y++;
1578 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1580 int s, l;
1582 s = 0;
1583 while ((mask & 1) == 0)
1585 mask >>= 1;
1586 s++;
1588 l = 0;
1589 while ((mask & 1) == 1)
1591 mask >>= 1;
1592 l++;
1594 *shift = s;
1595 *len = l;
1598 static DWORD GetField (DWORD pixel, int shift, int len)
1600 pixel = pixel & (((1 << (len)) - 1) << shift);
1601 pixel = pixel << (32 - (shift + len)) >> 24;
1602 while (len < 8)
1604 pixel |= (pixel >> len);
1605 len <<= 1;
1607 return pixel;
1611 static DWORD PutField (DWORD pixel, int shift, int len)
1613 shift = shift - (8 - len);
1614 if (len <= 8)
1615 pixel &= (((1 << len) - 1) << (8 - len));
1616 if (shift < 0)
1617 pixel >>= -shift;
1618 else
1619 pixel <<= shift;
1620 return pixel;
1623 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1624 int color)
1626 int r_shift, r_len;
1627 int g_shift, g_len;
1628 int b_shift, b_len;
1629 BYTE *maskLine, *mask, m;
1630 int maskStride;
1631 DWORD pixel;
1632 int width, height;
1633 int w, tx;
1634 BYTE src_r, src_g, src_b;
1636 x -= gi->x;
1637 y -= gi->y;
1638 width = gi->width;
1639 height = gi->height;
1641 maskLine = bitmap;
1642 maskStride = (width + 3) & ~3;
1644 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1645 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1646 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1648 src_r = GetField(color, r_shift, r_len);
1649 src_g = GetField(color, g_shift, g_len);
1650 src_b = GetField(color, b_shift, b_len);
1652 for(; height--; y++)
1654 mask = maskLine;
1655 maskLine += maskStride;
1656 w = width;
1657 tx = x;
1659 if(y < 0) continue;
1660 if(y >= image->height) break;
1662 for(; w--; tx++)
1664 if(tx >= image->width) break;
1666 m = *mask++;
1667 if(tx < 0) continue;
1669 if (m == 0xff)
1670 XPutPixel (image, tx, y, color);
1671 else if (m)
1673 BYTE r, g, b;
1675 pixel = XGetPixel (image, tx, y);
1677 r = GetField(pixel, r_shift, r_len);
1678 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1679 g = GetField(pixel, g_shift, g_len);
1680 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1681 b = GetField(pixel, b_shift, b_len);
1682 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1684 pixel = (PutField (r, r_shift, r_len) |
1685 PutField (g, g_shift, g_len) |
1686 PutField (b, b_shift, b_len));
1687 XPutPixel (image, tx, y, pixel);
1693 /*************************************************************
1694 * get_tile_pict
1696 * Returns an appropriate Picture for tiling the text colour.
1697 * Call and use result within the xrender_cs
1699 static Picture get_tile_pict(const WineXRenderFormat *wxr_format, int text_pixel)
1701 static struct
1703 Pixmap xpm;
1704 Picture pict;
1705 int current_color;
1706 } tiles[WXR_NB_FORMATS], *tile;
1707 XRenderColor col;
1709 tile = &tiles[wxr_format->format];
1711 if(!tile->xpm)
1713 XRenderPictureAttributes pa;
1715 wine_tsx11_lock();
1716 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1718 pa.repeat = RepeatNormal;
1719 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1720 wine_tsx11_unlock();
1722 /* init current_color to something different from text_pixel */
1723 tile->current_color = ~text_pixel;
1725 if(wxr_format->format == WXR_FORMAT_MONO)
1727 /* for a 1bpp bitmap we always need a 1 in the tile */
1728 col.red = col.green = col.blue = 0;
1729 col.alpha = 0xffff;
1730 wine_tsx11_lock();
1731 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1732 wine_tsx11_unlock();
1736 if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1738 get_xrender_color(wxr_format, text_pixel, &col);
1739 wine_tsx11_lock();
1740 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1741 wine_tsx11_unlock();
1742 tile->current_color = text_pixel;
1744 return tile->pict;
1747 /*************************************************************
1748 * get_mask_pict
1750 * Returns an appropriate Picture for masking with the specified alpha.
1751 * Call and use result within the xrender_cs
1753 static Picture get_mask_pict( int alpha )
1755 static Pixmap pixmap;
1756 static Picture pict;
1757 static int current_alpha;
1759 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1761 if (!pixmap)
1763 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
1764 XRenderPictureAttributes pa;
1766 wine_tsx11_lock();
1767 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1768 pa.repeat = RepeatNormal;
1769 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format, CPRepeat, &pa );
1770 wine_tsx11_unlock();
1771 current_alpha = -1;
1774 if (alpha != current_alpha)
1776 XRenderColor col;
1777 col.red = col.green = col.blue = 0;
1778 col.alpha = current_alpha = alpha;
1779 wine_tsx11_lock();
1780 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1781 wine_tsx11_unlock();
1783 return pict;
1786 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1788 return 1;
1791 /********************************************************************
1792 * is_dib_with_colortable
1794 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1796 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1798 DIBSECTION dib;
1800 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1801 dib.dsBmih.biBitCount <= 8 )
1802 return TRUE;
1804 return FALSE;
1807 /***********************************************************************
1808 * X11DRV_XRender_ExtTextOut
1810 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1811 const RECT *lprect, LPCWSTR wstr, UINT count,
1812 const INT *lpDx )
1814 XGCValues xgcval;
1815 gsCacheEntry *entry;
1816 gsCacheEntryFormat *formatEntry;
1817 BOOL retv = FALSE;
1818 int textPixel, backgroundPixel;
1819 HRGN saved_region = 0;
1820 BOOL disable_antialias = FALSE;
1821 AA_Type aa_type = AA_None;
1822 unsigned int idx;
1823 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
1824 Picture tile_pict = 0;
1826 if(is_dib_with_colortable( physDev ))
1828 TRACE("Disabling antialiasing\n");
1829 disable_antialias = TRUE;
1832 xgcval.function = GXcopy;
1833 xgcval.background = physDev->backgroundPixel;
1834 xgcval.fill_style = FillSolid;
1835 wine_tsx11_lock();
1836 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1837 wine_tsx11_unlock();
1839 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1841 if(physDev->depth == 1) {
1842 if((physDev->textPixel & 0xffffff) == 0) {
1843 textPixel = 0;
1844 backgroundPixel = 1;
1845 } else {
1846 textPixel = 1;
1847 backgroundPixel = 0;
1849 } else {
1850 textPixel = physDev->textPixel;
1851 backgroundPixel = physDev->backgroundPixel;
1854 if(flags & ETO_OPAQUE)
1856 wine_tsx11_lock();
1857 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1858 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1859 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1860 lprect->right - lprect->left, lprect->bottom - lprect->top );
1861 wine_tsx11_unlock();
1864 if(count == 0)
1866 retv = TRUE;
1867 goto done_unlock;
1870 if (flags & ETO_CLIPPED)
1872 HRGN clip_region;
1874 clip_region = CreateRectRgnIndirect( lprect );
1875 /* make a copy of the current device region */
1876 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1877 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1878 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1879 DeleteObject( clip_region );
1882 EnterCriticalSection(&xrender_cs);
1884 entry = glyphsetCache + physDev->xrender->cache_index;
1885 if( disable_antialias == FALSE )
1886 aa_type = entry->aa_default;
1887 formatEntry = entry->format[aa_type];
1889 for(idx = 0; idx < count; idx++) {
1890 if( !formatEntry ) {
1891 UploadGlyph(physDev, wstr[idx], aa_type);
1892 /* re-evaluate antialias since aa_default may have changed */
1893 if( disable_antialias == FALSE )
1894 aa_type = entry->aa_default;
1895 formatEntry = entry->format[aa_type];
1896 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1897 UploadGlyph(physDev, wstr[idx], aa_type);
1900 if (!formatEntry)
1902 WARN("could not upload requested glyphs\n");
1903 LeaveCriticalSection(&xrender_cs);
1904 goto done_unlock;
1907 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1908 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1910 if(X11DRV_XRender_Installed)
1912 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1913 POINT offset = {0, 0};
1914 POINT desired, current;
1915 int render_op = PictOpOver;
1916 Picture pict = get_xrender_picture(physDev);
1918 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1919 So we pass zeros to the function and move to our starting position using the first
1920 element of the elts array. */
1922 desired.x = physDev->dc_rect.left + x;
1923 desired.y = physDev->dc_rect.top + y;
1924 current.x = current.y = 0;
1926 tile_pict = get_tile_pict(dst_format, physDev->textPixel);
1928 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1930 if((dst_format->format == WXR_FORMAT_MONO) && (textPixel == 0))
1931 render_op = PictOpOutReverse; /* This gives us 'black' text */
1933 for(idx = 0; idx < count; idx++)
1935 elts[idx].glyphset = formatEntry->glyphset;
1936 elts[idx].chars = wstr + idx;
1937 elts[idx].nchars = 1;
1938 elts[idx].xOff = desired.x - current.x;
1939 elts[idx].yOff = desired.y - current.y;
1941 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1942 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1944 if(!lpDx)
1946 desired.x += formatEntry->gis[wstr[idx]].xOff;
1947 desired.y += formatEntry->gis[wstr[idx]].yOff;
1949 else
1951 if(flags & ETO_PDY)
1953 offset.x += lpDx[idx * 2];
1954 offset.y += lpDx[idx * 2 + 1];
1956 else
1957 offset.x += lpDx[idx];
1958 desired.x = physDev->dc_rect.left + x + offset.x;
1959 desired.y = physDev->dc_rect.top + y + offset.y;
1962 wine_tsx11_lock();
1963 /* Make sure we don't have any transforms set from a previous call */
1964 set_xrender_transformation(pict, 1, 1, 0, 0);
1965 pXRenderCompositeText16(gdi_display, render_op,
1966 tile_pict,
1967 pict,
1968 formatEntry->font_format->pict_format,
1969 0, 0, 0, 0, elts, count);
1970 wine_tsx11_unlock();
1971 HeapFree(GetProcessHeap(), 0, elts);
1972 } else {
1973 POINT offset = {0, 0};
1974 wine_tsx11_lock();
1975 XSetForeground( gdi_display, physDev->gc, textPixel );
1977 if(aa_type == AA_None || physDev->depth == 1)
1979 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1981 if(aa_type == AA_None)
1982 sharp_glyph_fn = SharpGlyphMono;
1983 else
1984 sharp_glyph_fn = SharpGlyphGray;
1986 for(idx = 0; idx < count; idx++) {
1987 sharp_glyph_fn(physDev,
1988 physDev->dc_rect.left + x + offset.x,
1989 physDev->dc_rect.top + y + offset.y,
1990 formatEntry->bitmaps[wstr[idx]],
1991 &formatEntry->gis[wstr[idx]]);
1992 if(lpDx)
1994 if(flags & ETO_PDY)
1996 offset.x += lpDx[idx * 2];
1997 offset.y += lpDx[idx * 2 + 1];
1999 else
2000 offset.x += lpDx[idx];
2002 else
2004 offset.x += formatEntry->gis[wstr[idx]].xOff;
2005 offset.y += formatEntry->gis[wstr[idx]].yOff;
2008 } else {
2009 XImage *image;
2010 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2011 RECT extents = {0, 0, 0, 0};
2012 POINT cur = {0, 0};
2013 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
2014 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
2016 TRACE("drawable %dx%d\n", w, h);
2018 for(idx = 0; idx < count; idx++) {
2019 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2020 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2021 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2022 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2023 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2024 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2025 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2026 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2028 if(lpDx)
2030 if(flags & ETO_PDY)
2032 cur.x += lpDx[idx * 2];
2033 cur.y += lpDx[idx * 2 + 1];
2035 else
2036 cur.x += lpDx[idx];
2038 else
2040 cur.x += formatEntry->gis[wstr[idx]].xOff;
2041 cur.y += formatEntry->gis[wstr[idx]].yOff;
2044 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2045 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
2047 if(physDev->dc_rect.left + x + extents.left >= 0) {
2048 image_x = physDev->dc_rect.left + x + extents.left;
2049 image_off_x = 0;
2050 } else {
2051 image_x = 0;
2052 image_off_x = physDev->dc_rect.left + x + extents.left;
2054 if(physDev->dc_rect.top + y + extents.top >= 0) {
2055 image_y = physDev->dc_rect.top + y + extents.top;
2056 image_off_y = 0;
2057 } else {
2058 image_y = 0;
2059 image_off_y = physDev->dc_rect.top + y + extents.top;
2061 if(physDev->dc_rect.left + x + extents.right < w)
2062 image_w = physDev->dc_rect.left + x + extents.right - image_x;
2063 else
2064 image_w = w - image_x;
2065 if(physDev->dc_rect.top + y + extents.bottom < h)
2066 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
2067 else
2068 image_h = h - image_y;
2070 if(image_w <= 0 || image_h <= 0) goto no_image;
2072 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2073 image = XGetImage(gdi_display, physDev->drawable,
2074 image_x, image_y, image_w, image_h,
2075 AllPlanes, ZPixmap);
2076 X11DRV_check_error();
2078 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2079 gdi_display, (int)physDev->drawable, image_x, image_y,
2080 image_w, image_h, AllPlanes, ZPixmap,
2081 physDev->depth, image);
2082 if(!image) {
2083 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2084 physDev->depth);
2085 GC gc;
2086 XGCValues gcv;
2088 gcv.graphics_exposures = False;
2089 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2090 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
2091 image_w, image_h, 0, 0);
2092 XFreeGC(gdi_display, gc);
2093 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2094 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2095 ZPixmap);
2096 X11DRV_check_error();
2097 XFreePixmap(gdi_display, xpm);
2099 if(!image) goto no_image;
2101 image->red_mask = visual->red_mask;
2102 image->green_mask = visual->green_mask;
2103 image->blue_mask = visual->blue_mask;
2105 for(idx = 0; idx < count; idx++) {
2106 SmoothGlyphGray(image,
2107 offset.x + image_off_x - extents.left,
2108 offset.y + image_off_y - extents.top,
2109 formatEntry->bitmaps[wstr[idx]],
2110 &formatEntry->gis[wstr[idx]],
2111 physDev->textPixel);
2112 if(lpDx)
2114 if(flags & ETO_PDY)
2116 offset.x += lpDx[idx * 2];
2117 offset.y += lpDx[idx * 2 + 1];
2119 else
2120 offset.x += lpDx[idx];
2122 else
2124 offset.x += formatEntry->gis[wstr[idx]].xOff;
2125 offset.y += formatEntry->gis[wstr[idx]].yOff;
2128 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
2129 image_x, image_y, image_w, image_h);
2130 XDestroyImage(image);
2132 no_image:
2133 wine_tsx11_unlock();
2135 LeaveCriticalSection(&xrender_cs);
2137 if (flags & ETO_CLIPPED)
2139 /* restore the device region */
2140 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
2141 DeleteObject( saved_region );
2144 retv = TRUE;
2146 done_unlock:
2147 X11DRV_UnlockDIBSection( physDev, TRUE );
2148 return retv;
2151 /* Helper function for (stretched) blitting using xrender */
2152 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2153 int x_src, int y_src, int x_dst, int y_dst,
2154 double xscale, double yscale, int width, int height )
2156 int x_offset, y_offset;
2158 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2159 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2160 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2161 if(xscale != 1.0 || yscale != 1.0)
2163 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2164 * in the wrong quadrant of the x-y plane.
2166 x_offset = (xscale < 0) ? -width : 0;
2167 y_offset = (yscale < 0) ? -height : 0;
2168 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2170 else
2172 x_offset = x_src;
2173 y_offset = y_src;
2174 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2176 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2177 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2180 /* Helper function for (stretched) mono->color blitting using xrender */
2181 static void xrender_mono_blit( Picture src_pict, Picture mask_pict, Picture dst_pict,
2182 int x_src, int y_src, double xscale, double yscale, int width, int height )
2184 int x_offset, y_offset;
2186 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2187 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
2188 * tile data. We need PictOpOver for correct rendering.
2189 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2190 * mask_x / mask_y
2192 if (xscale != 1.0 || yscale != 1.0)
2194 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2195 * in the wrong quadrant of the x-y plane.
2197 x_offset = (xscale < 0) ? -width : 0;
2198 y_offset = (yscale < 0) ? -height : 0;
2199 set_xrender_transformation(mask_pict, xscale, yscale, x_src, y_src);
2201 else
2203 x_offset = x_src;
2204 y_offset = y_src;
2205 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
2207 pXRenderComposite(gdi_display, PictOpOver, src_pict, mask_pict, dst_pict,
2208 0, 0, x_offset, y_offset, 0, 0, width, height);
2211 /******************************************************************************
2212 * AlphaBlend
2214 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2215 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2217 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2218 struct xrender_info *src_info = get_xrender_info( devSrc );
2219 double xscale, yscale;
2220 BOOL use_repeat;
2222 if(!X11DRV_XRender_Installed) {
2223 FIXME("Unable to AlphaBlend without Xrender\n");
2224 return FALSE;
2227 if (devSrc != devDst) X11DRV_LockDIBSection( devSrc, DIB_Status_GdiMod );
2228 X11DRV_LockDIBSection( devDst, DIB_Status_GdiMod );
2230 dst_pict = get_xrender_picture( devDst );
2232 use_repeat = use_source_repeat( devSrc );
2233 if (!use_repeat)
2235 xscale = src->width / (double)dst->width;
2236 yscale = src->height / (double)dst->height;
2238 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2240 if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && src_info->format)
2242 /* we need a source picture with no alpha */
2243 WXRFormat format = get_format_without_alpha( src_info->format->format );
2244 if (format != src_info->format->format)
2246 XRenderPictureAttributes pa;
2247 const WineXRenderFormat *fmt = get_xrender_format( format );
2249 wine_tsx11_lock();
2250 pa.subwindow_mode = IncludeInferiors;
2251 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2252 tmp_pict = pXRenderCreatePicture( gdi_display, devSrc->drawable, fmt->pict_format,
2253 CPSubwindowMode|CPRepeat, &pa );
2254 wine_tsx11_unlock();
2255 src_pict = tmp_pict;
2259 if (!src_pict) src_pict = get_xrender_picture_source( devSrc, use_repeat );
2261 EnterCriticalSection( &xrender_cs );
2262 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2264 wine_tsx11_lock();
2265 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2266 devSrc->dc_rect.left + src->visrect.left, devSrc->dc_rect.top + src->visrect.top,
2267 devDst->dc_rect.left + dst->visrect.left, devDst->dc_rect.top + dst->visrect.top,
2268 xscale, yscale,
2269 dst->visrect.right - dst->visrect.left, dst->visrect.bottom - dst->visrect.top );
2270 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2271 wine_tsx11_unlock();
2273 LeaveCriticalSection( &xrender_cs );
2274 if (devSrc != devDst) X11DRV_UnlockDIBSection( devSrc, FALSE );
2275 X11DRV_UnlockDIBSection( devDst, TRUE );
2276 return TRUE;
2280 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2282 /* 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 */
2283 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2284 const WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2285 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2287 wine_tsx11_lock();
2288 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2290 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2291 if( (physBitmap->pixmap_depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->pixmap_depth) ||
2292 (src_format->format == dst_format->format) )
2294 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2295 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2297 else /* We need depth conversion */
2299 Picture src_pict, dst_pict;
2300 XRenderPictureAttributes pa;
2301 pa.subwindow_mode = IncludeInferiors;
2302 pa.repeat = RepeatNone;
2304 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2305 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2307 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2308 pXRenderFreePicture(gdi_display, src_pict);
2309 pXRenderFreePicture(gdi_display, dst_pict);
2311 wine_tsx11_unlock();
2314 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2315 Pixmap pixmap, GC gc,
2316 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2318 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2319 int width = dst->visrect.right - dst->visrect.left;
2320 int height = dst->visrect.bottom - dst->visrect.top;
2321 int x_src = physDevSrc->dc_rect.left + src->visrect.left;
2322 int y_src = physDevSrc->dc_rect.top + src->visrect.top;
2323 struct xrender_info *src_info = get_xrender_info(physDevSrc);
2324 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDevDst->depth, physDevDst->color_shifts);
2325 Picture src_pict=0, dst_pict=0, mask_pict=0;
2326 BOOL use_repeat;
2327 double xscale, yscale;
2329 XRenderPictureAttributes pa;
2330 pa.subwindow_mode = IncludeInferiors;
2331 pa.repeat = RepeatNone;
2333 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2334 physDevSrc->depth, src->width, src->height, x_src, y_src);
2335 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst->depth, dst->width, dst->height);
2337 if(!X11DRV_XRender_Installed)
2339 TRACE("Not using XRender since it is not available or disabled\n");
2340 return FALSE;
2343 /* XRender can't handle palettes, so abort */
2344 if(X11DRV_PALETTE_XPixelToPalette)
2345 return FALSE;
2347 /* XRender is of no use in this case */
2348 if((physDevDst->depth == 1) && (physDevSrc->depth > 1))
2349 return FALSE;
2351 /* Just use traditional X copy when the formats match and we don't need stretching */
2352 if((src_info->format->format == dst_format->format) && !stretch)
2354 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2355 wine_tsx11_lock();
2356 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
2357 wine_tsx11_unlock();
2358 return TRUE;
2361 use_repeat = use_source_repeat( physDevSrc );
2362 if (!use_repeat)
2364 xscale = src->width / (double)dst->width;
2365 yscale = src->height / (double)dst->height;
2367 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2369 /* mono -> color */
2370 if(physDevSrc->depth == 1 && physDevDst->depth > 1)
2372 XRenderColor col;
2373 get_xrender_color(dst_format, physDevDst->textPixel, &col);
2375 /* We use the source drawable as a mask */
2376 mask_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2378 /* Use backgroundPixel as the foreground color */
2379 EnterCriticalSection( &xrender_cs );
2380 src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
2382 /* Create a destination picture and fill it with textPixel color as the background color */
2383 wine_tsx11_lock();
2384 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2385 pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height);
2387 xrender_mono_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
2389 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2390 wine_tsx11_unlock();
2391 LeaveCriticalSection( &xrender_cs );
2393 else /* color -> color (can be at different depths) or mono -> mono */
2395 if (physDevDst->depth == 32 && physDevSrc->depth < 32) mask_pict = get_no_alpha_mask();
2396 src_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2398 wine_tsx11_lock();
2399 dst_pict = pXRenderCreatePicture(gdi_display,
2400 pixmap, dst_format->pict_format,
2401 CPSubwindowMode|CPRepeat, &pa);
2403 xrender_blit(PictOpSrc, src_pict, mask_pict, dst_pict,
2404 x_src, y_src, 0, 0, xscale, yscale, width, height);
2406 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2407 wine_tsx11_unlock();
2409 return TRUE;
2412 #else /* SONAME_LIBXRENDER */
2414 void X11DRV_XRender_Init(void)
2416 TRACE("XRender support not compiled in.\n");
2417 return;
2420 void X11DRV_XRender_Finalize(void)
2424 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
2426 assert(0);
2427 return FALSE;
2430 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
2432 assert(0);
2433 return;
2436 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
2438 assert(0);
2439 return;
2442 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
2443 const RECT *lprect, LPCWSTR wstr, UINT count,
2444 const INT *lpDx )
2446 assert(0);
2447 return FALSE;
2450 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
2452 assert(0);
2453 return;
2456 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2457 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2459 FIXME("not supported - XRENDER headers were missing at compile time\n");
2460 return FALSE;
2463 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2465 wine_tsx11_lock();
2466 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
2468 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2469 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2470 wine_tsx11_unlock();
2473 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2475 return FALSE;
2478 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2479 Pixmap pixmap, GC gc,
2480 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2482 return FALSE;
2484 #endif /* SONAME_LIBXRENDER */