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 * X11DRV_XRender_Finalize
1045 void X11DRV_XRender_Finalize(void)
1049 EnterCriticalSection(&xrender_cs
);
1050 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
1052 LeaveCriticalSection(&xrender_cs
);
1053 DeleteCriticalSection(&xrender_cs
);
1056 /**********************************************************************
1057 * xrenderdrv_SelectFont
1059 static HFONT
xrenderdrv_SelectFont( PHYSDEV dev
, HFONT hfont
)
1062 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1063 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
1064 HFONT ret
= next
->funcs
->pSelectFont( next
, hfont
);
1068 GetObjectW( hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
1070 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1071 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
1072 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
1073 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
1074 lfsz
.devsize
.cx
= X11DRV_XWStoDS( dev
->hdc
, lfsz
.lf
.lfWidth
);
1075 lfsz
.devsize
.cy
= X11DRV_YWStoDS( dev
->hdc
, lfsz
.lf
.lfHeight
);
1077 GetTransform( dev
->hdc
, 0x204, &lfsz
.xform
);
1078 TRACE("font transform %f %f %f %f\n", lfsz
.xform
.eM11
, lfsz
.xform
.eM12
,
1079 lfsz
.xform
.eM21
, lfsz
.xform
.eM22
);
1081 if (GetGraphicsMode( dev
->hdc
) == GM_COMPATIBLE
&& lfsz
.xform
.eM11
* lfsz
.xform
.eM22
< 0)
1082 lfsz
.lf
.lfOrientation
= -lfsz
.lf
.lfOrientation
;
1084 /* Not used fields, would break hashing */
1085 lfsz
.xform
.eDx
= lfsz
.xform
.eDy
= 0;
1087 lfsz_calc_hash(&lfsz
);
1089 EnterCriticalSection(&xrender_cs
);
1090 if (physdev
->cache_index
!= -1)
1091 dec_ref_cache( physdev
->cache_index
);
1092 physdev
->cache_index
= GetCacheEntry( dev
->hdc
, &lfsz
);
1093 LeaveCriticalSection(&xrender_cs
);
1097 static BOOL
create_xrender_dc( PHYSDEV
*pdev
, enum wxr_format format
)
1099 X11DRV_PDEVICE
*x11dev
= get_x11drv_dev( *pdev
);
1100 struct xrender_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
1102 if (!physdev
) return FALSE
;
1103 physdev
->x11dev
= x11dev
;
1104 physdev
->cache_index
= -1;
1105 physdev
->format
= format
;
1106 physdev
->pict_format
= pict_formats
[format
];
1107 push_dc_driver( pdev
, &physdev
->dev
, &xrender_funcs
);
1111 /* store the color mask data in the bitmap info structure */
1112 static void set_color_info( XRenderPictFormat
*format
, BITMAPINFO
*info
)
1114 DWORD
*colors
= (DWORD
*)((char *)info
+ info
->bmiHeader
.biSize
);
1116 info
->bmiHeader
.biPlanes
= 1;
1117 info
->bmiHeader
.biBitCount
= pixmap_formats
[format
->depth
]->bits_per_pixel
;
1118 info
->bmiHeader
.biCompression
= BI_RGB
;
1119 info
->bmiHeader
.biClrUsed
= 0;
1121 switch (info
->bmiHeader
.biBitCount
)
1124 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
1125 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
1126 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
1127 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1130 colors
[0] = format
->direct
.redMask
<< format
->direct
.red
;
1131 colors
[1] = format
->direct
.greenMask
<< format
->direct
.green
;
1132 colors
[2] = format
->direct
.blueMask
<< format
->direct
.blue
;
1133 if (colors
[0] != 0xff0000 || colors
[1] != 0x00ff00 || colors
[2] != 0x0000ff)
1134 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1140 /**********************************************************************
1141 * xrenderdrv_CreateDC
1143 static BOOL
xrenderdrv_CreateDC( PHYSDEV
*pdev
, LPCWSTR driver
, LPCWSTR device
,
1144 LPCWSTR output
, const DEVMODEW
* initData
)
1146 return create_xrender_dc( pdev
, default_format
);
1149 /**********************************************************************
1150 * xrenderdrv_CreateCompatibleDC
1152 static BOOL
xrenderdrv_CreateCompatibleDC( PHYSDEV orig
, PHYSDEV
*pdev
)
1154 if (orig
) /* chain to x11drv first */
1156 orig
= GET_NEXT_PHYSDEV( orig
, pCreateCompatibleDC
);
1157 if (!orig
->funcs
->pCreateCompatibleDC( orig
, pdev
)) return FALSE
;
1159 /* otherwise we have been called by x11drv */
1161 return create_xrender_dc( pdev
, WXR_FORMAT_MONO
);
1164 /**********************************************************************
1165 * xrenderdrv_DeleteDC
1167 static BOOL
xrenderdrv_DeleteDC( PHYSDEV dev
)
1169 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1171 free_xrender_picture( physdev
);
1173 EnterCriticalSection( &xrender_cs
);
1174 if (physdev
->cache_index
!= -1) dec_ref_cache( physdev
->cache_index
);
1175 LeaveCriticalSection( &xrender_cs
);
1177 HeapFree( GetProcessHeap(), 0, physdev
);
1181 /**********************************************************************
1182 * xrenderdrv_ExtEscape
1184 static INT
xrenderdrv_ExtEscape( PHYSDEV dev
, INT escape
, INT in_count
, LPCVOID in_data
,
1185 INT out_count
, LPVOID out_data
)
1187 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1189 dev
= GET_NEXT_PHYSDEV( dev
, pExtEscape
);
1191 if (escape
== X11DRV_ESCAPE
&& in_data
&& in_count
>= sizeof(enum x11drv_escape_codes
))
1193 if (*(const enum x11drv_escape_codes
*)in_data
== X11DRV_SET_DRAWABLE
)
1195 BOOL ret
= dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
1196 if (ret
) free_xrender_picture( physdev
); /* pict format doesn't change, only drawable */
1200 return dev
->funcs
->pExtEscape( dev
, escape
, in_count
, in_data
, out_count
, out_data
);
1203 /***********************************************************************
1204 * xrenderdrv_SetDeviceClipping
1206 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev
, HRGN rgn
)
1208 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1210 physdev
->region
= rgn
;
1211 physdev
->update_clip
= TRUE
;
1213 dev
= GET_NEXT_PHYSDEV( dev
, pSetDeviceClipping
);
1214 dev
->funcs
->pSetDeviceClipping( dev
, rgn
);
1218 /************************************************************************
1221 * Helper to ExtTextOut. Must be called inside xrender_cs
1223 static void UploadGlyph(struct xrender_physdev
*physDev
, int glyph
, AA_Type format
)
1225 unsigned int buflen
;
1230 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->cache_index
;
1231 gsCacheEntryFormat
*formatEntry
;
1232 UINT ggo_format
= GGO_GLYPH_INDEX
;
1233 enum wxr_format wxr_format
;
1234 static const char zero
[4];
1235 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
1239 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
1242 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
1245 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
1248 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
1251 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
1255 ERR("aa = %d - not implemented\n", format
);
1257 ggo_format
|= GGO_BITMAP
;
1261 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1262 if(buflen
== GDI_ERROR
) {
1263 if(format
!= AA_None
) {
1265 entry
->aa_default
= AA_None
;
1266 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
1267 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
1269 if(buflen
== GDI_ERROR
) {
1270 WARN("GetGlyphOutlineW failed using default glyph\n");
1271 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0, ggo_format
, &gm
, 0, NULL
, &identity
);
1272 if(buflen
== GDI_ERROR
) {
1273 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1274 buflen
= GetGlyphOutlineW(physDev
->dev
.hdc
, 0x20, ggo_format
, &gm
, 0, NULL
, &identity
);
1275 if(buflen
== GDI_ERROR
) {
1276 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1281 TRACE("Turning off antialiasing for this monochrome font\n");
1284 /* If there is nothing for the current type, we create the entry. */
1285 if( !entry
->format
[format
] ) {
1286 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
1288 sizeof(gsCacheEntryFormat
));
1290 formatEntry
= entry
->format
[format
];
1292 if(formatEntry
->nrealized
<= glyph
) {
1293 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
1295 if (formatEntry
->realized
)
1296 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
1298 formatEntry
->realized
,
1299 formatEntry
->nrealized
* sizeof(BOOL
));
1301 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
1303 formatEntry
->nrealized
* sizeof(BOOL
));
1305 if (formatEntry
->gis
)
1306 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
1309 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1311 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
1313 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
1317 if(formatEntry
->glyphset
== 0) {
1320 wxr_format
= WXR_FORMAT_GRAY
;
1327 wxr_format
= WXR_FORMAT_A8R8G8B8
;
1331 ERR("aa = %d - not implemented\n", format
);
1333 wxr_format
= WXR_FORMAT_MONO
;
1337 formatEntry
->font_format
= pict_formats
[wxr_format
];
1338 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
1342 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
1343 GetGlyphOutlineW(physDev
->dev
.hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
1344 formatEntry
->realized
[glyph
] = TRUE
;
1346 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1348 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
1349 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1351 gi
.width
= gm
.gmBlackBoxX
;
1352 gi
.height
= gm
.gmBlackBoxY
;
1353 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
1354 gi
.y
= gm
.gmptGlyphOrigin
.y
;
1355 gi
.xOff
= gm
.gmCellIncX
;
1356 gi
.yOff
= gm
.gmCellIncY
;
1358 if(TRACE_ON(xrender
)) {
1361 unsigned char *line
;
1363 if(format
== AA_None
) {
1364 pitch
= ((gi
.width
+ 31) / 32) * 4;
1365 for(i
= 0; i
< gi
.height
; i
++) {
1366 line
= (unsigned char*) buf
+ i
* pitch
;
1368 for(j
= 0; j
< pitch
* 8; j
++) {
1369 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
1371 TRACE("%s\n", output
);
1374 static const char blks
[] = " .:;!o*#";
1378 pitch
= ((gi
.width
+ 3) / 4) * 4;
1379 for(i
= 0; i
< gi
.height
; i
++) {
1380 line
= (unsigned char*) buf
+ i
* pitch
;
1382 for(j
= 0; j
< pitch
; j
++) {
1383 str
[0] = blks
[line
[j
] >> 5];
1384 strcat(output
, str
);
1386 TRACE("%s\n", output
);
1392 if(formatEntry
->glyphset
) {
1393 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
1394 unsigned char *byte
= (unsigned char*) buf
, c
;
1400 /* magic to flip bit order */
1401 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
1402 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
1403 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
1408 else if ( format
!= AA_Grey
&&
1409 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
1411 unsigned int i
, *data
= (unsigned int *)buf
;
1412 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
1417 XRenderCompositeText seems to ignore 0x0 glyphs when
1418 AA_None, which means we lose the advance width of glyphs
1419 like the space. We'll pretend that such glyphs are 1x1
1424 gi
.width
= gi
.height
= 1;
1426 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
1427 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
1428 HeapFree(GetProcessHeap(), 0, buf
);
1431 formatEntry
->gis
[glyph
] = gi
;
1434 /*************************************************************
1437 * Returns an appropriate Picture for tiling the text colour.
1438 * Call and use result within the xrender_cs
1440 static Picture
get_tile_pict( enum wxr_format wxr_format
, const XRenderColor
*color
)
1446 XRenderColor current_color
;
1447 } tiles
[WXR_NB_FORMATS
], *tile
;
1449 tile
= &tiles
[wxr_format
];
1453 XRenderPictureAttributes pa
;
1454 XRenderPictFormat
*pict_format
= pict_formats
[wxr_format
];
1456 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_format
->depth
);
1458 pa
.repeat
= RepeatNormal
;
1459 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_format
, CPRepeat
, &pa
);
1461 /* init current_color to something different from text_pixel */
1462 tile
->current_color
= *color
;
1463 tile
->current_color
.red
^= 0xffff;
1465 if (wxr_format
== WXR_FORMAT_MONO
)
1467 /* for a 1bpp bitmap we always need a 1 in the tile */
1469 col
.red
= col
.green
= col
.blue
= 0;
1471 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1475 if (memcmp( color
, &tile
->current_color
, sizeof(*color
) ) && wxr_format
!= WXR_FORMAT_MONO
)
1477 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, color
, 0, 0, 1, 1);
1478 tile
->current_color
= *color
;
1483 /*************************************************************
1486 * Returns an appropriate Picture for masking with the specified alpha.
1487 * Call and use result within the xrender_cs
1489 static Picture
get_mask_pict( int alpha
)
1491 static Pixmap pixmap
;
1492 static Picture pict
;
1493 static int current_alpha
;
1495 if (alpha
== 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1499 XRenderPictureAttributes pa
;
1501 pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, 32 );
1502 pa
.repeat
= RepeatNormal
;
1503 pict
= pXRenderCreatePicture( gdi_display
, pixmap
,
1504 pict_formats
[WXR_FORMAT_A8R8G8B8
], CPRepeat
, &pa
);
1508 if (alpha
!= current_alpha
)
1511 col
.red
= col
.green
= col
.blue
= 0;
1512 col
.alpha
= current_alpha
= alpha
;
1513 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &col
, 0, 0, 1, 1 );
1518 /***********************************************************************
1519 * xrenderdrv_ExtTextOut
1521 static BOOL
xrenderdrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
,
1522 const RECT
*lprect
, LPCWSTR wstr
, UINT count
, const INT
*lpDx
)
1524 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
1525 gsCacheEntry
*entry
;
1526 gsCacheEntryFormat
*formatEntry
;
1527 AA_Type aa_type
= AA_None
;
1529 Picture pict
, tile_pict
= 0;
1531 POINT offset
, desired
, current
;
1532 int render_op
= PictOpOver
;
1536 get_xrender_color( physdev
, GetTextColor( physdev
->dev
.hdc
), &col
);
1537 pict
= get_xrender_picture( physdev
, 0, (flags
& ETO_CLIPPED
) ? lprect
: NULL
);
1539 if(flags
& ETO_OPAQUE
)
1543 if (physdev
->format
== WXR_FORMAT_MONO
)
1544 /* use the inverse of the text color */
1545 bg
.red
= bg
.green
= bg
.blue
= bg
.alpha
= ~col
.alpha
;
1547 get_xrender_color( physdev
, GetBkColor( physdev
->dev
.hdc
), &bg
);
1549 set_xrender_transformation( pict
, 1, 1, 0, 0 );
1550 pXRenderFillRectangle( gdi_display
, PictOpSrc
, pict
, &bg
,
1551 physdev
->x11dev
->dc_rect
.left
+ lprect
->left
,
1552 physdev
->x11dev
->dc_rect
.top
+ lprect
->top
,
1553 lprect
->right
- lprect
->left
,
1554 lprect
->bottom
- lprect
->top
);
1555 add_device_bounds( physdev
->x11dev
, lprect
);
1558 if(count
== 0) return TRUE
;
1560 EnterCriticalSection(&xrender_cs
);
1562 entry
= glyphsetCache
+ physdev
->cache_index
;
1563 aa_type
= entry
->aa_default
;
1564 formatEntry
= entry
->format
[aa_type
];
1566 for(idx
= 0; idx
< count
; idx
++) {
1567 if( !formatEntry
) {
1568 UploadGlyph(physdev
, wstr
[idx
], aa_type
);
1569 /* re-evaluate antialias since aa_default may have changed */
1570 aa_type
= entry
->aa_default
;
1571 formatEntry
= entry
->format
[aa_type
];
1572 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1573 UploadGlyph(physdev
, wstr
[idx
], aa_type
);
1578 WARN("could not upload requested glyphs\n");
1579 LeaveCriticalSection(&xrender_cs
);
1583 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1584 physdev
->x11dev
->dc_rect
.left
+ x
, physdev
->x11dev
->dc_rect
.top
+ y
);
1586 elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1588 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1589 So we pass zeros to the function and move to our starting position using the first
1590 element of the elts array. */
1592 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
;
1593 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
;
1594 offset
.x
= offset
.y
= 0;
1595 current
.x
= current
.y
= 0;
1597 tile_pict
= get_tile_pict(physdev
->format
, &col
);
1599 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1601 if (physdev
->format
== WXR_FORMAT_MONO
&& col
.red
== 0 && col
.green
== 0 && col
.blue
== 0)
1602 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1604 reset_bounds( &bounds
);
1605 for(idx
= 0; idx
< count
; idx
++)
1607 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1608 elts
[idx
].chars
= wstr
+ idx
;
1609 elts
[idx
].nchars
= 1;
1610 elts
[idx
].xOff
= desired
.x
- current
.x
;
1611 elts
[idx
].yOff
= desired
.y
- current
.y
;
1613 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1614 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1616 rect
.left
= desired
.x
- physdev
->x11dev
->dc_rect
.left
- formatEntry
->gis
[wstr
[idx
]].x
;
1617 rect
.top
= desired
.y
- physdev
->x11dev
->dc_rect
.top
- formatEntry
->gis
[wstr
[idx
]].y
;
1618 rect
.right
= rect
.left
+ formatEntry
->gis
[wstr
[idx
]].width
;
1619 rect
.bottom
= rect
.top
+ formatEntry
->gis
[wstr
[idx
]].height
;
1620 add_bounds_rect( &bounds
, &rect
);
1624 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1625 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1631 offset
.x
+= lpDx
[idx
* 2];
1632 offset
.y
+= lpDx
[idx
* 2 + 1];
1635 offset
.x
+= lpDx
[idx
];
1636 desired
.x
= physdev
->x11dev
->dc_rect
.left
+ x
+ offset
.x
;
1637 desired
.y
= physdev
->x11dev
->dc_rect
.top
+ y
+ offset
.y
;
1641 /* Make sure we don't have any transforms set from a previous call */
1642 set_xrender_transformation(pict
, 1, 1, 0, 0);
1643 pXRenderCompositeText16(gdi_display
, render_op
,
1646 formatEntry
->font_format
,
1647 0, 0, 0, 0, elts
, count
);
1648 HeapFree(GetProcessHeap(), 0, elts
);
1650 LeaveCriticalSection(&xrender_cs
);
1651 add_device_bounds( physdev
->x11dev
, &bounds
);
1655 /* multiply the alpha channel of a picture */
1656 static void multiply_alpha( Picture pict
, XRenderPictFormat
*format
, int alpha
,
1657 int x
, int y
, int width
, int height
)
1659 XRenderPictureAttributes pa
;
1660 Pixmap src_pixmap
, mask_pixmap
;
1661 Picture src_pict
, mask_pict
;
1664 src_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1665 mask_pixmap
= XCreatePixmap( gdi_display
, root_window
, 1, 1, format
->depth
);
1666 pa
.repeat
= RepeatNormal
;
1667 src_pict
= pXRenderCreatePicture( gdi_display
, src_pixmap
, format
, CPRepeat
, &pa
);
1668 pa
.component_alpha
= True
;
1669 mask_pict
= pXRenderCreatePicture( gdi_display
, mask_pixmap
, format
, CPRepeat
|CPComponentAlpha
, &pa
);
1670 color
.red
= color
.green
= color
.blue
= color
.alpha
= 0xffff;
1671 pXRenderFillRectangle( gdi_display
, PictOpSrc
, src_pict
, &color
, 0, 0, 1, 1 );
1672 color
.alpha
= alpha
;
1673 pXRenderFillRectangle( gdi_display
, PictOpSrc
, mask_pict
, &color
, 0, 0, 1, 1 );
1674 pXRenderComposite( gdi_display
, PictOpInReverse
, src_pict
, mask_pict
, pict
,
1675 0, 0, 0, 0, x
, y
, width
, height
);
1676 pXRenderFreePicture( gdi_display
, src_pict
);
1677 pXRenderFreePicture( gdi_display
, mask_pict
);
1678 XFreePixmap( gdi_display
, src_pixmap
);
1679 XFreePixmap( gdi_display
, mask_pixmap
);
1682 /* Helper function for (stretched) blitting using xrender */
1683 static void xrender_blit( int op
, Picture src_pict
, Picture mask_pict
, Picture dst_pict
,
1684 int x_src
, int y_src
, int width_src
, int height_src
,
1685 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1686 double xscale
, double yscale
)
1688 int x_offset
, y_offset
;
1692 x_src
+= width_src
+ 1;
1693 width_src
= -width_src
;
1697 y_src
+= height_src
+ 1;
1698 height_src
= -height_src
;
1702 x_dst
+= width_dst
+ 1;
1703 width_dst
= -width_dst
;
1707 y_dst
+= height_dst
+ 1;
1708 height_dst
= -height_dst
;
1711 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1712 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1713 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1714 if(xscale
!= 1.0 || yscale
!= 1.0)
1716 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1717 * in the wrong quadrant of the x-y plane.
1719 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1720 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1721 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1727 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1729 pXRenderComposite( gdi_display
, op
, src_pict
, mask_pict
, dst_pict
,
1730 x_offset
, y_offset
, 0, 0, x_dst
, y_dst
, width_dst
, height_dst
);
1733 /* Helper function for (stretched) mono->color blitting using xrender */
1734 static void xrender_mono_blit( Picture src_pict
, Picture dst_pict
,
1735 enum wxr_format dst_format
, XRenderColor
*fg
, XRenderColor
*bg
,
1736 int x_src
, int y_src
, int width_src
, int height_src
,
1737 int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1738 double xscale
, double yscale
)
1741 int x_offset
, y_offset
;
1746 x_src
+= width_src
+ 1;
1747 width_src
= -width_src
;
1751 y_src
+= height_src
+ 1;
1752 height_src
= -height_src
;
1756 x_dst
+= width_dst
+ 1;
1757 width_dst
= -width_dst
;
1761 y_dst
+= height_dst
+ 1;
1762 height_dst
= -height_dst
;
1765 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1766 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1769 EnterCriticalSection( &xrender_cs
);
1771 color
.alpha
= 0xffff; /* tile pict needs 100% alpha */
1772 tile_pict
= get_tile_pict( dst_format
, &color
);
1774 pXRenderFillRectangle( gdi_display
, PictOpSrc
, dst_pict
, fg
, x_dst
, y_dst
, width_dst
, height_dst
);
1776 if (xscale
!= 1.0 || yscale
!= 1.0)
1778 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1779 * in the wrong quadrant of the x-y plane.
1781 x_offset
= (xscale
< 0) ? -width_dst
: 0;
1782 y_offset
= (yscale
< 0) ? -height_dst
: 0;
1783 set_xrender_transformation(src_pict
, xscale
, yscale
, x_src
, y_src
);
1789 set_xrender_transformation(src_pict
, 1, 1, 0, 0);
1791 pXRenderComposite(gdi_display
, PictOpOver
, tile_pict
, src_pict
, dst_pict
,
1792 0, 0, x_offset
, y_offset
, x_dst
, y_dst
, width_dst
, height_dst
);
1793 LeaveCriticalSection( &xrender_cs
);
1795 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1796 if (bg
->alpha
!= 0xffff && (dst_format
== WXR_FORMAT_A8R8G8B8
|| dst_format
== WXR_FORMAT_B8G8R8A8
))
1797 multiply_alpha( dst_pict
, pict_formats
[dst_format
], bg
->alpha
,
1798 x_dst
, y_dst
, width_dst
, height_dst
);
1801 /* create a pixmap and render picture for an image */
1802 static DWORD
create_image_pixmap( BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
1803 struct bitblt_coords
*src
, enum wxr_format format
,
1804 Pixmap
*pixmap
, Picture
*pict
, BOOL
*use_repeat
)
1807 int width
= src
->visrect
.right
- src
->visrect
.left
;
1808 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
1809 int depth
= pict_formats
[format
]->depth
;
1810 struct gdi_image_bits dst_bits
;
1811 XRenderPictureAttributes pa
;
1815 image
= XCreateImage( gdi_display
, visual
, depth
, ZPixmap
, 0, NULL
,
1816 info
->bmiHeader
.biWidth
, height
, 32, 0 );
1817 if (!image
) return ERROR_OUTOFMEMORY
;
1819 ret
= copy_image_bits( info
, (format
== WXR_FORMAT_R8G8B8
), image
, bits
, &dst_bits
, src
, NULL
, ~0u );
1820 if (ret
) return ret
;
1822 image
->data
= dst_bits
.ptr
;
1824 *use_repeat
= (width
== 1 && height
== 1);
1825 pa
.repeat
= *use_repeat
? RepeatNormal
: RepeatNone
;
1827 *pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
, depth
);
1828 gc
= XCreateGC( gdi_display
, *pixmap
, 0, NULL
);
1829 XPutImage( gdi_display
, *pixmap
, gc
, image
, src
->visrect
.left
, 0, 0, 0, width
, height
);
1830 *pict
= pXRenderCreatePicture( gdi_display
, *pixmap
, pict_formats
[format
], CPRepeat
, &pa
);
1831 XFreeGC( gdi_display
, gc
);
1833 /* make coordinates relative to the pixmap */
1834 src
->x
-= src
->visrect
.left
;
1835 src
->y
-= src
->visrect
.top
;
1836 OffsetRect( &src
->visrect
, -src
->visrect
.left
, -src
->visrect
.top
);
1839 XDestroyImage( image
);
1840 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
1844 static void xrender_stretch_blit( struct xrender_physdev
*physdev_src
, struct xrender_physdev
*physdev_dst
,
1845 Drawable drawable
, const struct bitblt_coords
*src
,
1846 const struct bitblt_coords
*dst
)
1849 Picture src_pict
= 0, dst_pict
, mask_pict
= 0;
1850 double xscale
= src
->width
/ (double)dst
->width
;
1851 double yscale
= src
->height
/ (double)dst
->height
;
1853 if (drawable
) /* using an intermediate pixmap */
1857 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, physdev_dst
->pict_format
, 0, NULL
);
1861 x_dst
= physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
;
1862 y_dst
= physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
;
1863 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
1866 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
1869 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
1871 XRenderColor fg
, bg
;
1873 get_xrender_color( physdev_dst
, GetTextColor( physdev_dst
->dev
.hdc
), &fg
);
1874 get_xrender_color( physdev_dst
, GetBkColor( physdev_dst
->dev
.hdc
), &bg
);
1875 fg
.alpha
= bg
.alpha
= 0;
1877 xrender_mono_blit( src_pict
, dst_pict
, physdev_dst
->format
, &fg
, &bg
,
1878 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1879 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1880 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1882 else /* color -> color (can be at different depths) or mono -> mono */
1884 if (physdev_dst
->pict_format
->depth
== 32 && physdev_src
->pict_format
->depth
< 32)
1885 mask_pict
= get_no_alpha_mask();
1887 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
,
1888 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
1889 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
1890 src
->width
, src
->height
, x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1893 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1897 static void xrender_put_image( Pixmap src_pixmap
, Picture src_pict
, Picture mask_pict
, HRGN clip
,
1898 XRenderPictFormat
*dst_format
, struct xrender_physdev
*physdev
,
1899 Drawable drawable
, struct bitblt_coords
*src
,
1900 struct bitblt_coords
*dst
, BOOL use_repeat
)
1904 double xscale
, yscale
;
1906 if (drawable
) /* using an intermediate pixmap */
1908 RGNDATA
*clip_data
= NULL
;
1910 if (clip
) clip_data
= X11DRV_GetRegionData( clip
, 0 );
1913 dst_pict
= pXRenderCreatePicture( gdi_display
, drawable
, dst_format
, 0, NULL
);
1915 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
, 0, 0,
1916 (XRectangle
*)clip_data
->Buffer
, clip_data
->rdh
.nCount
);
1917 HeapFree( GetProcessHeap(), 0, clip_data
);
1921 x_dst
= physdev
->x11dev
->dc_rect
.left
+ dst
->x
;
1922 y_dst
= physdev
->x11dev
->dc_rect
.top
+ dst
->y
;
1923 dst_pict
= get_xrender_picture( physdev
, clip
, &dst
->visrect
);
1928 xscale
= src
->width
/ (double)dst
->width
;
1929 yscale
= src
->height
/ (double)dst
->height
;
1931 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
1933 xrender_blit( PictOpSrc
, src_pict
, mask_pict
, dst_pict
, src
->x
, src
->y
, src
->width
, src
->height
,
1934 x_dst
, y_dst
, dst
->width
, dst
->height
, xscale
, yscale
);
1936 if (drawable
) pXRenderFreePicture( gdi_display
, dst_pict
);
1940 /***********************************************************************
1941 * xrenderdrv_StretchBlt
1943 static BOOL
xrenderdrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
1944 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
1946 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
1947 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
1948 BOOL stretch
= (src
->width
!= dst
->width
) || (src
->height
!= dst
->height
);
1950 if (src_dev
->funcs
!= dst_dev
->funcs
)
1952 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pStretchBlt
);
1953 return dst_dev
->funcs
->pStretchBlt( dst_dev
, dst
, src_dev
, src
, rop
);
1956 /* XRender is of no use for color -> mono */
1957 if (physdev_dst
->format
== WXR_FORMAT_MONO
&& physdev_src
->format
!= WXR_FORMAT_MONO
)
1958 goto x11drv_fallback
;
1960 /* if not stretching, we only need to handle format conversion */
1961 if (!stretch
&& physdev_dst
->format
== physdev_src
->format
) goto x11drv_fallback
;
1967 struct bitblt_coords tmp
;
1969 /* make coordinates relative to tmp pixmap */
1971 tmp
.x
-= tmp
.visrect
.left
;
1972 tmp
.y
-= tmp
.visrect
.top
;
1973 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
1975 tmpGC
= XCreateGC( gdi_display
, physdev_dst
->x11dev
->drawable
, 0, NULL
);
1976 XSetSubwindowMode( gdi_display
, tmpGC
, IncludeInferiors
);
1977 XSetGraphicsExposures( gdi_display
, tmpGC
, False
);
1978 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, tmp
.visrect
.right
- tmp
.visrect
.left
,
1979 tmp
.visrect
.bottom
- tmp
.visrect
.top
, physdev_dst
->pict_format
->depth
);
1981 xrender_stretch_blit( physdev_src
, physdev_dst
, tmp_pixmap
, src
, &tmp
);
1982 execute_rop( physdev_dst
->x11dev
, tmp_pixmap
, tmpGC
, &dst
->visrect
, rop
);
1984 XFreePixmap( gdi_display
, tmp_pixmap
);
1985 XFreeGC( gdi_display
, tmpGC
);
1987 else xrender_stretch_blit( physdev_src
, physdev_dst
, 0, src
, dst
);
1989 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
1993 return X11DRV_StretchBlt( &physdev_dst
->x11dev
->dev
, dst
, &physdev_src
->x11dev
->dev
, src
, rop
);
1997 /***********************************************************************
1998 * xrenderdrv_PutImage
2000 static DWORD
xrenderdrv_PutImage( PHYSDEV dev
, HRGN clip
, BITMAPINFO
*info
,
2001 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
2002 struct bitblt_coords
*dst
, DWORD rop
)
2004 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2008 enum wxr_format src_format
, dst_format
;
2009 XRenderPictFormat
*pict_format
;
2011 Picture src_pict
, mask_pict
= 0;
2014 dst_format
= physdev
->format
;
2015 src_format
= get_xrender_format_from_bitmapinfo( info
);
2016 if (!(pict_format
= pict_formats
[src_format
])) goto update_format
;
2018 /* make sure we can create an image with the same bpp */
2019 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
2022 /* mono <-> color conversions not supported */
2023 if ((src_format
!= dst_format
) && (src_format
== WXR_FORMAT_MONO
|| dst_format
== WXR_FORMAT_MONO
))
2024 goto x11drv_fallback
;
2026 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
2028 if (!has_alpha( src_format
) && has_alpha( dst_format
)) mask_pict
= get_no_alpha_mask();
2030 ret
= create_image_pixmap( info
, bits
, src
, src_format
, &src_pixmap
, &src_pict
, &use_repeat
);
2033 struct bitblt_coords tmp
;
2037 BOOL restore_region
= add_extra_clipping_region( physdev
->x11dev
, clip
);
2039 /* make coordinates relative to tmp pixmap */
2041 tmp
.x
-= tmp
.visrect
.left
;
2042 tmp
.y
-= tmp
.visrect
.top
;
2043 OffsetRect( &tmp
.visrect
, -tmp
.visrect
.left
, -tmp
.visrect
.top
);
2045 gc
= XCreateGC( gdi_display
, physdev
->x11dev
->drawable
, 0, NULL
);
2046 XSetSubwindowMode( gdi_display
, gc
, IncludeInferiors
);
2047 XSetGraphicsExposures( gdi_display
, gc
, False
);
2048 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
,
2049 tmp
.visrect
.right
- tmp
.visrect
.left
,
2050 tmp
.visrect
.bottom
- tmp
.visrect
.top
,
2051 physdev
->pict_format
->depth
);
2053 xrender_put_image( src_pixmap
, src_pict
, mask_pict
, NULL
, physdev
->pict_format
,
2054 NULL
, tmp_pixmap
, src
, &tmp
, use_repeat
);
2055 execute_rop( physdev
->x11dev
, tmp_pixmap
, gc
, &dst
->visrect
, rop
);
2057 XFreePixmap( gdi_display
, tmp_pixmap
);
2058 XFreeGC( gdi_display
, gc
);
2059 if (restore_region
) restore_clipping_region( physdev
->x11dev
);
2061 else xrender_put_image( src_pixmap
, src_pict
, mask_pict
, clip
,
2062 physdev
->pict_format
, physdev
, 0, src
, dst
, use_repeat
);
2064 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
2066 pXRenderFreePicture( gdi_display
, src_pict
);
2067 XFreePixmap( gdi_display
, src_pixmap
);
2072 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
2073 set_color_info( pict_formats
[dst_format
], info
);
2074 return ERROR_BAD_FORMAT
;
2077 dev
= GET_NEXT_PHYSDEV( dev
, pPutImage
);
2078 return dev
->funcs
->pPutImage( dev
, clip
, info
, bits
, src
, dst
, rop
);
2082 /***********************************************************************
2083 * xrenderdrv_BlendImage
2085 static DWORD
xrenderdrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
2086 struct bitblt_coords
*src
, struct bitblt_coords
*dst
,
2087 BLENDFUNCTION func
)
2089 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2091 enum wxr_format format
;
2092 XRenderPictFormat
*pict_format
;
2093 Picture dst_pict
, src_pict
, mask_pict
;
2097 format
= get_xrender_format_from_bitmapinfo( info
);
2098 if (!(func
.AlphaFormat
& AC_SRC_ALPHA
))
2099 format
= get_format_without_alpha( format
);
2100 else if (format
!= WXR_FORMAT_A8R8G8B8
)
2101 return ERROR_INVALID_PARAMETER
;
2103 if (!(pict_format
= pict_formats
[format
])) goto update_format
;
2105 /* make sure we can create an image with the same bpp */
2106 if (info
->bmiHeader
.biBitCount
!= pixmap_formats
[pict_format
->depth
]->bits_per_pixel
)
2109 if (format
== WXR_FORMAT_MONO
&& physdev
->format
!= WXR_FORMAT_MONO
)
2112 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
2114 ret
= create_image_pixmap( info
, bits
, src
, format
, &src_pixmap
, &src_pict
, &use_repeat
);
2117 double xscale
, yscale
;
2121 xscale
= src
->width
/ (double)dst
->width
;
2122 yscale
= src
->height
/ (double)dst
->height
;
2124 else xscale
= yscale
= 1; /* no scaling needed with a repeating source */
2126 dst_pict
= get_xrender_picture( physdev
, 0, &dst
->visrect
);
2128 EnterCriticalSection( &xrender_cs
);
2129 mask_pict
= get_mask_pict( func
.SourceConstantAlpha
* 257 );
2131 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2132 src
->x
, src
->y
, src
->width
, src
->height
,
2133 physdev
->x11dev
->dc_rect
.left
+ dst
->x
,
2134 physdev
->x11dev
->dc_rect
.top
+ dst
->y
,
2135 dst
->width
, dst
->height
, xscale
, yscale
);
2137 pXRenderFreePicture( gdi_display
, src_pict
);
2138 XFreePixmap( gdi_display
, src_pixmap
);
2140 LeaveCriticalSection( &xrender_cs
);
2141 add_device_bounds( physdev
->x11dev
, &dst
->visrect
);
2146 if (info
->bmiHeader
.biHeight
> 0) info
->bmiHeader
.biHeight
= -info
->bmiHeader
.biHeight
;
2147 set_color_info( physdev
->pict_format
, info
);
2148 return ERROR_BAD_FORMAT
;
2152 /***********************************************************************
2153 * xrenderdrv_AlphaBlend
2155 static BOOL
xrenderdrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
2156 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION blendfn
)
2158 struct xrender_physdev
*physdev_dst
= get_xrender_dev( dst_dev
);
2159 struct xrender_physdev
*physdev_src
= get_xrender_dev( src_dev
);
2160 Picture dst_pict
, src_pict
= 0, mask_pict
= 0, tmp_pict
= 0;
2161 XRenderPictureAttributes pa
;
2162 Pixmap tmp_pixmap
= 0;
2163 double xscale
, yscale
;
2165 if (src_dev
->funcs
!= dst_dev
->funcs
)
2167 dst_dev
= GET_NEXT_PHYSDEV( dst_dev
, pAlphaBlend
);
2168 return dst_dev
->funcs
->pAlphaBlend( dst_dev
, dst
, src_dev
, src
, blendfn
);
2171 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->format
!= WXR_FORMAT_A8R8G8B8
)
2173 SetLastError( ERROR_INVALID_PARAMETER
);
2177 dst_pict
= get_xrender_picture( physdev_dst
, 0, &dst
->visrect
);
2179 xscale
= src
->width
/ (double)dst
->width
;
2180 yscale
= src
->height
/ (double)dst
->height
;
2182 src_pict
= get_xrender_picture_source( physdev_src
, FALSE
);
2184 if (physdev_src
->format
== WXR_FORMAT_MONO
&& physdev_dst
->format
!= WXR_FORMAT_MONO
)
2186 /* mono -> color blending needs an intermediate color pixmap */
2187 XRenderColor fg
, bg
;
2188 int width
= src
->visrect
.right
- src
->visrect
.left
;
2189 int height
= src
->visrect
.bottom
- src
->visrect
.top
;
2191 /* blending doesn't use the destination DC colors */
2192 fg
.red
= fg
.green
= fg
.blue
= 0;
2193 bg
.red
= bg
.green
= bg
.blue
= 0xffff;
2194 fg
.alpha
= bg
.alpha
= 0xffff;
2196 tmp_pixmap
= XCreatePixmap( gdi_display
, root_window
, width
, height
,
2197 physdev_dst
->pict_format
->depth
);
2198 tmp_pict
= pXRenderCreatePicture( gdi_display
, tmp_pixmap
, physdev_dst
->pict_format
, 0, NULL
);
2200 xrender_mono_blit( src_pict
, tmp_pict
, physdev_dst
->format
, &fg
, &bg
,
2201 src
->visrect
.left
, src
->visrect
.top
, width
, height
, 0, 0, width
, height
, 1, 1 );
2203 else if (!(blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && physdev_src
->pict_format
)
2205 /* we need a source picture with no alpha */
2206 enum wxr_format format
= get_format_without_alpha( physdev_src
->format
);
2207 if (format
!= physdev_src
->format
)
2209 pa
.subwindow_mode
= IncludeInferiors
;
2210 tmp_pict
= pXRenderCreatePicture( gdi_display
, physdev_src
->x11dev
->drawable
,
2211 pict_formats
[format
], CPSubwindowMode
, &pa
);
2215 if (tmp_pict
) src_pict
= tmp_pict
;
2217 EnterCriticalSection( &xrender_cs
);
2218 mask_pict
= get_mask_pict( blendfn
.SourceConstantAlpha
* 257 );
2220 xrender_blit( PictOpOver
, src_pict
, mask_pict
, dst_pict
,
2221 physdev_src
->x11dev
->dc_rect
.left
+ src
->x
,
2222 physdev_src
->x11dev
->dc_rect
.top
+ src
->y
,
2223 src
->width
, src
->height
,
2224 physdev_dst
->x11dev
->dc_rect
.left
+ dst
->x
,
2225 physdev_dst
->x11dev
->dc_rect
.top
+ dst
->y
,
2226 dst
->width
, dst
->height
, xscale
, yscale
);
2228 if (tmp_pict
) pXRenderFreePicture( gdi_display
, tmp_pict
);
2229 if (tmp_pixmap
) XFreePixmap( gdi_display
, tmp_pixmap
);
2231 LeaveCriticalSection( &xrender_cs
);
2232 add_device_bounds( physdev_dst
->x11dev
, &dst
->visrect
);
2236 /***********************************************************************
2237 * xrenderdrv_GradientFill
2239 static BOOL
xrenderdrv_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
2240 void * grad_array
, ULONG ngrad
, ULONG mode
)
2242 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2243 static const XFixed stops
[2] = { 0, 1 << 16 };
2244 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2245 XLinearGradient gradient
;
2246 XRenderColor colors
[2];
2247 Picture src_pict
, dst_pict
;
2249 const GRADIENT_RECT
*rect
= grad_array
;
2253 if (!pXRenderCreateLinearGradient
) goto fallback
;
2255 /* <= 16-bpp uses dithering */
2256 if (!physdev
->pict_format
|| physdev
->pict_format
->depth
<= 16) goto fallback
;
2260 case GRADIENT_FILL_RECT_H
:
2261 case GRADIENT_FILL_RECT_V
:
2262 for (i
= 0; i
< ngrad
; i
++, rect
++)
2264 const TRIVERTEX
*v1
= vert_array
+ rect
->UpperLeft
;
2265 const TRIVERTEX
*v2
= vert_array
+ rect
->LowerRight
;
2267 colors
[0].red
= v1
->Red
* 257 / 256;
2268 colors
[0].green
= v1
->Green
* 257 / 256;
2269 colors
[0].blue
= v1
->Blue
* 257 / 256;
2270 colors
[1].red
= v2
->Red
* 257 / 256;
2271 colors
[1].green
= v2
->Green
* 257 / 256;
2272 colors
[1].blue
= v2
->Blue
* 257 / 256;
2273 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2274 colors
[0].alpha
= colors
[1].alpha
= 65535;
2280 LPtoDP( dev
->hdc
, pt
, 2 );
2281 if (mode
== GRADIENT_FILL_RECT_H
)
2283 gradient
.p1
.y
= gradient
.p2
.y
= 0;
2284 if (pt
[1].x
> pt
[0].x
)
2287 gradient
.p2
.x
= (pt
[1].x
- pt
[0].x
) << 16;
2291 gradient
.p1
.x
= (pt
[0].x
- pt
[1].x
) << 16;
2297 gradient
.p1
.x
= gradient
.p2
.x
= 0;
2298 if (pt
[1].y
> pt
[0].y
)
2301 gradient
.p2
.y
= (pt
[1].y
- pt
[0].y
) << 16;
2305 gradient
.p1
.y
= (pt
[0].y
- pt
[1].y
) << 16;
2310 rc
.left
= min( pt
[0].x
, pt
[1].x
);
2311 rc
.top
= min( pt
[0].y
, pt
[1].y
);
2312 rc
.right
= max( pt
[0].x
, pt
[1].x
);
2313 rc
.bottom
= max( pt
[0].y
, pt
[1].y
);
2315 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2316 mode
, wine_dbgstr_rect( &rc
),
2317 colors
[0].red
, colors
[0].green
, colors
[0].blue
, colors
[0].alpha
,
2318 colors
[1].red
, colors
[1].green
, colors
[1].blue
, colors
[1].alpha
);
2320 dst_pict
= get_xrender_picture( physdev
, 0, NULL
);
2322 src_pict
= pXRenderCreateLinearGradient( gdi_display
, &gradient
, stops
, colors
, 2 );
2323 xrender_blit( PictOpSrc
, src_pict
, 0, dst_pict
,
2324 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
2325 physdev
->x11dev
->dc_rect
.left
+ rc
.left
,
2326 physdev
->x11dev
->dc_rect
.top
+ rc
.top
,
2327 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, 1, 1 );
2328 pXRenderFreePicture( gdi_display
, src_pict
);
2329 add_device_bounds( physdev
->x11dev
, &rc
);
2336 dev
= GET_NEXT_PHYSDEV( dev
, pGradientFill
);
2337 return dev
->funcs
->pGradientFill( dev
, vert_array
, nvert
, grad_array
, ngrad
, mode
);
2340 /***********************************************************************
2341 * xrenderdrv_SelectBrush
2343 static HBRUSH
xrenderdrv_SelectBrush( PHYSDEV dev
, HBRUSH hbrush
, const struct brush_pattern
*pattern
)
2345 struct xrender_physdev
*physdev
= get_xrender_dev( dev
);
2348 XRenderPictFormat
*format
= physdev
->pict_format
;
2350 if (!pattern
) goto x11drv_fallback
;
2351 if (pattern
->info
->bmiHeader
.biBitCount
== 1) goto x11drv_fallback
;
2352 if (physdev
->format
== WXR_FORMAT_MONO
) goto x11drv_fallback
;
2354 memset( &vis
, 0, sizeof(vis
) );
2355 vis
.depth
= format
->depth
;
2356 vis
.red_mask
= format
->direct
.redMask
<< format
->direct
.red
;
2357 vis
.green_mask
= format
->direct
.greenMask
<< format
->direct
.green
;
2358 vis
.blue_mask
= format
->direct
.blueMask
<< format
->direct
.blue
;
2360 pixmap
= create_pixmap_from_image( physdev
->dev
.hdc
, &vis
, pattern
->info
,
2361 &pattern
->bits
, pattern
->usage
);
2362 if (!pixmap
) return 0;
2364 if (physdev
->x11dev
->brush
.pixmap
) XFreePixmap( gdi_display
, physdev
->x11dev
->brush
.pixmap
);
2365 physdev
->x11dev
->brush
.pixmap
= pixmap
;
2366 physdev
->x11dev
->brush
.fillStyle
= FillTiled
;
2367 physdev
->x11dev
->brush
.pixel
= 0; /* ignored */
2368 physdev
->x11dev
->brush
.style
= BS_PATTERN
;
2372 dev
= GET_NEXT_PHYSDEV( dev
, pSelectBrush
);
2373 return dev
->funcs
->pSelectBrush( dev
, hbrush
, pattern
);
2377 static const struct gdi_dc_funcs xrender_funcs
=
2379 NULL
, /* pAbortDoc */
2380 NULL
, /* pAbortPath */
2381 xrenderdrv_AlphaBlend
, /* pAlphaBlend */
2382 NULL
, /* pAngleArc */
2385 NULL
, /* pBeginPath */
2386 xrenderdrv_BlendImage
, /* pBlendImage */
2388 NULL
, /* pCloseFigure */
2389 xrenderdrv_CreateCompatibleDC
, /* pCreateCompatibleDC */
2390 xrenderdrv_CreateDC
, /* pCreateDC */
2391 xrenderdrv_DeleteDC
, /* pDeleteDC */
2392 NULL
, /* pDeleteObject */
2393 NULL
, /* pDeviceCapabilities */
2394 NULL
, /* pEllipse */
2396 NULL
, /* pEndPage */
2397 NULL
, /* pEndPath */
2398 NULL
, /* pEnumFonts */
2399 NULL
, /* pEnumICMProfiles */
2400 NULL
, /* pExcludeClipRect */
2401 NULL
, /* pExtDeviceMode */
2402 xrenderdrv_ExtEscape
, /* pExtEscape */
2403 NULL
, /* pExtFloodFill */
2404 NULL
, /* pExtSelectClipRgn */
2405 xrenderdrv_ExtTextOut
, /* pExtTextOut */
2406 NULL
, /* pFillPath */
2407 NULL
, /* pFillRgn */
2408 NULL
, /* pFlattenPath */
2409 NULL
, /* pFontIsLinked */
2410 NULL
, /* pFrameRgn */
2411 NULL
, /* pGdiComment */
2412 NULL
, /* pGdiRealizationInfo */
2413 NULL
, /* pGetBoundsRect */
2414 NULL
, /* pGetCharABCWidths */
2415 NULL
, /* pGetCharABCWidthsI */
2416 NULL
, /* pGetCharWidth */
2417 NULL
, /* pGetDeviceCaps */
2418 NULL
, /* pGetDeviceGammaRamp */
2419 NULL
, /* pGetFontData */
2420 NULL
, /* pGetFontUnicodeRanges */
2421 NULL
, /* pGetGlyphIndices */
2422 NULL
, /* pGetGlyphOutline */
2423 NULL
, /* pGetICMProfile */
2424 NULL
, /* pGetImage */
2425 NULL
, /* pGetKerningPairs */
2426 NULL
, /* pGetNearestColor */
2427 NULL
, /* pGetOutlineTextMetrics */
2428 NULL
, /* pGetPixel */
2429 NULL
, /* pGetSystemPaletteEntries */
2430 NULL
, /* pGetTextCharsetInfo */
2431 NULL
, /* pGetTextExtentExPoint */
2432 NULL
, /* pGetTextExtentExPointI */
2433 NULL
, /* pGetTextFace */
2434 NULL
, /* pGetTextMetrics */
2435 xrenderdrv_GradientFill
, /* pGradientFill */
2436 NULL
, /* pIntersectClipRect */
2437 NULL
, /* pInvertRgn */
2439 NULL
, /* pModifyWorldTransform */
2441 NULL
, /* pOffsetClipRgn */
2442 NULL
, /* pOffsetViewportOrg */
2443 NULL
, /* pOffsetWindowOrg */
2444 NULL
, /* pPaintRgn */
2447 NULL
, /* pPolyBezier */
2448 NULL
, /* pPolyBezierTo */
2449 NULL
, /* pPolyDraw */
2450 NULL
, /* pPolyPolygon */
2451 NULL
, /* pPolyPolyline */
2452 NULL
, /* pPolygon */
2453 NULL
, /* pPolyline */
2454 NULL
, /* pPolylineTo */
2455 xrenderdrv_PutImage
, /* pPutImage */
2456 NULL
, /* pRealizeDefaultPalette */
2457 NULL
, /* pRealizePalette */
2458 NULL
, /* pRectangle */
2459 NULL
, /* pResetDC */
2460 NULL
, /* pRestoreDC */
2461 NULL
, /* pRoundRect */
2463 NULL
, /* pScaleViewportExt */
2464 NULL
, /* pScaleWindowExt */
2465 NULL
, /* pSelectBitmap */
2466 xrenderdrv_SelectBrush
, /* pSelectBrush */
2467 NULL
, /* pSelectClipPath */
2468 xrenderdrv_SelectFont
, /* pSelectFont */
2469 NULL
, /* pSelectPalette */
2470 NULL
, /* pSelectPen */
2471 NULL
, /* pSetArcDirection */
2472 NULL
, /* pSetBkColor */
2473 NULL
, /* pSetBkMode */
2474 NULL
, /* pSetBoundsRect */
2475 NULL
, /* pSetDCBrushColor */
2476 NULL
, /* pSetDCPenColor */
2477 NULL
, /* pSetDIBitsToDevice */
2478 xrenderdrv_SetDeviceClipping
, /* pSetDeviceClipping */
2479 NULL
, /* pSetDeviceGammaRamp */
2480 NULL
, /* pSetLayout */
2481 NULL
, /* pSetMapMode */
2482 NULL
, /* pSetMapperFlags */
2483 NULL
, /* pSetPixel */
2484 NULL
, /* pSetPolyFillMode */
2485 NULL
, /* pSetROP2 */
2486 NULL
, /* pSetRelAbs */
2487 NULL
, /* pSetStretchBltMode */
2488 NULL
, /* pSetTextAlign */
2489 NULL
, /* pSetTextCharacterExtra */
2490 NULL
, /* pSetTextColor */
2491 NULL
, /* pSetTextJustification */
2492 NULL
, /* pSetViewportExt */
2493 NULL
, /* pSetViewportOrg */
2494 NULL
, /* pSetWindowExt */
2495 NULL
, /* pSetWindowOrg */
2496 NULL
, /* pSetWorldTransform */
2497 NULL
, /* pStartDoc */
2498 NULL
, /* pStartPage */
2499 xrenderdrv_StretchBlt
, /* pStretchBlt */
2500 NULL
, /* pStretchDIBits */
2501 NULL
, /* pStrokeAndFillPath */
2502 NULL
, /* pStrokePath */
2503 NULL
, /* pSwapBuffers */
2504 NULL
, /* pUnrealizePalette */
2505 NULL
, /* pWidenPath */
2506 NULL
, /* wine_get_wgl_driver */
2507 GDI_PRIORITY_GRAPHICS_DRV
+ 10 /* priority */
2510 #else /* SONAME_LIBXRENDER */
2512 const struct gdi_dc_funcs
*X11DRV_XRender_Init(void)
2514 TRACE("XRender support not compiled in.\n");
2518 void X11DRV_XRender_Finalize(void)
2522 #endif /* SONAME_LIBXRENDER */