winex11: Don't use the bitfields for the BI_RGB case.
[wine.git] / dlls / winex11.drv / xrender.c
blob33e420aac3235d7162266fcca40f700731cc9b7a
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 );
1070 GetTransform( physDev->hdc, 0x204, &lfsz.xform );
1071 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1072 lfsz.xform.eM21, lfsz.xform.eM22);
1074 /* Not used fields, would break hashing */
1075 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1077 lfsz_calc_hash(&lfsz);
1079 info = get_xrender_info(physDev);
1080 if (!info) return 0;
1082 EnterCriticalSection(&xrender_cs);
1083 if(info->cache_index != -1)
1084 dec_ref_cache(info->cache_index);
1085 info->cache_index = GetCacheEntry(physDev, &lfsz);
1086 LeaveCriticalSection(&xrender_cs);
1087 return 0;
1090 /***********************************************************************
1091 * X11DRV_XRender_SetDeviceClipping
1093 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
1095 if (physDev->xrender->pict)
1097 wine_tsx11_lock();
1098 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1099 physDev->dc_rect.left, physDev->dc_rect.top,
1100 (XRectangle *)data->Buffer, data->rdh.nCount );
1101 wine_tsx11_unlock();
1105 /***********************************************************************
1106 * X11DRV_XRender_DeleteDC
1108 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1110 X11DRV_XRender_UpdateDrawable(physDev);
1112 EnterCriticalSection(&xrender_cs);
1113 if(physDev->xrender->cache_index != -1)
1114 dec_ref_cache(physDev->xrender->cache_index);
1115 LeaveCriticalSection(&xrender_cs);
1117 HeapFree(GetProcessHeap(), 0, physDev->xrender);
1118 physDev->xrender = NULL;
1119 return;
1122 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1124 const WineXRenderFormat *fmt;
1125 ColorShifts shifts;
1127 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1128 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1129 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1130 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1131 return FALSE;
1133 if (dib)
1135 const DWORD *bitfields;
1136 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1137 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1139 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1140 bitfields = dib->dsBitfields;
1141 else if(bits_pixel == 24 || bits_pixel == 32)
1142 bitfields = bitfields_32;
1143 else
1144 bitfields = bitfields_16;
1146 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1147 fmt = get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts);
1149 /* Common formats should be in our picture format table. */
1150 if (!fmt)
1152 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1153 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1154 return FALSE;
1157 else
1159 int red_mask, green_mask, blue_mask;
1161 /* We are dealing with a DDB */
1162 switch (bits_pixel)
1164 case 16:
1165 fmt = get_xrender_format(WXR_FORMAT_R5G6B5);
1166 break;
1167 case 24:
1168 fmt = get_xrender_format(WXR_FORMAT_R8G8B8);
1169 break;
1170 case 32:
1171 fmt = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1172 break;
1173 default:
1174 fmt = NULL;
1177 if (!fmt)
1179 TRACE("Unhandled DDB bits_pixel=%d\n", bits_pixel);
1180 return FALSE;
1183 red_mask = fmt->pict_format->direct.redMask << fmt->pict_format->direct.red;
1184 green_mask = fmt->pict_format->direct.greenMask << fmt->pict_format->direct.green;
1185 blue_mask = fmt->pict_format->direct.blueMask << fmt->pict_format->direct.blue;
1186 X11DRV_PALETTE_ComputeColorShifts(&shifts, red_mask, green_mask, blue_mask);
1189 physBitmap->pixmap_depth = fmt->pict_format->depth;
1190 physBitmap->trueColor = TRUE;
1191 physBitmap->pixmap_color_shifts = shifts;
1192 return TRUE;
1195 /***********************************************************************
1196 * X11DRV_XRender_UpdateDrawable
1198 * Deletes the pict and tile when the drawable changes.
1200 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1202 struct xrender_info *info = physDev->xrender;
1204 if (info->pict || info->pict_src)
1206 wine_tsx11_lock();
1207 XFlush( gdi_display );
1208 if (info->pict)
1210 TRACE("freeing pict = %lx dc = %p\n", info->pict, physDev->hdc);
1211 pXRenderFreePicture(gdi_display, info->pict);
1212 info->pict = 0;
1214 if(info->pict_src)
1216 TRACE("freeing pict = %lx dc = %p\n", info->pict_src, physDev->hdc);
1217 pXRenderFreePicture(gdi_display, info->pict_src);
1218 info->pict_src = 0;
1220 wine_tsx11_unlock();
1223 info->format = NULL;
1226 /************************************************************************
1227 * UploadGlyph
1229 * Helper to ExtTextOut. Must be called inside xrender_cs
1231 static void UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
1233 unsigned int buflen;
1234 char *buf;
1235 Glyph gid;
1236 GLYPHMETRICS gm;
1237 XGlyphInfo gi;
1238 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
1239 gsCacheEntryFormat *formatEntry;
1240 UINT ggo_format = GGO_GLYPH_INDEX;
1241 WXRFormat wxr_format;
1242 static const char zero[4];
1243 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1245 switch(format) {
1246 case AA_Grey:
1247 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1248 break;
1249 case AA_RGB:
1250 ggo_format |= WINE_GGO_HRGB_BITMAP;
1251 break;
1252 case AA_BGR:
1253 ggo_format |= WINE_GGO_HBGR_BITMAP;
1254 break;
1255 case AA_VRGB:
1256 ggo_format |= WINE_GGO_VRGB_BITMAP;
1257 break;
1258 case AA_VBGR:
1259 ggo_format |= WINE_GGO_VBGR_BITMAP;
1260 break;
1262 default:
1263 ERR("aa = %d - not implemented\n", format);
1264 case AA_None:
1265 ggo_format |= GGO_BITMAP;
1266 break;
1269 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1270 if(buflen == GDI_ERROR) {
1271 if(format != AA_None) {
1272 format = AA_None;
1273 entry->aa_default = AA_None;
1274 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1275 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1277 if(buflen == GDI_ERROR) {
1278 WARN("GetGlyphOutlineW failed using default glyph\n");
1279 buflen = GetGlyphOutlineW(physDev->hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1280 if(buflen == GDI_ERROR) {
1281 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1282 buflen = GetGlyphOutlineW(physDev->hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1283 if(buflen == GDI_ERROR) {
1284 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1285 return;
1289 TRACE("Turning off antialiasing for this monochrome font\n");
1292 /* If there is nothing for the current type, we create the entry. */
1293 if( !entry->format[format] ) {
1294 entry->format[format] = HeapAlloc(GetProcessHeap(),
1295 HEAP_ZERO_MEMORY,
1296 sizeof(gsCacheEntryFormat));
1298 formatEntry = entry->format[format];
1300 if(formatEntry->nrealized <= glyph) {
1301 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1303 if (formatEntry->realized)
1304 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1305 HEAP_ZERO_MEMORY,
1306 formatEntry->realized,
1307 formatEntry->nrealized * sizeof(BOOL));
1308 else
1309 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1310 HEAP_ZERO_MEMORY,
1311 formatEntry->nrealized * sizeof(BOOL));
1313 if(!X11DRV_XRender_Installed) {
1314 if (formatEntry->bitmaps)
1315 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1316 HEAP_ZERO_MEMORY,
1317 formatEntry->bitmaps,
1318 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1319 else
1320 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1321 HEAP_ZERO_MEMORY,
1322 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1324 if (formatEntry->gis)
1325 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1326 HEAP_ZERO_MEMORY,
1327 formatEntry->gis,
1328 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1329 else
1330 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1331 HEAP_ZERO_MEMORY,
1332 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1336 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1337 switch(format) {
1338 case AA_Grey:
1339 wxr_format = WXR_FORMAT_GRAY;
1340 break;
1342 case AA_RGB:
1343 case AA_BGR:
1344 case AA_VRGB:
1345 case AA_VBGR:
1346 wxr_format = WXR_FORMAT_A8R8G8B8;
1347 break;
1349 default:
1350 ERR("aa = %d - not implemented\n", format);
1351 case AA_None:
1352 wxr_format = WXR_FORMAT_MONO;
1353 break;
1356 wine_tsx11_lock();
1357 formatEntry->font_format = get_xrender_format(wxr_format);
1358 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
1359 wine_tsx11_unlock();
1363 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1364 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1365 formatEntry->realized[glyph] = TRUE;
1367 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1368 buflen,
1369 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1370 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1372 gi.width = gm.gmBlackBoxX;
1373 gi.height = gm.gmBlackBoxY;
1374 gi.x = -gm.gmptGlyphOrigin.x;
1375 gi.y = gm.gmptGlyphOrigin.y;
1376 gi.xOff = gm.gmCellIncX;
1377 gi.yOff = gm.gmCellIncY;
1379 if(TRACE_ON(xrender)) {
1380 int pitch, i, j;
1381 char output[300];
1382 unsigned char *line;
1384 if(format == AA_None) {
1385 pitch = ((gi.width + 31) / 32) * 4;
1386 for(i = 0; i < gi.height; i++) {
1387 line = (unsigned char*) buf + i * pitch;
1388 output[0] = '\0';
1389 for(j = 0; j < pitch * 8; j++) {
1390 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1392 TRACE("%s\n", output);
1394 } else {
1395 static const char blks[] = " .:;!o*#";
1396 char str[2];
1398 str[1] = '\0';
1399 pitch = ((gi.width + 3) / 4) * 4;
1400 for(i = 0; i < gi.height; i++) {
1401 line = (unsigned char*) buf + i * pitch;
1402 output[0] = '\0';
1403 for(j = 0; j < pitch; j++) {
1404 str[0] = blks[line[j] >> 5];
1405 strcat(output, str);
1407 TRACE("%s\n", output);
1413 if(formatEntry->glyphset) {
1414 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1415 unsigned char *byte = (unsigned char*) buf, c;
1416 int i = buflen;
1418 while(i--) {
1419 c = *byte;
1421 /* magic to flip bit order */
1422 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1423 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1424 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1426 *byte++ = c;
1429 else if ( format != AA_Grey &&
1430 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1432 unsigned int i, *data = (unsigned int *)buf;
1433 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1435 gid = glyph;
1438 XRenderCompositeText seems to ignore 0x0 glyphs when
1439 AA_None, which means we lose the advance width of glyphs
1440 like the space. We'll pretend that such glyphs are 1x1
1441 bitmaps.
1444 if(buflen == 0)
1445 gi.width = gi.height = 1;
1447 wine_tsx11_lock();
1448 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1449 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1450 wine_tsx11_unlock();
1451 HeapFree(GetProcessHeap(), 0, buf);
1452 } else {
1453 formatEntry->bitmaps[glyph] = buf;
1456 formatEntry->gis[glyph] = gi;
1459 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
1460 void *bitmap, XGlyphInfo *gi)
1462 unsigned char *srcLine = bitmap, *src;
1463 unsigned char bits, bitsMask;
1464 int width = gi->width;
1465 int stride = ((width + 31) & ~31) >> 3;
1466 int height = gi->height;
1467 int w;
1468 int xspan, lenspan;
1470 TRACE("%d, %d\n", x, y);
1471 x -= gi->x;
1472 y -= gi->y;
1473 while (height--)
1475 src = srcLine;
1476 srcLine += stride;
1477 w = width;
1479 bitsMask = 0x80; /* FreeType is always MSB first */
1480 bits = *src++;
1482 xspan = x;
1483 while (w)
1485 if (bits & bitsMask)
1487 lenspan = 0;
1490 lenspan++;
1491 if (lenspan == w)
1492 break;
1493 bitsMask = bitsMask >> 1;
1494 if (!bitsMask)
1496 bits = *src++;
1497 bitsMask = 0x80;
1499 } while (bits & bitsMask);
1500 XFillRectangle (gdi_display, physDev->drawable,
1501 physDev->gc, xspan, y, lenspan, 1);
1502 xspan += lenspan;
1503 w -= lenspan;
1505 else
1509 w--;
1510 xspan++;
1511 if (!w)
1512 break;
1513 bitsMask = bitsMask >> 1;
1514 if (!bitsMask)
1516 bits = *src++;
1517 bitsMask = 0x80;
1519 } while (!(bits & bitsMask));
1522 y++;
1526 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
1527 void *bitmap, XGlyphInfo *gi)
1529 unsigned char *srcLine = bitmap, *src, bits;
1530 int width = gi->width;
1531 int stride = ((width + 3) & ~3);
1532 int height = gi->height;
1533 int w;
1534 int xspan, lenspan;
1536 x -= gi->x;
1537 y -= gi->y;
1538 while (height--)
1540 src = srcLine;
1541 srcLine += stride;
1542 w = width;
1544 bits = *src++;
1545 xspan = x;
1546 while (w)
1548 if (bits >= 0x80)
1550 lenspan = 0;
1553 lenspan++;
1554 if (lenspan == w)
1555 break;
1556 bits = *src++;
1557 } while (bits >= 0x80);
1558 XFillRectangle (gdi_display, physDev->drawable,
1559 physDev->gc, xspan, y, lenspan, 1);
1560 xspan += lenspan;
1561 w -= lenspan;
1563 else
1567 w--;
1568 xspan++;
1569 if (!w)
1570 break;
1571 bits = *src++;
1572 } while (bits < 0x80);
1575 y++;
1580 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1582 int s, l;
1584 s = 0;
1585 while ((mask & 1) == 0)
1587 mask >>= 1;
1588 s++;
1590 l = 0;
1591 while ((mask & 1) == 1)
1593 mask >>= 1;
1594 l++;
1596 *shift = s;
1597 *len = l;
1600 static DWORD GetField (DWORD pixel, int shift, int len)
1602 pixel = pixel & (((1 << (len)) - 1) << shift);
1603 pixel = pixel << (32 - (shift + len)) >> 24;
1604 while (len < 8)
1606 pixel |= (pixel >> len);
1607 len <<= 1;
1609 return pixel;
1613 static DWORD PutField (DWORD pixel, int shift, int len)
1615 shift = shift - (8 - len);
1616 if (len <= 8)
1617 pixel &= (((1 << len) - 1) << (8 - len));
1618 if (shift < 0)
1619 pixel >>= -shift;
1620 else
1621 pixel <<= shift;
1622 return pixel;
1625 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1626 int color)
1628 int r_shift, r_len;
1629 int g_shift, g_len;
1630 int b_shift, b_len;
1631 BYTE *maskLine, *mask, m;
1632 int maskStride;
1633 DWORD pixel;
1634 int width, height;
1635 int w, tx;
1636 BYTE src_r, src_g, src_b;
1638 x -= gi->x;
1639 y -= gi->y;
1640 width = gi->width;
1641 height = gi->height;
1643 maskLine = bitmap;
1644 maskStride = (width + 3) & ~3;
1646 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1647 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1648 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1650 src_r = GetField(color, r_shift, r_len);
1651 src_g = GetField(color, g_shift, g_len);
1652 src_b = GetField(color, b_shift, b_len);
1654 for(; height--; y++)
1656 mask = maskLine;
1657 maskLine += maskStride;
1658 w = width;
1659 tx = x;
1661 if(y < 0) continue;
1662 if(y >= image->height) break;
1664 for(; w--; tx++)
1666 if(tx >= image->width) break;
1668 m = *mask++;
1669 if(tx < 0) continue;
1671 if (m == 0xff)
1672 XPutPixel (image, tx, y, color);
1673 else if (m)
1675 BYTE r, g, b;
1677 pixel = XGetPixel (image, tx, y);
1679 r = GetField(pixel, r_shift, r_len);
1680 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1681 g = GetField(pixel, g_shift, g_len);
1682 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1683 b = GetField(pixel, b_shift, b_len);
1684 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1686 pixel = (PutField (r, r_shift, r_len) |
1687 PutField (g, g_shift, g_len) |
1688 PutField (b, b_shift, b_len));
1689 XPutPixel (image, tx, y, pixel);
1695 /*************************************************************
1696 * get_tile_pict
1698 * Returns an appropriate Picture for tiling the text colour.
1699 * Call and use result within the xrender_cs
1701 static Picture get_tile_pict(const WineXRenderFormat *wxr_format, int text_pixel)
1703 static struct
1705 Pixmap xpm;
1706 Picture pict;
1707 int current_color;
1708 } tiles[WXR_NB_FORMATS], *tile;
1709 XRenderColor col;
1711 tile = &tiles[wxr_format->format];
1713 if(!tile->xpm)
1715 XRenderPictureAttributes pa;
1717 wine_tsx11_lock();
1718 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1720 pa.repeat = RepeatNormal;
1721 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1722 wine_tsx11_unlock();
1724 /* init current_color to something different from text_pixel */
1725 tile->current_color = ~text_pixel;
1727 if(wxr_format->format == WXR_FORMAT_MONO)
1729 /* for a 1bpp bitmap we always need a 1 in the tile */
1730 col.red = col.green = col.blue = 0;
1731 col.alpha = 0xffff;
1732 wine_tsx11_lock();
1733 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1734 wine_tsx11_unlock();
1738 if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1740 get_xrender_color(wxr_format, text_pixel, &col);
1741 wine_tsx11_lock();
1742 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1743 wine_tsx11_unlock();
1744 tile->current_color = text_pixel;
1746 return tile->pict;
1749 /*************************************************************
1750 * get_mask_pict
1752 * Returns an appropriate Picture for masking with the specified alpha.
1753 * Call and use result within the xrender_cs
1755 static Picture get_mask_pict( int alpha )
1757 static Pixmap pixmap;
1758 static Picture pict;
1759 static int current_alpha;
1761 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1763 if (!pixmap)
1765 const WineXRenderFormat *fmt = get_xrender_format( WXR_FORMAT_A8R8G8B8 );
1766 XRenderPictureAttributes pa;
1768 wine_tsx11_lock();
1769 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1770 pa.repeat = RepeatNormal;
1771 pict = pXRenderCreatePicture( gdi_display, pixmap, fmt->pict_format, CPRepeat, &pa );
1772 wine_tsx11_unlock();
1773 current_alpha = -1;
1776 if (alpha != current_alpha)
1778 XRenderColor col;
1779 col.red = col.green = col.blue = 0;
1780 col.alpha = current_alpha = alpha;
1781 wine_tsx11_lock();
1782 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1783 wine_tsx11_unlock();
1785 return pict;
1788 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1790 return 1;
1793 /***********************************************************************
1794 * X11DRV_XRender_ExtTextOut
1796 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1797 const RECT *lprect, LPCWSTR wstr, UINT count,
1798 const INT *lpDx )
1800 XGCValues xgcval;
1801 gsCacheEntry *entry;
1802 gsCacheEntryFormat *formatEntry;
1803 BOOL retv = FALSE;
1804 int textPixel, backgroundPixel;
1805 HRGN saved_region = 0;
1806 BOOL disable_antialias = FALSE;
1807 AA_Type aa_type = AA_None;
1808 DIBSECTION bmp;
1809 unsigned int idx;
1810 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
1811 Picture tile_pict = 0;
1813 /* Do we need to disable antialiasing because of palette mode? */
1814 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1815 TRACE("bitmap is not a DIB\n");
1817 else if (bmp.dsBmih.biBitCount <= 8) {
1818 TRACE("Disabling antialiasing\n");
1819 disable_antialias = TRUE;
1822 xgcval.function = GXcopy;
1823 xgcval.background = physDev->backgroundPixel;
1824 xgcval.fill_style = FillSolid;
1825 wine_tsx11_lock();
1826 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1827 wine_tsx11_unlock();
1829 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1831 if(physDev->depth == 1) {
1832 if((physDev->textPixel & 0xffffff) == 0) {
1833 textPixel = 0;
1834 backgroundPixel = 1;
1835 } else {
1836 textPixel = 1;
1837 backgroundPixel = 0;
1839 } else {
1840 textPixel = physDev->textPixel;
1841 backgroundPixel = physDev->backgroundPixel;
1844 if(flags & ETO_OPAQUE)
1846 wine_tsx11_lock();
1847 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1848 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1849 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1850 lprect->right - lprect->left, lprect->bottom - lprect->top );
1851 wine_tsx11_unlock();
1854 if(count == 0)
1856 retv = TRUE;
1857 goto done_unlock;
1860 if (flags & ETO_CLIPPED)
1862 HRGN clip_region;
1864 clip_region = CreateRectRgnIndirect( lprect );
1865 /* make a copy of the current device region */
1866 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1867 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1868 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1869 DeleteObject( clip_region );
1872 EnterCriticalSection(&xrender_cs);
1874 entry = glyphsetCache + physDev->xrender->cache_index;
1875 if( disable_antialias == FALSE )
1876 aa_type = entry->aa_default;
1877 formatEntry = entry->format[aa_type];
1879 for(idx = 0; idx < count; idx++) {
1880 if( !formatEntry ) {
1881 UploadGlyph(physDev, wstr[idx], aa_type);
1882 /* re-evaluate antialias since aa_default may have changed */
1883 if( disable_antialias == FALSE )
1884 aa_type = entry->aa_default;
1885 formatEntry = entry->format[aa_type];
1886 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1887 UploadGlyph(physDev, wstr[idx], aa_type);
1890 if (!formatEntry)
1892 WARN("could not upload requested glyphs\n");
1893 LeaveCriticalSection(&xrender_cs);
1894 goto done_unlock;
1897 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1898 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1900 if(X11DRV_XRender_Installed)
1902 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1903 POINT offset = {0, 0};
1904 POINT desired, current;
1905 int render_op = PictOpOver;
1906 Picture pict = get_xrender_picture(physDev);
1908 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1909 So we pass zeros to the function and move to our starting position using the first
1910 element of the elts array. */
1912 desired.x = physDev->dc_rect.left + x;
1913 desired.y = physDev->dc_rect.top + y;
1914 current.x = current.y = 0;
1916 tile_pict = get_tile_pict(dst_format, physDev->textPixel);
1918 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1920 if((dst_format->format == WXR_FORMAT_MONO) && (textPixel == 0))
1921 render_op = PictOpOutReverse; /* This gives us 'black' text */
1923 for(idx = 0; idx < count; idx++)
1925 elts[idx].glyphset = formatEntry->glyphset;
1926 elts[idx].chars = wstr + idx;
1927 elts[idx].nchars = 1;
1928 elts[idx].xOff = desired.x - current.x;
1929 elts[idx].yOff = desired.y - current.y;
1931 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1932 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1934 if(!lpDx)
1936 desired.x += formatEntry->gis[wstr[idx]].xOff;
1937 desired.y += formatEntry->gis[wstr[idx]].yOff;
1939 else
1941 if(flags & ETO_PDY)
1943 offset.x += lpDx[idx * 2];
1944 offset.y += lpDx[idx * 2 + 1];
1946 else
1947 offset.x += lpDx[idx];
1948 desired.x = physDev->dc_rect.left + x + offset.x;
1949 desired.y = physDev->dc_rect.top + y + offset.y;
1952 wine_tsx11_lock();
1953 /* Make sure we don't have any transforms set from a previous call */
1954 set_xrender_transformation(pict, 1, 1, 0, 0);
1955 pXRenderCompositeText16(gdi_display, render_op,
1956 tile_pict,
1957 pict,
1958 formatEntry->font_format->pict_format,
1959 0, 0, 0, 0, elts, count);
1960 wine_tsx11_unlock();
1961 HeapFree(GetProcessHeap(), 0, elts);
1962 } else {
1963 POINT offset = {0, 0};
1964 wine_tsx11_lock();
1965 XSetForeground( gdi_display, physDev->gc, textPixel );
1967 if(aa_type == AA_None || physDev->depth == 1)
1969 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1971 if(aa_type == AA_None)
1972 sharp_glyph_fn = SharpGlyphMono;
1973 else
1974 sharp_glyph_fn = SharpGlyphGray;
1976 for(idx = 0; idx < count; idx++) {
1977 sharp_glyph_fn(physDev,
1978 physDev->dc_rect.left + x + offset.x,
1979 physDev->dc_rect.top + y + offset.y,
1980 formatEntry->bitmaps[wstr[idx]],
1981 &formatEntry->gis[wstr[idx]]);
1982 if(lpDx)
1984 if(flags & ETO_PDY)
1986 offset.x += lpDx[idx * 2];
1987 offset.y += lpDx[idx * 2 + 1];
1989 else
1990 offset.x += lpDx[idx];
1992 else
1994 offset.x += formatEntry->gis[wstr[idx]].xOff;
1995 offset.y += formatEntry->gis[wstr[idx]].yOff;
1998 } else {
1999 XImage *image;
2000 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2001 RECT extents = {0, 0, 0, 0};
2002 POINT cur = {0, 0};
2003 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
2004 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
2006 TRACE("drawable %dx%d\n", w, h);
2008 for(idx = 0; idx < count; idx++) {
2009 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2010 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2011 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2012 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2013 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2014 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2015 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2016 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2018 if(lpDx)
2020 if(flags & ETO_PDY)
2022 cur.x += lpDx[idx * 2];
2023 cur.y += lpDx[idx * 2 + 1];
2025 else
2026 cur.x += lpDx[idx];
2028 else
2030 cur.x += formatEntry->gis[wstr[idx]].xOff;
2031 cur.y += formatEntry->gis[wstr[idx]].yOff;
2034 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2035 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
2037 if(physDev->dc_rect.left + x + extents.left >= 0) {
2038 image_x = physDev->dc_rect.left + x + extents.left;
2039 image_off_x = 0;
2040 } else {
2041 image_x = 0;
2042 image_off_x = physDev->dc_rect.left + x + extents.left;
2044 if(physDev->dc_rect.top + y + extents.top >= 0) {
2045 image_y = physDev->dc_rect.top + y + extents.top;
2046 image_off_y = 0;
2047 } else {
2048 image_y = 0;
2049 image_off_y = physDev->dc_rect.top + y + extents.top;
2051 if(physDev->dc_rect.left + x + extents.right < w)
2052 image_w = physDev->dc_rect.left + x + extents.right - image_x;
2053 else
2054 image_w = w - image_x;
2055 if(physDev->dc_rect.top + y + extents.bottom < h)
2056 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
2057 else
2058 image_h = h - image_y;
2060 if(image_w <= 0 || image_h <= 0) goto no_image;
2062 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2063 image = XGetImage(gdi_display, physDev->drawable,
2064 image_x, image_y, image_w, image_h,
2065 AllPlanes, ZPixmap);
2066 X11DRV_check_error();
2068 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2069 gdi_display, (int)physDev->drawable, image_x, image_y,
2070 image_w, image_h, AllPlanes, ZPixmap,
2071 physDev->depth, image);
2072 if(!image) {
2073 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2074 physDev->depth);
2075 GC gc;
2076 XGCValues gcv;
2078 gcv.graphics_exposures = False;
2079 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2080 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
2081 image_w, image_h, 0, 0);
2082 XFreeGC(gdi_display, gc);
2083 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2084 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2085 ZPixmap);
2086 X11DRV_check_error();
2087 XFreePixmap(gdi_display, xpm);
2089 if(!image) goto no_image;
2091 image->red_mask = visual->red_mask;
2092 image->green_mask = visual->green_mask;
2093 image->blue_mask = visual->blue_mask;
2095 for(idx = 0; idx < count; idx++) {
2096 SmoothGlyphGray(image,
2097 offset.x + image_off_x - extents.left,
2098 offset.y + image_off_y - extents.top,
2099 formatEntry->bitmaps[wstr[idx]],
2100 &formatEntry->gis[wstr[idx]],
2101 physDev->textPixel);
2102 if(lpDx)
2104 if(flags & ETO_PDY)
2106 offset.x += lpDx[idx * 2];
2107 offset.y += lpDx[idx * 2 + 1];
2109 else
2110 offset.x += lpDx[idx];
2112 else
2114 offset.x += formatEntry->gis[wstr[idx]].xOff;
2115 offset.y += formatEntry->gis[wstr[idx]].yOff;
2118 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
2119 image_x, image_y, image_w, image_h);
2120 XDestroyImage(image);
2122 no_image:
2123 wine_tsx11_unlock();
2125 LeaveCriticalSection(&xrender_cs);
2127 if (flags & ETO_CLIPPED)
2129 /* restore the device region */
2130 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
2131 DeleteObject( saved_region );
2134 retv = TRUE;
2136 done_unlock:
2137 X11DRV_UnlockDIBSection( physDev, TRUE );
2138 return retv;
2141 /* Helper function for (stretched) blitting using xrender */
2142 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2143 int x_src, int y_src, int x_dst, int y_dst,
2144 double xscale, double yscale, int width, int height )
2146 int x_offset, y_offset;
2148 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2149 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2150 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2151 if(xscale != 1.0 || yscale != 1.0)
2153 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2154 * in the wrong quadrant of the x-y plane.
2156 x_offset = (xscale < 0) ? -width : 0;
2157 y_offset = (yscale < 0) ? -height : 0;
2158 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2160 else
2162 x_offset = x_src;
2163 y_offset = y_src;
2164 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2166 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2167 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2170 /* Helper function for (stretched) mono->color blitting using xrender */
2171 static void xrender_mono_blit( Picture src_pict, Picture mask_pict, Picture dst_pict,
2172 int x_src, int y_src, double xscale, double yscale, int width, int height )
2174 int x_offset, y_offset;
2176 /* When doing a mono->color blit, 'src_pict' contains a 1x1 picture for tiling, the actual
2177 * source data is in mask_pict. The 'src_pict' data effectively acts as an alpha channel to the
2178 * tile data. We need PictOpOver for correct rendering.
2179 * Note since the 'source data' is in the mask picture, we have to pass x_src / y_src using
2180 * mask_x / mask_y
2182 if (xscale != 1.0 || yscale != 1.0)
2184 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2185 * in the wrong quadrant of the x-y plane.
2187 x_offset = (xscale < 0) ? -width : 0;
2188 y_offset = (yscale < 0) ? -height : 0;
2189 set_xrender_transformation(mask_pict, xscale, yscale, x_src, y_src);
2191 else
2193 x_offset = x_src;
2194 y_offset = y_src;
2195 set_xrender_transformation(mask_pict, 1, 1, 0, 0);
2197 pXRenderComposite(gdi_display, PictOpOver, src_pict, mask_pict, dst_pict,
2198 0, 0, x_offset, y_offset, 0, 0, width, height);
2201 /******************************************************************************
2202 * AlphaBlend
2204 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2205 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2207 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2208 struct xrender_info *src_info = get_xrender_info( devSrc );
2209 double xscale, yscale;
2210 BOOL use_repeat;
2212 if(!X11DRV_XRender_Installed) {
2213 FIXME("Unable to AlphaBlend without Xrender\n");
2214 return FALSE;
2217 if (devSrc != devDst) X11DRV_LockDIBSection( devSrc, DIB_Status_GdiMod );
2218 X11DRV_LockDIBSection( devDst, DIB_Status_GdiMod );
2220 dst_pict = get_xrender_picture( devDst );
2222 use_repeat = use_source_repeat( devSrc );
2223 if (!use_repeat)
2225 xscale = src->width / (double)dst->width;
2226 yscale = src->height / (double)dst->height;
2228 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2230 if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && src_info->format)
2232 /* we need a source picture with no alpha */
2233 WXRFormat format = get_format_without_alpha( src_info->format->format );
2234 if (format != src_info->format->format)
2236 XRenderPictureAttributes pa;
2237 const WineXRenderFormat *fmt = get_xrender_format( format );
2239 wine_tsx11_lock();
2240 pa.subwindow_mode = IncludeInferiors;
2241 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2242 tmp_pict = pXRenderCreatePicture( gdi_display, devSrc->drawable, fmt->pict_format,
2243 CPSubwindowMode|CPRepeat, &pa );
2244 wine_tsx11_unlock();
2245 src_pict = tmp_pict;
2249 if (!src_pict) src_pict = get_xrender_picture_source( devSrc, use_repeat );
2251 EnterCriticalSection( &xrender_cs );
2252 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2254 wine_tsx11_lock();
2255 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2256 devSrc->dc_rect.left + src->visrect.left, devSrc->dc_rect.top + src->visrect.top,
2257 devDst->dc_rect.left + dst->visrect.left, devDst->dc_rect.top + dst->visrect.top,
2258 xscale, yscale,
2259 dst->visrect.right - dst->visrect.left, dst->visrect.bottom - dst->visrect.top );
2260 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2261 wine_tsx11_unlock();
2263 LeaveCriticalSection( &xrender_cs );
2264 if (devSrc != devDst) X11DRV_UnlockDIBSection( devSrc, FALSE );
2265 X11DRV_UnlockDIBSection( devDst, TRUE );
2266 return TRUE;
2270 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2272 /* 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 */
2273 int depth = physBitmap->pixmap_depth == 1 ? 1 : physDev->depth;
2274 const WineXRenderFormat *src_format = get_xrender_format_from_color_shifts(physBitmap->pixmap_depth, &physBitmap->pixmap_color_shifts);
2275 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2277 wine_tsx11_lock();
2278 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2280 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2281 if( (physBitmap->pixmap_depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->pixmap_depth) ||
2282 (src_format->format == dst_format->format) )
2284 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2285 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2287 else /* We need depth conversion */
2289 Picture src_pict, dst_pict;
2290 XRenderPictureAttributes pa;
2291 pa.subwindow_mode = IncludeInferiors;
2292 pa.repeat = RepeatNone;
2294 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2295 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2297 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2298 pXRenderFreePicture(gdi_display, src_pict);
2299 pXRenderFreePicture(gdi_display, dst_pict);
2301 wine_tsx11_unlock();
2304 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2305 Pixmap pixmap, GC gc,
2306 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2308 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2309 int width = dst->visrect.right - dst->visrect.left;
2310 int height = dst->visrect.bottom - dst->visrect.top;
2311 int x_src = physDevSrc->dc_rect.left + src->visrect.left;
2312 int y_src = physDevSrc->dc_rect.top + src->visrect.top;
2313 struct xrender_info *src_info = get_xrender_info(physDevSrc);
2314 const WineXRenderFormat *dst_format = get_xrender_format_from_color_shifts(physDevDst->depth, physDevDst->color_shifts);
2315 Picture src_pict=0, dst_pict=0, mask_pict=0;
2316 BOOL use_repeat;
2317 double xscale, yscale;
2319 XRenderPictureAttributes pa;
2320 pa.subwindow_mode = IncludeInferiors;
2321 pa.repeat = RepeatNone;
2323 TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n",
2324 physDevSrc->depth, src->width, src->height, x_src, y_src);
2325 TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst->depth, dst->width, dst->height);
2327 if(!X11DRV_XRender_Installed)
2329 TRACE("Not using XRender since it is not available or disabled\n");
2330 return FALSE;
2333 /* XRender can't handle palettes, so abort */
2334 if(X11DRV_PALETTE_XPixelToPalette)
2335 return FALSE;
2337 /* XRender is of no use in this case */
2338 if((physDevDst->depth == 1) && (physDevSrc->depth > 1))
2339 return FALSE;
2341 /* Just use traditional X copy when the formats match and we don't need stretching */
2342 if((src_info->format->format == dst_format->format) && !stretch)
2344 TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
2345 wine_tsx11_lock();
2346 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
2347 wine_tsx11_unlock();
2348 return TRUE;
2351 use_repeat = use_source_repeat( physDevSrc );
2352 if (!use_repeat)
2354 xscale = src->width / (double)dst->width;
2355 yscale = src->height / (double)dst->height;
2357 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2359 /* mono -> color */
2360 if(physDevSrc->depth == 1 && physDevDst->depth > 1)
2362 XRenderColor col;
2363 get_xrender_color(dst_format, physDevDst->textPixel, &col);
2365 /* We use the source drawable as a mask */
2366 mask_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2368 /* Use backgroundPixel as the foreground color */
2369 EnterCriticalSection( &xrender_cs );
2370 src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
2372 /* Create a destination picture and fill it with textPixel color as the background color */
2373 wine_tsx11_lock();
2374 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
2375 pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height);
2377 xrender_mono_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
2379 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2380 wine_tsx11_unlock();
2381 LeaveCriticalSection( &xrender_cs );
2383 else /* color -> color (can be at different depths) or mono -> mono */
2385 if (physDevDst->depth == 32 && physDevSrc->depth < 32) mask_pict = get_no_alpha_mask();
2386 src_pict = get_xrender_picture_source( physDevSrc, use_repeat );
2388 wine_tsx11_lock();
2389 dst_pict = pXRenderCreatePicture(gdi_display,
2390 pixmap, dst_format->pict_format,
2391 CPSubwindowMode|CPRepeat, &pa);
2393 xrender_blit(PictOpSrc, src_pict, mask_pict, dst_pict,
2394 x_src, y_src, 0, 0, xscale, yscale, width, height);
2396 if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
2397 wine_tsx11_unlock();
2399 return TRUE;
2402 #else /* SONAME_LIBXRENDER */
2404 void X11DRV_XRender_Init(void)
2406 TRACE("XRender support not compiled in.\n");
2407 return;
2410 void X11DRV_XRender_Finalize(void)
2414 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
2416 assert(0);
2417 return FALSE;
2420 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
2422 assert(0);
2423 return;
2426 void X11DRV_XRender_SetDeviceClipping(X11DRV_PDEVICE *physDev, const RGNDATA *data)
2428 assert(0);
2429 return;
2432 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
2433 const RECT *lprect, LPCWSTR wstr, UINT count,
2434 const INT *lpDx )
2436 assert(0);
2437 return FALSE;
2440 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
2442 assert(0);
2443 return;
2446 BOOL XRender_AlphaBlend( X11DRV_PDEVICE *devDst, X11DRV_PDEVICE *devSrc,
2447 struct bitblt_coords *dst, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2449 FIXME("not supported - XRENDER headers were missing at compile time\n");
2450 return FALSE;
2453 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2455 wine_tsx11_lock();
2456 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
2458 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2459 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
2460 wine_tsx11_unlock();
2463 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2465 return FALSE;
2468 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
2469 Pixmap pixmap, GC gc,
2470 const struct bitblt_coords *src, const struct bitblt_coords *dst )
2472 return FALSE;
2474 #endif /* SONAME_LIBXRENDER */