1 /*
2 * Functions to use the XRender extension
3 *
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
6 * Copyright 2011 Alexandre Julliard
7 *
8 * Some parts also:
9 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
10 *
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.
15 *
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.
20 *
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
24 */
25 #include "config.h"
26 #include "wine/port.h"
27
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <stdlib.h>
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "x11drv.h"
36 #include "winternl.h"
37 #include "wine/library.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
40
41 int using_client_side_fonts = FALSE;
42
43 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
44
45 #ifdef SONAME_LIBXRENDER
46
47 WINE_DECLARE_DEBUG_CHANNEL(winediag);
48
49 static BOOL X11DRV_XRender_Installed = FALSE;
50
51 #include <X11/Xlib.h>
52 #include <X11/extensions/Xrender.h>
53
54 #ifndef RepeatNone /* added in 0.10 */
55 #define RepeatNone 0
56 #define RepeatNormal 1
57 #define RepeatPad 2
58 #define RepeatReflect 3
59 #endif
60
61 enum wxr_format
62 {
63 WXR_FORMAT_MONO,
64 WXR_FORMAT_GRAY,
65 WXR_FORMAT_X1R5G5B5,
66 WXR_FORMAT_X1B5G5R5,
67 WXR_FORMAT_R5G6B5,
68 WXR_FORMAT_B5G6R5,
69 WXR_FORMAT_R8G8B8,
70 WXR_FORMAT_B8G8R8,
71 WXR_FORMAT_A8R8G8B8,
72 WXR_FORMAT_B8G8R8A8,
73 WXR_FORMAT_X8R8G8B8,
74 WXR_FORMAT_B8G8R8X8,
75 WXR_NB_FORMATS,
76 WXR_INVALID_FORMAT = WXR_NB_FORMATS
77 };
78
79 typedef struct wine_xrender_format_template
80 {
81 unsigned int depth;
82 unsigned int alpha;
83 unsigned int alphaMask;
84 unsigned int red;
85 unsigned int redMask;
86 unsigned int green;
87 unsigned int greenMask;
88 unsigned int blue;
89 unsigned int blueMask;
90 } WineXRenderFormatTemplate;
91
92 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
93 {
94 /* Format depth alpha mask red mask green mask blue mask*/
95 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
96 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
97 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
98 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
99 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
100 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
101 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
103 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
105 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
106 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
107 };
108
109 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
110 {
111 /* format phys red phys green phys blue log red log green log blue */
112 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
113 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
114 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
115 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
116 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
117 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
118 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
120 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
121 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
122 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
123 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
124 };
125
126 static enum wxr_format default_format = WXR_INVALID_FORMAT;
127 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
128
129 typedef struct
130 {
131 LOGFONTW lf;
132 XFORM xform;
133 SIZE devsize; /* size in device coords */
134 DWORD hash;
135 } LFANDSIZE;
136
137 #define INITIAL_REALIZED_BUF_SIZE 128
138
139 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
140
141 typedef struct
142 {
143 GlyphSet glyphset;
144 XRenderPictFormat *font_format;
145 int nrealized;
146 BOOL *realized;
147 XGlyphInfo *gis;
148 } gsCacheEntryFormat;
149
150 typedef struct
151 {
152 LFANDSIZE lfsz;
153 AA_Type aa_default;
154 gsCacheEntryFormat * format[AA_MAXVALUE];
155 INT count;
156 INT next;
157 } gsCacheEntry;
158
159 struct xrender_physdev
160 {
161 struct gdi_physdev dev;
162 X11DRV_PDEVICE *x11dev;
163 enum wxr_format format;
164 int cache_index;
165 BOOL update_clip;
166 Picture pict;
167 Picture pict_src;
168 XRenderPictFormat *pict_format;
169 };
170
171 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
172 {
173 return (struct xrender_physdev *)dev;
174 }
175
176 static const struct gdi_dc_funcs xrender_funcs;
177
178 static gsCacheEntry *glyphsetCache = NULL;
179 static DWORD glyphsetCacheSize = 0;
180 static INT lastfree = -1;
181 static INT mru = -1;
182
183 #define INIT_CACHE_SIZE 10
184
185 static int antialias = 1;
186
187 static void *xrender_handle;
188
189 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
190 MAKE_FUNCPTR(XRenderAddGlyphs)
191 MAKE_FUNCPTR(XRenderChangePicture)
192 MAKE_FUNCPTR(XRenderComposite)
193 MAKE_FUNCPTR(XRenderCompositeText16)
194 MAKE_FUNCPTR(XRenderCreateGlyphSet)
195 MAKE_FUNCPTR(XRenderCreatePicture)
196 MAKE_FUNCPTR(XRenderFillRectangle)
197 MAKE_FUNCPTR(XRenderFindFormat)
198 MAKE_FUNCPTR(XRenderFindVisualFormat)
199 MAKE_FUNCPTR(XRenderFreeGlyphSet)
200 MAKE_FUNCPTR(XRenderFreePicture)
201 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
202 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
203 MAKE_FUNCPTR(XRenderCreateLinearGradient)
204 #endif
205 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
206 MAKE_FUNCPTR(XRenderSetPictureTransform)
207 #endif
208 MAKE_FUNCPTR(XRenderQueryExtension)
209
210 #ifdef SONAME_LIBFONTCONFIG
211 #include <fontconfig/fontconfig.h>
212 MAKE_FUNCPTR(FcConfigSubstitute)
213 MAKE_FUNCPTR(FcDefaultSubstitute)
214 MAKE_FUNCPTR(FcFontMatch)
215 MAKE_FUNCPTR(FcInit)
216 MAKE_FUNCPTR(FcPatternCreate)
217 MAKE_FUNCPTR(FcPatternDestroy)
218 MAKE_FUNCPTR(FcPatternAddInteger)
219 MAKE_FUNCPTR(FcPatternAddString)
220 MAKE_FUNCPTR(FcPatternGetBool)
221 MAKE_FUNCPTR(FcPatternGetInteger)
222 MAKE_FUNCPTR(FcPatternGetString)
223 static void *fontconfig_handle;
224 static BOOL fontconfig_installed;
225 #endif
226
227 #undef MAKE_FUNCPTR
228
229 static CRITICAL_SECTION xrender_cs;
230 static CRITICAL_SECTION_DEBUG critsect_debug =
231 {
232 0, 0, &xrender_cs,
233 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
234 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
235 };
236 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
237
238 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
239 ( ( (ULONG)_x4 << 24 ) | \
240 ( (ULONG)_x3 << 16 ) | \
241 ( (ULONG)_x2 << 8 ) | \
242 (ULONG)_x1 )
243
244 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
245
246 #define GASP_GRIDFIT 0x01
247 #define GASP_DOGRAY 0x02
248
249 #ifdef WORDS_BIGENDIAN
250 #define get_be_word(x) (x)
251 #define NATIVE_BYTE_ORDER MSBFirst
252 #else
253 #define get_be_word(x) RtlUshortByteSwap(x)
254 #define NATIVE_BYTE_ORDER LSBFirst
255 #endif
256
257 static BOOL has_alpha( enum wxr_format format )
258 {
259 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
260 }
261
262 static enum wxr_format get_format_without_alpha( enum wxr_format format )
263 {
264 switch (format)
265 {
266 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
267 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
268 default: return format;
269 }
270 }
271
272 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
273 {
274 templ->id = 0;
275 templ->type = PictTypeDirect;
276 templ->depth = fmt->depth;
277 templ->direct.alpha = fmt->alpha;
278 templ->direct.alphaMask = fmt->alphaMask;
279 templ->direct.red = fmt->red;
280 templ->direct.redMask = fmt->redMask;
281 templ->direct.green = fmt->green;
282 templ->direct.greenMask = fmt->greenMask;
283 templ->direct.blue = fmt->blue;
284 templ->direct.blueMask = fmt->blueMask;
285 templ->colormap = 0;
286
287 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
288
289 return TRUE;
290 }
291
292 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
293 {
294 if(fmt->depth != screen_depth)
295 return FALSE;
296 if( (fmt->redMask << fmt->red) != visual->red_mask)
297 return FALSE;
298 if( (fmt->greenMask << fmt->green) != visual->green_mask)
299 return FALSE;
300 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
301 return FALSE;
302
303 /* We never select a default ARGB visual */
304 if(fmt->alphaMask)
305 return FALSE;
306
307 return TRUE;
308 }
309
310 static int load_xrender_formats(void)
311 {
312 int count = 0;
313 unsigned int i;
314
315 for (i = 0; i < WXR_NB_FORMATS; i++)
316 {
317 XRenderPictFormat templ;
318
319 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
320 {
321 wine_tsx11_lock();
322 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
323 if (!pict_formats[i])
324 {
325 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
326 if (visual->class == DirectColor)
327 {
328 XVisualInfo info;
329 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
330 screen_depth, TrueColor, &info ))
331 {
332 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
333 if (pict_formats[i]) visual = info.visual;
334 }
335 }
336 }
337 wine_tsx11_unlock();
338 if (pict_formats[i]) default_format = i;
339 }
340 else
341 {
342 unsigned long mask = 0;
343 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
344
345 wine_tsx11_lock();
346 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
347 wine_tsx11_unlock();
348 }
349 if (pict_formats[i])
350 {
351 count++;
352 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
353 }
354 }
355 return count;
356 }
357
358 /***********************************************************************
359 * X11DRV_XRender_Init
360 *
361 * Let's see if our XServer has the extension available
362 *
363 */
364 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
365 {
366 int event_base, i;
367
368 using_client_side_fonts = client_side_with_render || client_side_with_core;
369
370 if (!client_side_with_render) return NULL;
371 if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
372
373 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
374 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
375 LOAD_FUNCPTR(XRenderAddGlyphs);
376 LOAD_FUNCPTR(XRenderChangePicture);
377 LOAD_FUNCPTR(XRenderComposite);
378 LOAD_FUNCPTR(XRenderCompositeText16);
379 LOAD_FUNCPTR(XRenderCreateGlyphSet);
380 LOAD_FUNCPTR(XRenderCreatePicture);
381 LOAD_FUNCPTR(XRenderFillRectangle);
382 LOAD_FUNCPTR(XRenderFindFormat);
383 LOAD_FUNCPTR(XRenderFindVisualFormat);
384 LOAD_FUNCPTR(XRenderFreeGlyphSet);
385 LOAD_FUNCPTR(XRenderFreePicture);
386 LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
387 LOAD_FUNCPTR(XRenderQueryExtension);
388 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
389 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
390 #endif
391 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
392 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
393 #endif
394 #undef LOAD_OPTIONAL_FUNCPTR
395 #undef LOAD_FUNCPTR
396
397 wine_tsx11_lock();
398 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
399 wine_tsx11_unlock();
400 if (!X11DRV_XRender_Installed) return NULL;
401
402 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
403 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
404 {
405 ERR_(winediag)("Wine has detected that you probably have a buggy version "
406 "of libXrender. Because of this client side font rendering "
407 "will be disabled. Please upgrade this library.\n");
408 X11DRV_XRender_Installed = FALSE;
409 return NULL;
410 }
411
412 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask)
413 {
414 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
415 X11DRV_XRender_Installed = FALSE;
416 return NULL;
417 }
418
419 #ifdef SONAME_LIBFONTCONFIG
420 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
421 {
422 #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;}
423 LOAD_FUNCPTR(FcConfigSubstitute);
424 LOAD_FUNCPTR(FcDefaultSubstitute);
425 LOAD_FUNCPTR(FcFontMatch);
426 LOAD_FUNCPTR(FcInit);
427 LOAD_FUNCPTR(FcPatternCreate);
428 LOAD_FUNCPTR(FcPatternDestroy);
429 LOAD_FUNCPTR(FcPatternAddInteger);
430 LOAD_FUNCPTR(FcPatternAddString);
431 LOAD_FUNCPTR(FcPatternGetBool);
432 LOAD_FUNCPTR(FcPatternGetInteger);
433 LOAD_FUNCPTR(FcPatternGetString);
434 #undef LOAD_FUNCPTR
435 fontconfig_installed = pFcInit();
436 }
437 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
438
439 sym_not_found:
440 #endif
441
442 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
443 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
444
445 glyphsetCacheSize = INIT_CACHE_SIZE;
446 lastfree = 0;
447 for(i = 0; i < INIT_CACHE_SIZE; i++) {
448 glyphsetCache[i].next = i + 1;
449 glyphsetCache[i].count = -1;
450 }
451 glyphsetCache[i-1].next = -1;
452
453 if(screen_depth <= 8 || !client_side_antialias_with_render) antialias = 0;
454
455 return &xrender_funcs;
456 }
457
458 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
459 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
460 {
461 if(pf->direct.redMask)
462 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
463 else
464 dst_color->red = 0;
465
466 if(pf->direct.greenMask)
467 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
468 else
469 dst_color->green = 0;
470
471 if(pf->direct.blueMask)
472 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
473 else
474 dst_color->blue = 0;
475
476 dst_color->alpha = 0xffff;
477 }
478
479 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
480 {
481 int redMask, greenMask, blueMask;
482 unsigned int i;
483
484 if (depth == 1) return WXR_FORMAT_MONO;
485
486 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
487 if (!shifts) return default_format;
488
489 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
490 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
491 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
492
493 /* Try to locate a format which matches the specification of the dibsection. */
494 for(i = 0; i < WXR_NB_FORMATS; i++)
495 {
496 if( depth == wxr_formats_template[i].depth &&
497 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
498 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
499 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
500 return i;
501 }
502
503 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
504 ERR("No XRender format found for %u %08x/%08x/%08x\n", depth, redMask, greenMask, blueMask);
505 return WXR_INVALID_FORMAT;
506 }
507
508 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
509 {
510 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
511
512 switch (info->bmiHeader.biBitCount)
513 {
514 case 1:
515 return WXR_FORMAT_MONO;
516 case 4:
517 case 8:
518 break;
519 case 24:
520 if (info->bmiHeader.biCompression != BI_RGB) break;
521 return WXR_FORMAT_R8G8B8;
522 case 16:
523 case 32:
524 if (info->bmiHeader.biCompression == BI_BITFIELDS)
525 {
526 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
527 unsigned int i;
528
529 for (i = 0; i < WXR_NB_FORMATS; i++)
530 {
531 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
532 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
533 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
534 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
535 return i;
536 }
537 break;
538 }
539 if (info->bmiHeader.biCompression != BI_RGB) break;
540 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
541 }
542 return WXR_INVALID_FORMAT;
543 }
544
545 static enum wxr_format get_bitmap_format( int bpp )
546 {
547 enum wxr_format format = WXR_INVALID_FORMAT;
548
549 if (bpp == screen_bpp)
550 {
551 switch (bpp)
552 {
553 case 16: format = WXR_FORMAT_R5G6B5; break;
554 case 24: format = WXR_FORMAT_R8G8B8; break;
555 case 32: format = WXR_FORMAT_A8R8G8B8; break;
556 }
557 }
558 return format;
559 }
560
561 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
562 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
563 {
564 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
565 XTransform xform = {{
566 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
567 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
568 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
569 }};
570
571 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
572 #endif
573 }
574
575 /* check if we can use repeating instead of scaling for the specified source DC */
576 static BOOL use_source_repeat( struct xrender_physdev *dev )
577 {
578 return (dev->x11dev->bitmap &&
579 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
580 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
581 }
582
583 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
584 {
585 XRenderPictureAttributes pa;
586 RGNDATA *data;
587
588 if (!rgn)
589 {
590 wine_tsx11_lock();
591 pa.clip_mask = None;
592 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
593 wine_tsx11_unlock();
594 }
595 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
596 {
597 wine_tsx11_lock();
598 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
599 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
600 (XRectangle *)data->Buffer, data->rdh.nCount );
601 wine_tsx11_unlock();
602 HeapFree( GetProcessHeap(), 0, data );
603 }
604 }
605
606
607 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
608 {
609 if (!dev->pict && dev->pict_format)
610 {
611 XRenderPictureAttributes pa;
612
613 wine_tsx11_lock();
614 pa.subwindow_mode = IncludeInferiors;
615 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
616 dev->pict_format, CPSubwindowMode, &pa );
617 wine_tsx11_unlock();
618 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
619 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
620 dev->update_clip = (dev->x11dev->region != 0);
621 }
622
623 if (clip_rect)
624 {
625 HRGN rgn = CreateRectRgnIndirect( clip_rect );
626 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
627 if (dev->x11dev->region) CombineRgn( rgn, rgn, dev->x11dev->region, RGN_AND );
628 update_xrender_clipping( dev, rgn );
629 DeleteObject( rgn );
630 }
631 else if (clip_rgn)
632 {
633 if (dev->x11dev->region)
634 {
635 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
636 CombineRgn( rgn, clip_rgn, dev->x11dev->region, RGN_AND );
637 update_xrender_clipping( dev, rgn );
638 DeleteObject( rgn );
639 }
640 else update_xrender_clipping( dev, clip_rgn );
641 }
642 else if (dev->update_clip) update_xrender_clipping( dev, dev->x11dev->region );
643
644 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
645 return dev->pict;
646 }
647
648 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
649 {
650 if (!dev->pict_src && dev->pict_format)
651 {
652 XRenderPictureAttributes pa;
653
654 wine_tsx11_lock();
655 pa.subwindow_mode = IncludeInferiors;
656 pa.repeat = repeat ? RepeatNormal : RepeatNone;
657 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
658 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
659 wine_tsx11_unlock();
660
661 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
662 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
663 }
664
665 return dev->pict_src;
666 }
667
668 static void free_xrender_picture( struct xrender_physdev *dev )
669 {
670 if (dev->pict || dev->pict_src)
671 {
672 wine_tsx11_lock();
673 XFlush( gdi_display );
674 if (dev->pict)
675 {
676 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
677 pXRenderFreePicture(gdi_display, dev->pict);
678 dev->pict = 0;
679 }
680 if(dev->pict_src)
681 {
682 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
683 pXRenderFreePicture(gdi_display, dev->pict_src);
684 dev->pict_src = 0;
685 }
686 wine_tsx11_unlock();
687 }
688 }
689
690 /* return a mask picture used to force alpha to 0 */
691 static Picture get_no_alpha_mask(void)
692 {
693 static Pixmap pixmap;
694 static Picture pict;
695
696 wine_tsx11_lock();
697 if (!pict)
698 {
699 XRenderPictureAttributes pa;
700 XRenderColor col;
701
702 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
703 pa.repeat = RepeatNormal;
704 pa.component_alpha = True;
705 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
706 CPRepeat|CPComponentAlpha, &pa );
707 col.red = col.green = col.blue = 0xffff;
708 col.alpha = 0;
709 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
710 }
711 wine_tsx11_unlock();
712 return pict;
713 }
714
715 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
716 {
717 if(p1->hash != p2->hash) return TRUE;
718 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
719 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
720 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
721 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
722 }
723
724 #if 0
725 static void walk_cache(void)
726 {
727 int i;
728
729 EnterCriticalSection(&xrender_cs);
730 for(i=mru; i >= 0; i = glyphsetCache[i].next)
731 TRACE("item %d\n", i);
732 LeaveCriticalSection(&xrender_cs);
733 }
734 #endif
735
736 static int LookupEntry(LFANDSIZE *plfsz)
737 {
738 int i, prev_i = -1;
739
740 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
741 TRACE("%d\n", i);
742 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
743
744 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
745 glyphsetCache[i].count++;
746 if(prev_i >= 0) {
747 glyphsetCache[prev_i].next = glyphsetCache[i].next;
748 glyphsetCache[i].next = mru;
749 mru = i;
750 }
751 TRACE("found font in cache %d\n", i);
752 return i;
753 }
754 prev_i = i;
755 }
756 TRACE("font not in cache\n");
757 return -1;
758 }
759
760 static void FreeEntry(int entry)
761 {
762 int format;
763
764 for(format = 0; format < AA_MAXVALUE; format++) {
765 gsCacheEntryFormat * formatEntry;
766
767 if( !glyphsetCache[entry].format[format] )
768 continue;
769
770 formatEntry = glyphsetCache[entry].format[format];
771
772 if(formatEntry->glyphset) {
773 wine_tsx11_lock();
774 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
775 wine_tsx11_unlock();
776 formatEntry->glyphset = 0;
777 }
778 if(formatEntry->nrealized) {
779 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
780 formatEntry->realized = NULL;
781 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
782 formatEntry->gis = NULL;
783 formatEntry->nrealized = 0;
784 }
785
786 HeapFree(GetProcessHeap(), 0, formatEntry);
787 glyphsetCache[entry].format[format] = NULL;
788 }
789 }
790
791 static int AllocEntry(void)
792 {
793 int best = -1, prev_best = -1, i, prev_i = -1;
794
795 if(lastfree >= 0) {
796 assert(glyphsetCache[lastfree].count == -1);
797 glyphsetCache[lastfree].count = 1;
798 best = lastfree;
799 lastfree = glyphsetCache[lastfree].next;
800 assert(best != mru);
801 glyphsetCache[best].next = mru;
802 mru = best;
803
804 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
805 return mru;
806 }
807
808 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
809 if(glyphsetCache[i].count == 0) {
810 best = i;
811 prev_best = prev_i;
812 }
813 prev_i = i;
814 }
815
816 if(best >= 0) {
817 TRACE("freeing unused glyphset at cache %d\n", best);
818 FreeEntry(best);
819 glyphsetCache[best].count = 1;
820 if(prev_best >= 0) {
821 glyphsetCache[prev_best].next = glyphsetCache[best].next;
822 glyphsetCache[best].next = mru;
823 mru = best;
824 } else {
825 assert(mru == best);
826 }
827 return mru;
828 }
829
830 TRACE("Growing cache\n");
831
832 if (glyphsetCache)
833 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
834 glyphsetCache,
835 (glyphsetCacheSize + INIT_CACHE_SIZE)
836 * sizeof(*glyphsetCache));
837 else
838 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
839 (glyphsetCacheSize + INIT_CACHE_SIZE)
840 * sizeof(*glyphsetCache));
841
842 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
843 i++) {
844 glyphsetCache[i].next = i + 1;
845 glyphsetCache[i].count = -1;
846 }
847 glyphsetCache[i-1].next = -1;
848 glyphsetCacheSize += INIT_CACHE_SIZE;
849
850 lastfree = glyphsetCache[best].next;
851 glyphsetCache[best].count = 1;
852 glyphsetCache[best].next = mru;
853 mru = best;
854 TRACE("new free cache slot at %d\n", mru);
855 return mru;
856 }
857
858 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
859 {
860 DWORD size;
861 WORD *gasp, *buffer;
862 WORD num_recs;
863 DWORD ppem;
864 TEXTMETRICW tm;
865
866 *flags = 0;
867
868 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
869 if(size == GDI_ERROR)
870 return FALSE;
871
872 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
873 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
874
875 GetTextMetricsW(hdc, &tm);
876 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
877
878 gasp++;
879 num_recs = get_be_word(*gasp);
880 gasp++;
881 while(num_recs--)
882 {
883 *flags = get_be_word(*(gasp + 1));
884 if(ppem <= get_be_word(*gasp))
885 break;
886 gasp += 2;
887 }
888 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
889
890 HeapFree(GetProcessHeap(), 0, buffer);
891 return TRUE;
892 }
893
894 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
895 {
896 AA_Type ret;
897 WORD flags;
898 UINT font_smoothing_type, font_smoothing_orientation;
899
900 if (X11DRV_XRender_Installed && subpixel &&
901 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
902 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
903 {
904 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
905 &font_smoothing_orientation, 0) &&
906 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
907 {
908 ret = AA_BGR;
909 }
910 else
911 ret = AA_RGB;
912 /*FIXME
913 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
914 But, Wine's subpixel rendering can support the portrait mode.
915 */
916 }
917 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
918 ret = AA_Grey;
919 else
920 ret = AA_None;
921
922 return ret;
923 }
924
925 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
926 {
927 int ret;
928 int format;
929 gsCacheEntry *entry;
930 static int hinter = -1;
931 static int subpixel = -1;
932 BOOL font_smoothing;
933
934 if((ret = LookupEntry(plfsz)) != -1) return ret;
935
936 ret = AllocEntry();
937 entry = glyphsetCache + ret;
938 entry->lfsz = *plfsz;
939 for( format = 0; format < AA_MAXVALUE; format++ ) {
940 assert( !entry->format[format] );
941 }
942
943 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
944 {
945 if(hinter == -1 || subpixel == -1)
946 {
947 RASTERIZER_STATUS status;
948 GetRasterizerCaps(&status, sizeof(status));
949 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
950 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
951 }
952
953 switch (plfsz->lf.lfQuality)
954 {
955 case ANTIALIASED_QUALITY:
956 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
957 return ret; /* ignore further configuration */
958 case CLEARTYPE_QUALITY:
959 case CLEARTYPE_NATURAL_QUALITY:
960 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
961 break;
962 case DEFAULT_QUALITY:
963 case DRAFT_QUALITY:
964 case PROOF_QUALITY:
965 default:
966 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
967 font_smoothing)
968 {
969 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
970 }
971 else
972 entry->aa_default = AA_None;
973 break;
974 }
975
976 font_smoothing = TRUE; /* default to enabled */
977 #ifdef SONAME_LIBFONTCONFIG
978 if (fontconfig_installed)
979 {
980 FcPattern *match, *pattern;
981 FcResult result;
982 char family[LF_FACESIZE * 4];
983
984 #if defined(__i386__) && defined(__GNUC__)
985 /* fontconfig generates floating point exceptions, mask them */
986 WORD cw, default_cw = 0x37f;
987 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
988 #endif
989
990 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
991 pattern = pFcPatternCreate();
992 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
993 if (plfsz->lf.lfWeight != FW_DONTCARE)
994 {
995 int weight;
996 switch (plfsz->lf.lfWeight)
997 {
998 case FW_THIN: weight = FC_WEIGHT_THIN; break;
999 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
1000 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
1001 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
1002 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
1003 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
1004 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
1005 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
1006 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
1007 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
1008 }
1009 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
1010 }
1011 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
1012 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1013 pFcDefaultSubstitute( pattern );
1014 if ((match = pFcFontMatch( NULL, pattern, &result )))
1015 {
1016 int rgba;
1017 FcBool antialias;
1018
1019 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
1020 antialias = TRUE;
1021 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
1022 {
1023 FcChar8 *file;
1024 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
1025
1026 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
1027 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
1028
1029 switch (rgba)
1030 {
1031 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
1032 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
1033 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1034 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1035 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1036 }
1037 }
1038 if (!antialias) font_smoothing = FALSE;
1039 pFcPatternDestroy( match );
1040 }
1041 pFcPatternDestroy( pattern );
1042
1043 #if defined(__i386__) && defined(__GNUC__)
1044 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
1045 #endif
1046 }
1047 #endif /* SONAME_LIBFONTCONFIG */
1048
1049 /* now check Xft resources */
1050 {
1051 char *value;
1052 BOOL antialias = TRUE;
1053
1054 wine_tsx11_lock();
1055 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1056 {
1057 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1058 value[0] == '' || !strcasecmp( value, "off" ))
1059 antialias = FALSE;
1060 }
1061 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1062 {
1063 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1064 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1065 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1066 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1067 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1068 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1069 }
1070 wine_tsx11_unlock();
1071 if (!antialias) font_smoothing = FALSE;
1072 }
1073
1074 if (!font_smoothing) entry->aa_default = AA_None;
1075
1076 /* we can't support subpixel without xrender */
1077 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1078 }
1079 else
1080 entry->aa_default = AA_None;
1081
1082 return ret;
1083 }
1084
1085 static void dec_ref_cache(int index)
1086 {
1087 assert(index >= 0);
1088 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1089 assert(glyphsetCache[index].count > 0);
1090 glyphsetCache[index].count--;
1091 }
1092
1093 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1094 {
1095 DWORD hash = 0, *ptr, two_chars;
1096 WORD *pwc;
1097 int i;
1098
1099 hash ^= plfsz->devsize.cx;
1100 hash ^= plfsz->devsize.cy;
1101 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1102 hash ^= *ptr;
1103 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1104 hash ^= *ptr;
1105 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1106 two_chars = *ptr;
1107 pwc = (WCHAR *)&two_chars;
1108 if(!*pwc) break;
1109 *pwc = toupperW(*pwc);
1110 pwc++;
1111 *pwc = toupperW(*pwc);
1112 hash ^= two_chars;
1113 if(!*pwc) break;
1114 }
1115 plfsz->hash = hash;
1116 return;
1117 }
1118
1119 /***********************************************************************
1120 * X11DRV_XRender_Finalize
1121 */
1122 void X11DRV_XRender_Finalize(void)
1123 {
1124 int i;
1125
1126 EnterCriticalSection(&xrender_cs);
1127 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1128 FreeEntry(i);
1129 LeaveCriticalSection(&xrender_cs);
1130 DeleteCriticalSection(&xrender_cs);
1131 }
1132
1133 /**********************************************************************
1134 * xrenderdrv_SelectFont
1135 */
1136 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1137 {
1138 struct xrender_physdev *physdev = get_xrender_dev( dev );
1139 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1140 HFONT ret = next->funcs->pSelectFont( next, hfont );
1141
1142 if (!ret) return 0;
1143
1144 if (physdev->x11dev->has_gdi_font)
1145 {
1146 LFANDSIZE lfsz;
1147
1148 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1149
1150 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1151 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1152 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1153 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1154 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1155 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1156
1157 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1158 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1159 lfsz.xform.eM21, lfsz.xform.eM22);
1160
1161 /* Not used fields, would break hashing */
1162 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1163
1164 lfsz_calc_hash(&lfsz);
1165
1166 EnterCriticalSection(&xrender_cs);
1167 if (physdev->cache_index != -1)
1168 dec_ref_cache( physdev->cache_index );
1169 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1170 LeaveCriticalSection(&xrender_cs);
1171 }
1172 else
1173 {
1174 EnterCriticalSection( &xrender_cs );
1175 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1176 physdev->cache_index = -1;
1177 LeaveCriticalSection( &xrender_cs );
1178 }
1179 return ret;
1180 }
1181
1182 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1183 {
1184 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1185 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1186
1187 if (!physdev) return FALSE;
1188 physdev->x11dev = x11dev;
1189 physdev->cache_index = -1;
1190 physdev->format = format;
1191 physdev->pict_format = pict_formats[format];
1192 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1193 return TRUE;
1194 }
1195
1196 /* store the color mask data in the bitmap info structure */
1197 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1198 {
1199 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1200
1201 info->bmiHeader.biPlanes = 1;
1202 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1203 info->bmiHeader.biCompression = BI_RGB;
1204 info->bmiHeader.biClrUsed = 0;
1205
1206 switch (info->bmiHeader.biBitCount)
1207 {
1208 case 16:
1209 colors[0] = format->direct.redMask << format->direct.red;
1210 colors[1] = format->direct.greenMask << format->direct.green;
1211 colors[2] = format->direct.blueMask << format->direct.blue;
1212 info->bmiHeader.biCompression = BI_BITFIELDS;
1213 break;
1214 case 32:
1215 colors[0] = format->direct.redMask << format->direct.red;
1216 colors[1] = format->direct.greenMask << format->direct.green;
1217 colors[2] = format->direct.blueMask << format->direct.blue;
1218 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1219 info->bmiHeader.biCompression = BI_BITFIELDS;
1220 break;
1221 }
1222 }
1223
1224
1225 /**********************************************************************
1226 * xrenderdrv_CreateDC
1227 */
1228 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1229 LPCWSTR output, const DEVMODEW* initData )
1230 {
1231 return create_xrender_dc( pdev, default_format );
1232 }
1233
1234 /**********************************************************************
1235 * xrenderdrv_CreateCompatibleDC
1236 */
1237 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1238 {
1239 if (orig) /* chain to x11drv first */
1240 {
1241 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1242 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1243 }
1244 /* otherwise we have been called by x11drv */
1245
1246 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1247 }
1248
1249 /**********************************************************************
1250 * xrenderdrv_DeleteDC
1251 */
1252 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1253 {
1254 struct xrender_physdev *physdev = get_xrender_dev( dev );
1255
1256 free_xrender_picture( physdev );
1257
1258 EnterCriticalSection( &xrender_cs );
1259 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1260 LeaveCriticalSection( &xrender_cs );
1261
1262 HeapFree( GetProcessHeap(), 0, physdev );
1263 return TRUE;
1264 }
1265
1266 /**********************************************************************
1267 * xrenderdrv_ExtEscape
1268 */
1269 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1270 INT out_count, LPVOID out_data )
1271 {
1272 struct xrender_physdev *physdev = get_xrender_dev( dev );
1273
1274 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1275
1276 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1277 {
1278 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1279 {
1280 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1281 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1282 return ret;
1283 }
1284 }
1285 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1286 }
1287
1288 /****************************************************************************
1289 * xrenderdrv_CopyBitmap
1290 */
1291 static BOOL xrenderdrv_CopyBitmap( HBITMAP src, HBITMAP dst )
1292 {
1293 return X11DRV_CopyBitmap( src, dst );
1294 }
1295
1296 /****************************************************************************
1297 * xrenderdrv_CreateBitmap
1298 */
1299 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1300 {
1301 enum wxr_format format;
1302 BITMAP bitmap;
1303
1304 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1305
1306 format = get_bitmap_format( bitmap.bmBitsPixel );
1307
1308 if (pict_formats[format])
1309 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth,
1310 TRUE, &wxr_color_shifts[format] );
1311
1312 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1313 return dev->funcs->pCreateBitmap( dev, hbitmap );
1314 }
1315
1316 /****************************************************************************
1317 * xrenderdrv_DeleteBitmap
1318 */
1319 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1320 {
1321 return X11DRV_DeleteBitmap( hbitmap );
1322 }
1323
1324 /***********************************************************************
1325 * xrenderdrv_SelectBitmap
1326 */
1327 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1328 {
1329 HBITMAP ret;
1330 struct xrender_physdev *physdev = get_xrender_dev( dev );
1331
1332 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1333 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1334 if (ret)
1335 {
1336 free_xrender_picture( physdev );
1337 physdev->format = get_xrender_format_from_color_shifts( physdev->x11dev->depth,
1338 physdev->x11dev->color_shifts );
1339 physdev->pict_format = pict_formats[physdev->format];
1340 }
1341 return ret;
1342 }
1343
1344 /***********************************************************************
1345 * xrenderdrv_GetImage
1346 */
1347 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1348 struct gdi_image_bits *bits, struct bitblt_coords *src )
1349 {
1350 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1351 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1352 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1353 }
1354
1355 /***********************************************************************
1356 * xrenderdrv_SetDeviceClipping
1357 */
1358 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1359 {
1360 struct xrender_physdev *physdev = get_xrender_dev( dev );
1361
1362 physdev->update_clip = TRUE;
1363
1364 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1365 dev->funcs->pSetDeviceClipping( dev, rgn );
1366 }
1367
1368
1369 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1370 {
1371 XRenderPictFormat *pict_format;
1372 ColorShifts shifts;
1373 const DWORD *bitfields;
1374 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1375 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1376
1377
1378 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1379 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1380 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1381 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1382 return FALSE;
1383
1384 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1385 bitfields = dib->dsBitfields;
1386 else if(bits_pixel == 24 || bits_pixel == 32)
1387 bitfields = bitfields_32;
1388 else
1389 bitfields = bitfields_16;
1390
1391 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1392 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1393
1394 /* Common formats should be in our picture format table. */
1395 if (!pict_format)
1396 {
1397 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1398 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1399 return FALSE;
1400 }
1401
1402 physBitmap->depth = pict_format->depth;
1403 physBitmap->trueColor = TRUE;
1404 physBitmap->color_shifts = shifts;
1405 return TRUE;
1406 }
1407
1408 /************************************************************************
1409 * UploadGlyph
1410 *
1411 * Helper to ExtTextOut. Must be called inside xrender_cs
1412 */
1413 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1414 {
1415 unsigned int buflen;
1416 char *buf;
1417 Glyph gid;
1418 GLYPHMETRICS gm;
1419 XGlyphInfo gi;
1420 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1421 gsCacheEntryFormat *formatEntry;
1422 UINT ggo_format = GGO_GLYPH_INDEX;
1423 enum wxr_format wxr_format;
1424 static const char zero[4];
1425 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1426
1427 switch(format) {
1428 case AA_Grey:
1429 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1430 break;
1431 case AA_RGB:
1432 ggo_format |= WINE_GGO_HRGB_BITMAP;
1433 break;
1434 case AA_BGR:
1435 ggo_format |= WINE_GGO_HBGR_BITMAP;
1436 break;
1437 case AA_VRGB:
1438 ggo_format |= WINE_GGO_VRGB_BITMAP;
1439 break;
1440 case AA_VBGR:
1441 ggo_format |= WINE_GGO_VBGR_BITMAP;
1442 break;
1443
1444 default:
1445 ERR("aa = %d - not implemented\n", format);
1446 case AA_None:
1447 ggo_format |= GGO_BITMAP;
1448 break;
1449 }
1450
1451 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1452 if(buflen == GDI_ERROR) {
1453 if(format != AA_None) {
1454 format = AA_None;
1455 entry->aa_default = AA_None;
1456 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1457 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1458 }
1459 if(buflen == GDI_ERROR) {
1460 WARN("GetGlyphOutlineW failed using default glyph\n");
1461 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1462 if(buflen == GDI_ERROR) {
1463 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1464 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1465 if(buflen == GDI_ERROR) {
1466 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1467 return;
1468 }
1469 }
1470 }
1471 TRACE("Turning off antialiasing for this monochrome font\n");
1472 }
1473
1474 /* If there is nothing for the current type, we create the entry. */
1475 if( !entry->format[format] ) {
1476 entry->format[format] = HeapAlloc(GetProcessHeap(),
1477 HEAP_ZERO_MEMORY,
1478 sizeof(gsCacheEntryFormat));
1479 }
1480 formatEntry = entry->format[format];
1481
1482 if(formatEntry->nrealized <= glyph) {
1483 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1484
1485 if (formatEntry->realized)
1486 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1487 HEAP_ZERO_MEMORY,
1488 formatEntry->realized,
1489 formatEntry->nrealized * sizeof(BOOL));
1490 else
1491 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1492 HEAP_ZERO_MEMORY,
1493 formatEntry->nrealized * sizeof(BOOL));
1494
1495 if (formatEntry->gis)
1496 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1497 HEAP_ZERO_MEMORY,
1498 formatEntry->gis,
1499 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1500 else
1501 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1502 HEAP_ZERO_MEMORY,
1503 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1504 }
1505
1506
1507 if(formatEntry->glyphset == 0) {
1508 switch(format) {
1509 case AA_Grey:
1510 wxr_format = WXR_FORMAT_GRAY;
1511 break;
1512
1513 case AA_RGB:
1514 case AA_BGR:
1515 case AA_VRGB:
1516 case AA_VBGR:
1517 wxr_format = WXR_FORMAT_A8R8G8B8;
1518 break;
1519
1520 default:
1521 ERR("aa = %d - not implemented\n", format);
1522 case AA_None:
1523 wxr_format = WXR_FORMAT_MONO;
1524 break;
1525 }
1526
1527 wine_tsx11_lock();
1528 formatEntry->font_format = pict_formats[wxr_format];
1529 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1530 wine_tsx11_unlock();
1531 }
1532
1533
1534 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1535 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1536 formatEntry->realized[glyph] = TRUE;
1537
1538 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1539 buflen,
1540 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1541 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1542
1543 gi.width = gm.gmBlackBoxX;
1544 gi.height = gm.gmBlackBoxY;
1545 gi.x = -gm.gmptGlyphOrigin.x;
1546 gi.y = gm.gmptGlyphOrigin.y;
1547 gi.xOff = gm.gmCellIncX;
1548 gi.yOff = gm.gmCellIncY;
1549
1550 if(TRACE_ON(xrender)) {
1551 int pitch, i, j;
1552 char output[300];
1553 unsigned char *line;
1554
1555 if(format == AA_None) {
1556 pitch = ((gi.width + 31) / 32) * 4;
1557 for(i = 0; i < gi.height; i++) {
1558 line = (unsigned char*) buf + i * pitch;
1559 output[0] = '\0';
1560 for(j = 0; j < pitch * 8; j++) {
1561 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1562 }
1563 TRACE("%s\n", output);
1564 }
1565 } else {
1566 static const char blks[] = " .:;!o*#";
1567 char str[2];
1568
1569 str[1] = '\0';
1570 pitch = ((gi.width + 3) / 4) * 4;
1571 for(i = 0; i < gi.height; i++) {
1572 line = (unsigned char*) buf + i * pitch;
1573 output[0] = '\0';
1574 for(j = 0; j < pitch; j++) {
1575 str[0] = blks[line[j] >> 5];
1576 strcat(output, str);
1577 }
1578 TRACE("%s\n", output);
1579 }
1580 }
1581 }
1582
1583
1584 if(formatEntry->glyphset) {
1585 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1586 unsigned char *byte = (unsigned char*) buf, c;
1587 int i = buflen;
1588
1589 while(i--) {
1590 c = *byte;
1591
1592 /* magic to flip bit order */
1593 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1594 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1595 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1596
1597 *byte++ = c;
1598 }
1599 }
1600 else if ( format != AA_Grey &&
1601 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1602 {
1603 unsigned int i, *data = (unsigned int *)buf;
1604 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1605 }
1606 gid = glyph;
1607
1608 /*
1609 XRenderCompositeText seems to ignore 0x0 glyphs when
1610 AA_None, which means we lose the advance width of glyphs
1611 like the space. We'll pretend that such glyphs are 1x1
1612 bitmaps.
1613 */
1614
1615 if(buflen == 0)
1616 gi.width = gi.height = 1;
1617
1618 wine_tsx11_lock();
1619 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1620 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1621 wine_tsx11_unlock();
1622 HeapFree(GetProcessHeap(), 0, buf);
1623 }
1624
1625 formatEntry->gis[glyph] = gi;
1626 }
1627
1628 /*************************************************************
1629 * get_tile_pict
1630 *
1631 * Returns an appropriate Picture for tiling the text colour.
1632 * Call and use result within the xrender_cs
1633 */
1634 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1635 {
1636 static struct
1637 {
1638 Pixmap xpm;
1639 Picture pict;
1640 XRenderColor current_color;
1641 } tiles[WXR_NB_FORMATS], *tile;
1642
1643 tile = &tiles[wxr_format];
1644
1645 if(!tile->xpm)
1646 {
1647 XRenderPictureAttributes pa;
1648 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1649
1650 wine_tsx11_lock();
1651 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1652
1653 pa.repeat = RepeatNormal;
1654 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1655 wine_tsx11_unlock();
1656
1657 /* init current_color to something different from text_pixel */
1658 tile->current_color = *color;
1659 tile->current_color.red ^= 0xffff;
1660
1661 if (wxr_format == WXR_FORMAT_MONO)
1662 {
1663 /* for a 1bpp bitmap we always need a 1 in the tile */
1664 XRenderColor col;
1665 col.red = col.green = col.blue = 0;
1666 col.alpha = 0xffff;
1667 wine_tsx11_lock();
1668 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1669 wine_tsx11_unlock();
1670 }
1671 }
1672
1673 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1674 {
1675 wine_tsx11_lock();
1676 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1677 wine_tsx11_unlock();
1678 tile->current_color = *color;
1679 }
1680 return tile->pict;
1681 }
1682
1683 /*************************************************************
1684 * get_mask_pict
1685 *
1686 * Returns an appropriate Picture for masking with the specified alpha.
1687 * Call and use result within the xrender_cs
1688 */
1689 static Picture get_mask_pict( int alpha )
1690 {
1691 static Pixmap pixmap;
1692 static Picture pict;
1693 static int current_alpha;
1694
1695 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1696
1697 if (!pixmap)
1698 {
1699 XRenderPictureAttributes pa;
1700
1701 wine_tsx11_lock();
1702 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1703 pa.repeat = RepeatNormal;
1704 pict = pXRenderCreatePicture( gdi_display, pixmap,
1705 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1706 wine_tsx11_unlock();
1707 current_alpha = -1;
1708 }
1709
1710 if (alpha != current_alpha)
1711 {
1712 XRenderColor col;
1713 col.red = col.green = col.blue = 0;
1714 col.alpha = current_alpha = alpha;
1715 wine_tsx11_lock();
1716 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1717 wine_tsx11_unlock();
1718 }
1719 return pict;
1720 }
1721
1722 /***********************************************************************
1723 * xrenderdrv_ExtTextOut
1724 */
1725 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1726 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1727 {
1728 struct xrender_physdev *physdev = get_xrender_dev( dev );
1729 XGCValues xgcval;
1730 gsCacheEntry *entry;
1731 gsCacheEntryFormat *formatEntry;
1732 int textPixel, backgroundPixel;
1733 AA_Type aa_type = AA_None;
1734 unsigned int idx;
1735 Picture pict, tile_pict = 0;
1736 XGlyphElt16 *elts;
1737 POINT offset, desired, current;
1738 int render_op = PictOpOver;
1739 XRenderColor col;
1740
1741 if (!X11DRV_XRender_Installed || !physdev->x11dev->has_gdi_font)
1742 {
1743 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1744 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1745 }
1746
1747 xgcval.function = GXcopy;
1748 xgcval.background = physdev->x11dev->backgroundPixel;
1749 xgcval.fill_style = FillSolid;
1750 wine_tsx11_lock();
1751 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1752 wine_tsx11_unlock();
1753
1754 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
1755
1756 if(physdev->x11dev->depth == 1) {
1757 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1758 textPixel = 0;
1759 backgroundPixel = 1;
1760 } else {
1761 textPixel = 1;
1762 backgroundPixel = 0;
1763 }
1764 } else {
1765 textPixel = physdev->x11dev->textPixel;
1766 backgroundPixel = physdev->x11dev->backgroundPixel;
1767 }
1768
1769 if(flags & ETO_OPAQUE)
1770 {
1771 wine_tsx11_lock();
1772 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
1773 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
1774 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
1775 lprect->right - lprect->left, lprect->bottom - lprect->top );
1776 wine_tsx11_unlock();
1777 }
1778
1779 if(count == 0)
1780 {
1781 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1782 return TRUE;
1783 }
1784
1785 EnterCriticalSection(&xrender_cs);
1786
1787 entry = glyphsetCache + physdev->cache_index;
1788 aa_type = entry->aa_default;
1789 formatEntry = entry->format[aa_type];
1790
1791 for(idx = 0; idx < count; idx++) {
1792 if( !formatEntry ) {
1793 UploadGlyph(physdev, wstr[idx], aa_type);
1794 /* re-evaluate antialias since aa_default may have changed */
1795 aa_type = entry->aa_default;
1796 formatEntry = entry->format[aa_type];
1797 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1798 UploadGlyph(physdev, wstr[idx], aa_type);
1799 }
1800 }
1801 if (!formatEntry)
1802 {
1803 WARN("could not upload requested glyphs\n");
1804 LeaveCriticalSection(&xrender_cs);
1805 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1806 return FALSE;
1807 }
1808
1809 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1810 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1811
1812 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1813 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1814
1815 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1816 So we pass zeros to the function and move to our starting position using the first
1817 element of the elts array. */
1818
1819 desired.x = physdev->x11dev->dc_rect.left + x;
1820 desired.y = physdev->x11dev->dc_rect.top + y;
1821 offset.x = offset.y = 0;
1822 current.x = current.y = 0;
1823
1824 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
1825 tile_pict = get_tile_pict(physdev->format, &col);
1826
1827 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1828 */
1829 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
1830 render_op = PictOpOutReverse; /* This gives us 'black' text */
1831
1832 for(idx = 0; idx < count; idx++)
1833 {
1834 elts[idx].glyphset = formatEntry->glyphset;
1835 elts[idx].chars = wstr + idx;
1836 elts[idx].nchars = 1;
1837 elts[idx].xOff = desired.x - current.x;
1838 elts[idx].yOff = desired.y - current.y;
1839
1840 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1841 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1842
1843 if(!lpDx)
1844 {
1845 desired.x += formatEntry->gis[wstr[idx]].xOff;
1846 desired.y += formatEntry->gis[wstr[idx]].yOff;
1847 }
1848 else
1849 {
1850 if(flags & ETO_PDY)
1851 {
1852 offset.x += lpDx[idx * 2];
1853 offset.y += lpDx[idx * 2 + 1];
1854 }
1855 else
1856 offset.x += lpDx[idx];
1857 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1858 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1859 }
1860 }
1861
1862 wine_tsx11_lock();
1863 /* Make sure we don't have any transforms set from a previous call */
1864 set_xrender_transformation(pict, 1, 1, 0, 0);
1865 pXRenderCompositeText16(gdi_display, render_op,
1866 tile_pict,
1867 pict,
1868 formatEntry->font_format,
1869 0, 0, 0, 0, elts, count);
1870 wine_tsx11_unlock();
1871 HeapFree(GetProcessHeap(), 0, elts);
1872
1873 LeaveCriticalSection(&xrender_cs);
1874 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1875 return TRUE;
1876 }
1877
1878 /* multiply the alpha channel of a picture */
1879 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1880 int x, int y, int width, int height )
1881 {
1882 XRenderPictureAttributes pa;
1883 Pixmap src_pixmap, mask_pixmap;
1884 Picture src_pict, mask_pict;
1885 XRenderColor color;
1886
1887 wine_tsx11_lock();
1888 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1889 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1890 pa.repeat = RepeatNormal;
1891 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1892 pa.component_alpha = True;
1893 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1894 color.red = color.green = color.blue = color.alpha = 0xffff;
1895 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1896 color.alpha = alpha;
1897 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1898 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1899 0, 0, 0, 0, x, y, width, height );
1900 pXRenderFreePicture( gdi_display, src_pict );
1901 pXRenderFreePicture( gdi_display, mask_pict );
1902 XFreePixmap( gdi_display, src_pixmap );
1903 XFreePixmap( gdi_display, mask_pixmap );
1904 wine_tsx11_unlock();
1905 }
1906
1907 /* Helper function for (stretched) blitting using xrender */
1908 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1909 int x_src, int y_src, int x_dst, int y_dst,
1910 double xscale, double yscale, int width, int height )
1911 {
1912 int x_offset, y_offset;
1913
1914 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1915 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1916 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1917 wine_tsx11_lock();
1918 if(xscale != 1.0 || yscale != 1.0)
1919 {
1920 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1921 * in the wrong quadrant of the x-y plane.
1922 */
1923 x_offset = (xscale < 0) ? -width : 0;
1924 y_offset = (yscale < 0) ? -height : 0;
1925 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1926 }
1927 else
1928 {
1929 x_offset = x_src;
1930 y_offset = y_src;
1931 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1932 }
1933 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1934 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
1935 wine_tsx11_unlock();
1936 }
1937
1938 /* Helper function for (stretched) mono->color blitting using xrender */
1939 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1940 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1941 int x_src, int y_src, int x_dst, int y_dst,
1942 double xscale, double yscale, int width, int height )
1943 {
1944 Picture tile_pict;
1945 int x_offset, y_offset;
1946 XRenderColor color;
1947
1948 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1949 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1950 * the tile data.
1951 */
1952 EnterCriticalSection( &xrender_cs );
1953 color = *bg;
1954 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1955 tile_pict = get_tile_pict( dst_format, &color );
1956
1957 wine_tsx11_lock();
1958 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
1959
1960 if (xscale != 1.0 || yscale != 1.0)
1961 {
1962 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1963 * in the wrong quadrant of the x-y plane.
1964 */
1965 x_offset = (xscale < 0) ? -width : 0;
1966 y_offset = (yscale < 0) ? -height : 0;
1967 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1968 }
1969 else
1970 {
1971 x_offset = x_src;
1972 y_offset = y_src;
1973 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1974 }
1975 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1976 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
1977 wine_tsx11_unlock();
1978 LeaveCriticalSection( &xrender_cs );
1979
1980 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1981 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1982 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
1983 }
1984
1985 /* create a pixmap and render picture for an image */
1986 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1987 struct bitblt_coords *src, enum wxr_format format,
1988 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1989 {
1990 DWORD ret;
1991 int width = src->visrect.right - src->visrect.left;
1992 int height = src->visrect.bottom - src->visrect.top;
1993 int depth = pict_formats[format]->depth;
1994 struct gdi_image_bits dst_bits;
1995 XRenderPictureAttributes pa;
1996 XImage *image;
1997
1998 wine_tsx11_lock();
1999 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
2000 info->bmiHeader.biWidth, height, 32, 0 );
2001 wine_tsx11_unlock();
2002 if (!image) return ERROR_OUTOFMEMORY;
2003
2004 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
2005 if (ret) return ret;
2006
2007 image->data = dst_bits.ptr;
2008 /* hack: make sure the bits are readable if we are reading from a DIB section */
2009 /* to be removed once we get rid of DIB access protections */
2010 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2011
2012 *use_repeat = (width == 1 && height == 1);
2013 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2014
2015 wine_tsx11_lock();
2016 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2017 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2018 src->visrect.left, 0, 0, 0, width, height );
2019 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2020 wine_tsx11_unlock();
2021
2022 /* make coordinates relative to the pixmap */
2023 src->x -= src->visrect.left;
2024 src->y -= src->visrect.top;
2025 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2026
2027 image->data = NULL;
2028 wine_tsx11_lock();
2029 XDestroyImage( image );
2030 wine_tsx11_unlock();
2031 if (dst_bits.free) dst_bits.free( &dst_bits );
2032 return ret;
2033 }
2034
2035 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2036 Drawable drawable, const struct bitblt_coords *src,
2037 const struct bitblt_coords *dst )
2038 {
2039 int width = abs( dst->width );
2040 int height = abs( dst->height );
2041 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2042 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2043 int x_dst, y_dst;
2044 Picture src_pict = 0, dst_pict, mask_pict = 0;
2045 BOOL use_repeat;
2046 double xscale, yscale;
2047
2048 use_repeat = use_source_repeat( physdev_src );
2049 if (!use_repeat)
2050 {
2051 xscale = src->width / (double)dst->width;
2052 yscale = src->height / (double)dst->height;
2053 }
2054 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2055
2056 if (drawable) /* using an intermediate pixmap */
2057 {
2058 XRenderPictureAttributes pa;
2059
2060 x_dst = dst->x;
2061 y_dst = dst->y;
2062 pa.repeat = RepeatNone;
2063 wine_tsx11_lock();
2064 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2065 wine_tsx11_unlock();
2066 }
2067 else
2068 {
2069 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2070 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2071 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2072 }
2073
2074 if (src->width < 0) x_src += src->width + 1;
2075 if (src->height < 0) y_src += src->height + 1;
2076 if (dst->width < 0) x_dst += dst->width + 1;
2077 if (dst->height < 0) y_dst += dst->height + 1;
2078
2079 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2080
2081 /* mono -> color */
2082 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2083 {
2084 XRenderColor fg, bg;
2085
2086 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, &fg );
2087 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, &bg );
2088 fg.alpha = bg.alpha = 0;
2089
2090 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2091 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2092 }
2093 else /* color -> color (can be at different depths) or mono -> mono */
2094 {
2095 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2096 mask_pict = get_no_alpha_mask();
2097
2098 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2099 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2100 }
2101
2102 if (drawable)
2103 {
2104 wine_tsx11_lock();
2105 pXRenderFreePicture( gdi_display, dst_pict );
2106 wine_tsx11_unlock();
2107 }
2108 }
2109
2110
2111 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2112 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2113 Drawable drawable, struct bitblt_coords *src,
2114 struct bitblt_coords *dst, BOOL use_repeat )
2115 {
2116 int x_src, y_src, x_dst, y_dst;
2117 Picture dst_pict;
2118 XRenderPictureAttributes pa;
2119 double xscale, yscale;
2120
2121 if (drawable) /* using an intermediate pixmap */
2122 {
2123 RGNDATA *clip_data = NULL;
2124
2125 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2126 x_dst = dst->x;
2127 y_dst = dst->y;
2128 pa.repeat = RepeatNone;
2129 wine_tsx11_lock();
2130 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2131 if (clip_data)
2132 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2133 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2134 wine_tsx11_unlock();
2135 HeapFree( GetProcessHeap(), 0, clip_data );
2136 }
2137 else
2138 {
2139 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2140 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2141 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2142 }
2143
2144 if (!use_repeat)
2145 {
2146 xscale = src->width / (double)dst->width;
2147 yscale = src->height / (double)dst->height;
2148 }
2149 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2150
2151 x_src = src->x;
2152 y_src = src->y;
2153 if (src->width < 0) x_src += src->width + 1;
2154 if (src->height < 0) y_src += src->height + 1;
2155 if (dst->width < 0) x_dst += dst->width + 1;
2156 if (dst->height < 0) y_dst += dst->height + 1;
2157
2158 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2159 xscale, yscale, abs( dst->width ), abs( dst->height ));
2160
2161 if (drawable)
2162 {
2163 wine_tsx11_lock();
2164 pXRenderFreePicture( gdi_display, dst_pict );
2165 wine_tsx11_unlock();
2166 }
2167 }
2168
2169
2170 /***********************************************************************
2171 * xrenderdrv_StretchBlt
2172 */
2173 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2174 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2175 {
2176 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2177 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2178 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2179
2180 if (src_dev->funcs != dst_dev->funcs)
2181 {
2182 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2183 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2184 }
2185
2186 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2187
2188 /* XRender is of no use for color -> mono */
2189 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2190 goto x11drv_fallback;
2191
2192 /* if not stretching, we only need to handle format conversion */
2193 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2194
2195 if (rop != SRCCOPY)
2196 {
2197 GC tmpGC;
2198 Pixmap tmp_pixmap;
2199 struct bitblt_coords tmp;
2200
2201 /* make coordinates relative to tmp pixmap */
2202 tmp = *dst;
2203 tmp.x -= tmp.visrect.left;
2204 tmp.y -= tmp.visrect.top;
2205 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2206
2207 wine_tsx11_lock();
2208 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2209 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2210 XSetGraphicsExposures( gdi_display, tmpGC, False );
2211 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2212 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2213 wine_tsx11_unlock();
2214
2215 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2216 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2217
2218 wine_tsx11_lock();
2219 XFreePixmap( gdi_display, tmp_pixmap );
2220 XFreeGC( gdi_display, tmpGC );
2221 wine_tsx11_unlock();
2222 }
2223 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2224
2225 return TRUE;
2226
2227 x11drv_fallback:
2228 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2229 }
2230
2231
2232 /***********************************************************************
2233 * xrenderdrv_PutImage
2234 */
2235 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2236 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2237 struct bitblt_coords *dst, DWORD rop )
2238 {
2239 struct xrender_physdev *physdev;
2240 X_PHYSBITMAP *bitmap;
2241 DWORD ret;
2242 Pixmap tmp_pixmap;
2243 GC gc;
2244 enum wxr_format src_format, dst_format;
2245 XRenderPictFormat *pict_format;
2246 Pixmap src_pixmap;
2247 Picture src_pict, mask_pict = 0;
2248 BOOL use_repeat;
2249
2250 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2251
2252 if (hbitmap)
2253 {
2254 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2255 physdev = NULL;
2256 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2257 }
2258 else
2259 {
2260 physdev = get_xrender_dev( dev );
2261 bitmap = NULL;
2262 dst_format = physdev->format;
2263 }
2264
2265 src_format = get_xrender_format_from_bitmapinfo( info );
2266 if (!(pict_format = pict_formats[src_format])) goto update_format;
2267
2268 /* make sure we can create an image with the same bpp */
2269 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2270 goto update_format;
2271
2272 /* mono <-> color conversions not supported */
2273 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2274 goto x11drv_fallback;
2275
2276 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2277
2278 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2279
2280 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2281 if (!ret)
2282 {
2283 struct bitblt_coords tmp;
2284
2285 if (bitmap)
2286 {
2287 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2288 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2289
2290 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2291 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2292 DeleteObject( rgn );
2293 }
2294 else
2295 {
2296 if (rop != SRCCOPY)
2297 {
2298 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2299
2300 /* make coordinates relative to tmp pixmap */
2301 tmp = *dst;
2302 tmp.x -= tmp.visrect.left;
2303 tmp.y -= tmp.visrect.top;
2304 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2305
2306 wine_tsx11_lock();
2307 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2308 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2309 XSetGraphicsExposures( gdi_display, gc, False );
2310 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2311 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2312 wine_tsx11_unlock();
2313
2314 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2315 NULL, tmp_pixmap, src, &tmp, use_repeat );
2316 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2317
2318 wine_tsx11_lock();
2319 XFreePixmap( gdi_display, tmp_pixmap );
2320 XFreeGC( gdi_display, gc );
2321 wine_tsx11_unlock();
2322
2323 if (restore_region) restore_clipping_region( physdev->x11dev );
2324 }
2325 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2326 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2327 }
2328
2329 wine_tsx11_lock();
2330 pXRenderFreePicture( gdi_display, src_pict );
2331 XFreePixmap( gdi_display, src_pixmap );
2332 wine_tsx11_unlock();
2333 }
2334 return ret;
2335
2336 update_format:
2337 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2338 set_color_info( pict_formats[dst_format], info );
2339 return ERROR_BAD_FORMAT;
2340
2341 x11drv_fallback:
2342 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2343 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2344 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2345 }
2346
2347
2348 /***********************************************************************
2349 * xrenderdrv_BlendImage
2350 */
2351 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2352 struct bitblt_coords *src, struct bitblt_coords *dst,
2353 BLENDFUNCTION func )
2354 {
2355 struct xrender_physdev *physdev = get_xrender_dev( dev );
2356 DWORD ret;
2357 enum wxr_format format;
2358 XRenderPictFormat *pict_format;
2359 Picture dst_pict, src_pict, mask_pict;
2360 Pixmap src_pixmap;
2361 BOOL use_repeat;
2362
2363 if (!X11DRV_XRender_Installed)
2364 {
2365 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2366 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2367 }
2368
2369 format = get_xrender_format_from_bitmapinfo( info );
2370 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2371 format = get_format_without_alpha( format );
2372 else if (format != WXR_FORMAT_A8R8G8B8)
2373 return ERROR_INVALID_PARAMETER;
2374
2375 if (!(pict_format = pict_formats[format])) goto update_format;
2376
2377 /* make sure we can create an image with the same bpp */
2378 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2379 goto update_format;
2380
2381 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2382 goto update_format;
2383
2384 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2385
2386 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2387 if (!ret)
2388 {
2389 double xscale, yscale;
2390
2391 if (!use_repeat)
2392 {
2393 xscale = src->width / (double)dst->width;
2394 yscale = src->height / (double)dst->height;
2395 }
2396 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2397
2398 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2399
2400 EnterCriticalSection( &xrender_cs );
2401 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2402
2403 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2404 physdev->x11dev->dc_rect.left + dst->x,
2405 physdev->x11dev->dc_rect.top + dst->y,
2406 xscale, yscale, dst->width, dst->height );
2407
2408 wine_tsx11_lock();
2409 pXRenderFreePicture( gdi_display, src_pict );
2410 XFreePixmap( gdi_display, src_pixmap );
2411 wine_tsx11_unlock();
2412
2413 LeaveCriticalSection( &xrender_cs );
2414 }
2415 return ret;
2416
2417 update_format:
2418 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2419 set_color_info( physdev->pict_format, info );
2420 return ERROR_BAD_FORMAT;
2421 }
2422
2423
2424 /***********************************************************************
2425 * xrenderdrv_AlphaBlend
2426 */
2427 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2428 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2429 {
2430 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2431 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2432 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2433 XRenderPictureAttributes pa;
2434 Pixmap tmp_pixmap = 0;
2435 double xscale, yscale;
2436 BOOL use_repeat;
2437
2438 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2439 {
2440 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2441 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2442 }
2443
2444 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2445 {
2446 SetLastError( ERROR_INVALID_PARAMETER );
2447 return FALSE;
2448 }
2449
2450 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2451
2452 use_repeat = use_source_repeat( physdev_src );
2453 if (!use_repeat)
2454 {
2455 xscale = src->width / (double)dst->width;
2456 yscale = src->height / (double)dst->height;
2457 }
2458 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2459
2460 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2461
2462 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2463 {
2464 /* mono -> color blending needs an intermediate color pixmap */
2465 XRenderColor fg, bg;
2466 int width = src->visrect.right - src->visrect.left;
2467 int height = src->visrect.bottom - src->visrect.top;
2468
2469 /* blending doesn't use the destination DC colors */
2470 fg.red = fg.green = fg.blue = 0;
2471 bg.red = bg.green = bg.blue = 0xffff;
2472 fg.alpha = bg.alpha = 0xffff;
2473
2474 wine_tsx11_lock();
2475 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2476 physdev_dst->pict_format->depth );
2477 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2478 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2479 CPRepeat, &pa );
2480 wine_tsx11_unlock();
2481
2482 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2483 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2484 }
2485 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2486 {
2487 /* we need a source picture with no alpha */
2488 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2489 if (format != physdev_src->format)
2490 {
2491 wine_tsx11_lock();
2492 pa.subwindow_mode = IncludeInferiors;
2493 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2494 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2495 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2496 wine_tsx11_unlock();
2497 }
2498 }
2499
2500 if (tmp_pict) src_pict = tmp_pict;
2501
2502 EnterCriticalSection( &xrender_cs );
2503 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2504
2505 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2506 physdev_src->x11dev->dc_rect.left + src->x,
2507 physdev_src->x11dev->dc_rect.top + src->y,
2508 physdev_dst->x11dev->dc_rect.left + dst->x,
2509 physdev_dst->x11dev->dc_rect.top + dst->y,
2510 xscale, yscale, dst->width, dst->height );
2511
2512 wine_tsx11_lock();
2513 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2514 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2515 wine_tsx11_unlock();
2516
2517 LeaveCriticalSection( &xrender_cs );
2518 return TRUE;
2519 }
2520
2521 /***********************************************************************
2522 * xrenderdrv_GradientFill
2523 */
2524 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2525 void * grad_array, ULONG ngrad, ULONG mode )
2526 {
2527 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2528 static const XFixed stops[2] = { 0, 1 << 16 };
2529 struct xrender_physdev *physdev = get_xrender_dev( dev );
2530 XLinearGradient gradient;
2531 XRenderColor colors[2];
2532 Picture src_pict, dst_pict;
2533 unsigned int i;
2534 const GRADIENT_RECT *rect = grad_array;
2535 POINT pt[2];
2536
2537 if (!X11DRV_XRender_Installed) goto fallback;
2538 if (!pXRenderCreateLinearGradient) goto fallback;
2539
2540 /* <= 16-bpp uses dithering */
2541 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2542
2543 switch (mode)
2544 {
2545 case GRADIENT_FILL_RECT_H:
2546 case GRADIENT_FILL_RECT_V:
2547 for (i = 0; i < ngrad; i++, rect++)
2548 {
2549 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2550 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2551
2552 colors[0].red = v1->Red * 257 / 256;
2553 colors[0].green = v1->Green * 257 / 256;
2554 colors[0].blue = v1->Blue * 257 / 256;
2555 colors[1].red = v2->Red * 257 / 256;
2556 colors[1].green = v2->Green * 257 / 256;
2557 colors[1].blue = v2->Blue * 257 / 256;
2558 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2559 colors[0].alpha = colors[1].alpha = 65535;
2560
2561 pt[0].x = v1->x;
2562 pt[0].y = v1->y;
2563 pt[1].x = v2->x;
2564 pt[1].y = v2->y;
2565 LPtoDP( dev->hdc, pt, 2 );
2566 if (mode == GRADIENT_FILL_RECT_H)
2567 {
2568 gradient.p1.y = gradient.p2.y = 0;
2569 if (pt[1].x > pt[0].x)
2570 {
2571 gradient.p1.x = 0;
2572 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2573 }
2574 else
2575 {
2576 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2577 gradient.p2.x = 0;
2578 }
2579 }
2580 else
2581 {
2582 gradient.p1.x = gradient.p2.x = 0;
2583 if (pt[1].y > pt[0].y)
2584 {
2585 gradient.p1.y = 0;
2586 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2587 }
2588 else
2589 {
2590 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2591 gradient.p2.y = 0;
2592 }
2593 }
2594
2595 TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2596 mode, pt[0].x, pt[0].y, pt[1].x, pt[1].y,
2597 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2598 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2599
2600 dst_pict = get_xrender_picture( physdev, 0, NULL );
2601
2602 wine_tsx11_lock();
2603 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2604 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0,
2605 physdev->x11dev->dc_rect.left + min( pt[0].x, pt[1].x ),
2606 physdev->x11dev->dc_rect.top + min( pt[0].y, pt[1].y ),
2607 1, 1, abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y) );
2608 pXRenderFreePicture( gdi_display, src_pict );
2609 wine_tsx11_unlock();
2610 }
2611 return TRUE;
2612 }
2613
2614 fallback:
2615 #endif
2616 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2617 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2618 }
2619
2620 /***********************************************************************
2621 * xrenderdrv_SelectBrush
2622 */
2623 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2624 {
2625 struct xrender_physdev *physdev = get_xrender_dev( dev );
2626 X_PHYSBITMAP *physbitmap;
2627 enum wxr_format format;
2628 BOOL delete_bitmap = FALSE;
2629 BITMAP bm;
2630 HBITMAP bitmap;
2631 Pixmap pixmap;
2632 Picture src_pict, dst_pict;
2633 XRenderPictureAttributes pa;
2634
2635 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2636 if (!pattern) goto x11drv_fallback;
2637 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2638
2639 bitmap = pattern->bitmap;
2640 if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2641 {
2642 if (!(bitmap = create_brush_bitmap( physdev->x11dev, pattern ))) return 0;
2643 physbitmap = X11DRV_get_phys_bitmap( bitmap );
2644 delete_bitmap = TRUE;
2645 }
2646
2647 format = get_xrender_format_from_color_shifts( physbitmap->depth, &physbitmap->color_shifts );
2648 if (format == WXR_FORMAT_MONO || !pict_formats[format]) goto x11drv_fallback;
2649
2650 GetObjectW( bitmap, sizeof(bm), &bm );
2651
2652 X11DRV_DIB_Lock( physbitmap, DIB_Status_GdiMod );
2653
2654 wine_tsx11_lock();
2655 pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
2656 physdev->pict_format->depth );
2657
2658 pa.repeat = RepeatNone;
2659 src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_formats[format], CPRepeat, &pa);
2660 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
2661
2662 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, bm.bmWidth, bm.bmHeight );
2663 pXRenderFreePicture( gdi_display, src_pict );
2664 pXRenderFreePicture( gdi_display, dst_pict );
2665
2666 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2667 physdev->x11dev->brush.pixmap = pixmap;
2668 physdev->x11dev->brush.fillStyle = FillTiled;
2669 physdev->x11dev->brush.pixel = 0; /* ignored */
2670 physdev->x11dev->brush.style = BS_PATTERN;
2671 wine_tsx11_unlock();
2672
2673 X11DRV_DIB_Unlock( physbitmap, TRUE );
2674 if (delete_bitmap) DeleteObject( bitmap );
2675 return hbrush;
2676
2677 x11drv_fallback:
2678 if (delete_bitmap) DeleteObject( bitmap );
2679 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2680 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2681 }
2682
2683
2684 static const struct gdi_dc_funcs xrender_funcs =
2685 {
2686 NULL, /* pAbortDoc */
2687 NULL, /* pAbortPath */
2688 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2689 NULL, /* pAngleArc */
2690 NULL, /* pArc */
2691 NULL, /* pArcTo */
2692 NULL, /* pBeginPath */
2693 xrenderdrv_BlendImage, /* pBlendImage */
2694 NULL, /* pChoosePixelFormat */
2695 NULL, /* pChord */
2696 NULL, /* pCloseFigure */
2697 xrenderdrv_CopyBitmap, /* pCopyBitmap */
2698 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2699 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2700 xrenderdrv_CreateDC, /* pCreateDC */
2701 NULL, /* pCreateDIBSection */
2702 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
2703 xrenderdrv_DeleteDC, /* pDeleteDC */
2704 NULL, /* pDeleteObject */
2705 NULL, /* pDescribePixelFormat */
2706 NULL, /* pDeviceCapabilities */
2707 NULL, /* pEllipse */
2708 NULL, /* pEndDoc */
2709 NULL, /* pEndPage */
2710 NULL, /* pEndPath */
2711 NULL, /* pEnumFonts */
2712 NULL, /* pEnumICMProfiles */
2713 NULL, /* pExcludeClipRect */
2714 NULL, /* pExtDeviceMode */
2715 xrenderdrv_ExtEscape, /* pExtEscape */
2716 NULL, /* pExtFloodFill */
2717 NULL, /* pExtSelectClipRgn */
2718 xrenderdrv_ExtTextOut, /* pExtTextOut */
2719 NULL, /* pFillPath */
2720 NULL, /* pFillRgn */
2721 NULL, /* pFlattenPath */
2722 NULL, /* pFontIsLinked */
2723 NULL, /* pFrameRgn */
2724 NULL, /* pGdiComment */
2725 NULL, /* pGdiRealizationInfo */
2726 NULL, /* pGetCharABCWidths */
2727 NULL, /* pGetCharABCWidthsI */
2728 NULL, /* pGetCharWidth */
2729 NULL, /* pGetDeviceCaps */
2730 NULL, /* pGetDeviceGammaRamp */
2731 NULL, /* pGetFontData */
2732 NULL, /* pGetFontUnicodeRanges */
2733 NULL, /* pGetGlyphIndices */
2734 NULL, /* pGetGlyphOutline */
2735 NULL, /* pGetICMProfile */
2736 xrenderdrv_GetImage, /* pGetImage */
2737 NULL, /* pGetKerningPairs */
2738 NULL, /* pGetNearestColor */
2739 NULL, /* pGetOutlineTextMetrics */
2740 NULL, /* pGetPixel */
2741 NULL, /* pGetPixelFormat */
2742 NULL, /* pGetSystemPaletteEntries */
2743 NULL, /* pGetTextCharsetInfo */
2744 NULL, /* pGetTextExtentExPoint */
2745 NULL, /* pGetTextExtentExPointI */
2746 NULL, /* pGetTextFace */
2747 NULL, /* pGetTextMetrics */
2748 xrenderdrv_GradientFill, /* pGradientFill */
2749 NULL, /* pIntersectClipRect */
2750 NULL, /* pInvertRgn */
2751 NULL, /* pLineTo */
2752 NULL, /* pModifyWorldTransform */
2753 NULL, /* pMoveTo */
2754 NULL, /* pOffsetClipRgn */
2755 NULL, /* pOffsetViewportOrg */
2756 NULL, /* pOffsetWindowOrg */
2757 NULL, /* pPaintRgn */
2758 NULL, /* pPatBlt */
2759 NULL, /* pPie */
2760 NULL, /* pPolyBezier */
2761 NULL, /* pPolyBezierTo */
2762 NULL, /* pPolyDraw */
2763 NULL, /* pPolyPolygon */
2764 NULL, /* pPolyPolyline */
2765 NULL, /* pPolygon */
2766 NULL, /* pPolyline */
2767 NULL, /* pPolylineTo */
2768 xrenderdrv_PutImage, /* pPutImage */
2769 NULL, /* pRealizeDefaultPalette */
2770 NULL, /* pRealizePalette */
2771 NULL, /* pRectangle */
2772 NULL, /* pResetDC */
2773 NULL, /* pRestoreDC */
2774 NULL, /* pRoundRect */
2775 NULL, /* pSaveDC */
2776 NULL, /* pScaleViewportExt */
2777 NULL, /* pScaleWindowExt */
2778 xrenderdrv_SelectBitmap, /* pSelectBitmap */
2779 xrenderdrv_SelectBrush, /* pSelectBrush */
2780 NULL, /* pSelectClipPath */
2781 xrenderdrv_SelectFont, /* pSelectFont */
2782 NULL, /* pSelectPalette */
2783 NULL, /* pSelectPen */
2784 NULL, /* pSetArcDirection */
2785 NULL, /* pSetBkColor */
2786 NULL, /* pSetBkMode */
2787 NULL, /* pSetDCBrushColor */
2788 NULL, /* pSetDCPenColor */
2789 NULL, /* pSetDIBColorTable */
2790 NULL, /* pSetDIBitsToDevice */
2791 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2792 NULL, /* pSetDeviceGammaRamp */
2793 NULL, /* pSetLayout */
2794 NULL, /* pSetMapMode */
2795 NULL, /* pSetMapperFlags */
2796 NULL, /* pSetPixel */
2797 NULL, /* pSetPixelFormat */
2798 NULL, /* pSetPolyFillMode */
2799 NULL, /* pSetROP2 */
2800 NULL, /* pSetRelAbs */
2801 NULL, /* pSetStretchBltMode */
2802 NULL, /* pSetTextAlign */
2803 NULL, /* pSetTextCharacterExtra */
2804 NULL, /* pSetTextColor */
2805 NULL, /* pSetTextJustification */
2806 NULL, /* pSetViewportExt */
2807 NULL, /* pSetViewportOrg */
2808 NULL, /* pSetWindowExt */
2809 NULL, /* pSetWindowOrg */
2810 NULL, /* pSetWorldTransform */
2811 NULL, /* pStartDoc */
2812 NULL, /* pStartPage */
2813 xrenderdrv_StretchBlt, /* pStretchBlt */
2814 NULL, /* pStretchDIBits */
2815 NULL, /* pStrokeAndFillPath */
2816 NULL, /* pStrokePath */
2817 NULL, /* pSwapBuffers */
2818 NULL, /* pUnrealizePalette */
2819 NULL, /* pWidenPath */
2820 /* OpenGL not supported */
2821 };
2822
2823 #else /* SONAME_LIBXRENDER */
2824
2825 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2826 {
2827 TRACE("XRender support not compiled in.\n");
2828 return NULL;
2829 }
2830
2831 void X11DRV_XRender_Finalize(void)
2832 {
2833 }
2834
2835 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2836 {
2837 return FALSE;
2838 }
2839
2840 #endif /* SONAME_LIBXRENDER */
2841
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.