configure: Changes from running autconf after previous patch.
[wine/hacks.git] / dlls / winex11.drv / xrender.c
blob4f900b2f7bf722f0ae16f595e6ad75be6dbdd571
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 font_smoothing = TRUE; /* default to enabled */
909 #ifdef SONAME_LIBFONTCONFIG
910 if (fontconfig_installed)
912 FcPattern *match, *pattern = pFcPatternCreate();
913 FcResult result;
914 char family[LF_FACESIZE * 4];
916 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
917 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
918 if (plfsz->lf.lfWeight != FW_DONTCARE)
920 int weight;
921 switch (plfsz->lf.lfWeight)
923 case FW_THIN: weight = FC_WEIGHT_THIN; break;
924 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
925 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
926 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
927 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
928 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
929 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
930 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
931 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
932 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
934 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
936 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
937 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
938 pFcDefaultSubstitute( pattern );
939 if ((match = pFcFontMatch( NULL, pattern, &result )))
941 int rgba;
942 FcBool antialias;
944 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
945 antialias = TRUE;
946 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
948 FcChar8 *file;
949 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
951 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
952 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
954 switch (rgba)
956 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
957 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
958 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
959 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
960 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
963 if (!antialias) font_smoothing = FALSE;
964 pFcPatternDestroy( match );
966 pFcPatternDestroy( pattern );
968 #endif /* SONAME_LIBFONTCONFIG */
970 /* now check Xft resources */
972 char *value;
973 BOOL antialias = TRUE;
975 wine_tsx11_lock();
976 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
978 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
979 value[0] == '0' || !strcasecmp( value, "off" ))
980 antialias = FALSE;
982 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
984 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
985 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
986 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
987 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
988 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
989 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
991 wine_tsx11_unlock();
992 if (!antialias) font_smoothing = FALSE;
995 if (!font_smoothing) entry->aa_default = AA_None;
997 /* we can't support subpixel without xrender */
998 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1000 else
1001 entry->aa_default = AA_None;
1003 return ret;
1006 static void dec_ref_cache(int index)
1008 assert(index >= 0);
1009 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1010 assert(glyphsetCache[index].count > 0);
1011 glyphsetCache[index].count--;
1014 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1016 DWORD hash = 0, *ptr, two_chars;
1017 WORD *pwc;
1018 int i;
1020 hash ^= plfsz->devsize.cx;
1021 hash ^= plfsz->devsize.cy;
1022 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1023 hash ^= *ptr;
1024 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1025 hash ^= *ptr;
1026 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1027 two_chars = *ptr;
1028 pwc = (WCHAR *)&two_chars;
1029 if(!*pwc) break;
1030 *pwc = toupperW(*pwc);
1031 pwc++;
1032 *pwc = toupperW(*pwc);
1033 hash ^= two_chars;
1034 if(!*pwc) break;
1036 plfsz->hash = hash;
1037 return;
1040 /***********************************************************************
1041 * X11DRV_XRender_Finalize
1043 void X11DRV_XRender_Finalize(void)
1045 int i;
1047 EnterCriticalSection(&xrender_cs);
1048 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1049 FreeEntry(i);
1050 LeaveCriticalSection(&xrender_cs);
1054 /***********************************************************************
1055 * X11DRV_XRender_SelectFont
1057 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1059 LFANDSIZE lfsz;
1060 struct xrender_info *info;
1062 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
1063 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1064 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1065 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1066 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1067 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
1068 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
1069 GetWorldTransform( physDev->hdc, &lfsz.xform );
1070 lfsz_calc_hash(&lfsz);
1072 info = get_xrender_info(physDev);
1073 if (!info) return 0;
1075 EnterCriticalSection(&xrender_cs);
1076 if(info->cache_index != -1)
1077 dec_ref_cache(info->cache_index);
1078 info->cache_index = GetCacheEntry(physDev, &lfsz);
1079 LeaveCriticalSection(&xrender_cs);
1080 return 0;
1083 /***********************************************************************
1084 * X11DRV_XRender_SetDeviceClipping
1086 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
1088 if (physDev->xrender->pict)
1090 wine_tsx11_lock();
1091 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1092 physDev->dc_rect.left, physDev->dc_rect.top,
1093 (XRectangle *)data->Buffer, data->rdh.nCount );
1094 wine_tsx11_unlock();
1098 /***********************************************************************
1099 * X11DRV_XRender_DeleteDC
1101 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1103 X11DRV_XRender_UpdateDrawable(physDev);
1105 EnterCriticalSection(&xrender_cs);
1106 if(physDev->xrender->cache_index != -1)
1107 dec_ref_cache(physDev->xrender->cache_index);
1108 LeaveCriticalSection(&xrender_cs);
1110 HeapFree(GetProcessHeap(), 0, physDev->xrender);
1111 physDev->xrender = NULL;
1112 return;
1115 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1117 const WineXRenderFormat *fmt;
1118 ColorShifts shifts;
1120 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1121 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1122 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1123 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1124 return FALSE;
1126 if (dib)
1128 X11DRV_PALETTE_ComputeColorShifts(&shifts, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
1129 fmt = get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts);
1131 /* Common formats should be in our picture format table. */
1132 if (!fmt)
1134 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1135 dib->dsBm.bmBitsPixel, dib->dsBitfields[0], dib->dsBitfields[1], dib->dsBitfields[2]);
1136 return FALSE;
1139 else
1141 int red_mask, green_mask, blue_mask;
1143 /* We are dealing with a DDB */
1144 switch (bits_pixel)
1146 case 16:
1147 fmt = get_xrender_format(WXR_FORMAT_R5G6B5);
1148 break;
1149 case 24:
1150 fmt = get_xrender_format(WXR_FORMAT_R8G8B8);
1151 break;
1152 case 32:
1153 fmt = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1154 break;
1155 default:
1156 fmt = NULL;
1159 if (!fmt)
1161 TRACE("Unhandled DDB bits_pixel=%d\n", bits_pixel);
1162 return FALSE;
1165 red_mask = fmt->pict_format->direct.redMask << fmt->pict_format->direct.red;
1166 green_mask = fmt->pict_format->direct.greenMask << fmt->pict_format->direct.green;
1167 blue_mask = fmt->pict_format->direct.blueMask << fmt->pict_format->direct.blue;
1168 X11DRV_PALETTE_ComputeColorShifts(&shifts, red_mask, green_mask, blue_mask);
1171 physBitmap->pixmap_depth = fmt->pict_format->depth;
1172 physBitmap->trueColor = TRUE;
1173 physBitmap->pixmap_color_shifts = shifts;
1174 return TRUE;
1177 /***********************************************************************
1178 * X11DRV_XRender_UpdateDrawable
1180 * Deletes the pict and tile when the drawable changes.
1182 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1184 struct xrender_info *info = physDev->xrender;
1186 if (info->pict || info->pict_src)
1188 wine_tsx11_lock();
1189 XFlush( gdi_display );
1190 if (info->pict)
1192 TRACE("freeing pict = %lx dc = %p\n", info->pict, physDev->hdc);
1193 pXRenderFreePicture(gdi_display, info->pict);
1194 info->pict = 0;
1196 if(info->pict_src)
1198 TRACE("freeing pict = %lx dc = %p\n", info->pict_src, physDev->hdc);
1199 pXRenderFreePicture(gdi_display, info->pict_src);
1200 info->pict_src = 0;
1202 wine_tsx11_unlock();
1205 info->format = NULL;
1208 /************************************************************************
1209 * UploadGlyph
1211 * Helper to ExtTextOut. Must be called inside xrender_cs
1213 static void UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
1215 unsigned int buflen;
1216 char *buf;
1217 Glyph gid;
1218 GLYPHMETRICS gm;
1219 XGlyphInfo gi;
1220 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
1221 gsCacheEntryFormat *formatEntry;
1222 UINT ggo_format = GGO_GLYPH_INDEX;
1223 WXRFormat wxr_format;
1224 static const char zero[4];
1225 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1227 switch(format) {
1228 case AA_Grey:
1229 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1230 break;
1231 case AA_RGB:
1232 ggo_format |= WINE_GGO_HRGB_BITMAP;
1233 break;
1234 case AA_BGR:
1235 ggo_format |= WINE_GGO_HBGR_BITMAP;
1236 break;
1237 case AA_VRGB:
1238 ggo_format |= WINE_GGO_VRGB_BITMAP;
1239 break;
1240 case AA_VBGR:
1241 ggo_format |= WINE_GGO_VBGR_BITMAP;
1242 break;
1244 default:
1245 ERR("aa = %d - not implemented\n", format);
1246 case AA_None:
1247 ggo_format |= GGO_BITMAP;
1248 break;
1251 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1252 if(buflen == GDI_ERROR) {
1253 if(format != AA_None) {
1254 format = AA_None;
1255 entry->aa_default = AA_None;
1256 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1257 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1259 if(buflen == GDI_ERROR) {
1260 WARN("GetGlyphOutlineW failed using default glyph\n");
1261 buflen = GetGlyphOutlineW(physDev->hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1262 if(buflen == GDI_ERROR) {
1263 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1264 buflen = GetGlyphOutlineW(physDev->hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1265 if(buflen == GDI_ERROR) {
1266 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1267 return;
1271 TRACE("Turning off antialiasing for this monochrome font\n");
1274 /* If there is nothing for the current type, we create the entry. */
1275 if( !entry->format[format] ) {
1276 entry->format[format] = HeapAlloc(GetProcessHeap(),
1277 HEAP_ZERO_MEMORY,
1278 sizeof(gsCacheEntryFormat));
1280 formatEntry = entry->format[format];
1282 if(formatEntry->nrealized <= glyph) {
1283 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1285 if (formatEntry->realized)
1286 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1287 HEAP_ZERO_MEMORY,
1288 formatEntry->realized,
1289 formatEntry->nrealized * sizeof(BOOL));
1290 else
1291 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1292 HEAP_ZERO_MEMORY,
1293 formatEntry->nrealized * sizeof(BOOL));
1295 if(!X11DRV_XRender_Installed) {
1296 if (formatEntry->bitmaps)
1297 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1298 HEAP_ZERO_MEMORY,
1299 formatEntry->bitmaps,
1300 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1301 else
1302 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1303 HEAP_ZERO_MEMORY,
1304 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1306 if (formatEntry->gis)
1307 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1308 HEAP_ZERO_MEMORY,
1309 formatEntry->gis,
1310 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1311 else
1312 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1313 HEAP_ZERO_MEMORY,
1314 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1318 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1319 switch(format) {
1320 case AA_Grey:
1321 wxr_format = WXR_FORMAT_GRAY;
1322 break;
1324 case AA_RGB:
1325 case AA_BGR:
1326 case AA_VRGB:
1327 case AA_VBGR:
1328 wxr_format = WXR_FORMAT_A8R8G8B8;
1329 break;
1331 default:
1332 ERR("aa = %d - not implemented\n", format);
1333 case AA_None:
1334 wxr_format = WXR_FORMAT_MONO;
1335 break;
1338 wine_tsx11_lock();
1339 formatEntry->font_format = get_xrender_format(wxr_format);
1340 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
1341 wine_tsx11_unlock();
1345 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1346 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1347 formatEntry->realized[glyph] = TRUE;
1349 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1350 buflen,
1351 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1352 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1354 gi.width = gm.gmBlackBoxX;
1355 gi.height = gm.gmBlackBoxY;
1356 gi.x = -gm.gmptGlyphOrigin.x;
1357 gi.y = gm.gmptGlyphOrigin.y;
1358 gi.xOff = gm.gmCellIncX;
1359 gi.yOff = gm.gmCellIncY;
1361 if(TRACE_ON(xrender)) {
1362 int pitch, i, j;
1363 char output[300];
1364 unsigned char *line;
1366 if(format == AA_None) {
1367 pitch = ((gi.width + 31) / 32) * 4;
1368 for(i = 0; i < gi.height; i++) {
1369 line = (unsigned char*) buf + i * pitch;
1370 output[0] = '\0';
1371 for(j = 0; j < pitch * 8; j++) {
1372 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1374 TRACE("%s\n", output);
1376 } else {
1377 static const char blks[] = " .:;!o*#";
1378 char str[2];
1380 str[1] = '\0';
1381 pitch = ((gi.width + 3) / 4) * 4;
1382 for(i = 0; i < gi.height; i++) {
1383 line = (unsigned char*) buf + i * pitch;
1384 output[0] = '\0';
1385 for(j = 0; j < pitch; j++) {
1386 str[0] = blks[line[j] >> 5];
1387 strcat(output, str);
1389 TRACE("%s\n", output);
1395 if(formatEntry->glyphset) {
1396 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1397 unsigned char *byte = (unsigned char*) buf, c;
1398 int i = buflen;
1400 while(i--) {
1401 c = *byte;
1403 /* magic to flip bit order */
1404 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1405 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1406 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1408 *byte++ = c;
1411 else if ( format != AA_Grey &&
1412 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1414 unsigned int i, *data = (unsigned int *)buf;
1415 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1417 gid = glyph;
1420 XRenderCompositeText seems to ignore 0x0 glyphs when
1421 AA_None, which means we lose the advance width of glyphs
1422 like the space. We'll pretend that such glyphs are 1x1
1423 bitmaps.
1426 if(buflen == 0)
1427 gi.width = gi.height = 1;
1429 wine_tsx11_lock();
1430 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1431 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1432 wine_tsx11_unlock();
1433 HeapFree(GetProcessHeap(), 0, buf);
1434 } else {
1435 formatEntry->bitmaps[glyph] = buf;
1438 formatEntry->gis[glyph] = gi;
1441 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
1442 void *bitmap, XGlyphInfo *gi)
1444 unsigned char *srcLine = bitmap, *src;
1445 unsigned char bits, bitsMask;
1446 int width = gi->width;
1447 int stride = ((width + 31) & ~31) >> 3;
1448 int height = gi->height;
1449 int w;
1450 int xspan, lenspan;
1452 TRACE("%d, %d\n", x, y);
1453 x -= gi->x;
1454 y -= gi->y;
1455 while (height--)
1457 src = srcLine;
1458 srcLine += stride;
1459 w = width;
1461 bitsMask = 0x80; /* FreeType is always MSB first */
1462 bits = *src++;
1464 xspan = x;
1465 while (w)
1467 if (bits & bitsMask)
1469 lenspan = 0;
1472 lenspan++;
1473 if (lenspan == w)
1474 break;
1475 bitsMask = bitsMask >> 1;
1476 if (!bitsMask)
1478 bits = *src++;
1479 bitsMask = 0x80;
1481 } while (bits & bitsMask);
1482 XFillRectangle (gdi_display, physDev->drawable,
1483 physDev->gc, xspan, y, lenspan, 1);
1484 xspan += lenspan;
1485 w -= lenspan;
1487 else
1491 w--;
1492 xspan++;
1493 if (!w)
1494 break;
1495 bitsMask = bitsMask >> 1;
1496 if (!bitsMask)
1498 bits = *src++;
1499 bitsMask = 0x80;
1501 } while (!(bits & bitsMask));
1504 y++;
1508 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
1509 void *bitmap, XGlyphInfo *gi)
1511 unsigned char *srcLine = bitmap, *src, bits;
1512 int width = gi->width;
1513 int stride = ((width + 3) & ~3);
1514 int height = gi->height;
1515 int w;
1516 int xspan, lenspan;
1518 x -= gi->x;
1519 y -= gi->y;
1520 while (height--)
1522 src = srcLine;
1523 srcLine += stride;
1524 w = width;
1526 bits = *src++;
1527 xspan = x;
1528 while (w)
1530 if (bits >= 0x80)
1532 lenspan = 0;
1535 lenspan++;
1536 if (lenspan == w)
1537 break;
1538 bits = *src++;
1539 } while (bits >= 0x80);
1540 XFillRectangle (gdi_display, physDev->drawable,
1541 physDev->gc, xspan, y, lenspan, 1);
1542 xspan += lenspan;
1543 w -= lenspan;
1545 else
1549 w--;
1550 xspan++;
1551 if (!w)
1552 break;
1553 bits = *src++;
1554 } while (bits < 0x80);
1557 y++;
1562 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1564 int s, l;
1566 s = 0;
1567 while ((mask & 1) == 0)
1569 mask >>= 1;
1570 s++;
1572 l = 0;
1573 while ((mask & 1) == 1)
1575 mask >>= 1;
1576 l++;
1578 *shift = s;
1579 *len = l;
1582 static DWORD GetField (DWORD pixel, int shift, int len)
1584 pixel = pixel & (((1 << (len)) - 1) << shift);
1585 pixel = pixel << (32 - (shift + len)) >> 24;
1586 while (len < 8)
1588 pixel |= (pixel >> len);
1589 len <<= 1;
1591 return pixel;
1595 static DWORD PutField (DWORD pixel, int shift, int len)
1597 shift = shift - (8 - len);
1598 if (len <= 8)
1599 pixel &= (((1 << len) - 1) << (8 - len));
1600 if (shift < 0)
1601 pixel >>= -shift;
1602 else
1603 pixel <<= shift;
1604 return pixel;
1607 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1608 int color)
1610 int r_shift, r_len;
1611 int g_shift, g_len;
1612 int b_shift, b_len;
1613 BYTE *maskLine, *mask, m;
1614 int maskStride;
1615 DWORD pixel;
1616 int width, height;
1617 int w, tx;
1618 BYTE src_r, src_g, src_b;
1620 x -= gi->x;
1621 y -= gi->y;
1622 width = gi->width;
1623 height = gi->height;
1625 maskLine = bitmap;
1626 maskStride = (width + 3) & ~3;
1628 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1629 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1630 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1632 src_r = GetField(color, r_shift, r_len);
1633 src_g = GetField(color, g_shift, g_len);
1634 src_b = GetField(color, b_shift, b_len);
1636 for(; height--; y++)
1638 mask = maskLine;
1639 maskLine += maskStride;
1640 w = width;
1641 tx = x;
1643 if(y < 0) continue;
1644 if(y >= image->height) break;
1646 for(; w--; tx++)
1648 if(tx >= image->width) break;
1650 m = *mask++;
1651 if(tx < 0) continue;
1653 if (m == 0xff)
1654 XPutPixel (image, tx, y, color);
1655 else if (m)
1657 BYTE r, g, b;
1659 pixel = XGetPixel (image, tx, y);
1661 r = GetField(pixel, r_shift, r_len);
1662 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1663 g = GetField(pixel, g_shift, g_len);
1664 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1665 b = GetField(pixel, b_shift, b_len);
1666 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1668 pixel = (PutField (r, r_shift, r_len) |
1669 PutField (g, g_shift, g_len) |
1670 PutField (b, b_shift, b_len));
1671 XPutPixel (image, tx, y, pixel);
1677 /*************************************************************
1678 * get_tile_pict
1680 * Returns an appropriate Picture for tiling the text colour.
1681 * Call and use result within the xrender_cs
1683 static Picture get_tile_pict(const WineXRenderFormat *wxr_format, int text_pixel)
1685 static struct
1687 Pixmap xpm;
1688 Picture pict;
1689 int current_color;
1690 } tiles[WXR_NB_FORMATS], *tile;
1691 XRenderColor col;
1693 tile = &tiles[wxr_format->format];
1695 if(!tile->xpm)
1697 XRenderPictureAttributes pa;
1699 wine_tsx11_lock();
1700 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1702 pa.repeat = RepeatNormal;
1703 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1704 wine_tsx11_unlock();
1706 /* init current_color to something different from text_pixel */
1707 tile->current_color = ~text_pixel;
1709 if(wxr_format->format == WXR_FORMAT_MONO)
1711 /* for a 1bpp bitmap we always need a 1 in the tile */
1712 col.red = col.green = col.blue = 0;
1713 col.alpha = 0xffff;
1714 wine_tsx11_lock();
1715 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1716 wine_tsx11_unlock();
1720 if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1722 get_xrender_color(wxr_format, text_pixel, &col);
1723 wine_tsx11_lock();
1724 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1725 wine_tsx11_unlock();
1726 tile->current_color = text_pixel;
1728 return tile->pict;
1731 /*************************************************************
1732 * get_mask_pict
1734 * Returns an appropriate Picture for masking with the specified alpha.
1735 * Call and use result within the xrender_cs
1737 static Picture get_mask_pict( int alpha )
1739 static Pixmap pixmap;
1740 static Picture pict;
1741 static int current_alpha;
1743 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1745 if (!pixmap)
1747 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
1748 XRenderPictureAttributes pa;
1750 wine_tsx11_lock();
1751 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1752 pa.repeat = RepeatNormal;
1753 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format, CPRepeat, &pa );
1754 wine_tsx11_unlock();
1755 current_alpha = -1;
1758 if (alpha != current_alpha)
1760 XRenderColor col;
1761 col.red = col.green = col.blue = 0;
1762 col.alpha = current_alpha = alpha;
1763 wine_tsx11_lock();
1764 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1765 wine_tsx11_unlock();
1767 return pict;
1770 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1772 return 1;
1775 /***********************************************************************
1776 * X11DRV_XRender_ExtTextOut
1778 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1779 const RECT *lprect, LPCWSTR wstr, UINT count,
1780 const INT *lpDx )
1782 XGCValues xgcval;
1783 gsCacheEntry *entry;
1784 gsCacheEntryFormat *formatEntry;
1785 BOOL retv = FALSE;
1786 int textPixel, backgroundPixel;
1787 HRGN saved_region = 0;
1788 BOOL disable_antialias = FALSE;
1789 AA_Type aa_type = AA_None;
1790 DIBSECTION bmp;
1791 unsigned int idx;
1792 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
1793 Picture tile_pict = 0;
1795 /* Do we need to disable antialiasing because of palette mode? */
1796 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1797 TRACE("bitmap is not a DIB\n");
1799 else if (bmp.dsBmih.biBitCount <= 8) {
1800 TRACE("Disabling antialiasing\n");
1801 disable_antialias = TRUE;
1804 xgcval.function = GXcopy;
1805 xgcval.background = physDev->backgroundPixel;
1806 xgcval.fill_style = FillSolid;
1807 wine_tsx11_lock();
1808 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1809 wine_tsx11_unlock();
1811 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1813 if(physDev->depth == 1) {
1814 if((physDev->textPixel & 0xffffff) == 0) {
1815 textPixel = 0;
1816 backgroundPixel = 1;
1817 } else {
1818 textPixel = 1;
1819 backgroundPixel = 0;
1821 } else {
1822 textPixel = physDev->textPixel;
1823 backgroundPixel = physDev->backgroundPixel;
1826 if(flags & ETO_OPAQUE)
1828 wine_tsx11_lock();
1829 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1830 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1831 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1832 lprect->right - lprect->left, lprect->bottom - lprect->top );
1833 wine_tsx11_unlock();
1836 if(count == 0)
1838 retv = TRUE;
1839 goto done_unlock;
1842 if (flags & ETO_CLIPPED)
1844 HRGN clip_region;
1846 clip_region = CreateRectRgnIndirect( lprect );
1847 /* make a copy of the current device region */
1848 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1849 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1850 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1851 DeleteObject( clip_region );
1854 EnterCriticalSection(&xrender_cs);
1856 entry = glyphsetCache + physDev->xrender->cache_index;
1857 if( disable_antialias == FALSE )
1858 aa_type = entry->aa_default;
1859 formatEntry = entry->format[aa_type];
1861 for(idx = 0; idx < count; idx++) {
1862 if( !formatEntry ) {
1863 UploadGlyph(physDev, wstr[idx], aa_type);
1864 /* re-evaluate antialias since aa_default may have changed */
1865 if( disable_antialias == FALSE )
1866 aa_type = entry->aa_default;
1867 formatEntry = entry->format[aa_type];
1868 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1869 UploadGlyph(physDev, wstr[idx], aa_type);
1872 if (!formatEntry)
1874 WARN("could not upload requested glyphs\n");
1875 LeaveCriticalSection(&xrender_cs);
1876 goto done_unlock;
1879 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1880 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1882 if(X11DRV_XRender_Installed)
1884 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1885 POINT offset = {0, 0};
1886 POINT desired, current;
1887 int render_op = PictOpOver;
1888 Picture pict = get_xrender_picture(physDev);
1890 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1891 So we pass zeros to the function and move to our starting position using the first
1892 element of the elts array. */
1894 desired.x = physDev->dc_rect.left + x;
1895 desired.y = physDev->dc_rect.top + y;
1896 current.x = current.y = 0;
1898 tile_pict = get_tile_pict(dst_format, physDev->textPixel);
1900 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1902 if((dst_format->format == WXR_FORMAT_MONO) && (textPixel == 0))
1903 render_op = PictOpOutReverse; /* This gives us 'black' text */
1905 for(idx = 0; idx < count; idx++)
1907 elts[idx].glyphset = formatEntry->glyphset;
1908 elts[idx].chars = wstr + idx;
1909 elts[idx].nchars = 1;
1910 elts[idx].xOff = desired.x - current.x;
1911 elts[idx].yOff = desired.y - current.y;
1913 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1914 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1916 if(!lpDx)
1918 desired.x += formatEntry->gis[wstr[idx]].xOff;
1919 desired.y += formatEntry->gis[wstr[idx]].yOff;
1921 else
1923 if(flags & ETO_PDY)
1925 offset.x += lpDx[idx * 2];
1926 offset.y += lpDx[idx * 2 + 1];
1928 else
1929 offset.x += lpDx[idx];
1930 desired.x = physDev->dc_rect.left + x + offset.x;
1931 desired.y = physDev->dc_rect.top + y + offset.y;
1934 wine_tsx11_lock();
1935 /* Make sure we don't have any transforms set from a previous call */
1936 set_xrender_transformation(pict, 1, 1, 0, 0);
1937 pXRenderCompositeText16(gdi_display, render_op,
1938 tile_pict,
1939 pict,
1940 formatEntry->font_format->pict_format,
1941 0, 0, 0, 0, elts, count);
1942 wine_tsx11_unlock();
1943 HeapFree(GetProcessHeap(), 0, elts);
1944 } else {
1945 POINT offset = {0, 0};
1946 wine_tsx11_lock();
1947 XSetForeground( gdi_display, physDev->gc, textPixel );
1949 if(aa_type == AA_None || physDev->depth == 1)
1951 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1953 if(aa_type == AA_None)
1954 sharp_glyph_fn = SharpGlyphMono;
1955 else
1956 sharp_glyph_fn = SharpGlyphGray;
1958 for(idx = 0; idx < count; idx++) {
1959 sharp_glyph_fn(physDev,
1960 physDev->dc_rect.left + x + offset.x,
1961 physDev->dc_rect.top + y + offset.y,
1962 formatEntry->bitmaps[wstr[idx]],
1963 &formatEntry->gis[wstr[idx]]);
1964 if(lpDx)
1966 if(flags & ETO_PDY)
1968 offset.x += lpDx[idx * 2];
1969 offset.y += lpDx[idx * 2 + 1];
1971 else
1972 offset.x += lpDx[idx];
1974 else
1976 offset.x += formatEntry->gis[wstr[idx]].xOff;
1977 offset.y += formatEntry->gis[wstr[idx]].yOff;
1980 } else {
1981 XImage *image;
1982 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1983 RECT extents = {0, 0, 0, 0};
1984 POINT cur = {0, 0};
1985 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1986 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1988 TRACE("drawable %dx%d\n", w, h);
1990 for(idx = 0; idx < count; idx++) {
1991 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1992 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1993 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1994 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1995 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1996 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1997 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1998 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2000 if(lpDx)
2002 if(flags & ETO_PDY)
2004 cur.x += lpDx[idx * 2];
2005 cur.y += lpDx[idx * 2 + 1];
2007 else
2008 cur.x += lpDx[idx];
2010 else
2012 cur.x += formatEntry->gis[wstr[idx]].xOff;
2013 cur.y += formatEntry->gis[wstr[idx]].yOff;
2016 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2017 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
2019 if(physDev->dc_rect.left + x + extents.left >= 0) {
2020 image_x = physDev->dc_rect.left + x + extents.left;
2021 image_off_x = 0;
2022 } else {
2023 image_x = 0;
2024 image_off_x = physDev->dc_rect.left + x + extents.left;
2026 if(physDev->dc_rect.top + y + extents.top >= 0) {
2027 image_y = physDev->dc_rect.top + y + extents.top;
2028 image_off_y = 0;
2029 } else {
2030 image_y = 0;
2031 image_off_y = physDev->dc_rect.top + y + extents.top;
2033 if(physDev->dc_rect.left + x + extents.right < w)
2034 image_w = physDev->dc_rect.left + x + extents.right - image_x;
2035 else
2036 image_w = w - image_x;
2037 if(physDev->dc_rect.top + y + extents.bottom < h)
2038 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
2039 else
2040 image_h = h - image_y;
2042 if(image_w <= 0 || image_h <= 0) goto no_image;
2044 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2045 image = XGetImage(gdi_display, physDev->drawable,
2046 image_x, image_y, image_w, image_h,
2047 AllPlanes, ZPixmap);
2048 X11DRV_check_error();
2050 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2051 gdi_display, (int)physDev->drawable, image_x, image_y,
2052 image_w, image_h, AllPlanes, ZPixmap,
2053 physDev->depth, image);
2054 if(!image) {
2055 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2056 physDev->depth);
2057 GC gc;
2058 XGCValues gcv;
2060 gcv.graphics_exposures = False;
2061 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2062 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
2063 image_w, image_h, 0, 0);
2064 XFreeGC(gdi_display, gc);
2065 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2066 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2067 ZPixmap);
2068 X11DRV_check_error();
2069 XFreePixmap(gdi_display, xpm);
2071 if(!image) goto no_image;
2073 image->red_mask = visual->red_mask;
2074 image->green_mask = visual->green_mask;
2075 image->blue_mask = visual->blue_mask;
2077 for(idx = 0; idx < count; idx++) {
2078 SmoothGlyphGray(image,
2079 offset.x + image_off_x - extents.left,
2080 offset.y + image_off_y - extents.top,
2081 formatEntry->bitmaps[wstr[idx]],
2082 &formatEntry->gis[wstr[idx]],
2083 physDev->textPixel);
2084 if(lpDx)
2086 if(flags & ETO_PDY)
2088 offset.x += lpDx[idx * 2];
2089 offset.y += lpDx[idx * 2 + 1];
2091 else
2092 offset.x += lpDx[idx];
2094 else
2096 offset.x += formatEntry->gis[wstr[idx]].xOff;
2097 offset.y += formatEntry->gis[wstr[idx]].yOff;
2100 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
2101 image_x, image_y, image_w, image_h);
2102 XDestroyImage(image);
2104 no_image:
2105 wine_tsx11_unlock();
2107 LeaveCriticalSection(&xrender_cs);
2109 if (flags & ETO_CLIPPED)
2111 /* restore the device region */
2112 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
2113 DeleteObject( saved_region );
2116 retv = TRUE;
2118 done_unlock:
2119 X11DRV_UnlockDIBSection( physDev, TRUE );
2120 return retv;
2123 /* Helper function for (stretched) blitting using xrender */
2124 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2125 int x_src, int y_src, int x_dst, int y_dst,
2126 double xscale, double yscale, int width, int height )
2128 int x_offset, y_offset;
2130 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2131 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2132 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2133 if(xscale != 1.0 || yscale != 1.0)
2135 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2136 * in the wrong quadrant of the x-y plane.
2138 x_offset = (xscale < 0) ? -width : 0;
2139 y_offset = (yscale < 0) ? -height : 0;
2140 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2142 else
2144 x_offset = x_src;
2145 y_offset = y_src;
2146 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2148 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2149 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2152 /* Helper function for (stretched) mono->color blitting using xrender */
2153 static void xrender_mono_blit( Picture src_pict, Picture mask_pict, Picture dst_pict,
2154 int x_src, int y_src, double xscale, double yscale, int width, int height )
2156 int x_offset, y_offset;
2158 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2159 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
2160 * tile data. We need PictOpOver for correct rendering.
2161 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2162 * mask_x / mask_y
2164 if (xscale != 1.0 || yscale != 1.0)
2166 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2167 * in the wrong quadrant of the x-y plane.
2169 x_offset = (xscale < 0) ? -width : 0;
2170 y_offset = (yscale < 0) ? -height : 0;
2171 set_xrender_transformation(mask_pict, xscale, yscale, x_src, y_src);
2173 else
2175 x_offset = x_src;
2176 y_offset = y_src;
2177 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
2179 pXRenderComposite(gdi_display, PictOpOver, src_pict, mask_pict, dst_pict,
2180 0, 0, x_offset, y_offset, 0, 0, width, height);
2183 /******************************************************************************
2184 * AlphaBlend
2186 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2187 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2189 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2190 struct xrender_info *src_info = get_xrender_info( devSrc );
2191 double xscale, yscale;
2192 BOOL use_repeat;
2194 if(!X11DRV_XRender_Installed) {
2195 FIXME("Unable to AlphaBlend without Xrender\n");
2196 return FALSE;
2199 if (devSrc != devDst) X11DRV_LockDIBSection( devSrc, DIB_Status_GdiMod );
2200 X11DRV_LockDIBSection( devDst, DIB_Status_GdiMod );
2202 dst_pict = get_xrender_picture( devDst );
2204 use_repeat = use_source_repeat( devSrc );
2205 if (!use_repeat)
2207 xscale = src->width / (double)dst->width;
2208 yscale = src->height / (double)dst->height;
2210 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2212 if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && src_info->format)
2214 /* we need a source picture with no alpha */
2215 WXRFormat format = get_format_without_alpha( src_info->format->format );
2216 if (format != src_info->format->format)
2218 XRenderPictureAttributes pa;
2219 const WineXRenderFormat *fmt = get_xrender_format( format );
2221 wine_tsx11_lock();
2222 pa.subwindow_mode = IncludeInferiors;
2223 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2224 tmp_pict = pXRenderCreatePicture( gdi_display, devSrc->drawable, fmt->pict_format,
2225 CPSubwindowMode|CPRepeat, &pa );
2226 wine_tsx11_unlock();
2227 src_pict = tmp_pict;
2231 if (!src_pict) src_pict = get_xrender_picture_source( devSrc, use_repeat );
2233 EnterCriticalSection( &xrender_cs );
2234 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2236 wine_tsx11_lock();
2237 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2238 devSrc->dc_rect.left + src->visrect.left, devSrc->dc_rect.top + src->visrect.top,
2239 devDst->dc_rect.left + dst->visrect.left, devDst->dc_rect.top + dst->visrect.top,
2240 xscale, yscale,
2241 dst->visrect.right - dst->visrect.left, dst->visrect.bottom - dst->visrect.top );
2242 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2243 wine_tsx11_unlock();
2245 LeaveCriticalSection( &xrender_cs );
2246 if (devSrc != devDst) X11DRV_UnlockDIBSection( devSrc, FALSE );
2247 X11DRV_UnlockDIBSection( devDst, TRUE );
2248 return TRUE;
2252 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2254 /* 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 */
2255 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2256 const WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2257 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2259 wine_tsx11_lock();
2260 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2262 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2263 if( (physBitmap->pixmap_depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->pixmap_depth) ||
2264 (src_format->format == dst_format->format) )
2266 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2267 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2269 else /* We need depth conversion */
2271 Picture src_pict, dst_pict;
2272 XRenderPictureAttributes pa;
2273 pa.subwindow_mode = IncludeInferiors;
2274 pa.repeat = RepeatNone;
2276 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2277 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2279 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2280 pXRenderFreePicture(gdi_display, src_pict);
2281 pXRenderFreePicture(gdi_display, dst_pict);
2283 wine_tsx11_unlock();
2286 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2287 Pixmap pixmap, GC gc,
2288 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2290 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2291 int width = dst->visrect.right - dst->visrect.left;
2292 int height = dst->visrect.bottom - dst->visrect.top;
2293 int x_src = physDevSrc->dc_rect.left + src->visrect.left;
2294 int y_src = physDevSrc->dc_rect.top + src->visrect.top;
2295 struct xrender_info *src_info = get_xrender_info(physDevSrc);
2296 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDevDst->depth, physDevDst->color_shifts);
2297 Picture src_pict=0, dst_pict=0, mask_pict=0;
2298 BOOL use_repeat;
2299 double xscale, yscale;
2301 XRenderPictureAttributes pa;
2302 pa.subwindow_mode = IncludeInferiors;
2303 pa.repeat = RepeatNone;
2305 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2306 physDevSrc->depth, src->width, src->height, x_src, y_src);
2307 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst->depth, dst->width, dst->height);
2309 if(!X11DRV_XRender_Installed)
2311 TRACE("Not using XRender since it is not available or disabled\n");
2312 return FALSE;
2315 /* XRender can't handle palettes, so abort */
2316 if(X11DRV_PALETTE_XPixelToPalette)
2317 return FALSE;
2319 /* XRender is of no use in this case */
2320 if((physDevDst->depth == 1) && (physDevSrc->depth > 1))
2321 return FALSE;
2323 /* Just use traditional X copy when the formats match and we don't need stretching */
2324 if((src_info->format->format == dst_format->format) && !stretch)
2326 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2327 wine_tsx11_lock();
2328 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
2329 wine_tsx11_unlock();
2330 return TRUE;
2333 use_repeat = use_source_repeat( physDevSrc );
2334 if (!use_repeat)
2336 xscale = src->width / (double)dst->width;
2337 yscale = src->height / (double)dst->height;
2339 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2341 /* mono -> color */
2342 if(physDevSrc->depth == 1 && physDevDst->depth > 1)
2344 XRenderColor col;
2345 get_xrender_color(dst_format, physDevDst->textPixel, &col);
2347 /* We use the source drawable as a mask */
2348 mask_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2350 /* Use backgroundPixel as the foreground color */
2351 EnterCriticalSection( &xrender_cs );
2352 src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
2354 /* Create a destination picture and fill it with textPixel color as the background color */
2355 wine_tsx11_lock();
2356 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2357 pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height);
2359 xrender_mono_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
2361 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2362 wine_tsx11_unlock();
2363 LeaveCriticalSection( &xrender_cs );
2365 else /* color -> color (can be at different depths) or mono -> mono */
2367 if (physDevDst->depth == 32 && physDevSrc->depth < 32) mask_pict = get_no_alpha_mask();
2368 src_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2370 wine_tsx11_lock();
2371 dst_pict = pXRenderCreatePicture(gdi_display,
2372 pixmap, dst_format->pict_format,
2373 CPSubwindowMode|CPRepeat, &pa);
2375 xrender_blit(PictOpSrc, src_pict, mask_pict, dst_pict,
2376 x_src, y_src, 0, 0, xscale, yscale, width, height);
2378 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2379 wine_tsx11_unlock();
2381 return TRUE;
2384 #else /* SONAME_LIBXRENDER */
2386 void X11DRV_XRender_Init(void)
2388 TRACE("XRender support not compiled in.\n");
2389 return;
2392 void X11DRV_XRender_Finalize(void)
2396 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
2398 assert(0);
2399 return FALSE;
2402 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
2404 assert(0);
2405 return;
2408 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
2410 assert(0);
2411 return;
2414 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
2415 const RECT *lprect, LPCWSTR wstr, UINT count,
2416 const INT *lpDx )
2418 assert(0);
2419 return FALSE;
2422 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
2424 assert(0);
2425 return;
2428 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2429 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2431 FIXME("not supported - XRENDER headers were missing at compile time\n");
2432 return FALSE;
2435 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2437 wine_tsx11_lock();
2438 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
2440 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2441 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2442 wine_tsx11_unlock();
2445 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2447 return FALSE;
2450 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2451 Pixmap pixmap, GC gc,
2452 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2454 return FALSE;
2456 #endif /* SONAME_LIBXRENDER */