pop fafc973c8c92ea6fa823adc8f5a7f591f01396fd
[wine/hacks.git] / dlls / winex11.drv / xrender.c
blob2fc804acdad0b549ad7190e11cf2dbc858b4d7b5
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 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
350 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
351 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
354 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
355 LOAD_FUNCPTR(XRenderAddGlyphs)
356 LOAD_FUNCPTR(XRenderComposite)
357 LOAD_FUNCPTR(XRenderCompositeString8)
358 LOAD_FUNCPTR(XRenderCompositeString16)
359 LOAD_FUNCPTR(XRenderCompositeString32)
360 LOAD_FUNCPTR(XRenderCompositeText16)
361 LOAD_FUNCPTR(XRenderCreateGlyphSet)
362 LOAD_FUNCPTR(XRenderCreatePicture)
363 LOAD_FUNCPTR(XRenderFillRectangle)
364 LOAD_FUNCPTR(XRenderFindFormat)
365 LOAD_FUNCPTR(XRenderFindVisualFormat)
366 LOAD_FUNCPTR(XRenderFreeGlyphSet)
367 LOAD_FUNCPTR(XRenderFreePicture)
368 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
369 LOAD_FUNCPTR(XRenderQueryExtension)
370 #undef LOAD_FUNCPTR
371 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
372 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
373 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
374 #undef LOAD_OPTIONAL_FUNCPTR
375 #endif
377 wine_tsx11_lock();
378 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
379 wine_tsx11_unlock();
380 if(X11DRV_XRender_Installed) {
381 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
382 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
384 wine_tsx11_unlock();
385 WINE_MESSAGE(
386 "Wine has detected that you probably have a buggy version\n"
387 "of libXrender.so . Because of this client side font rendering\n"
388 "will be disabled. Please upgrade this library.\n");
389 X11DRV_XRender_Installed = FALSE;
390 return;
393 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
394 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
395 X11DRV_XRender_Installed = FALSE;
400 #ifdef SONAME_LIBFONTCONFIG
401 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
403 #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;}
404 LOAD_FUNCPTR(FcConfigSubstitute);
405 LOAD_FUNCPTR(FcDefaultSubstitute);
406 LOAD_FUNCPTR(FcFontMatch);
407 LOAD_FUNCPTR(FcInit);
408 LOAD_FUNCPTR(FcPatternCreate);
409 LOAD_FUNCPTR(FcPatternDestroy);
410 LOAD_FUNCPTR(FcPatternAddInteger);
411 LOAD_FUNCPTR(FcPatternAddString);
412 LOAD_FUNCPTR(FcPatternGetBool);
413 LOAD_FUNCPTR(FcPatternGetInteger);
414 LOAD_FUNCPTR(FcPatternGetString);
415 #undef LOAD_FUNCPTR
416 fontconfig_installed = pFcInit();
418 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
419 #endif
421 sym_not_found:
422 if(X11DRV_XRender_Installed || client_side_with_core)
424 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
425 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
427 glyphsetCacheSize = INIT_CACHE_SIZE;
428 lastfree = 0;
429 for(i = 0; i < INIT_CACHE_SIZE; i++) {
430 glyphsetCache[i].next = i + 1;
431 glyphsetCache[i].count = -1;
433 glyphsetCache[i-1].next = -1;
434 using_client_side_fonts = 1;
436 if(!X11DRV_XRender_Installed) {
437 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
438 if(screen_depth <= 8 || !client_side_antialias_with_core)
439 antialias = 0;
440 } else {
441 if(screen_depth <= 8 || !client_side_antialias_with_render)
442 antialias = 0;
445 else TRACE("Using X11 core fonts\n");
448 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
449 static void get_xrender_color(const WineXRenderFormat *wxr_format, int src_color, XRenderColor *dst_color)
451 XRenderPictFormat *pf = wxr_format->pict_format;
453 if(pf->direct.redMask)
454 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
455 else
456 dst_color->red = 0;
458 if(pf->direct.greenMask)
459 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
460 else
461 dst_color->green = 0;
463 if(pf->direct.blueMask)
464 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
465 else
466 dst_color->blue = 0;
468 dst_color->alpha = 0xffff;
471 static const WineXRenderFormat *get_xrender_format(WXRFormat format)
473 int i;
474 for(i=0; i<WineXRenderFormatsListSize; i++)
476 if(wxr_formats[i].format == format)
478 TRACE("Returning wxr_format=%#x\n", format);
479 return &wxr_formats[i];
482 return NULL;
485 static const WineXRenderFormat *get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
487 int redMask, greenMask, blueMask;
488 unsigned int i;
490 if(depth == 1)
491 return get_xrender_format(WXR_FORMAT_MONO);
493 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
494 if(!shifts)
495 return default_format;
497 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
498 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
499 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
501 /* Try to locate a format which matches the specification of the dibsection. */
502 for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
504 if( depth == wxr_formats_template[i].depth &&
505 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
506 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
507 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
510 /* When we reach this stage the format was found in our template table but this doesn't mean that
511 * the Xserver also supports this format (e.g. its depth might be too low). The call below verifies that.
513 return get_xrender_format(wxr_formats_template[i].wxr_format);
517 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
518 ERR("No XRender format found!\n");
519 return NULL;
522 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
523 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
525 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
526 XTransform xform = {{
527 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
528 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
529 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
532 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
533 #endif
536 /* check if we can use repeating instead of scaling for the specified source DC */
537 static BOOL use_source_repeat( X11DRV_PDEVICE *physDev )
539 return (physDev->bitmap &&
540 physDev->drawable_rect.right - physDev->drawable_rect.left == 1 &&
541 physDev->drawable_rect.bottom - physDev->drawable_rect.top == 1);
544 static struct xrender_info *get_xrender_info(X11DRV_PDEVICE *physDev)
546 if(!physDev->xrender)
548 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physDev->xrender));
550 if(!physDev->xrender)
552 ERR("Unable to allocate XRENDERINFO!\n");
553 return NULL;
555 physDev->xrender->cache_index = -1;
557 if (!physDev->xrender->format)
558 physDev->xrender->format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
560 return physDev->xrender;
563 static Picture get_xrender_picture(X11DRV_PDEVICE *physDev)
565 struct xrender_info *info = get_xrender_info(physDev);
566 if (!info) return 0;
568 if (!info->pict && info->format)
570 XRenderPictureAttributes pa;
571 RGNDATA *clip = X11DRV_GetRegionData( physDev->region, 0 );
573 wine_tsx11_lock();
574 pa.subwindow_mode = IncludeInferiors;
575 info->pict = pXRenderCreatePicture(gdi_display, physDev->drawable, info->format->pict_format,
576 CPSubwindowMode, &pa);
577 if (info->pict && clip)
578 pXRenderSetPictureClipRectangles( gdi_display, info->pict,
579 physDev->dc_rect.left, physDev->dc_rect.top,
580 (XRectangle *)clip->Buffer, clip->rdh.nCount );
581 wine_tsx11_unlock();
582 TRACE("Allocing pict=%lx dc=%p drawable=%08lx\n", info->pict, physDev->hdc, physDev->drawable);
583 HeapFree( GetProcessHeap(), 0, clip );
586 return info->pict;
589 static Picture get_xrender_picture_source(X11DRV_PDEVICE *physDev, BOOL repeat)
591 struct xrender_info *info = get_xrender_info(physDev);
592 if (!info) return 0;
594 if (!info->pict_src && info->format)
596 XRenderPictureAttributes pa;
598 wine_tsx11_lock();
599 pa.subwindow_mode = IncludeInferiors;
600 pa.repeat = repeat ? RepeatNormal : RepeatNone;
601 info->pict_src = pXRenderCreatePicture(gdi_display, physDev->drawable, info->format->pict_format,
602 CPSubwindowMode|CPRepeat, &pa);
603 wine_tsx11_unlock();
605 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
606 info->pict_src, physDev->hdc, physDev->drawable, pa.repeat);
609 return info->pict_src;
612 /* return a mask picture used to force alpha to 0 */
613 static Picture get_no_alpha_mask(void)
615 static Pixmap pixmap;
616 static Picture pict;
618 wine_tsx11_lock();
619 if (!pict)
621 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
622 XRenderPictureAttributes pa;
623 XRenderColor col;
625 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
626 pa.repeat = RepeatNormal;
627 pa.component_alpha = True;
628 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format,
629 CPRepeat|CPComponentAlpha, &pa );
630 col.red = col.green = col.blue = 0xffff;
631 col.alpha = 0;
632 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
634 wine_tsx11_unlock();
635 return pict;
638 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
640 if(p1->hash != p2->hash) return TRUE;
641 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
642 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
643 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
644 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
647 #if 0
648 static void walk_cache(void)
650 int i;
652 EnterCriticalSection(&xrender_cs);
653 for(i=mru; i >= 0; i = glyphsetCache[i].next)
654 TRACE("item %d\n", i);
655 LeaveCriticalSection(&xrender_cs);
657 #endif
659 static int LookupEntry(LFANDSIZE *plfsz)
661 int i, prev_i = -1;
663 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
664 TRACE("%d\n", i);
665 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
666 i = -1;
667 break;
670 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
671 glyphsetCache[i].count++;
672 if(prev_i >= 0) {
673 glyphsetCache[prev_i].next = glyphsetCache[i].next;
674 glyphsetCache[i].next = mru;
675 mru = i;
677 TRACE("found font in cache %d\n", i);
678 return i;
680 prev_i = i;
682 TRACE("font not in cache\n");
683 return -1;
686 static void FreeEntry(int entry)
688 int i, format;
690 for(format = 0; format < AA_MAXVALUE; format++) {
691 gsCacheEntryFormat * formatEntry;
693 if( !glyphsetCache[entry].format[format] )
694 continue;
696 formatEntry = glyphsetCache[entry].format[format];
698 if(formatEntry->glyphset) {
699 wine_tsx11_lock();
700 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
701 wine_tsx11_unlock();
702 formatEntry->glyphset = 0;
704 if(formatEntry->nrealized) {
705 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
706 formatEntry->realized = NULL;
707 if(formatEntry->bitmaps) {
708 for(i = 0; i < formatEntry->nrealized; i++)
709 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
710 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
711 formatEntry->bitmaps = NULL;
713 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
714 formatEntry->gis = NULL;
715 formatEntry->nrealized = 0;
718 HeapFree(GetProcessHeap(), 0, formatEntry);
719 glyphsetCache[entry].format[format] = NULL;
723 static int AllocEntry(void)
725 int best = -1, prev_best = -1, i, prev_i = -1;
727 if(lastfree >= 0) {
728 assert(glyphsetCache[lastfree].count == -1);
729 glyphsetCache[lastfree].count = 1;
730 best = lastfree;
731 lastfree = glyphsetCache[lastfree].next;
732 assert(best != mru);
733 glyphsetCache[best].next = mru;
734 mru = best;
736 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
737 return mru;
740 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
741 if(glyphsetCache[i].count == 0) {
742 best = i;
743 prev_best = prev_i;
745 prev_i = i;
748 if(best >= 0) {
749 TRACE("freeing unused glyphset at cache %d\n", best);
750 FreeEntry(best);
751 glyphsetCache[best].count = 1;
752 if(prev_best >= 0) {
753 glyphsetCache[prev_best].next = glyphsetCache[best].next;
754 glyphsetCache[best].next = mru;
755 mru = best;
756 } else {
757 assert(mru == best);
759 return mru;
762 TRACE("Growing cache\n");
764 if (glyphsetCache)
765 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
766 glyphsetCache,
767 (glyphsetCacheSize + INIT_CACHE_SIZE)
768 * sizeof(*glyphsetCache));
769 else
770 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
771 (glyphsetCacheSize + INIT_CACHE_SIZE)
772 * sizeof(*glyphsetCache));
774 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
775 i++) {
776 glyphsetCache[i].next = i + 1;
777 glyphsetCache[i].count = -1;
779 glyphsetCache[i-1].next = -1;
780 glyphsetCacheSize += INIT_CACHE_SIZE;
782 lastfree = glyphsetCache[best].next;
783 glyphsetCache[best].count = 1;
784 glyphsetCache[best].next = mru;
785 mru = best;
786 TRACE("new free cache slot at %d\n", mru);
787 return mru;
790 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
792 DWORD size;
793 WORD *gasp, *buffer;
794 WORD num_recs;
795 DWORD ppem;
796 TEXTMETRICW tm;
798 *flags = 0;
800 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
801 if(size == GDI_ERROR)
802 return FALSE;
804 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
805 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
807 GetTextMetricsW(physDev->hdc, &tm);
808 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
810 gasp++;
811 num_recs = get_be_word(*gasp);
812 gasp++;
813 while(num_recs--)
815 *flags = get_be_word(*(gasp + 1));
816 if(ppem <= get_be_word(*gasp))
817 break;
818 gasp += 2;
820 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
822 HeapFree(GetProcessHeap(), 0, buffer);
823 return TRUE;
826 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
828 AA_Type ret;
829 WORD flags;
830 UINT font_smoothing_type, font_smoothing_orientation;
832 if (X11DRV_XRender_Installed && subpixel &&
833 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
834 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
836 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
837 &font_smoothing_orientation, 0) &&
838 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
840 ret = AA_BGR;
842 else
843 ret = AA_RGB;
844 /*FIXME
845 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
846 But, Wine's subpixel rendering can support the portrait mode.
849 else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
850 ret = AA_Grey;
851 else
852 ret = AA_None;
854 return ret;
857 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
859 int ret;
860 int format;
861 gsCacheEntry *entry;
862 static int hinter = -1;
863 static int subpixel = -1;
864 BOOL font_smoothing;
866 if((ret = LookupEntry(plfsz)) != -1) return ret;
868 ret = AllocEntry();
869 entry = glyphsetCache + ret;
870 entry->lfsz = *plfsz;
871 for( format = 0; format < AA_MAXVALUE; format++ ) {
872 assert( !entry->format[format] );
875 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
877 if(hinter == -1 || subpixel == -1)
879 RASTERIZER_STATUS status;
880 GetRasterizerCaps(&status, sizeof(status));
881 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
882 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
885 switch (plfsz->lf.lfQuality)
887 case ANTIALIASED_QUALITY:
888 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
889 return ret; /* ignore further configuration */
890 case CLEARTYPE_QUALITY:
891 case CLEARTYPE_NATURAL_QUALITY:
892 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
893 break;
894 case DEFAULT_QUALITY:
895 case DRAFT_QUALITY:
896 case PROOF_QUALITY:
897 default:
898 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
899 font_smoothing)
901 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
903 else
904 entry->aa_default = AA_None;
905 break;
908 #ifdef SONAME_LIBFONTCONFIG
909 if (fontconfig_installed)
911 FcPattern *match, *pattern = pFcPatternCreate();
912 FcResult result;
913 char family[LF_FACESIZE * 4];
915 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
916 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
917 if (plfsz->lf.lfWeight != FW_DONTCARE)
919 int weight;
920 switch (plfsz->lf.lfWeight)
922 case FW_THIN: weight = FC_WEIGHT_THIN; break;
923 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
924 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
925 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
926 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
927 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
928 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
929 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
930 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
931 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
933 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
935 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
936 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
937 pFcDefaultSubstitute( pattern );
938 if ((match = pFcFontMatch( NULL, pattern, &result )))
940 int rgba;
941 FcBool antialias;
943 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
944 antialias = TRUE;
945 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
947 FcChar8 *file;
948 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
950 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
951 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
953 switch (rgba)
955 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
956 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
957 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
958 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
959 case FC_RGBA_NONE: entry->aa_default = antialias ? AA_Grey : AA_None; break;
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 = antialias ? AA_Grey : AA_None;
989 wine_tsx11_unlock();
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 );
1064 GetWorldTransform( physDev->hdc, &lfsz.xform );
1065 lfsz_calc_hash(&lfsz);
1067 info = get_xrender_info(physDev);
1068 if (!info) return 0;
1070 EnterCriticalSection(&xrender_cs);
1071 if(info->cache_index != -1)
1072 dec_ref_cache(info->cache_index);
1073 info->cache_index = GetCacheEntry(physDev, &lfsz);
1074 LeaveCriticalSection(&xrender_cs);
1075 return 0;
1078 /***********************************************************************
1079 * X11DRV_XRender_SetDeviceClipping
1081 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
1083 if (physDev->xrender->pict)
1085 wine_tsx11_lock();
1086 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1087 physDev->dc_rect.left, physDev->dc_rect.top,
1088 (XRectangle *)data->Buffer, data->rdh.nCount );
1089 wine_tsx11_unlock();
1093 /***********************************************************************
1094 * X11DRV_XRender_DeleteDC
1096 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1098 X11DRV_XRender_UpdateDrawable(physDev);
1100 EnterCriticalSection(&xrender_cs);
1101 if(physDev->xrender->cache_index != -1)
1102 dec_ref_cache(physDev->xrender->cache_index);
1103 LeaveCriticalSection(&xrender_cs);
1105 HeapFree(GetProcessHeap(), 0, physDev->xrender);
1106 physDev->xrender = NULL;
1107 return;
1110 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1112 const WineXRenderFormat *fmt;
1113 ColorShifts shifts;
1115 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1116 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1117 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1118 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1119 return FALSE;
1121 if (dib)
1123 X11DRV_PALETTE_ComputeColorShifts(&shifts, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
1124 fmt = get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts);
1126 /* Common formats should be in our picture format table. */
1127 if (!fmt)
1129 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1130 dib->dsBm.bmBitsPixel, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
1131 return FALSE;
1134 else
1136 int red_mask, green_mask, blue_mask;
1138 /* We are dealing with a DDB */
1139 switch (bits_pixel)
1141 case 16:
1142 fmt = get_xrender_format(WXR_FORMAT_R5G6B5);
1143 break;
1144 case 24:
1145 fmt = get_xrender_format(WXR_FORMAT_R8G8B8);
1146 break;
1147 case 32:
1148 fmt = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1149 break;
1150 default:
1151 fmt = NULL;
1154 if (!fmt)
1156 TRACE("Unhandled DDB bits_pixel=%d\n", bits_pixel);
1157 return FALSE;
1160 red_mask = fmt->pict_format->direct.redMask << fmt->pict_format->direct.red;
1161 green_mask = fmt->pict_format->direct.greenMask << fmt->pict_format->direct.green;
1162 blue_mask = fmt->pict_format->direct.blueMask << fmt->pict_format->direct.blue;
1163 X11DRV_PALETTE_ComputeColorShifts(&shifts, red_mask, green_mask, blue_mask);
1166 physBitmap->pixmap_depth = fmt->pict_format->depth;
1167 physBitmap->trueColor = TRUE;
1168 physBitmap->pixmap_color_shifts = shifts;
1169 return TRUE;
1172 /***********************************************************************
1173 * X11DRV_XRender_UpdateDrawable
1175 * Deletes the pict and tile when the drawable changes.
1177 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1179 struct xrender_info *info = physDev->xrender;
1181 if (info->pict || info->pict_src)
1183 wine_tsx11_lock();
1184 XFlush( gdi_display );
1185 if (info->pict)
1187 TRACE("freeing pict = %lx dc = %p\n", info->pict, physDev->hdc);
1188 pXRenderFreePicture(gdi_display, info->pict);
1189 info->pict = 0;
1191 if(info->pict_src)
1193 TRACE("freeing pict = %lx dc = %p\n", info->pict_src, physDev->hdc);
1194 pXRenderFreePicture(gdi_display, info->pict_src);
1195 info->pict_src = 0;
1197 wine_tsx11_unlock();
1200 info->format = NULL;
1203 /************************************************************************
1204 * UploadGlyph
1206 * Helper to ExtTextOut. Must be called inside xrender_cs
1208 static void UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
1210 unsigned int buflen;
1211 char *buf;
1212 Glyph gid;
1213 GLYPHMETRICS gm;
1214 XGlyphInfo gi;
1215 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
1216 gsCacheEntryFormat *formatEntry;
1217 UINT ggo_format = GGO_GLYPH_INDEX;
1218 WXRFormat wxr_format;
1219 static const char zero[4];
1220 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1222 switch(format) {
1223 case AA_Grey:
1224 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1225 break;
1226 case AA_RGB:
1227 ggo_format |= WINE_GGO_HRGB_BITMAP;
1228 break;
1229 case AA_BGR:
1230 ggo_format |= WINE_GGO_HBGR_BITMAP;
1231 break;
1232 case AA_VRGB:
1233 ggo_format |= WINE_GGO_VRGB_BITMAP;
1234 break;
1235 case AA_VBGR:
1236 ggo_format |= WINE_GGO_VBGR_BITMAP;
1237 break;
1239 default:
1240 ERR("aa = %d - not implemented\n", format);
1241 case AA_None:
1242 ggo_format |= GGO_BITMAP;
1243 break;
1246 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1247 if(buflen == GDI_ERROR) {
1248 if(format != AA_None) {
1249 format = AA_None;
1250 entry->aa_default = AA_None;
1251 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1252 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1254 if(buflen == GDI_ERROR) {
1255 WARN("GetGlyphOutlineW failed using default glyph\n");
1256 buflen = GetGlyphOutlineW(physDev->hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1257 if(buflen == GDI_ERROR) {
1258 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1259 buflen = GetGlyphOutlineW(physDev->hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1260 if(buflen == GDI_ERROR) {
1261 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1262 return;
1266 TRACE("Turning off antialiasing for this monochrome font\n");
1269 /* If there is nothing for the current type, we create the entry. */
1270 if( !entry->format[format] ) {
1271 entry->format[format] = HeapAlloc(GetProcessHeap(),
1272 HEAP_ZERO_MEMORY,
1273 sizeof(gsCacheEntryFormat));
1275 formatEntry = entry->format[format];
1277 if(formatEntry->nrealized <= glyph) {
1278 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1280 if (formatEntry->realized)
1281 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1282 HEAP_ZERO_MEMORY,
1283 formatEntry->realized,
1284 formatEntry->nrealized * sizeof(BOOL));
1285 else
1286 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1287 HEAP_ZERO_MEMORY,
1288 formatEntry->nrealized * sizeof(BOOL));
1290 if(!X11DRV_XRender_Installed) {
1291 if (formatEntry->bitmaps)
1292 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1293 HEAP_ZERO_MEMORY,
1294 formatEntry->bitmaps,
1295 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1296 else
1297 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1298 HEAP_ZERO_MEMORY,
1299 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1301 if (formatEntry->gis)
1302 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1303 HEAP_ZERO_MEMORY,
1304 formatEntry->gis,
1305 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1306 else
1307 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1308 HEAP_ZERO_MEMORY,
1309 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1313 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1314 switch(format) {
1315 case AA_Grey:
1316 wxr_format = WXR_FORMAT_GRAY;
1317 break;
1319 case AA_RGB:
1320 case AA_BGR:
1321 case AA_VRGB:
1322 case AA_VBGR:
1323 wxr_format = WXR_FORMAT_A8R8G8B8;
1324 break;
1326 default:
1327 ERR("aa = %d - not implemented\n", format);
1328 case AA_None:
1329 wxr_format = WXR_FORMAT_MONO;
1330 break;
1333 wine_tsx11_lock();
1334 formatEntry->font_format = get_xrender_format(wxr_format);
1335 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
1336 wine_tsx11_unlock();
1340 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1341 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1342 formatEntry->realized[glyph] = TRUE;
1344 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1345 buflen,
1346 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1347 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1349 gi.width = gm.gmBlackBoxX;
1350 gi.height = gm.gmBlackBoxY;
1351 gi.x = -gm.gmptGlyphOrigin.x;
1352 gi.y = gm.gmptGlyphOrigin.y;
1353 gi.xOff = gm.gmCellIncX;
1354 gi.yOff = gm.gmCellIncY;
1356 if(TRACE_ON(xrender)) {
1357 int pitch, i, j;
1358 char output[300];
1359 unsigned char *line;
1361 if(format == AA_None) {
1362 pitch = ((gi.width + 31) / 32) * 4;
1363 for(i = 0; i < gi.height; i++) {
1364 line = (unsigned char*) buf + i * pitch;
1365 output[0] = '\0';
1366 for(j = 0; j < pitch * 8; j++) {
1367 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1369 TRACE("%s\n", output);
1371 } else {
1372 static const char blks[] = " .:;!o*#";
1373 char str[2];
1375 str[1] = '\0';
1376 pitch = ((gi.width + 3) / 4) * 4;
1377 for(i = 0; i < gi.height; i++) {
1378 line = (unsigned char*) buf + i * pitch;
1379 output[0] = '\0';
1380 for(j = 0; j < pitch; j++) {
1381 str[0] = blks[line[j] >> 5];
1382 strcat(output, str);
1384 TRACE("%s\n", output);
1390 if(formatEntry->glyphset) {
1391 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1392 unsigned char *byte = (unsigned char*) buf, c;
1393 int i = buflen;
1395 while(i--) {
1396 c = *byte;
1398 /* magic to flip bit order */
1399 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1400 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1401 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1403 *byte++ = c;
1406 else if ( format != AA_Grey &&
1407 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1409 unsigned int i, *data = (unsigned int *)buf;
1410 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1412 gid = glyph;
1415 XRenderCompositeText seems to ignore 0x0 glyphs when
1416 AA_None, which means we lose the advance width of glyphs
1417 like the space. We'll pretend that such glyphs are 1x1
1418 bitmaps.
1421 if(buflen == 0)
1422 gi.width = gi.height = 1;
1424 wine_tsx11_lock();
1425 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1426 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1427 wine_tsx11_unlock();
1428 HeapFree(GetProcessHeap(), 0, buf);
1429 } else {
1430 formatEntry->bitmaps[glyph] = buf;
1433 formatEntry->gis[glyph] = gi;
1436 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
1437 void *bitmap, XGlyphInfo *gi)
1439 unsigned char *srcLine = bitmap, *src;
1440 unsigned char bits, bitsMask;
1441 int width = gi->width;
1442 int stride = ((width + 31) & ~31) >> 3;
1443 int height = gi->height;
1444 int w;
1445 int xspan, lenspan;
1447 TRACE("%d, %d\n", x, y);
1448 x -= gi->x;
1449 y -= gi->y;
1450 while (height--)
1452 src = srcLine;
1453 srcLine += stride;
1454 w = width;
1456 bitsMask = 0x80; /* FreeType is always MSB first */
1457 bits = *src++;
1459 xspan = x;
1460 while (w)
1462 if (bits & bitsMask)
1464 lenspan = 0;
1467 lenspan++;
1468 if (lenspan == w)
1469 break;
1470 bitsMask = bitsMask >> 1;
1471 if (!bitsMask)
1473 bits = *src++;
1474 bitsMask = 0x80;
1476 } while (bits & bitsMask);
1477 XFillRectangle (gdi_display, physDev->drawable,
1478 physDev->gc, xspan, y, lenspan, 1);
1479 xspan += lenspan;
1480 w -= lenspan;
1482 else
1486 w--;
1487 xspan++;
1488 if (!w)
1489 break;
1490 bitsMask = bitsMask >> 1;
1491 if (!bitsMask)
1493 bits = *src++;
1494 bitsMask = 0x80;
1496 } while (!(bits & bitsMask));
1499 y++;
1503 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
1504 void *bitmap, XGlyphInfo *gi)
1506 unsigned char *srcLine = bitmap, *src, bits;
1507 int width = gi->width;
1508 int stride = ((width + 3) & ~3);
1509 int height = gi->height;
1510 int w;
1511 int xspan, lenspan;
1513 x -= gi->x;
1514 y -= gi->y;
1515 while (height--)
1517 src = srcLine;
1518 srcLine += stride;
1519 w = width;
1521 bits = *src++;
1522 xspan = x;
1523 while (w)
1525 if (bits >= 0x80)
1527 lenspan = 0;
1530 lenspan++;
1531 if (lenspan == w)
1532 break;
1533 bits = *src++;
1534 } while (bits >= 0x80);
1535 XFillRectangle (gdi_display, physDev->drawable,
1536 physDev->gc, xspan, y, lenspan, 1);
1537 xspan += lenspan;
1538 w -= lenspan;
1540 else
1544 w--;
1545 xspan++;
1546 if (!w)
1547 break;
1548 bits = *src++;
1549 } while (bits < 0x80);
1552 y++;
1557 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1559 int s, l;
1561 s = 0;
1562 while ((mask & 1) == 0)
1564 mask >>= 1;
1565 s++;
1567 l = 0;
1568 while ((mask & 1) == 1)
1570 mask >>= 1;
1571 l++;
1573 *shift = s;
1574 *len = l;
1577 static DWORD GetField (DWORD pixel, int shift, int len)
1579 pixel = pixel & (((1 << (len)) - 1) << shift);
1580 pixel = pixel << (32 - (shift + len)) >> 24;
1581 while (len < 8)
1583 pixel |= (pixel >> len);
1584 len <<= 1;
1586 return pixel;
1590 static DWORD PutField (DWORD pixel, int shift, int len)
1592 shift = shift - (8 - len);
1593 if (len <= 8)
1594 pixel &= (((1 << len) - 1) << (8 - len));
1595 if (shift < 0)
1596 pixel >>= -shift;
1597 else
1598 pixel <<= shift;
1599 return pixel;
1602 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1603 int color)
1605 int r_shift, r_len;
1606 int g_shift, g_len;
1607 int b_shift, b_len;
1608 BYTE *maskLine, *mask, m;
1609 int maskStride;
1610 DWORD pixel;
1611 int width, height;
1612 int w, tx;
1613 BYTE src_r, src_g, src_b;
1615 x -= gi->x;
1616 y -= gi->y;
1617 width = gi->width;
1618 height = gi->height;
1620 maskLine = bitmap;
1621 maskStride = (width + 3) & ~3;
1623 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1624 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1625 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1627 src_r = GetField(color, r_shift, r_len);
1628 src_g = GetField(color, g_shift, g_len);
1629 src_b = GetField(color, b_shift, b_len);
1631 for(; height--; y++)
1633 mask = maskLine;
1634 maskLine += maskStride;
1635 w = width;
1636 tx = x;
1638 if(y < 0) continue;
1639 if(y >= image->height) break;
1641 for(; w--; tx++)
1643 if(tx >= image->width) break;
1645 m = *mask++;
1646 if(tx < 0) continue;
1648 if (m == 0xff)
1649 XPutPixel (image, tx, y, color);
1650 else if (m)
1652 BYTE r, g, b;
1654 pixel = XGetPixel (image, tx, y);
1656 r = GetField(pixel, r_shift, r_len);
1657 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1658 g = GetField(pixel, g_shift, g_len);
1659 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1660 b = GetField(pixel, b_shift, b_len);
1661 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1663 pixel = (PutField (r, r_shift, r_len) |
1664 PutField (g, g_shift, g_len) |
1665 PutField (b, b_shift, b_len));
1666 XPutPixel (image, tx, y, pixel);
1672 /*************************************************************
1673 * get_tile_pict
1675 * Returns an appropriate Picture for tiling the text colour.
1676 * Call and use result within the xrender_cs
1678 static Picture get_tile_pict(const WineXRenderFormat *wxr_format, int text_pixel)
1680 static struct
1682 Pixmap xpm;
1683 Picture pict;
1684 int current_color;
1685 } tiles[WXR_NB_FORMATS], *tile;
1686 XRenderColor col;
1688 tile = &tiles[wxr_format->format];
1690 if(!tile->xpm)
1692 XRenderPictureAttributes pa;
1694 wine_tsx11_lock();
1695 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1697 pa.repeat = RepeatNormal;
1698 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1699 wine_tsx11_unlock();
1701 /* init current_color to something different from text_pixel */
1702 tile->current_color = ~text_pixel;
1704 if(wxr_format->format == WXR_FORMAT_MONO)
1706 /* for a 1bpp bitmap we always need a 1 in the tile */
1707 col.red = col.green = col.blue = 0;
1708 col.alpha = 0xffff;
1709 wine_tsx11_lock();
1710 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1711 wine_tsx11_unlock();
1715 if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1717 get_xrender_color(wxr_format, text_pixel, &col);
1718 wine_tsx11_lock();
1719 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1720 wine_tsx11_unlock();
1721 tile->current_color = text_pixel;
1723 return tile->pict;
1726 /*************************************************************
1727 * get_mask_pict
1729 * Returns an appropriate Picture for masking with the specified alpha.
1730 * Call and use result within the xrender_cs
1732 static Picture get_mask_pict( int alpha )
1734 static Pixmap pixmap;
1735 static Picture pict;
1736 static int current_alpha;
1738 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1740 if (!pixmap)
1742 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
1743 XRenderPictureAttributes pa;
1745 wine_tsx11_lock();
1746 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1747 pa.repeat = RepeatNormal;
1748 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format, CPRepeat, &pa );
1749 wine_tsx11_unlock();
1750 current_alpha = -1;
1753 if (alpha != current_alpha)
1755 XRenderColor col;
1756 col.red = col.green = col.blue = 0;
1757 col.alpha = current_alpha = alpha;
1758 wine_tsx11_lock();
1759 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1760 wine_tsx11_unlock();
1762 return pict;
1765 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1767 return 1;
1770 /***********************************************************************
1771 * X11DRV_XRender_ExtTextOut
1773 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1774 const RECT *lprect, LPCWSTR wstr, UINT count,
1775 const INT *lpDx )
1777 XGCValues xgcval;
1778 gsCacheEntry *entry;
1779 gsCacheEntryFormat *formatEntry;
1780 BOOL retv = FALSE;
1781 int textPixel, backgroundPixel;
1782 HRGN saved_region = 0;
1783 BOOL disable_antialias = FALSE;
1784 AA_Type aa_type = AA_None;
1785 DIBSECTION bmp;
1786 unsigned int idx;
1787 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
1788 Picture tile_pict = 0;
1790 /* Do we need to disable antialiasing because of palette mode? */
1791 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1792 TRACE("bitmap is not a DIB\n");
1794 else if (bmp.dsBmih.biBitCount <= 8) {
1795 TRACE("Disabling antialiasing\n");
1796 disable_antialias = TRUE;
1799 xgcval.function = GXcopy;
1800 xgcval.background = physDev->backgroundPixel;
1801 xgcval.fill_style = FillSolid;
1802 wine_tsx11_lock();
1803 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1804 wine_tsx11_unlock();
1806 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1808 if(physDev->depth == 1) {
1809 if((physDev->textPixel & 0xffffff) == 0) {
1810 textPixel = 0;
1811 backgroundPixel = 1;
1812 } else {
1813 textPixel = 1;
1814 backgroundPixel = 0;
1816 } else {
1817 textPixel = physDev->textPixel;
1818 backgroundPixel = physDev->backgroundPixel;
1821 if(flags & ETO_OPAQUE)
1823 wine_tsx11_lock();
1824 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1825 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1826 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1827 lprect->right - lprect->left, lprect->bottom - lprect->top );
1828 wine_tsx11_unlock();
1831 if(count == 0)
1833 retv = TRUE;
1834 goto done_unlock;
1837 if (flags & ETO_CLIPPED)
1839 HRGN clip_region;
1841 clip_region = CreateRectRgnIndirect( lprect );
1842 /* make a copy of the current device region */
1843 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1844 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1845 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1846 DeleteObject( clip_region );
1849 EnterCriticalSection(&xrender_cs);
1851 entry = glyphsetCache + physDev->xrender->cache_index;
1852 if( disable_antialias == FALSE )
1853 aa_type = entry->aa_default;
1854 formatEntry = entry->format[aa_type];
1856 for(idx = 0; idx < count; idx++) {
1857 if( !formatEntry ) {
1858 UploadGlyph(physDev, wstr[idx], aa_type);
1859 /* re-evaluate antialias since aa_default may have changed */
1860 if( disable_antialias == FALSE )
1861 aa_type = entry->aa_default;
1862 formatEntry = entry->format[aa_type];
1863 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1864 UploadGlyph(physDev, wstr[idx], aa_type);
1867 if (!formatEntry)
1869 WARN("could not upload requested glyphs\n");
1870 LeaveCriticalSection(&xrender_cs);
1871 goto done_unlock;
1874 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1875 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1877 if(X11DRV_XRender_Installed)
1879 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1880 POINT offset = {0, 0};
1881 POINT desired, current;
1882 int render_op = PictOpOver;
1883 Picture pict = get_xrender_picture(physDev);
1885 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1886 So we pass zeros to the function and move to our starting position using the first
1887 element of the elts array. */
1889 desired.x = physDev->dc_rect.left + x;
1890 desired.y = physDev->dc_rect.top + y;
1891 current.x = current.y = 0;
1893 tile_pict = get_tile_pict(dst_format, physDev->textPixel);
1895 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1897 if((dst_format->format == WXR_FORMAT_MONO) && (textPixel == 0))
1898 render_op = PictOpOutReverse; /* This gives us 'black' text */
1900 for(idx = 0; idx < count; idx++)
1902 elts[idx].glyphset = formatEntry->glyphset;
1903 elts[idx].chars = wstr + idx;
1904 elts[idx].nchars = 1;
1905 elts[idx].xOff = desired.x - current.x;
1906 elts[idx].yOff = desired.y - current.y;
1908 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1909 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1911 if(!lpDx)
1913 desired.x += formatEntry->gis[wstr[idx]].xOff;
1914 desired.y += formatEntry->gis[wstr[idx]].yOff;
1916 else
1918 if(flags & ETO_PDY)
1920 offset.x += lpDx[idx * 2];
1921 offset.y += lpDx[idx * 2 + 1];
1923 else
1924 offset.x += lpDx[idx];
1925 desired.x = physDev->dc_rect.left + x + offset.x;
1926 desired.y = physDev->dc_rect.top + y + offset.y;
1929 wine_tsx11_lock();
1930 /* Make sure we don't have any transforms set from a previous call */
1931 set_xrender_transformation(pict, 1, 1, 0, 0);
1932 pXRenderCompositeText16(gdi_display, render_op,
1933 tile_pict,
1934 pict,
1935 formatEntry->font_format->pict_format,
1936 0, 0, 0, 0, elts, count);
1937 wine_tsx11_unlock();
1938 HeapFree(GetProcessHeap(), 0, elts);
1939 } else {
1940 POINT offset = {0, 0};
1941 wine_tsx11_lock();
1942 XSetForeground( gdi_display, physDev->gc, textPixel );
1944 if(aa_type == AA_None || physDev->depth == 1)
1946 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1948 if(aa_type == AA_None)
1949 sharp_glyph_fn = SharpGlyphMono;
1950 else
1951 sharp_glyph_fn = SharpGlyphGray;
1953 for(idx = 0; idx < count; idx++) {
1954 sharp_glyph_fn(physDev,
1955 physDev->dc_rect.left + x + offset.x,
1956 physDev->dc_rect.top + y + offset.y,
1957 formatEntry->bitmaps[wstr[idx]],
1958 &formatEntry->gis[wstr[idx]]);
1959 if(lpDx)
1961 if(flags & ETO_PDY)
1963 offset.x += lpDx[idx * 2];
1964 offset.y += lpDx[idx * 2 + 1];
1966 else
1967 offset.x += lpDx[idx];
1969 else
1971 offset.x += formatEntry->gis[wstr[idx]].xOff;
1972 offset.y += formatEntry->gis[wstr[idx]].yOff;
1975 } else {
1976 XImage *image;
1977 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1978 RECT extents = {0, 0, 0, 0};
1979 POINT cur = {0, 0};
1980 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1981 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1983 TRACE("drawable %dx%d\n", w, h);
1985 for(idx = 0; idx < count; idx++) {
1986 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1987 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1988 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1989 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1990 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1991 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1992 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1993 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1995 if(lpDx)
1997 if(flags & ETO_PDY)
1999 cur.x += lpDx[idx * 2];
2000 cur.y += lpDx[idx * 2 + 1];
2002 else
2003 cur.x += lpDx[idx];
2005 else
2007 cur.x += formatEntry->gis[wstr[idx]].xOff;
2008 cur.y += formatEntry->gis[wstr[idx]].yOff;
2011 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2012 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
2014 if(physDev->dc_rect.left + x + extents.left >= 0) {
2015 image_x = physDev->dc_rect.left + x + extents.left;
2016 image_off_x = 0;
2017 } else {
2018 image_x = 0;
2019 image_off_x = physDev->dc_rect.left + x + extents.left;
2021 if(physDev->dc_rect.top + y + extents.top >= 0) {
2022 image_y = physDev->dc_rect.top + y + extents.top;
2023 image_off_y = 0;
2024 } else {
2025 image_y = 0;
2026 image_off_y = physDev->dc_rect.top + y + extents.top;
2028 if(physDev->dc_rect.left + x + extents.right < w)
2029 image_w = physDev->dc_rect.left + x + extents.right - image_x;
2030 else
2031 image_w = w - image_x;
2032 if(physDev->dc_rect.top + y + extents.bottom < h)
2033 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
2034 else
2035 image_h = h - image_y;
2037 if(image_w <= 0 || image_h <= 0) goto no_image;
2039 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2040 image = XGetImage(gdi_display, physDev->drawable,
2041 image_x, image_y, image_w, image_h,
2042 AllPlanes, ZPixmap);
2043 X11DRV_check_error();
2045 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2046 gdi_display, (int)physDev->drawable, image_x, image_y,
2047 image_w, image_h, AllPlanes, ZPixmap,
2048 physDev->depth, image);
2049 if(!image) {
2050 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2051 physDev->depth);
2052 GC gc;
2053 XGCValues gcv;
2055 gcv.graphics_exposures = False;
2056 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2057 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
2058 image_w, image_h, 0, 0);
2059 XFreeGC(gdi_display, gc);
2060 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2061 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2062 ZPixmap);
2063 X11DRV_check_error();
2064 XFreePixmap(gdi_display, xpm);
2066 if(!image) goto no_image;
2068 image->red_mask = visual->red_mask;
2069 image->green_mask = visual->green_mask;
2070 image->blue_mask = visual->blue_mask;
2072 for(idx = 0; idx < count; idx++) {
2073 SmoothGlyphGray(image,
2074 offset.x + image_off_x - extents.left,
2075 offset.y + image_off_y - extents.top,
2076 formatEntry->bitmaps[wstr[idx]],
2077 &formatEntry->gis[wstr[idx]],
2078 physDev->textPixel);
2079 if(lpDx)
2081 if(flags & ETO_PDY)
2083 offset.x += lpDx[idx * 2];
2084 offset.y += lpDx[idx * 2 + 1];
2086 else
2087 offset.x += lpDx[idx];
2089 else
2091 offset.x += formatEntry->gis[wstr[idx]].xOff;
2092 offset.y += formatEntry->gis[wstr[idx]].yOff;
2095 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
2096 image_x, image_y, image_w, image_h);
2097 XDestroyImage(image);
2099 no_image:
2100 wine_tsx11_unlock();
2102 LeaveCriticalSection(&xrender_cs);
2104 if (flags & ETO_CLIPPED)
2106 /* restore the device region */
2107 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
2108 DeleteObject( saved_region );
2111 retv = TRUE;
2113 done_unlock:
2114 X11DRV_UnlockDIBSection( physDev, TRUE );
2115 return retv;
2118 /* Helper function for (stretched) blitting using xrender */
2119 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2120 int x_src, int y_src, int x_dst, int y_dst,
2121 double xscale, double yscale, int width, int height )
2123 int x_offset, y_offset;
2125 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2126 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2127 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2128 if(xscale != 1.0 || yscale != 1.0)
2130 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2131 * in the wrong quadrant of the x-y plane.
2133 x_offset = (xscale < 0) ? -width : 0;
2134 y_offset = (yscale < 0) ? -height : 0;
2135 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2137 else
2139 x_offset = x_src;
2140 y_offset = y_src;
2141 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2143 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2144 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2147 /* Helper function for (stretched) mono->color blitting using xrender */
2148 static void xrender_mono_blit( Picture src_pict, Picture mask_pict, Picture dst_pict,
2149 int x_src, int y_src, double xscale, double yscale, int width, int height )
2151 int x_offset, y_offset;
2153 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2154 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
2155 * tile data. We need PictOpOver for correct rendering.
2156 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2157 * mask_x / mask_y
2159 if (xscale != 1.0 || yscale != 1.0)
2161 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2162 * in the wrong quadrant of the x-y plane.
2164 x_offset = (xscale < 0) ? -width : 0;
2165 y_offset = (yscale < 0) ? -height : 0;
2166 set_xrender_transformation(mask_pict, xscale, yscale, x_src, y_src);
2168 else
2170 x_offset = x_src;
2171 y_offset = y_src;
2172 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
2174 pXRenderComposite(gdi_display, PictOpOver, src_pict, mask_pict, dst_pict,
2175 0, 0, x_offset, y_offset, 0, 0, width, height);
2178 /******************************************************************************
2179 * AlphaBlend
2181 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2182 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2184 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2185 struct xrender_info *src_info = get_xrender_info( devSrc );
2186 double xscale, yscale;
2187 BOOL use_repeat;
2189 if(!X11DRV_XRender_Installed) {
2190 FIXME("Unable to AlphaBlend without Xrender\n");
2191 return FALSE;
2194 if (devSrc != devDst) X11DRV_LockDIBSection( devSrc, DIB_Status_GdiMod );
2195 X11DRV_LockDIBSection( devDst, DIB_Status_GdiMod );
2197 dst_pict = get_xrender_picture( devDst );
2199 use_repeat = use_source_repeat( devSrc );
2200 if (!use_repeat)
2202 xscale = src->width / (double)dst->width;
2203 yscale = src->height / (double)dst->height;
2205 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2207 if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && src_info->format)
2209 /* we need a source picture with no alpha */
2210 WXRFormat format = get_format_without_alpha( src_info->format->format );
2211 if (format != src_info->format->format)
2213 XRenderPictureAttributes pa;
2214 const WineXRenderFormat *fmt = get_xrender_format( format );
2216 wine_tsx11_lock();
2217 pa.subwindow_mode = IncludeInferiors;
2218 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2219 tmp_pict = pXRenderCreatePicture( gdi_display, devSrc->drawable, fmt->pict_format,
2220 CPSubwindowMode|CPRepeat, &pa );
2221 wine_tsx11_unlock();
2222 src_pict = tmp_pict;
2226 if (!src_pict) src_pict = get_xrender_picture_source( devSrc, use_repeat );
2228 EnterCriticalSection( &xrender_cs );
2229 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2231 wine_tsx11_lock();
2232 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2233 devSrc->dc_rect.left + src->visrect.left, devSrc->dc_rect.top + src->visrect.top,
2234 devDst->dc_rect.left + dst->visrect.left, devDst->dc_rect.top + dst->visrect.top,
2235 xscale, yscale,
2236 dst->visrect.right - dst->visrect.left, dst->visrect.bottom - dst->visrect.top );
2237 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2238 wine_tsx11_unlock();
2240 LeaveCriticalSection( &xrender_cs );
2241 if (devSrc != devDst) X11DRV_UnlockDIBSection( devSrc, FALSE );
2242 X11DRV_UnlockDIBSection( devDst, TRUE );
2243 return TRUE;
2247 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2249 /* 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 */
2250 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2251 const WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2252 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2254 wine_tsx11_lock();
2255 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2257 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2258 if( (physBitmap->pixmap_depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->pixmap_depth) ||
2259 (src_format->format == dst_format->format) )
2261 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2262 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2264 else /* We need depth conversion */
2266 Picture src_pict, dst_pict;
2267 XRenderPictureAttributes pa;
2268 pa.subwindow_mode = IncludeInferiors;
2269 pa.repeat = RepeatNone;
2271 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2272 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2274 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2275 pXRenderFreePicture(gdi_display, src_pict);
2276 pXRenderFreePicture(gdi_display, dst_pict);
2278 wine_tsx11_unlock();
2281 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2282 Pixmap pixmap, GC gc,
2283 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2285 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2286 int width = dst->visrect.right - dst->visrect.left;
2287 int height = dst->visrect.bottom - dst->visrect.top;
2288 int x_src = physDevSrc->dc_rect.left + src->visrect.left;
2289 int y_src = physDevSrc->dc_rect.top + src->visrect.top;
2290 struct xrender_info *src_info = get_xrender_info(physDevSrc);
2291 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDevDst->depth, physDevDst->color_shifts);
2292 Picture src_pict=0, dst_pict=0, mask_pict=0;
2293 BOOL use_repeat;
2294 double xscale, yscale;
2296 XRenderPictureAttributes pa;
2297 pa.subwindow_mode = IncludeInferiors;
2298 pa.repeat = RepeatNone;
2300 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2301 physDevSrc->depth, src->width, src->height, x_src, y_src);
2302 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst->depth, dst->width, dst->height);
2304 if(!X11DRV_XRender_Installed)
2306 TRACE("Not using XRender since it is not available or disabled\n");
2307 return FALSE;
2310 /* XRender can't handle palettes, so abort */
2311 if(X11DRV_PALETTE_XPixelToPalette)
2312 return FALSE;
2314 /* XRender is of no use in this case */
2315 if((physDevDst->depth == 1) && (physDevSrc->depth > 1))
2316 return FALSE;
2318 /* Just use traditional X copy when the formats match and we don't need stretching */
2319 if((src_info->format->format == dst_format->format) && !stretch)
2321 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2322 wine_tsx11_lock();
2323 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
2324 wine_tsx11_unlock();
2325 return TRUE;
2328 use_repeat = use_source_repeat( physDevSrc );
2329 if (!use_repeat)
2331 xscale = src->width / (double)dst->width;
2332 yscale = src->height / (double)dst->height;
2334 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2336 /* mono -> color */
2337 if(physDevSrc->depth == 1 && physDevDst->depth > 1)
2339 XRenderColor col;
2340 get_xrender_color(dst_format, physDevDst->textPixel, &col);
2342 /* We use the source drawable as a mask */
2343 mask_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2345 /* Use backgroundPixel as the foreground color */
2346 EnterCriticalSection( &xrender_cs );
2347 src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
2349 /* Create a destination picture and fill it with textPixel color as the background color */
2350 wine_tsx11_lock();
2351 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2352 pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height);
2354 xrender_mono_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
2356 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2357 wine_tsx11_unlock();
2358 LeaveCriticalSection( &xrender_cs );
2360 else /* color -> color (can be at different depths) or mono -> mono */
2362 if (physDevDst->depth == 32 && physDevSrc->depth < 32) mask_pict = get_no_alpha_mask();
2363 src_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2365 wine_tsx11_lock();
2366 dst_pict = pXRenderCreatePicture(gdi_display,
2367 pixmap, dst_format->pict_format,
2368 CPSubwindowMode|CPRepeat, &pa);
2370 xrender_blit(PictOpSrc, src_pict, mask_pict, dst_pict,
2371 x_src, y_src, 0, 0, xscale, yscale, width, height);
2373 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2374 wine_tsx11_unlock();
2376 return TRUE;
2379 #else /* SONAME_LIBXRENDER */
2381 void X11DRV_XRender_Init(void)
2383 TRACE("XRender support not compiled in.\n");
2384 return;
2387 void X11DRV_XRender_Finalize(void)
2391 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
2393 assert(0);
2394 return FALSE;
2397 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
2399 assert(0);
2400 return;
2403 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
2405 assert(0);
2406 return;
2409 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
2410 const RECT *lprect, LPCWSTR wstr, UINT count,
2411 const INT *lpDx )
2413 assert(0);
2414 return FALSE;
2417 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
2419 assert(0);
2420 return;
2423 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2424 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2426 FIXME("not supported - XRENDER headers were missing at compile time\n");
2427 return FALSE;
2430 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2432 wine_tsx11_lock();
2433 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
2435 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2436 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2437 wine_tsx11_unlock();
2440 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2442 return FALSE;
2445 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2446 Pixmap pixmap, GC gc,
2447 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2449 return FALSE;
2451 #endif /* SONAME_LIBXRENDER */