2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
6 * Copyright 2011 Alexandre Julliard
9 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
37 #include "wine/library.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
43 #ifdef SONAME_LIBXRENDER
45 WINE_DECLARE_DEBUG_CHANNEL(winediag);
48 #include <X11/extensions/Xrender.h>
50 #ifndef RepeatNone /* added in 0.10 */
52 #define RepeatNormal 1
54 #define RepeatReflect 3
72 WXR_INVALID_FORMAT = WXR_NB_FORMATS
75 typedef struct wine_xrender_format_template
79 unsigned int alphaMask;
83 unsigned int greenMask;
85 unsigned int blueMask;
86 } WineXRenderFormatTemplate;
88 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
90 /* Format depth alpha mask red mask green mask blue mask*/
91 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
92 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
93 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
94 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
95 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
96 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
97 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
98 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
99 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
101 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
105 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
107 /* format phys red phys green phys blue log red log green log blue */
108 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
109 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
110 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
111 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
112 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
113 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
114 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
115 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
116 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
117 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
118 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
122 static enum wxr_format default_format = WXR_INVALID_FORMAT;
123 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
129 SIZE devsize; /* size in device coords */
133 #define INITIAL_REALIZED_BUF_SIZE 128
135 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
140 XRenderPictFormat *font_format;
144 } gsCacheEntryFormat;
150 gsCacheEntryFormat * format[AA_MAXVALUE];
155 struct xrender_physdev
157 struct gdi_physdev dev;
158 X11DRV_PDEVICE *x11dev;
160 enum wxr_format format;
165 XRenderPictFormat *pict_format;
168 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
170 return (struct xrender_physdev *)dev;
173 static const struct gdi_dc_funcs xrender_funcs;
175 static gsCacheEntry *glyphsetCache = NULL;
176 static DWORD glyphsetCacheSize = 0;
177 static INT lastfree = -1;
180 #define INIT_CACHE_SIZE 10
182 static int antialias = 1;
184 static void *xrender_handle;
186 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
187 MAKE_FUNCPTR(XRenderAddGlyphs)
188 MAKE_FUNCPTR(XRenderChangePicture)
189 MAKE_FUNCPTR(XRenderComposite)
190 MAKE_FUNCPTR(XRenderCompositeText16)
191 MAKE_FUNCPTR(XRenderCreateGlyphSet)
192 MAKE_FUNCPTR(XRenderCreatePicture)
193 MAKE_FUNCPTR(XRenderFillRectangle)
194 MAKE_FUNCPTR(XRenderFindFormat)
195 MAKE_FUNCPTR(XRenderFindVisualFormat)
196 MAKE_FUNCPTR(XRenderFreeGlyphSet)
197 MAKE_FUNCPTR(XRenderFreePicture)
198 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
199 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
200 MAKE_FUNCPTR(XRenderCreateLinearGradient)
202 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
203 MAKE_FUNCPTR(XRenderSetPictureTransform)
205 MAKE_FUNCPTR(XRenderQueryExtension)
207 #ifdef SONAME_LIBFONTCONFIG
208 #include <fontconfig/fontconfig.h>
209 MAKE_FUNCPTR(FcConfigSubstitute)
210 MAKE_FUNCPTR(FcDefaultSubstitute)
211 MAKE_FUNCPTR(FcFontMatch)
213 MAKE_FUNCPTR(FcPatternCreate)
214 MAKE_FUNCPTR(FcPatternDestroy)
215 MAKE_FUNCPTR(FcPatternAddInteger)
216 MAKE_FUNCPTR(FcPatternAddString)
217 MAKE_FUNCPTR(FcPatternGetBool)
218 MAKE_FUNCPTR(FcPatternGetInteger)
219 MAKE_FUNCPTR(FcPatternGetString)
220 static void *fontconfig_handle;
221 static BOOL fontconfig_installed;
226 static CRITICAL_SECTION xrender_cs;
227 static CRITICAL_SECTION_DEBUG critsect_debug =
230 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
231 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
233 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
235 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
236 ( ( (ULONG)_x4 << 24 ) | \
237 ( (ULONG)_x3 << 16 ) | \
238 ( (ULONG)_x2 << 8 ) | \
241 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
243 #define GASP_GRIDFIT 0x01
244 #define GASP_DOGRAY 0x02
246 #ifdef WORDS_BIGENDIAN
247 #define get_be_word(x) (x)
248 #define NATIVE_BYTE_ORDER MSBFirst
250 #define get_be_word(x) RtlUshortByteSwap(x)
251 #define NATIVE_BYTE_ORDER LSBFirst
254 static BOOL has_alpha( enum wxr_format format )
256 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
259 static enum wxr_format get_format_without_alpha( enum wxr_format format )
263 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
264 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
265 default: return format;
269 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
272 templ->type = PictTypeDirect;
273 templ->depth = fmt->depth;
274 templ->direct.alpha = fmt->alpha;
275 templ->direct.alphaMask = fmt->alphaMask;
276 templ->direct.red = fmt->red;
277 templ->direct.redMask = fmt->redMask;
278 templ->direct.green = fmt->green;
279 templ->direct.greenMask = fmt->greenMask;
280 templ->direct.blue = fmt->blue;
281 templ->direct.blueMask = fmt->blueMask;
284 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
289 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
291 if(fmt->depth != screen_depth)
293 if( (fmt->redMask << fmt->red) != visual->red_mask)
295 if( (fmt->greenMask << fmt->green) != visual->green_mask)
297 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
300 /* We never select a default ARGB visual */
307 static int load_xrender_formats(void)
312 for (i = 0; i < WXR_NB_FORMATS; i++)
314 XRenderPictFormat templ;
316 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
318 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
319 if (!pict_formats[i])
321 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
322 if (visual->class == DirectColor)
325 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
326 screen_depth, TrueColor, &info ))
328 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
329 if (pict_formats[i]) visual = info.visual;
333 if (pict_formats[i]) default_format = i;
337 unsigned long mask = 0;
338 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
339 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
344 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
350 /***********************************************************************
351 * X11DRV_XRender_Init
353 * Let's see if our XServer has the extension available
356 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
360 if (!client_side_with_render) return NULL;
361 if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
363 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
364 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
365 LOAD_FUNCPTR(XRenderAddGlyphs);
366 LOAD_FUNCPTR(XRenderChangePicture);
367 LOAD_FUNCPTR(XRenderComposite);
368 LOAD_FUNCPTR(XRenderCompositeText16);
369 LOAD_FUNCPTR(XRenderCreateGlyphSet);
370 LOAD_FUNCPTR(XRenderCreatePicture);
371 LOAD_FUNCPTR(XRenderFillRectangle);
372 LOAD_FUNCPTR(XRenderFindFormat);
373 LOAD_FUNCPTR(XRenderFindVisualFormat);
374 LOAD_FUNCPTR(XRenderFreeGlyphSet);
375 LOAD_FUNCPTR(XRenderFreePicture);
376 LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
377 LOAD_FUNCPTR(XRenderQueryExtension);
378 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
379 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
381 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
382 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
384 #undef LOAD_OPTIONAL_FUNCPTR
387 if (!pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) return NULL;
389 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
390 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
392 ERR_(winediag)("Wine has detected that you probably have a buggy version "
393 "of libXrender. Because of this client side font rendering "
394 "will be disabled. Please upgrade this library.\n");
398 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask)
400 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
404 #ifdef SONAME_LIBFONTCONFIG
405 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
407 #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;}
408 LOAD_FUNCPTR(FcConfigSubstitute);
409 LOAD_FUNCPTR(FcDefaultSubstitute);
410 LOAD_FUNCPTR(FcFontMatch);
411 LOAD_FUNCPTR(FcInit);
412 LOAD_FUNCPTR(FcPatternCreate);
413 LOAD_FUNCPTR(FcPatternDestroy);
414 LOAD_FUNCPTR(FcPatternAddInteger);
415 LOAD_FUNCPTR(FcPatternAddString);
416 LOAD_FUNCPTR(FcPatternGetBool);
417 LOAD_FUNCPTR(FcPatternGetInteger);
418 LOAD_FUNCPTR(FcPatternGetString);
420 fontconfig_installed = pFcInit();
422 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
427 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
428 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
430 glyphsetCacheSize = INIT_CACHE_SIZE;
432 for(i = 0; i < INIT_CACHE_SIZE; i++) {
433 glyphsetCache[i].next = i + 1;
434 glyphsetCache[i].count = -1;
436 glyphsetCache[i-1].next = -1;
438 if(screen_depth <= 8 || !client_side_antialias_with_render) antialias = 0;
440 return &xrender_funcs;
443 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
444 static void get_xrender_color( struct xrender_physdev *physdev, COLORREF src_color, XRenderColor *dst_color )
446 if (src_color & (1 << 24)) /* PALETTEINDEX */
448 HPALETTE pal = GetCurrentObject( physdev->dev.hdc, OBJ_PAL );
449 PALETTEENTRY pal_ent;
451 if (!GetPaletteEntries( pal, LOWORD(src_color), 1, &pal_ent ))
452 GetPaletteEntries( pal, 0, 1, &pal_ent );
453 dst_color->red = pal_ent.peRed * 257;
454 dst_color->green = pal_ent.peGreen * 257;
455 dst_color->blue = pal_ent.peBlue * 257;
459 if (src_color >> 16 == 0x10ff) src_color = 0; /* DIBINDEX */
461 dst_color->red = GetRValue( src_color ) * 257;
462 dst_color->green = GetGValue( src_color ) * 257;
463 dst_color->blue = GetBValue( src_color ) * 257;
466 if (physdev->format == WXR_FORMAT_MONO && !dst_color->red && !dst_color->green && !dst_color->blue)
467 dst_color->alpha = 0;
469 dst_color->alpha = 0xffff;
472 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
474 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
476 switch (info->bmiHeader.biBitCount)
479 return WXR_FORMAT_MONO;
484 if (info->bmiHeader.biCompression != BI_RGB) break;
485 return WXR_FORMAT_R8G8B8;
488 if (info->bmiHeader.biCompression == BI_BITFIELDS)
490 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
493 for (i = 0; i < WXR_NB_FORMATS; i++)
495 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
496 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
497 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
498 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
503 if (info->bmiHeader.biCompression != BI_RGB) break;
504 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
506 return WXR_INVALID_FORMAT;
509 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
510 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
512 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
513 XTransform xform = {{
514 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
515 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
516 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
519 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
523 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
525 XRenderPictureAttributes pa;
531 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
533 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
535 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
536 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
537 (XRectangle *)data->Buffer, data->rdh.nCount );
538 HeapFree( GetProcessHeap(), 0, data );
543 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
545 if (!dev->pict && dev->pict_format)
547 XRenderPictureAttributes pa;
549 pa.subwindow_mode = IncludeInferiors;
550 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
551 dev->pict_format, CPSubwindowMode, &pa );
552 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
553 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
554 dev->update_clip = (dev->region != 0);
559 HRGN rgn = CreateRectRgnIndirect( clip_rect );
560 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
561 if (dev->region) CombineRgn( rgn, rgn, dev->region, RGN_AND );
562 update_xrender_clipping( dev, rgn );
569 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
570 CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
571 update_xrender_clipping( dev, rgn );
574 else update_xrender_clipping( dev, clip_rgn );
576 else if (dev->update_clip) update_xrender_clipping( dev, dev->region );
578 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
582 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
584 if (!dev->pict_src && dev->pict_format)
586 XRenderPictureAttributes pa;
588 pa.subwindow_mode = IncludeInferiors;
589 pa.repeat = repeat ? RepeatNormal : RepeatNone;
590 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
591 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
593 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
594 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
597 return dev->pict_src;
600 static void free_xrender_picture( struct xrender_physdev *dev )
602 if (dev->pict || dev->pict_src)
604 XFlush( gdi_display );
607 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
608 pXRenderFreePicture(gdi_display, dev->pict);
613 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
614 pXRenderFreePicture(gdi_display, dev->pict_src);
620 /* return a mask picture used to force alpha to 0 */
621 static Picture get_no_alpha_mask(void)
623 static Pixmap pixmap;
626 EnterCriticalSection( &xrender_cs );
629 XRenderPictureAttributes pa;
632 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
633 pa.repeat = RepeatNormal;
634 pa.component_alpha = True;
635 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
636 CPRepeat|CPComponentAlpha, &pa );
637 col.red = col.green = col.blue = 0xffff;
639 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
641 LeaveCriticalSection( &xrender_cs );
645 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
647 if(p1->hash != p2->hash) return TRUE;
648 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
649 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
650 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
651 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
655 static void walk_cache(void)
659 EnterCriticalSection(&xrender_cs);
660 for(i=mru; i >= 0; i = glyphsetCache[i].next)
661 TRACE("item %d\n", i);
662 LeaveCriticalSection(&xrender_cs);
666 static int LookupEntry(LFANDSIZE *plfsz)
670 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
672 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
674 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
675 glyphsetCache[i].count++;
677 glyphsetCache[prev_i].next = glyphsetCache[i].next;
678 glyphsetCache[i].next = mru;
681 TRACE("found font in cache %d\n", i);
686 TRACE("font not in cache\n");
690 static void FreeEntry(int entry)
694 for(format = 0; format < AA_MAXVALUE; format++) {
695 gsCacheEntryFormat * formatEntry;
697 if( !glyphsetCache[entry].format[format] )
700 formatEntry = glyphsetCache[entry].format[format];
702 if(formatEntry->glyphset) {
703 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
704 formatEntry->glyphset = 0;
706 if(formatEntry->nrealized) {
707 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
708 formatEntry->realized = NULL;
709 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
710 formatEntry->gis = NULL;
711 formatEntry->nrealized = 0;
714 HeapFree(GetProcessHeap(), 0, formatEntry);
715 glyphsetCache[entry].format[format] = NULL;
719 static int AllocEntry(void)
721 int best = -1, prev_best = -1, i, prev_i = -1;
724 assert(glyphsetCache[lastfree].count == -1);
725 glyphsetCache[lastfree].count = 1;
727 lastfree = glyphsetCache[lastfree].next;
729 glyphsetCache[best].next = mru;
732 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
736 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
737 if(glyphsetCache[i].count == 0) {
745 TRACE("freeing unused glyphset at cache %d\n", best);
747 glyphsetCache[best].count = 1;
749 glyphsetCache[prev_best].next = glyphsetCache[best].next;
750 glyphsetCache[best].next = mru;
758 TRACE("Growing cache\n");
761 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
763 (glyphsetCacheSize + INIT_CACHE_SIZE)
764 * sizeof(*glyphsetCache));
766 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
767 (glyphsetCacheSize + INIT_CACHE_SIZE)
768 * sizeof(*glyphsetCache));
770 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
772 glyphsetCache[i].next = i + 1;
773 glyphsetCache[i].count = -1;
775 glyphsetCache[i-1].next = -1;
776 glyphsetCacheSize += INIT_CACHE_SIZE;
778 lastfree = glyphsetCache[best].next;
779 glyphsetCache[best].count = 1;
780 glyphsetCache[best].next = mru;
782 TRACE("new free cache slot at %d\n", mru);
786 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
796 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
797 if(size == GDI_ERROR)
800 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
801 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
803 GetTextMetricsW(hdc, &tm);
804 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
807 num_recs = get_be_word(*gasp);
811 *flags = get_be_word(*(gasp + 1));
812 if(ppem <= get_be_word(*gasp))
816 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
818 HeapFree(GetProcessHeap(), 0, buffer);
822 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
826 UINT font_smoothing_type, font_smoothing_orientation;
829 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
830 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
832 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
833 &font_smoothing_orientation, 0) &&
834 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
841 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
842 But, Wine's subpixel rendering can support the portrait mode.
845 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
853 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
858 static int hinter = -1;
859 static int subpixel = -1;
862 if((ret = LookupEntry(plfsz)) != -1) return ret;
865 entry = glyphsetCache + ret;
866 entry->lfsz = *plfsz;
867 for( format = 0; format < AA_MAXVALUE; format++ ) {
868 assert( !entry->format[format] );
871 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
873 if(hinter == -1 || subpixel == -1)
875 RASTERIZER_STATUS status;
876 GetRasterizerCaps(&status, sizeof(status));
877 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
878 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
881 switch (plfsz->lf.lfQuality)
883 case ANTIALIASED_QUALITY:
884 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
885 return ret; /* ignore further configuration */
886 case CLEARTYPE_QUALITY:
887 case CLEARTYPE_NATURAL_QUALITY:
888 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
890 case DEFAULT_QUALITY:
894 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
897 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
900 entry->aa_default = AA_None;
904 font_smoothing = TRUE; /* default to enabled */
905 #ifdef SONAME_LIBFONTCONFIG
906 if (fontconfig_installed)
908 FcPattern *match, *pattern;
910 char family[LF_FACESIZE * 4];
912 #if defined(__i386__) && defined(__GNUC__)
913 /* fontconfig generates floating point exceptions, mask them */
914 WORD cw, default_cw = 0x37f;
915 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
918 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
919 pattern = pFcPatternCreate();
920 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
921 if (plfsz->lf.lfWeight != FW_DONTCARE)
924 switch (plfsz->lf.lfWeight)
926 case FW_THIN: weight = FC_WEIGHT_THIN; break;
927 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
928 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
929 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
930 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
931 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
932 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
933 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
934 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
935 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
937 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
939 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
940 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
941 pFcDefaultSubstitute( pattern );
942 if ((match = pFcFontMatch( NULL, pattern, &result )))
947 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
949 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
952 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
954 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
955 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
959 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
960 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
961 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
962 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
963 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
966 if (!antialias) font_smoothing = FALSE;
967 pFcPatternDestroy( match );
969 pFcPatternDestroy( pattern );
971 #if defined(__i386__) && defined(__GNUC__)
972 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
975 #endif /* SONAME_LIBFONTCONFIG */
977 /* now check Xft resources */
980 BOOL antialias = TRUE;
982 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
984 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
985 value[0] == '0' || !strcasecmp( value, "off" ))
988 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
990 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
991 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
992 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
993 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
994 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
995 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
997 if (!antialias) font_smoothing = FALSE;
1000 if (!font_smoothing) entry->aa_default = AA_None;
1003 entry->aa_default = AA_None;
1008 static void dec_ref_cache(int index)
1011 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1012 assert(glyphsetCache[index].count > 0);
1013 glyphsetCache[index].count--;
1016 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1018 DWORD hash = 0, *ptr, two_chars;
1022 hash ^= plfsz->devsize.cx;
1023 hash ^= plfsz->devsize.cy;
1024 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1026 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1028 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1030 pwc = (WCHAR *)&two_chars;
1032 *pwc = toupperW(*pwc);
1034 *pwc = toupperW(*pwc);
1042 /**********************************************************************
1043 * xrenderdrv_SelectFont
1045 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1048 struct xrender_physdev *physdev = get_xrender_dev( dev );
1049 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1050 HFONT ret = next->funcs->pSelectFont( next, hfont );
1054 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1056 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1057 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1058 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1059 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1060 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1061 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1063 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1064 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1065 lfsz.xform.eM21, lfsz.xform.eM22);
1067 if (GetGraphicsMode( dev->hdc ) == GM_COMPATIBLE && lfsz.xform.eM11 * lfsz.xform.eM22 < 0)
1068 lfsz.lf.lfOrientation = -lfsz.lf.lfOrientation;
1070 /* Not used fields, would break hashing */
1071 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1073 lfsz_calc_hash(&lfsz);
1075 EnterCriticalSection(&xrender_cs);
1076 if (physdev->cache_index != -1)
1077 dec_ref_cache( physdev->cache_index );
1078 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1079 LeaveCriticalSection(&xrender_cs);
1083 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1085 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1086 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1088 if (!physdev) return FALSE;
1089 physdev->x11dev = x11dev;
1090 physdev->cache_index = -1;
1091 physdev->format = format;
1092 physdev->pict_format = pict_formats[format];
1093 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1097 /* store the color mask data in the bitmap info structure */
1098 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1100 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1102 info->bmiHeader.biPlanes = 1;
1103 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1104 info->bmiHeader.biCompression = BI_RGB;
1105 info->bmiHeader.biClrUsed = 0;
1107 switch (info->bmiHeader.biBitCount)
1110 colors[0] = format->direct.redMask << format->direct.red;
1111 colors[1] = format->direct.greenMask << format->direct.green;
1112 colors[2] = format->direct.blueMask << format->direct.blue;
1113 info->bmiHeader.biCompression = BI_BITFIELDS;
1116 colors[0] = format->direct.redMask << format->direct.red;
1117 colors[1] = format->direct.greenMask << format->direct.green;
1118 colors[2] = format->direct.blueMask << format->direct.blue;
1119 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1120 info->bmiHeader.biCompression = BI_BITFIELDS;
1126 /**********************************************************************
1127 * xrenderdrv_CreateDC
1129 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1130 LPCWSTR output, const DEVMODEW* initData )
1132 return create_xrender_dc( pdev, default_format );
1135 /**********************************************************************
1136 * xrenderdrv_CreateCompatibleDC
1138 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1140 if (orig) /* chain to x11drv first */
1142 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1143 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1145 /* otherwise we have been called by x11drv */
1147 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1150 /**********************************************************************
1151 * xrenderdrv_DeleteDC
1153 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1155 struct xrender_physdev *physdev = get_xrender_dev( dev );
1157 free_xrender_picture( physdev );
1159 EnterCriticalSection( &xrender_cs );
1160 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1161 LeaveCriticalSection( &xrender_cs );
1163 HeapFree( GetProcessHeap(), 0, physdev );
1167 /**********************************************************************
1168 * xrenderdrv_ExtEscape
1170 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1171 INT out_count, LPVOID out_data )
1173 struct xrender_physdev *physdev = get_xrender_dev( dev );
1175 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1177 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1179 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1181 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1182 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1186 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1189 /***********************************************************************
1190 * xrenderdrv_SetDeviceClipping
1192 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1194 struct xrender_physdev *physdev = get_xrender_dev( dev );
1196 physdev->region = rgn;
1197 physdev->update_clip = TRUE;
1199 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1200 dev->funcs->pSetDeviceClipping( dev, rgn );
1204 /************************************************************************
1207 * Helper to ExtTextOut. Must be called inside xrender_cs
1209 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1211 unsigned int buflen;
1216 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1217 gsCacheEntryFormat *formatEntry;
1218 UINT ggo_format = GGO_GLYPH_INDEX;
1219 enum wxr_format wxr_format;
1220 static const char zero[4];
1221 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1225 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1228 ggo_format |= WINE_GGO_HRGB_BITMAP;
1231 ggo_format |= WINE_GGO_HBGR_BITMAP;
1234 ggo_format |= WINE_GGO_VRGB_BITMAP;
1237 ggo_format |= WINE_GGO_VBGR_BITMAP;
1241 ERR("aa = %d - not implemented\n", format);
1243 ggo_format |= GGO_BITMAP;
1247 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1248 if(buflen == GDI_ERROR) {
1249 if(format != AA_None) {
1251 entry->aa_default = AA_None;
1252 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1253 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1255 if(buflen == GDI_ERROR) {
1256 WARN("GetGlyphOutlineW failed using default glyph\n");
1257 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1258 if(buflen == GDI_ERROR) {
1259 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1260 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1261 if(buflen == GDI_ERROR) {
1262 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1267 TRACE("Turning off antialiasing for this monochrome font\n");
1270 /* If there is nothing for the current type, we create the entry. */
1271 if( !entry->format[format] ) {
1272 entry->format[format] = HeapAlloc(GetProcessHeap(),
1274 sizeof(gsCacheEntryFormat));
1276 formatEntry = entry->format[format];
1278 if(formatEntry->nrealized <= glyph) {
1279 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1281 if (formatEntry->realized)
1282 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1284 formatEntry->realized,
1285 formatEntry->nrealized * sizeof(BOOL));
1287 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1289 formatEntry->nrealized * sizeof(BOOL));
1291 if (formatEntry->gis)
1292 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1295 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1297 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1299 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1303 if(formatEntry->glyphset == 0) {
1306 wxr_format = WXR_FORMAT_GRAY;
1313 wxr_format = WXR_FORMAT_A8R8G8B8;
1317 ERR("aa = %d - not implemented\n", format);
1319 wxr_format = WXR_FORMAT_MONO;
1323 formatEntry->font_format = pict_formats[wxr_format];
1324 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1328 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1329 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1330 formatEntry->realized[glyph] = TRUE;
1332 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1334 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1335 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1337 gi.width = gm.gmBlackBoxX;
1338 gi.height = gm.gmBlackBoxY;
1339 gi.x = -gm.gmptGlyphOrigin.x;
1340 gi.y = gm.gmptGlyphOrigin.y;
1341 gi.xOff = gm.gmCellIncX;
1342 gi.yOff = gm.gmCellIncY;
1344 if(TRACE_ON(xrender)) {
1347 unsigned char *line;
1349 if(format == AA_None) {
1350 pitch = ((gi.width + 31) / 32) * 4;
1351 for(i = 0; i < gi.height; i++) {
1352 line = (unsigned char*) buf + i * pitch;
1354 for(j = 0; j < pitch * 8; j++) {
1355 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1357 TRACE("%s\n", output);
1360 static const char blks[] = " .:;!o*#";
1364 pitch = ((gi.width + 3) / 4) * 4;
1365 for(i = 0; i < gi.height; i++) {
1366 line = (unsigned char*) buf + i * pitch;
1368 for(j = 0; j < pitch; j++) {
1369 str[0] = blks[line[j] >> 5];
1370 strcat(output, str);
1372 TRACE("%s\n", output);
1378 if(formatEntry->glyphset) {
1379 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1380 unsigned char *byte = (unsigned char*) buf, c;
1386 /* magic to flip bit order */
1387 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1388 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1389 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1394 else if ( format != AA_Grey &&
1395 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1397 unsigned int i, *data = (unsigned int *)buf;
1398 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1403 XRenderCompositeText seems to ignore 0x0 glyphs when
1404 AA_None, which means we lose the advance width of glyphs
1405 like the space. We'll pretend that such glyphs are 1x1
1410 gi.width = gi.height = 1;
1412 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1413 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1414 HeapFree(GetProcessHeap(), 0, buf);
1417 formatEntry->gis[glyph] = gi;
1420 /*************************************************************
1423 * Returns an appropriate Picture for tiling the text colour.
1424 * Call and use result within the xrender_cs
1426 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1432 XRenderColor current_color;
1433 } tiles[WXR_NB_FORMATS], *tile;
1435 tile = &tiles[wxr_format];
1439 XRenderPictureAttributes pa;
1440 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1442 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1444 pa.repeat = RepeatNormal;
1445 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1447 /* init current_color to something different from text_pixel */
1448 tile->current_color = *color;
1449 tile->current_color.red ^= 0xffff;
1451 if (wxr_format == WXR_FORMAT_MONO)
1453 /* for a 1bpp bitmap we always need a 1 in the tile */
1455 col.red = col.green = col.blue = 0;
1457 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1461 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1463 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1464 tile->current_color = *color;
1469 /*************************************************************
1472 * Returns an appropriate Picture for masking with the specified alpha.
1473 * Call and use result within the xrender_cs
1475 static Picture get_mask_pict( int alpha )
1477 static Pixmap pixmap;
1478 static Picture pict;
1479 static int current_alpha;
1481 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1485 XRenderPictureAttributes pa;
1487 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1488 pa.repeat = RepeatNormal;
1489 pict = pXRenderCreatePicture( gdi_display, pixmap,
1490 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1494 if (alpha != current_alpha)
1497 col.red = col.green = col.blue = 0;
1498 col.alpha = current_alpha = alpha;
1499 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1504 /***********************************************************************
1505 * xrenderdrv_ExtTextOut
1507 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1508 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1510 struct xrender_physdev *physdev = get_xrender_dev( dev );
1511 gsCacheEntry *entry;
1512 gsCacheEntryFormat *formatEntry;
1513 AA_Type aa_type = AA_None;
1515 Picture pict, tile_pict = 0;
1517 POINT offset, desired, current;
1518 int render_op = PictOpOver;
1522 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1523 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1525 if(flags & ETO_OPAQUE)
1529 if (physdev->format == WXR_FORMAT_MONO)
1530 /* use the inverse of the text color */
1531 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1533 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1535 set_xrender_transformation( pict, 1, 1, 0, 0 );
1536 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1537 physdev->x11dev->dc_rect.left + lprect->left,
1538 physdev->x11dev->dc_rect.top + lprect->top,
1539 lprect->right - lprect->left,
1540 lprect->bottom - lprect->top );
1541 add_device_bounds( physdev->x11dev, lprect );
1544 if(count == 0) return TRUE;
1546 EnterCriticalSection(&xrender_cs);
1548 entry = glyphsetCache + physdev->cache_index;
1549 aa_type = entry->aa_default;
1550 formatEntry = entry->format[aa_type];
1552 for(idx = 0; idx < count; idx++) {
1553 if( !formatEntry ) {
1554 UploadGlyph(physdev, wstr[idx], aa_type);
1555 /* re-evaluate antialias since aa_default may have changed */
1556 aa_type = entry->aa_default;
1557 formatEntry = entry->format[aa_type];
1558 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1559 UploadGlyph(physdev, wstr[idx], aa_type);
1564 WARN("could not upload requested glyphs\n");
1565 LeaveCriticalSection(&xrender_cs);
1569 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1570 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1572 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1574 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1575 So we pass zeros to the function and move to our starting position using the first
1576 element of the elts array. */
1578 desired.x = physdev->x11dev->dc_rect.left + x;
1579 desired.y = physdev->x11dev->dc_rect.top + y;
1580 offset.x = offset.y = 0;
1581 current.x = current.y = 0;
1583 tile_pict = get_tile_pict(physdev->format, &col);
1585 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1587 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1588 render_op = PictOpOutReverse; /* This gives us 'black' text */
1590 reset_bounds( &bounds );
1591 for(idx = 0; idx < count; idx++)
1593 elts[idx].glyphset = formatEntry->glyphset;
1594 elts[idx].chars = wstr + idx;
1595 elts[idx].nchars = 1;
1596 elts[idx].xOff = desired.x - current.x;
1597 elts[idx].yOff = desired.y - current.y;
1599 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1600 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1602 rect.left = desired.x - physdev->x11dev->dc_rect.left - formatEntry->gis[wstr[idx]].x;
1603 rect.top = desired.y - physdev->x11dev->dc_rect.top - formatEntry->gis[wstr[idx]].y;
1604 rect.right = rect.left + formatEntry->gis[wstr[idx]].width;
1605 rect.bottom = rect.top + formatEntry->gis[wstr[idx]].height;
1606 add_bounds_rect( &bounds, &rect );
1610 desired.x += formatEntry->gis[wstr[idx]].xOff;
1611 desired.y += formatEntry->gis[wstr[idx]].yOff;
1617 offset.x += lpDx[idx * 2];
1618 offset.y += lpDx[idx * 2 + 1];
1621 offset.x += lpDx[idx];
1622 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1623 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1627 /* Make sure we don't have any transforms set from a previous call */
1628 set_xrender_transformation(pict, 1, 1, 0, 0);
1629 pXRenderCompositeText16(gdi_display, render_op,
1632 formatEntry->font_format,
1633 0, 0, 0, 0, elts, count);
1634 HeapFree(GetProcessHeap(), 0, elts);
1636 LeaveCriticalSection(&xrender_cs);
1637 add_device_bounds( physdev->x11dev, &bounds );
1641 /* multiply the alpha channel of a picture */
1642 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1643 int x, int y, int width, int height )
1645 XRenderPictureAttributes pa;
1646 Pixmap src_pixmap, mask_pixmap;
1647 Picture src_pict, mask_pict;
1650 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1651 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1652 pa.repeat = RepeatNormal;
1653 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1654 pa.component_alpha = True;
1655 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1656 color.red = color.green = color.blue = color.alpha = 0xffff;
1657 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1658 color.alpha = alpha;
1659 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1660 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1661 0, 0, 0, 0, x, y, width, height );
1662 pXRenderFreePicture( gdi_display, src_pict );
1663 pXRenderFreePicture( gdi_display, mask_pict );
1664 XFreePixmap( gdi_display, src_pixmap );
1665 XFreePixmap( gdi_display, mask_pixmap );
1668 /* Helper function for (stretched) blitting using xrender */
1669 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1670 int x_src, int y_src, int width_src, int height_src,
1671 int x_dst, int y_dst, int width_dst, int height_dst,
1672 double xscale, double yscale )
1674 int x_offset, y_offset;
1678 x_src += width_src + 1;
1679 width_src = -width_src;
1683 y_src += height_src + 1;
1684 height_src = -height_src;
1688 x_dst += width_dst + 1;
1689 width_dst = -width_dst;
1693 y_dst += height_dst + 1;
1694 height_dst = -height_dst;
1697 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1698 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1699 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1700 if(xscale != 1.0 || yscale != 1.0)
1702 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1703 * in the wrong quadrant of the x-y plane.
1705 x_offset = (xscale < 0) ? -width_dst : 0;
1706 y_offset = (yscale < 0) ? -height_dst : 0;
1707 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1713 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1715 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1716 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1719 /* Helper function for (stretched) mono->color blitting using xrender */
1720 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1721 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1722 int x_src, int y_src, int width_src, int height_src,
1723 int x_dst, int y_dst, int width_dst, int height_dst,
1724 double xscale, double yscale )
1727 int x_offset, y_offset;
1732 x_src += width_src + 1;
1733 width_src = -width_src;
1737 y_src += height_src + 1;
1738 height_src = -height_src;
1742 x_dst += width_dst + 1;
1743 width_dst = -width_dst;
1747 y_dst += height_dst + 1;
1748 height_dst = -height_dst;
1751 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1752 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1755 EnterCriticalSection( &xrender_cs );
1757 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1758 tile_pict = get_tile_pict( dst_format, &color );
1760 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1762 if (xscale != 1.0 || yscale != 1.0)
1764 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1765 * in the wrong quadrant of the x-y plane.
1767 x_offset = (xscale < 0) ? -width_dst : 0;
1768 y_offset = (yscale < 0) ? -height_dst : 0;
1769 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1775 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1777 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1778 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1779 LeaveCriticalSection( &xrender_cs );
1781 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1782 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1783 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1784 x_dst, y_dst, width_dst, height_dst );
1787 /* create a pixmap and render picture for an image */
1788 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1789 struct bitblt_coords *src, enum wxr_format format,
1790 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1793 int width = src->visrect.right - src->visrect.left;
1794 int height = src->visrect.bottom - src->visrect.top;
1795 int depth = pict_formats[format]->depth;
1796 struct gdi_image_bits dst_bits;
1797 XRenderPictureAttributes pa;
1801 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1802 info->bmiHeader.biWidth, height, 32, 0 );
1803 if (!image) return ERROR_OUTOFMEMORY;
1805 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1806 if (ret) return ret;
1808 image->data = dst_bits.ptr;
1810 *use_repeat = (width == 1 && height == 1);
1811 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1813 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1814 gc = XCreateGC( gdi_display, *pixmap, 0, NULL );
1815 XPutImage( gdi_display, *pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1816 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1817 XFreeGC( gdi_display, gc );
1819 /* make coordinates relative to the pixmap */
1820 src->x -= src->visrect.left;
1821 src->y -= src->visrect.top;
1822 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1825 XDestroyImage( image );
1826 if (dst_bits.free) dst_bits.free( &dst_bits );
1830 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
1831 Drawable drawable, const struct bitblt_coords *src,
1832 const struct bitblt_coords *dst )
1835 Picture src_pict = 0, dst_pict, mask_pict = 0;
1836 double xscale = src->width / (double)dst->width;
1837 double yscale = src->height / (double)dst->height;
1839 if (drawable) /* using an intermediate pixmap */
1843 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, 0, NULL );
1847 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
1848 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
1849 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1852 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1855 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1857 XRenderColor fg, bg;
1859 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
1860 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
1861 fg.alpha = bg.alpha = 0;
1863 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
1864 physdev_src->x11dev->dc_rect.left + src->x,
1865 physdev_src->x11dev->dc_rect.top + src->y,
1866 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1868 else /* color -> color (can be at different depths) or mono -> mono */
1870 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
1871 mask_pict = get_no_alpha_mask();
1873 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
1874 physdev_src->x11dev->dc_rect.left + src->x,
1875 physdev_src->x11dev->dc_rect.top + src->y,
1876 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1879 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1883 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
1884 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
1885 Drawable drawable, struct bitblt_coords *src,
1886 struct bitblt_coords *dst, BOOL use_repeat )
1890 double xscale, yscale;
1892 if (drawable) /* using an intermediate pixmap */
1894 RGNDATA *clip_data = NULL;
1896 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1899 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, 0, NULL );
1901 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
1902 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
1903 HeapFree( GetProcessHeap(), 0, clip_data );
1907 x_dst = physdev->x11dev->dc_rect.left + dst->x;
1908 y_dst = physdev->x11dev->dc_rect.top + dst->y;
1909 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
1914 xscale = src->width / (double)dst->width;
1915 yscale = src->height / (double)dst->height;
1917 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1919 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
1920 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1922 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1926 /***********************************************************************
1927 * xrenderdrv_StretchBlt
1929 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1930 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1932 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1933 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1934 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
1936 if (src_dev->funcs != dst_dev->funcs)
1938 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
1939 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
1942 /* XRender is of no use for color -> mono */
1943 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
1944 goto x11drv_fallback;
1946 /* if not stretching, we only need to handle format conversion */
1947 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
1953 struct bitblt_coords tmp;
1955 /* make coordinates relative to tmp pixmap */
1957 tmp.x -= tmp.visrect.left;
1958 tmp.y -= tmp.visrect.top;
1959 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1961 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
1962 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1963 XSetGraphicsExposures( gdi_display, tmpGC, False );
1964 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
1965 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
1967 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
1968 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
1970 XFreePixmap( gdi_display, tmp_pixmap );
1971 XFreeGC( gdi_display, tmpGC );
1973 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
1975 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
1979 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
1983 /***********************************************************************
1984 * xrenderdrv_PutImage
1986 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1987 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1988 struct bitblt_coords *dst, DWORD rop )
1990 struct xrender_physdev *physdev = get_xrender_dev( dev );
1994 enum wxr_format src_format, dst_format;
1995 XRenderPictFormat *pict_format;
1997 Picture src_pict, mask_pict = 0;
2000 dst_format = physdev->format;
2001 src_format = get_xrender_format_from_bitmapinfo( info );
2002 if (!(pict_format = pict_formats[src_format])) goto update_format;
2004 /* make sure we can create an image with the same bpp */
2005 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2008 /* mono <-> color conversions not supported */
2009 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2010 goto x11drv_fallback;
2012 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2014 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2016 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2019 struct bitblt_coords tmp;
2023 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2025 /* make coordinates relative to tmp pixmap */
2027 tmp.x -= tmp.visrect.left;
2028 tmp.y -= tmp.visrect.top;
2029 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2031 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2032 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2033 XSetGraphicsExposures( gdi_display, gc, False );
2034 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
2035 tmp.visrect.right - tmp.visrect.left,
2036 tmp.visrect.bottom - tmp.visrect.top,
2037 physdev->pict_format->depth );
2039 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2040 NULL, tmp_pixmap, src, &tmp, use_repeat );
2041 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2043 XFreePixmap( gdi_display, tmp_pixmap );
2044 XFreeGC( gdi_display, gc );
2045 if (restore_region) restore_clipping_region( physdev->x11dev );
2047 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2048 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2050 add_device_bounds( physdev->x11dev, &dst->visrect );
2052 pXRenderFreePicture( gdi_display, src_pict );
2053 XFreePixmap( gdi_display, src_pixmap );
2058 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2059 set_color_info( pict_formats[dst_format], info );
2060 return ERROR_BAD_FORMAT;
2063 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2064 return dev->funcs->pPutImage( dev, clip, info, bits, src, dst, rop );
2068 /***********************************************************************
2069 * xrenderdrv_BlendImage
2071 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2072 struct bitblt_coords *src, struct bitblt_coords *dst,
2073 BLENDFUNCTION func )
2075 struct xrender_physdev *physdev = get_xrender_dev( dev );
2077 enum wxr_format format;
2078 XRenderPictFormat *pict_format;
2079 Picture dst_pict, src_pict, mask_pict;
2083 format = get_xrender_format_from_bitmapinfo( info );
2084 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2085 format = get_format_without_alpha( format );
2086 else if (format != WXR_FORMAT_A8R8G8B8)
2087 return ERROR_INVALID_PARAMETER;
2089 if (!(pict_format = pict_formats[format])) goto update_format;
2091 /* make sure we can create an image with the same bpp */
2092 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2095 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2098 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2100 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2103 double xscale, yscale;
2107 xscale = src->width / (double)dst->width;
2108 yscale = src->height / (double)dst->height;
2110 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2112 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2114 EnterCriticalSection( &xrender_cs );
2115 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2117 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2118 src->x, src->y, src->width, src->height,
2119 physdev->x11dev->dc_rect.left + dst->x,
2120 physdev->x11dev->dc_rect.top + dst->y,
2121 dst->width, dst->height, xscale, yscale );
2123 pXRenderFreePicture( gdi_display, src_pict );
2124 XFreePixmap( gdi_display, src_pixmap );
2126 LeaveCriticalSection( &xrender_cs );
2127 add_device_bounds( physdev->x11dev, &dst->visrect );
2132 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2133 set_color_info( physdev->pict_format, info );
2134 return ERROR_BAD_FORMAT;
2138 /***********************************************************************
2139 * xrenderdrv_AlphaBlend
2141 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2142 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2144 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2145 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2146 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2147 XRenderPictureAttributes pa;
2148 Pixmap tmp_pixmap = 0;
2149 double xscale, yscale;
2151 if (src_dev->funcs != dst_dev->funcs)
2153 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2154 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2157 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2159 SetLastError( ERROR_INVALID_PARAMETER );
2163 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2165 xscale = src->width / (double)dst->width;
2166 yscale = src->height / (double)dst->height;
2168 src_pict = get_xrender_picture_source( physdev_src, FALSE );
2170 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2172 /* mono -> color blending needs an intermediate color pixmap */
2173 XRenderColor fg, bg;
2174 int width = src->visrect.right - src->visrect.left;
2175 int height = src->visrect.bottom - src->visrect.top;
2177 /* blending doesn't use the destination DC colors */
2178 fg.red = fg.green = fg.blue = 0;
2179 bg.red = bg.green = bg.blue = 0xffff;
2180 fg.alpha = bg.alpha = 0xffff;
2182 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2183 physdev_dst->pict_format->depth );
2184 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format, 0, NULL );
2186 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2187 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
2189 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2191 /* we need a source picture with no alpha */
2192 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2193 if (format != physdev_src->format)
2195 pa.subwindow_mode = IncludeInferiors;
2196 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2197 pict_formats[format], CPSubwindowMode, &pa );
2201 if (tmp_pict) src_pict = tmp_pict;
2203 EnterCriticalSection( &xrender_cs );
2204 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2206 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2207 physdev_src->x11dev->dc_rect.left + src->x,
2208 physdev_src->x11dev->dc_rect.top + src->y,
2209 src->width, src->height,
2210 physdev_dst->x11dev->dc_rect.left + dst->x,
2211 physdev_dst->x11dev->dc_rect.top + dst->y,
2212 dst->width, dst->height, xscale, yscale );
2214 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2215 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2217 LeaveCriticalSection( &xrender_cs );
2218 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2222 /***********************************************************************
2223 * xrenderdrv_GradientFill
2225 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2226 void * grad_array, ULONG ngrad, ULONG mode )
2228 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2229 static const XFixed stops[2] = { 0, 1 << 16 };
2230 struct xrender_physdev *physdev = get_xrender_dev( dev );
2231 XLinearGradient gradient;
2232 XRenderColor colors[2];
2233 Picture src_pict, dst_pict;
2235 const GRADIENT_RECT *rect = grad_array;
2239 if (!pXRenderCreateLinearGradient) goto fallback;
2241 /* <= 16-bpp uses dithering */
2242 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2246 case GRADIENT_FILL_RECT_H:
2247 case GRADIENT_FILL_RECT_V:
2248 for (i = 0; i < ngrad; i++, rect++)
2250 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2251 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2253 colors[0].red = v1->Red * 257 / 256;
2254 colors[0].green = v1->Green * 257 / 256;
2255 colors[0].blue = v1->Blue * 257 / 256;
2256 colors[1].red = v2->Red * 257 / 256;
2257 colors[1].green = v2->Green * 257 / 256;
2258 colors[1].blue = v2->Blue * 257 / 256;
2259 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2260 colors[0].alpha = colors[1].alpha = 65535;
2266 LPtoDP( dev->hdc, pt, 2 );
2267 if (mode == GRADIENT_FILL_RECT_H)
2269 gradient.p1.y = gradient.p2.y = 0;
2270 if (pt[1].x > pt[0].x)
2273 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2277 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2283 gradient.p1.x = gradient.p2.x = 0;
2284 if (pt[1].y > pt[0].y)
2287 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2291 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2296 rc.left = min( pt[0].x, pt[1].x );
2297 rc.top = min( pt[0].y, pt[1].y );
2298 rc.right = max( pt[0].x, pt[1].x );
2299 rc.bottom = max( pt[0].y, pt[1].y );
2301 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2302 mode, wine_dbgstr_rect( &rc ),
2303 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2304 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2306 dst_pict = get_xrender_picture( physdev, 0, NULL );
2308 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2309 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2310 0, 0, rc.right - rc.left, rc.bottom - rc.top,
2311 physdev->x11dev->dc_rect.left + rc.left,
2312 physdev->x11dev->dc_rect.top + rc.top,
2313 rc.right - rc.left, rc.bottom - rc.top, 1, 1 );
2314 pXRenderFreePicture( gdi_display, src_pict );
2315 add_device_bounds( physdev->x11dev, &rc );
2322 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2323 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2326 /***********************************************************************
2327 * xrenderdrv_SelectBrush
2329 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2331 struct xrender_physdev *physdev = get_xrender_dev( dev );
2334 XRenderPictFormat *format = physdev->pict_format;
2336 if (!pattern) goto x11drv_fallback;
2337 if (pattern->info->bmiHeader.biBitCount == 1) goto x11drv_fallback;
2338 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2340 memset( &vis, 0, sizeof(vis) );
2341 vis.depth = format->depth;
2342 vis.red_mask = format->direct.redMask << format->direct.red;
2343 vis.green_mask = format->direct.greenMask << format->direct.green;
2344 vis.blue_mask = format->direct.blueMask << format->direct.blue;
2346 pixmap = create_pixmap_from_image( physdev->dev.hdc, &vis, pattern->info,
2347 &pattern->bits, pattern->usage );
2348 if (!pixmap) return 0;
2350 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2351 physdev->x11dev->brush.pixmap = pixmap;
2352 physdev->x11dev->brush.fillStyle = FillTiled;
2353 physdev->x11dev->brush.pixel = 0; /* ignored */
2354 physdev->x11dev->brush.style = BS_PATTERN;
2358 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2359 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2363 static const struct gdi_dc_funcs xrender_funcs =
2365 NULL, /* pAbortDoc */
2366 NULL, /* pAbortPath */
2367 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2368 NULL, /* pAngleArc */
2371 NULL, /* pBeginPath */
2372 xrenderdrv_BlendImage, /* pBlendImage */
2374 NULL, /* pCloseFigure */
2375 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2376 xrenderdrv_CreateDC, /* pCreateDC */
2377 xrenderdrv_DeleteDC, /* pDeleteDC */
2378 NULL, /* pDeleteObject */
2379 NULL, /* pDeviceCapabilities */
2380 NULL, /* pEllipse */
2382 NULL, /* pEndPage */
2383 NULL, /* pEndPath */
2384 NULL, /* pEnumFonts */
2385 NULL, /* pEnumICMProfiles */
2386 NULL, /* pExcludeClipRect */
2387 NULL, /* pExtDeviceMode */
2388 xrenderdrv_ExtEscape, /* pExtEscape */
2389 NULL, /* pExtFloodFill */
2390 NULL, /* pExtSelectClipRgn */
2391 xrenderdrv_ExtTextOut, /* pExtTextOut */
2392 NULL, /* pFillPath */
2393 NULL, /* pFillRgn */
2394 NULL, /* pFlattenPath */
2395 NULL, /* pFontIsLinked */
2396 NULL, /* pFrameRgn */
2397 NULL, /* pGdiComment */
2398 NULL, /* pGdiRealizationInfo */
2399 NULL, /* pGetBoundsRect */
2400 NULL, /* pGetCharABCWidths */
2401 NULL, /* pGetCharABCWidthsI */
2402 NULL, /* pGetCharWidth */
2403 NULL, /* pGetDeviceCaps */
2404 NULL, /* pGetDeviceGammaRamp */
2405 NULL, /* pGetFontData */
2406 NULL, /* pGetFontUnicodeRanges */
2407 NULL, /* pGetGlyphIndices */
2408 NULL, /* pGetGlyphOutline */
2409 NULL, /* pGetICMProfile */
2410 NULL, /* pGetImage */
2411 NULL, /* pGetKerningPairs */
2412 NULL, /* pGetNearestColor */
2413 NULL, /* pGetOutlineTextMetrics */
2414 NULL, /* pGetPixel */
2415 NULL, /* pGetSystemPaletteEntries */
2416 NULL, /* pGetTextCharsetInfo */
2417 NULL, /* pGetTextExtentExPoint */
2418 NULL, /* pGetTextExtentExPointI */
2419 NULL, /* pGetTextFace */
2420 NULL, /* pGetTextMetrics */
2421 xrenderdrv_GradientFill, /* pGradientFill */
2422 NULL, /* pIntersectClipRect */
2423 NULL, /* pInvertRgn */
2425 NULL, /* pModifyWorldTransform */
2427 NULL, /* pOffsetClipRgn */
2428 NULL, /* pOffsetViewportOrg */
2429 NULL, /* pOffsetWindowOrg */
2430 NULL, /* pPaintRgn */
2433 NULL, /* pPolyBezier */
2434 NULL, /* pPolyBezierTo */
2435 NULL, /* pPolyDraw */
2436 NULL, /* pPolyPolygon */
2437 NULL, /* pPolyPolyline */
2438 NULL, /* pPolygon */
2439 NULL, /* pPolyline */
2440 NULL, /* pPolylineTo */
2441 xrenderdrv_PutImage, /* pPutImage */
2442 NULL, /* pRealizeDefaultPalette */
2443 NULL, /* pRealizePalette */
2444 NULL, /* pRectangle */
2445 NULL, /* pResetDC */
2446 NULL, /* pRestoreDC */
2447 NULL, /* pRoundRect */
2449 NULL, /* pScaleViewportExt */
2450 NULL, /* pScaleWindowExt */
2451 NULL, /* pSelectBitmap */
2452 xrenderdrv_SelectBrush, /* pSelectBrush */
2453 NULL, /* pSelectClipPath */
2454 xrenderdrv_SelectFont, /* pSelectFont */
2455 NULL, /* pSelectPalette */
2456 NULL, /* pSelectPen */
2457 NULL, /* pSetArcDirection */
2458 NULL, /* pSetBkColor */
2459 NULL, /* pSetBkMode */
2460 NULL, /* pSetBoundsRect */
2461 NULL, /* pSetDCBrushColor */
2462 NULL, /* pSetDCPenColor */
2463 NULL, /* pSetDIBitsToDevice */
2464 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2465 NULL, /* pSetDeviceGammaRamp */
2466 NULL, /* pSetLayout */
2467 NULL, /* pSetMapMode */
2468 NULL, /* pSetMapperFlags */
2469 NULL, /* pSetPixel */
2470 NULL, /* pSetPolyFillMode */
2471 NULL, /* pSetROP2 */
2472 NULL, /* pSetRelAbs */
2473 NULL, /* pSetStretchBltMode */
2474 NULL, /* pSetTextAlign */
2475 NULL, /* pSetTextCharacterExtra */
2476 NULL, /* pSetTextColor */
2477 NULL, /* pSetTextJustification */
2478 NULL, /* pSetViewportExt */
2479 NULL, /* pSetViewportOrg */
2480 NULL, /* pSetWindowExt */
2481 NULL, /* pSetWindowOrg */
2482 NULL, /* pSetWorldTransform */
2483 NULL, /* pStartDoc */
2484 NULL, /* pStartPage */
2485 xrenderdrv_StretchBlt, /* pStretchBlt */
2486 NULL, /* pStretchDIBits */
2487 NULL, /* pStrokeAndFillPath */
2488 NULL, /* pStrokePath */
2489 NULL, /* pUnrealizePalette */
2490 NULL, /* pWidenPath */
2491 NULL, /* wine_get_wgl_driver */
2492 GDI_PRIORITY_GRAPHICS_DRV + 10 /* priority */
2495 #else /* SONAME_LIBXRENDER */
2497 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2499 TRACE("XRender support not compiled in.\n");
2503 #endif /* SONAME_LIBXRENDER */