push cc8bc80451cc24f4d7cf75168b569f0ebfe19547
[wine/hacks.git] / dlls / winex11.drv / xrender.c
blobafe60cd3c6d8e039e8f7929d66ef94d2a89f9e62
1 /*
2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
6 * Some parts also:
7 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <stdlib.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "x11drv.h"
34 #include "winternl.h"
35 #include "wine/library.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 int using_client_side_fonts = FALSE;
41 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
43 #ifdef SONAME_LIBXRENDER
45 static BOOL X11DRV_XRender_Installed = FALSE;
47 #include <X11/Xlib.h>
48 #include <X11/extensions/Xrender.h>
50 #ifndef RepeatNone /* added in 0.10 */
51 #define RepeatNone 0
52 #define RepeatNormal 1
53 #define RepeatPad 2
54 #define RepeatReflect 3
55 #endif
57 enum drawable_depth_type {mono_drawable, color_drawable};
58 static XRenderPictFormat *pict_formats[2];
60 typedef struct
62 LOGFONTW lf;
63 XFORM xform;
64 SIZE devsize; /* size in device coords */
65 DWORD hash;
66 } LFANDSIZE;
68 #define INITIAL_REALIZED_BUF_SIZE 128
70 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
72 typedef struct
74 GlyphSet glyphset;
75 XRenderPictFormat *font_format;
76 int nrealized;
77 BOOL *realized;
78 void **bitmaps;
79 XGlyphInfo *gis;
80 } gsCacheEntryFormat;
82 typedef struct
84 LFANDSIZE lfsz;
85 AA_Type aa_default;
86 gsCacheEntryFormat * format[AA_MAXVALUE];
87 INT count;
88 INT next;
89 } gsCacheEntry;
91 struct tagXRENDERINFO
93 int cache_index;
94 Picture pict;
98 static gsCacheEntry *glyphsetCache = NULL;
99 static DWORD glyphsetCacheSize = 0;
100 static INT lastfree = -1;
101 static INT mru = -1;
103 #define INIT_CACHE_SIZE 10
105 static int antialias = 1;
107 static void *xrender_handle;
109 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
110 MAKE_FUNCPTR(XRenderAddGlyphs)
111 MAKE_FUNCPTR(XRenderComposite)
112 MAKE_FUNCPTR(XRenderCompositeString8)
113 MAKE_FUNCPTR(XRenderCompositeString16)
114 MAKE_FUNCPTR(XRenderCompositeString32)
115 MAKE_FUNCPTR(XRenderCompositeText16)
116 MAKE_FUNCPTR(XRenderCreateGlyphSet)
117 MAKE_FUNCPTR(XRenderCreatePicture)
118 MAKE_FUNCPTR(XRenderFillRectangle)
119 MAKE_FUNCPTR(XRenderFindFormat)
120 MAKE_FUNCPTR(XRenderFindVisualFormat)
121 MAKE_FUNCPTR(XRenderFreeGlyphSet)
122 MAKE_FUNCPTR(XRenderFreePicture)
123 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
124 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
125 MAKE_FUNCPTR(XRenderSetPictureTransform)
126 #endif
127 MAKE_FUNCPTR(XRenderQueryExtension)
128 #undef MAKE_FUNCPTR
130 static CRITICAL_SECTION xrender_cs;
131 static CRITICAL_SECTION_DEBUG critsect_debug =
133 0, 0, &xrender_cs,
134 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
135 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
137 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
139 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
140 ( ( (ULONG)_x4 << 24 ) | \
141 ( (ULONG)_x3 << 16 ) | \
142 ( (ULONG)_x2 << 8 ) | \
143 (ULONG)_x1 )
145 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
147 #define GASP_GRIDFIT 0x01
148 #define GASP_DOGRAY 0x02
150 #ifdef WORDS_BIGENDIAN
151 #define get_be_word(x) (x)
152 #define NATIVE_BYTE_ORDER MSBFirst
153 #else
154 #define get_be_word(x) RtlUshortByteSwap(x)
155 #define NATIVE_BYTE_ORDER LSBFirst
156 #endif
158 /***********************************************************************
159 * X11DRV_XRender_Init
161 * Let's see if our XServer has the extension available
164 void X11DRV_XRender_Init(void)
166 int event_base, i;
167 XRenderPictFormat pf;
169 if (client_side_with_render &&
170 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
171 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
172 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
175 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
176 LOAD_FUNCPTR(XRenderAddGlyphs)
177 LOAD_FUNCPTR(XRenderComposite)
178 LOAD_FUNCPTR(XRenderCompositeString8)
179 LOAD_FUNCPTR(XRenderCompositeString16)
180 LOAD_FUNCPTR(XRenderCompositeString32)
181 LOAD_FUNCPTR(XRenderCompositeText16)
182 LOAD_FUNCPTR(XRenderCreateGlyphSet)
183 LOAD_FUNCPTR(XRenderCreatePicture)
184 LOAD_FUNCPTR(XRenderFillRectangle)
185 LOAD_FUNCPTR(XRenderFindFormat)
186 LOAD_FUNCPTR(XRenderFindVisualFormat)
187 LOAD_FUNCPTR(XRenderFreeGlyphSet)
188 LOAD_FUNCPTR(XRenderFreePicture)
189 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
190 LOAD_FUNCPTR(XRenderQueryExtension)
191 #undef LOAD_FUNCPTR
192 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
193 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
194 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
195 #undef LOAD_OPTIONAL_FUNCPTR
196 #endif
199 wine_tsx11_lock();
200 if(pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) {
201 X11DRV_XRender_Installed = TRUE;
202 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
203 pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, visual);
204 if(!pict_formats[color_drawable])
206 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
207 if (visual->class == DirectColor)
209 XVisualInfo info;
210 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
211 screen_depth, TrueColor, &info ))
213 pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, info.visual);
214 if (pict_formats[color_drawable]) visual = info.visual;
218 if(!pict_formats[color_drawable]) /* This fails in buggy versions of libXrender.so */
220 wine_tsx11_unlock();
221 WINE_MESSAGE(
222 "Wine has detected that you probably have a buggy version\n"
223 "of libXrender.so . Because of this client side font rendering\n"
224 "will be disabled. Please upgrade this library.\n");
225 X11DRV_XRender_Installed = FALSE;
226 return;
228 pf.type = PictTypeDirect;
229 pf.depth = 1;
230 pf.direct.alpha = 0;
231 pf.direct.alphaMask = 1;
232 pict_formats[mono_drawable] = pXRenderFindFormat(gdi_display, PictFormatType |
233 PictFormatDepth | PictFormatAlpha |
234 PictFormatAlphaMask, &pf, 0);
235 if(!pict_formats[mono_drawable]) {
236 ERR("mono_format == NULL?\n");
237 X11DRV_XRender_Installed = FALSE;
239 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
240 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
241 X11DRV_XRender_Installed = FALSE;
244 wine_tsx11_unlock();
247 sym_not_found:
248 if(X11DRV_XRender_Installed || client_side_with_core)
250 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
251 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
253 glyphsetCacheSize = INIT_CACHE_SIZE;
254 lastfree = 0;
255 for(i = 0; i < INIT_CACHE_SIZE; i++) {
256 glyphsetCache[i].next = i + 1;
257 glyphsetCache[i].count = -1;
259 glyphsetCache[i-1].next = -1;
260 using_client_side_fonts = 1;
262 if(!X11DRV_XRender_Installed) {
263 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
264 if(screen_depth <= 8 || !client_side_antialias_with_core)
265 antialias = 0;
266 } else {
267 if(screen_depth <= 8 || !client_side_antialias_with_render)
268 antialias = 0;
271 else TRACE("Using X11 core fonts\n");
274 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
276 if(p1->hash != p2->hash) return TRUE;
277 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
278 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
279 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
280 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
283 #if 0
284 static void walk_cache(void)
286 int i;
288 EnterCriticalSection(&xrender_cs);
289 for(i=mru; i >= 0; i = glyphsetCache[i].next)
290 TRACE("item %d\n", i);
291 LeaveCriticalSection(&xrender_cs);
293 #endif
295 static int LookupEntry(LFANDSIZE *plfsz)
297 int i, prev_i = -1;
299 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
300 TRACE("%d\n", i);
301 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
302 i = -1;
303 break;
306 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
307 glyphsetCache[i].count++;
308 if(prev_i >= 0) {
309 glyphsetCache[prev_i].next = glyphsetCache[i].next;
310 glyphsetCache[i].next = mru;
311 mru = i;
313 TRACE("found font in cache %d\n", i);
314 return i;
316 prev_i = i;
318 TRACE("font not in cache\n");
319 return -1;
322 static void FreeEntry(int entry)
324 int i, format;
326 for(format = 0; format < AA_MAXVALUE; format++) {
327 gsCacheEntryFormat * formatEntry;
329 if( !glyphsetCache[entry].format[format] )
330 continue;
332 formatEntry = glyphsetCache[entry].format[format];
334 if(formatEntry->glyphset) {
335 wine_tsx11_lock();
336 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
337 wine_tsx11_unlock();
338 formatEntry->glyphset = 0;
340 if(formatEntry->nrealized) {
341 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
342 formatEntry->realized = NULL;
343 if(formatEntry->bitmaps) {
344 for(i = 0; i < formatEntry->nrealized; i++)
345 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
346 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
347 formatEntry->bitmaps = NULL;
349 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
350 formatEntry->gis = NULL;
351 formatEntry->nrealized = 0;
354 HeapFree(GetProcessHeap(), 0, formatEntry);
355 glyphsetCache[entry].format[format] = NULL;
359 static int AllocEntry(void)
361 int best = -1, prev_best = -1, i, prev_i = -1;
363 if(lastfree >= 0) {
364 assert(glyphsetCache[lastfree].count == -1);
365 glyphsetCache[lastfree].count = 1;
366 best = lastfree;
367 lastfree = glyphsetCache[lastfree].next;
368 assert(best != mru);
369 glyphsetCache[best].next = mru;
370 mru = best;
372 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
373 return mru;
376 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
377 if(glyphsetCache[i].count == 0) {
378 best = i;
379 prev_best = prev_i;
381 prev_i = i;
384 if(best >= 0) {
385 TRACE("freeing unused glyphset at cache %d\n", best);
386 FreeEntry(best);
387 glyphsetCache[best].count = 1;
388 if(prev_best >= 0) {
389 glyphsetCache[prev_best].next = glyphsetCache[best].next;
390 glyphsetCache[best].next = mru;
391 mru = best;
392 } else {
393 assert(mru == best);
395 return mru;
398 TRACE("Growing cache\n");
400 if (glyphsetCache)
401 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
402 glyphsetCache,
403 (glyphsetCacheSize + INIT_CACHE_SIZE)
404 * sizeof(*glyphsetCache));
405 else
406 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
407 (glyphsetCacheSize + INIT_CACHE_SIZE)
408 * sizeof(*glyphsetCache));
410 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
411 i++) {
412 glyphsetCache[i].next = i + 1;
413 glyphsetCache[i].count = -1;
415 glyphsetCache[i-1].next = -1;
416 glyphsetCacheSize += INIT_CACHE_SIZE;
418 lastfree = glyphsetCache[best].next;
419 glyphsetCache[best].count = 1;
420 glyphsetCache[best].next = mru;
421 mru = best;
422 TRACE("new free cache slot at %d\n", mru);
423 return mru;
426 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
428 DWORD size;
429 WORD *gasp, *buffer;
430 WORD num_recs;
431 DWORD ppem;
432 TEXTMETRICW tm;
434 *flags = 0;
436 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
437 if(size == GDI_ERROR)
438 return FALSE;
440 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
441 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
443 GetTextMetricsW(physDev->hdc, &tm);
444 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
446 gasp++;
447 num_recs = get_be_word(*gasp);
448 gasp++;
449 while(num_recs--)
451 *flags = get_be_word(*(gasp + 1));
452 if(ppem <= get_be_word(*gasp))
453 break;
454 gasp += 2;
456 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
458 HeapFree(GetProcessHeap(), 0, buffer);
459 return TRUE;
462 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
464 AA_Type ret;
465 WORD flags;
466 UINT font_smoothing_type, font_smoothing_orientation;
468 if (X11DRV_XRender_Installed && subpixel &&
469 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
470 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
472 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
473 &font_smoothing_orientation, 0) &&
474 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
476 ret = AA_BGR;
478 else
479 ret = AA_RGB;
480 /*FIXME
481 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
482 But, Wine's subpixel rendering can support the portrait mode.
485 else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
486 ret = AA_Grey;
487 else
488 ret = AA_None;
490 return ret;
493 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
495 int ret;
496 int format;
497 gsCacheEntry *entry;
498 static int hinter = -1;
499 static int subpixel = -1;
500 BOOL font_smoothing;
502 if((ret = LookupEntry(plfsz)) != -1) return ret;
504 ret = AllocEntry();
505 entry = glyphsetCache + ret;
506 entry->lfsz = *plfsz;
507 for( format = 0; format < AA_MAXVALUE; format++ ) {
508 assert( !entry->format[format] );
511 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
513 if(hinter == -1 || subpixel == -1)
515 RASTERIZER_STATUS status;
516 GetRasterizerCaps(&status, sizeof(status));
517 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
518 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
521 switch (plfsz->lf.lfQuality)
523 case ANTIALIASED_QUALITY:
524 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
525 break;
526 case CLEARTYPE_QUALITY:
527 case CLEARTYPE_NATURAL_QUALITY:
528 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
529 break;
530 case DEFAULT_QUALITY:
531 case DRAFT_QUALITY:
532 case PROOF_QUALITY:
533 default:
534 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
535 font_smoothing)
537 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
539 else
540 entry->aa_default = AA_None;
541 break;
544 else
545 entry->aa_default = AA_None;
547 return ret;
550 static void dec_ref_cache(int index)
552 assert(index >= 0);
553 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
554 assert(glyphsetCache[index].count > 0);
555 glyphsetCache[index].count--;
558 static void lfsz_calc_hash(LFANDSIZE *plfsz)
560 DWORD hash = 0, *ptr, two_chars;
561 WORD *pwc;
562 int i;
564 hash ^= plfsz->devsize.cx;
565 hash ^= plfsz->devsize.cy;
566 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
567 hash ^= *ptr;
568 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
569 hash ^= *ptr;
570 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
571 two_chars = *ptr;
572 pwc = (WCHAR *)&two_chars;
573 if(!*pwc) break;
574 *pwc = toupperW(*pwc);
575 pwc++;
576 *pwc = toupperW(*pwc);
577 hash ^= two_chars;
578 if(!*pwc) break;
580 plfsz->hash = hash;
581 return;
584 /***********************************************************************
585 * X11DRV_XRender_Finalize
587 void X11DRV_XRender_Finalize(void)
589 int i;
591 EnterCriticalSection(&xrender_cs);
592 for(i = mru; i >= 0; i = glyphsetCache[i].next)
593 FreeEntry(i);
594 LeaveCriticalSection(&xrender_cs);
598 /***********************************************************************
599 * X11DRV_XRender_SelectFont
601 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
603 LFANDSIZE lfsz;
605 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
606 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
607 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
608 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
609 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
610 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
611 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
612 GetWorldTransform( physDev->hdc, &lfsz.xform );
613 lfsz_calc_hash(&lfsz);
615 EnterCriticalSection(&xrender_cs);
616 if(!physDev->xrender) {
617 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
618 sizeof(*physDev->xrender));
619 physDev->xrender->cache_index = -1;
621 else if(physDev->xrender->cache_index != -1)
622 dec_ref_cache(physDev->xrender->cache_index);
623 physDev->xrender->cache_index = GetCacheEntry(physDev, &lfsz);
624 LeaveCriticalSection(&xrender_cs);
625 return 0;
628 /***********************************************************************
629 * X11DRV_XRender_DeleteDC
631 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
633 X11DRV_XRender_UpdateDrawable(physDev);
635 EnterCriticalSection(&xrender_cs);
636 if(physDev->xrender->cache_index != -1)
637 dec_ref_cache(physDev->xrender->cache_index);
638 LeaveCriticalSection(&xrender_cs);
640 HeapFree(GetProcessHeap(), 0, physDev->xrender);
641 physDev->xrender = NULL;
642 return;
645 /***********************************************************************
646 * X11DRV_XRender_UpdateDrawable
648 * Deletes the pict and tile when the drawable changes.
650 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
652 wine_tsx11_lock();
654 if(physDev->xrender->pict)
656 TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
657 XFlush(gdi_display);
658 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
659 physDev->xrender->pict = 0;
661 wine_tsx11_unlock();
663 return;
666 /************************************************************************
667 * UploadGlyph
669 * Helper to ExtTextOut. Must be called inside xrender_cs
671 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
673 unsigned int buflen;
674 char *buf;
675 Glyph gid;
676 GLYPHMETRICS gm;
677 XGlyphInfo gi;
678 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
679 gsCacheEntryFormat *formatEntry;
680 UINT ggo_format = GGO_GLYPH_INDEX;
681 XRenderPictFormat pf;
682 unsigned long pf_mask;
683 static const char zero[4];
684 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
686 switch(format) {
687 case AA_Grey:
688 ggo_format |= WINE_GGO_GRAY16_BITMAP;
689 break;
690 case AA_RGB:
691 ggo_format |= WINE_GGO_HRGB_BITMAP;
692 break;
693 case AA_BGR:
694 ggo_format |= WINE_GGO_HBGR_BITMAP;
695 break;
696 case AA_VRGB:
697 ggo_format |= WINE_GGO_VRGB_BITMAP;
698 break;
699 case AA_VBGR:
700 ggo_format |= WINE_GGO_VBGR_BITMAP;
701 break;
703 default:
704 ERR("aa = %d - not implemented\n", format);
705 case AA_None:
706 ggo_format |= GGO_BITMAP;
707 break;
710 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
711 if(buflen == GDI_ERROR) {
712 if(format != AA_None) {
713 format = AA_None;
714 entry->aa_default = AA_None;
715 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
716 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
718 if(buflen == GDI_ERROR) {
719 WARN("GetGlyphOutlineW failed\n");
720 return FALSE;
722 TRACE("Turning off antialiasing for this monochrome font\n");
725 /* If there is nothing for the current type, we create the entry. */
726 if( !entry->format[format] ) {
727 entry->format[format] = HeapAlloc(GetProcessHeap(),
728 HEAP_ZERO_MEMORY,
729 sizeof(gsCacheEntryFormat));
731 formatEntry = entry->format[format];
733 if(formatEntry->nrealized <= glyph) {
734 formatEntry->nrealized = (glyph / 128 + 1) * 128;
736 if (formatEntry->realized)
737 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
738 HEAP_ZERO_MEMORY,
739 formatEntry->realized,
740 formatEntry->nrealized * sizeof(BOOL));
741 else
742 formatEntry->realized = HeapAlloc(GetProcessHeap(),
743 HEAP_ZERO_MEMORY,
744 formatEntry->nrealized * sizeof(BOOL));
746 if(!X11DRV_XRender_Installed) {
747 if (formatEntry->bitmaps)
748 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
749 HEAP_ZERO_MEMORY,
750 formatEntry->bitmaps,
751 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
752 else
753 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
754 HEAP_ZERO_MEMORY,
755 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
757 if (formatEntry->gis)
758 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
759 HEAP_ZERO_MEMORY,
760 formatEntry->gis,
761 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
762 else
763 formatEntry->gis = HeapAlloc(GetProcessHeap(),
764 HEAP_ZERO_MEMORY,
765 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
769 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
770 switch(format) {
771 case AA_Grey:
772 pf_mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask,
773 pf.type = PictTypeDirect;
774 pf.depth = 8;
775 pf.direct.alpha = 0;
776 pf.direct.alphaMask = 0xff;
777 break;
779 case AA_RGB:
780 case AA_BGR:
781 case AA_VRGB:
782 case AA_VBGR:
783 pf_mask = PictFormatType | PictFormatDepth | PictFormatRed | PictFormatRedMask |
784 PictFormatGreen | PictFormatGreenMask | PictFormatBlue |
785 PictFormatBlueMask | PictFormatAlpha | PictFormatAlphaMask;
786 pf.type = PictTypeDirect;
787 pf.depth = 32;
788 pf.direct.red = 16;
789 pf.direct.redMask = 0xff;
790 pf.direct.green = 8;
791 pf.direct.greenMask = 0xff;
792 pf.direct.blue = 0;
793 pf.direct.blueMask = 0xff;
794 pf.direct.alpha = 24;
795 pf.direct.alphaMask = 0xff;
796 break;
798 default:
799 ERR("aa = %d - not implemented\n", format);
800 case AA_None:
801 pf_mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask,
802 pf.type = PictTypeDirect;
803 pf.depth = 1;
804 pf.direct.alpha = 0;
805 pf.direct.alphaMask = 1;
806 break;
809 wine_tsx11_lock();
810 formatEntry->font_format = pXRenderFindFormat(gdi_display, pf_mask, &pf, 0);
811 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
812 wine_tsx11_unlock();
816 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
817 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
818 formatEntry->realized[glyph] = TRUE;
820 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
821 buflen,
822 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
823 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
825 gi.width = gm.gmBlackBoxX;
826 gi.height = gm.gmBlackBoxY;
827 gi.x = -gm.gmptGlyphOrigin.x;
828 gi.y = gm.gmptGlyphOrigin.y;
829 gi.xOff = gm.gmCellIncX;
830 gi.yOff = gm.gmCellIncY;
832 if(TRACE_ON(xrender)) {
833 int pitch, i, j;
834 char output[300];
835 unsigned char *line;
837 if(format == AA_None) {
838 pitch = ((gi.width + 31) / 32) * 4;
839 for(i = 0; i < gi.height; i++) {
840 line = (unsigned char*) buf + i * pitch;
841 output[0] = '\0';
842 for(j = 0; j < pitch * 8; j++) {
843 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
845 TRACE("%s\n", output);
847 } else {
848 static const char blks[] = " .:;!o*#";
849 char str[2];
851 str[1] = '\0';
852 pitch = ((gi.width + 3) / 4) * 4;
853 for(i = 0; i < gi.height; i++) {
854 line = (unsigned char*) buf + i * pitch;
855 output[0] = '\0';
856 for(j = 0; j < pitch; j++) {
857 str[0] = blks[line[j] >> 5];
858 strcat(output, str);
860 TRACE("%s\n", output);
866 if(formatEntry->glyphset) {
867 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
868 unsigned char *byte = (unsigned char*) buf, c;
869 int i = buflen;
871 while(i--) {
872 c = *byte;
874 /* magic to flip bit order */
875 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
876 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
877 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
879 *byte++ = c;
882 else if ( format != AA_Grey &&
883 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
885 unsigned int i, *data = (unsigned int *)buf;
886 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
888 gid = glyph;
891 XRenderCompositeText seems to ignore 0x0 glyphs when
892 AA_None, which means we lose the advance width of glyphs
893 like the space. We'll pretend that such glyphs are 1x1
894 bitmaps.
897 if(buflen == 0)
898 gi.width = gi.height = 1;
900 wine_tsx11_lock();
901 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
902 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
903 wine_tsx11_unlock();
904 HeapFree(GetProcessHeap(), 0, buf);
905 } else {
906 formatEntry->bitmaps[glyph] = buf;
909 formatEntry->gis[glyph] = gi;
911 return TRUE;
914 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
915 void *bitmap, XGlyphInfo *gi)
917 unsigned char *srcLine = bitmap, *src;
918 unsigned char bits, bitsMask;
919 int width = gi->width;
920 int stride = ((width + 31) & ~31) >> 3;
921 int height = gi->height;
922 int w;
923 int xspan, lenspan;
925 TRACE("%d, %d\n", x, y);
926 x -= gi->x;
927 y -= gi->y;
928 while (height--)
930 src = srcLine;
931 srcLine += stride;
932 w = width;
934 bitsMask = 0x80; /* FreeType is always MSB first */
935 bits = *src++;
937 xspan = x;
938 while (w)
940 if (bits & bitsMask)
942 lenspan = 0;
945 lenspan++;
946 if (lenspan == w)
947 break;
948 bitsMask = bitsMask >> 1;
949 if (!bitsMask)
951 bits = *src++;
952 bitsMask = 0x80;
954 } while (bits & bitsMask);
955 XFillRectangle (gdi_display, physDev->drawable,
956 physDev->gc, xspan, y, lenspan, 1);
957 xspan += lenspan;
958 w -= lenspan;
960 else
964 w--;
965 xspan++;
966 if (!w)
967 break;
968 bitsMask = bitsMask >> 1;
969 if (!bitsMask)
971 bits = *src++;
972 bitsMask = 0x80;
974 } while (!(bits & bitsMask));
977 y++;
981 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
982 void *bitmap, XGlyphInfo *gi)
984 unsigned char *srcLine = bitmap, *src, bits;
985 int width = gi->width;
986 int stride = ((width + 3) & ~3);
987 int height = gi->height;
988 int w;
989 int xspan, lenspan;
991 x -= gi->x;
992 y -= gi->y;
993 while (height--)
995 src = srcLine;
996 srcLine += stride;
997 w = width;
999 bits = *src++;
1000 xspan = x;
1001 while (w)
1003 if (bits >= 0x80)
1005 lenspan = 0;
1008 lenspan++;
1009 if (lenspan == w)
1010 break;
1011 bits = *src++;
1012 } while (bits >= 0x80);
1013 XFillRectangle (gdi_display, physDev->drawable,
1014 physDev->gc, xspan, y, lenspan, 1);
1015 xspan += lenspan;
1016 w -= lenspan;
1018 else
1022 w--;
1023 xspan++;
1024 if (!w)
1025 break;
1026 bits = *src++;
1027 } while (bits < 0x80);
1030 y++;
1035 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1037 int s, l;
1039 s = 0;
1040 while ((mask & 1) == 0)
1042 mask >>= 1;
1043 s++;
1045 l = 0;
1046 while ((mask & 1) == 1)
1048 mask >>= 1;
1049 l++;
1051 *shift = s;
1052 *len = l;
1055 static DWORD GetField (DWORD pixel, int shift, int len)
1057 pixel = pixel & (((1 << (len)) - 1) << shift);
1058 pixel = pixel << (32 - (shift + len)) >> 24;
1059 while (len < 8)
1061 pixel |= (pixel >> len);
1062 len <<= 1;
1064 return pixel;
1068 static DWORD PutField (DWORD pixel, int shift, int len)
1070 shift = shift - (8 - len);
1071 if (len <= 8)
1072 pixel &= (((1 << len) - 1) << (8 - len));
1073 if (shift < 0)
1074 pixel >>= -shift;
1075 else
1076 pixel <<= shift;
1077 return pixel;
1080 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1081 int color)
1083 int r_shift, r_len;
1084 int g_shift, g_len;
1085 int b_shift, b_len;
1086 BYTE *maskLine, *mask, m;
1087 int maskStride;
1088 DWORD pixel;
1089 int width, height;
1090 int w, tx;
1091 BYTE src_r, src_g, src_b;
1093 x -= gi->x;
1094 y -= gi->y;
1095 width = gi->width;
1096 height = gi->height;
1098 maskLine = bitmap;
1099 maskStride = (width + 3) & ~3;
1101 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1102 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1103 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1105 src_r = GetField(color, r_shift, r_len);
1106 src_g = GetField(color, g_shift, g_len);
1107 src_b = GetField(color, b_shift, b_len);
1109 for(; height--; y++)
1111 mask = maskLine;
1112 maskLine += maskStride;
1113 w = width;
1114 tx = x;
1116 if(y < 0) continue;
1117 if(y >= image->height) break;
1119 for(; w--; tx++)
1121 if(tx >= image->width) break;
1123 m = *mask++;
1124 if(tx < 0) continue;
1126 if (m == 0xff)
1127 XPutPixel (image, tx, y, color);
1128 else if (m)
1130 BYTE r, g, b;
1132 pixel = XGetPixel (image, tx, y);
1134 r = GetField(pixel, r_shift, r_len);
1135 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1136 g = GetField(pixel, g_shift, g_len);
1137 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1138 b = GetField(pixel, b_shift, b_len);
1139 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1141 pixel = (PutField (r, r_shift, r_len) |
1142 PutField (g, g_shift, g_len) |
1143 PutField (b, b_shift, b_len));
1144 XPutPixel (image, tx, y, pixel);
1150 /*************************************************************
1151 * get_tile_pict
1153 * Returns an appropriate Picture for tiling the text colour.
1154 * Call and use result within the xrender_cs
1156 static Picture get_tile_pict(enum drawable_depth_type type, int text_pixel)
1158 static struct
1160 Pixmap xpm;
1161 Picture pict;
1162 int current_color;
1163 } tiles[2], *tile;
1164 XRenderColor col;
1166 tile = &tiles[type];
1168 if(!tile->xpm)
1170 XRenderPictureAttributes pa;
1172 wine_tsx11_lock();
1173 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_formats[type]->depth);
1175 pa.repeat = RepeatNormal;
1176 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_formats[type], CPRepeat, &pa);
1177 wine_tsx11_unlock();
1179 /* init current_color to something different from text_pixel */
1180 tile->current_color = ~text_pixel;
1182 if(type == mono_drawable)
1184 /* for a 1bpp bitmap we always need a 1 in the tile */
1185 col.red = col.green = col.blue = 0;
1186 col.alpha = 0xffff;
1187 wine_tsx11_lock();
1188 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1189 wine_tsx11_unlock();
1193 if(text_pixel != tile->current_color && type == color_drawable)
1195 /* Map 0 -- 0xff onto 0 -- 0xffff */
1196 int r_shift, r_len;
1197 int g_shift, g_len;
1198 int b_shift, b_len;
1200 ExamineBitfield (visual->red_mask, &r_shift, &r_len );
1201 ExamineBitfield (visual->green_mask, &g_shift, &g_len);
1202 ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
1204 col.red = GetField(text_pixel, r_shift, r_len);
1205 col.red |= col.red << 8;
1206 col.green = GetField(text_pixel, g_shift, g_len);
1207 col.green |= col.green << 8;
1208 col.blue = GetField(text_pixel, b_shift, b_len);
1209 col.blue |= col.blue << 8;
1210 col.alpha = 0xffff;
1212 wine_tsx11_lock();
1213 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1214 wine_tsx11_unlock();
1215 tile->current_color = text_pixel;
1217 return tile->pict;
1220 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1222 return 1;
1225 /***********************************************************************
1226 * X11DRV_XRender_ExtTextOut
1228 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1229 const RECT *lprect, LPCWSTR wstr, UINT count,
1230 const INT *lpDx )
1232 RGNDATA *data;
1233 XGCValues xgcval;
1234 gsCacheEntry *entry;
1235 gsCacheEntryFormat *formatEntry;
1236 BOOL retv = FALSE;
1237 HDC hdc = physDev->hdc;
1238 int textPixel, backgroundPixel;
1239 HRGN saved_region = 0;
1240 BOOL disable_antialias = FALSE;
1241 AA_Type aa_type = AA_None;
1242 DIBSECTION bmp;
1243 unsigned int idx;
1244 double cosEsc, sinEsc;
1245 LOGFONTW lf;
1246 enum drawable_depth_type depth_type = (physDev->depth == 1) ? mono_drawable : color_drawable;
1247 Picture tile_pict = 0;
1249 /* Do we need to disable antialiasing because of palette mode? */
1250 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1251 TRACE("bitmap is not a DIB\n");
1253 else if (bmp.dsBmih.biBitCount <= 8) {
1254 TRACE("Disabling antialiasing\n");
1255 disable_antialias = TRUE;
1258 xgcval.function = GXcopy;
1259 xgcval.background = physDev->backgroundPixel;
1260 xgcval.fill_style = FillSolid;
1261 wine_tsx11_lock();
1262 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1263 wine_tsx11_unlock();
1265 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1267 if(physDev->depth == 1) {
1268 if((physDev->textPixel & 0xffffff) == 0) {
1269 textPixel = 0;
1270 backgroundPixel = 1;
1271 } else {
1272 textPixel = 1;
1273 backgroundPixel = 0;
1275 } else {
1276 textPixel = physDev->textPixel;
1277 backgroundPixel = physDev->backgroundPixel;
1280 if(flags & ETO_OPAQUE)
1282 wine_tsx11_lock();
1283 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1284 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1285 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1286 lprect->right - lprect->left, lprect->bottom - lprect->top );
1287 wine_tsx11_unlock();
1290 if(count == 0)
1292 retv = TRUE;
1293 goto done_unlock;
1297 GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1298 if(lf.lfEscapement != 0) {
1299 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1300 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1301 } else {
1302 cosEsc = 1;
1303 sinEsc = 0;
1306 if (flags & ETO_CLIPPED)
1308 HRGN clip_region;
1310 clip_region = CreateRectRgnIndirect( lprect );
1311 /* make a copy of the current device region */
1312 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1313 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1314 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1315 DeleteObject( clip_region );
1318 if(X11DRV_XRender_Installed) {
1319 if(!physDev->xrender->pict) {
1320 XRenderPictureAttributes pa;
1321 pa.subwindow_mode = IncludeInferiors;
1323 wine_tsx11_lock();
1324 physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1325 physDev->drawable,
1326 pict_formats[depth_type],
1327 CPSubwindowMode, &pa);
1328 wine_tsx11_unlock();
1330 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1331 physDev->xrender->pict, hdc, physDev->drawable);
1332 } else {
1333 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1334 physDev->xrender->pict, hdc, physDev->drawable);
1337 if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1339 wine_tsx11_lock();
1340 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1341 physDev->dc_rect.left, physDev->dc_rect.top,
1342 (XRectangle *)data->Buffer, data->rdh.nCount );
1343 wine_tsx11_unlock();
1344 HeapFree( GetProcessHeap(), 0, data );
1348 EnterCriticalSection(&xrender_cs);
1350 entry = glyphsetCache + physDev->xrender->cache_index;
1351 if( disable_antialias == FALSE )
1352 aa_type = entry->aa_default;
1353 formatEntry = entry->format[aa_type];
1355 for(idx = 0; idx < count; idx++) {
1356 if( !formatEntry ) {
1357 UploadGlyph(physDev, wstr[idx], aa_type);
1358 /* re-evaluate antialias since aa_default may have changed */
1359 if( disable_antialias == FALSE )
1360 aa_type = entry->aa_default;
1361 formatEntry = entry->format[aa_type];
1362 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1363 UploadGlyph(physDev, wstr[idx], aa_type);
1366 if (!formatEntry)
1368 WARN("could not upload requested glyphs\n");
1369 LeaveCriticalSection(&xrender_cs);
1370 goto done_unlock;
1373 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1374 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1376 if(X11DRV_XRender_Installed)
1378 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1379 INT offset = 0;
1380 POINT desired, current;
1381 int render_op = PictOpOver;
1383 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1384 So we pass zeros to the function and move to our starting position using the first
1385 element of the elts array. */
1387 desired.x = physDev->dc_rect.left + x;
1388 desired.y = physDev->dc_rect.top + y;
1389 current.x = current.y = 0;
1391 tile_pict = get_tile_pict(depth_type, physDev->textPixel);
1393 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1395 if((depth_type == mono_drawable) && (textPixel == 0))
1396 render_op = PictOpOutReverse; /* This gives us 'black' text */
1398 for(idx = 0; idx < count; idx++)
1400 elts[idx].glyphset = formatEntry->glyphset;
1401 elts[idx].chars = wstr + idx;
1402 elts[idx].nchars = 1;
1403 elts[idx].xOff = desired.x - current.x;
1404 elts[idx].yOff = desired.y - current.y;
1406 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1407 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1409 if(!lpDx)
1411 desired.x += formatEntry->gis[wstr[idx]].xOff;
1412 desired.y += formatEntry->gis[wstr[idx]].yOff;
1414 else
1416 offset += lpDx[idx];
1417 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1418 desired.y = physDev->dc_rect.top + y - offset * sinEsc;
1421 wine_tsx11_lock();
1422 pXRenderCompositeText16(gdi_display, render_op,
1423 tile_pict,
1424 physDev->xrender->pict,
1425 formatEntry->font_format,
1426 0, 0, 0, 0, elts, count);
1427 wine_tsx11_unlock();
1428 HeapFree(GetProcessHeap(), 0, elts);
1429 } else {
1430 INT offset = 0, xoff = 0, yoff = 0;
1431 wine_tsx11_lock();
1432 XSetForeground( gdi_display, physDev->gc, textPixel );
1434 if(aa_type == AA_None || physDev->depth == 1)
1436 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1438 if(aa_type == AA_None)
1439 sharp_glyph_fn = SharpGlyphMono;
1440 else
1441 sharp_glyph_fn = SharpGlyphGray;
1443 for(idx = 0; idx < count; idx++) {
1444 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1445 physDev->dc_rect.top + y + yoff,
1446 formatEntry->bitmaps[wstr[idx]],
1447 &formatEntry->gis[wstr[idx]]);
1448 if(lpDx) {
1449 offset += lpDx[idx];
1450 xoff = offset * cosEsc;
1451 yoff = offset * -sinEsc;
1452 } else {
1453 xoff += formatEntry->gis[wstr[idx]].xOff;
1454 yoff += formatEntry->gis[wstr[idx]].yOff;
1457 } else {
1458 XImage *image;
1459 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1460 RECT extents = {0, 0, 0, 0};
1461 POINT cur = {0, 0};
1462 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1463 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1465 TRACE("drawable %dx%d\n", w, h);
1467 for(idx = 0; idx < count; idx++) {
1468 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1469 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1470 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1471 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1472 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1473 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1474 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1475 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1476 if(lpDx) {
1477 offset += lpDx[idx];
1478 cur.x = offset * cosEsc;
1479 cur.y = offset * -sinEsc;
1480 } else {
1481 cur.x += formatEntry->gis[wstr[idx]].xOff;
1482 cur.y += formatEntry->gis[wstr[idx]].yOff;
1485 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1486 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1488 if(physDev->dc_rect.left + x + extents.left >= 0) {
1489 image_x = physDev->dc_rect.left + x + extents.left;
1490 image_off_x = 0;
1491 } else {
1492 image_x = 0;
1493 image_off_x = physDev->dc_rect.left + x + extents.left;
1495 if(physDev->dc_rect.top + y + extents.top >= 0) {
1496 image_y = physDev->dc_rect.top + y + extents.top;
1497 image_off_y = 0;
1498 } else {
1499 image_y = 0;
1500 image_off_y = physDev->dc_rect.top + y + extents.top;
1502 if(physDev->dc_rect.left + x + extents.right < w)
1503 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1504 else
1505 image_w = w - image_x;
1506 if(physDev->dc_rect.top + y + extents.bottom < h)
1507 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1508 else
1509 image_h = h - image_y;
1511 if(image_w <= 0 || image_h <= 0) goto no_image;
1513 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1514 image = XGetImage(gdi_display, physDev->drawable,
1515 image_x, image_y, image_w, image_h,
1516 AllPlanes, ZPixmap);
1517 X11DRV_check_error();
1519 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1520 gdi_display, (int)physDev->drawable, image_x, image_y,
1521 image_w, image_h, AllPlanes, ZPixmap,
1522 physDev->depth, image);
1523 if(!image) {
1524 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
1525 physDev->depth);
1526 GC gc;
1527 XGCValues gcv;
1529 gcv.graphics_exposures = False;
1530 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1531 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1532 image_w, image_h, 0, 0);
1533 XFreeGC(gdi_display, gc);
1534 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1535 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1536 ZPixmap);
1537 X11DRV_check_error();
1538 XFreePixmap(gdi_display, xpm);
1540 if(!image) goto no_image;
1542 image->red_mask = visual->red_mask;
1543 image->green_mask = visual->green_mask;
1544 image->blue_mask = visual->blue_mask;
1546 offset = xoff = yoff = 0;
1547 for(idx = 0; idx < count; idx++) {
1548 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1549 yoff + image_off_y - extents.top,
1550 formatEntry->bitmaps[wstr[idx]],
1551 &formatEntry->gis[wstr[idx]],
1552 physDev->textPixel);
1553 if(lpDx) {
1554 offset += lpDx[idx];
1555 xoff = offset * cosEsc;
1556 yoff = offset * -sinEsc;
1557 } else {
1558 xoff += formatEntry->gis[wstr[idx]].xOff;
1559 yoff += formatEntry->gis[wstr[idx]].yOff;
1562 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1563 image_x, image_y, image_w, image_h);
1564 XDestroyImage(image);
1566 no_image:
1567 wine_tsx11_unlock();
1569 LeaveCriticalSection(&xrender_cs);
1571 if (flags & ETO_CLIPPED)
1573 /* restore the device region */
1574 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1575 DeleteObject( saved_region );
1578 retv = TRUE;
1580 done_unlock:
1581 X11DRV_UnlockDIBSection( physDev, TRUE );
1582 return retv;
1585 /******************************************************************************
1586 * AlphaBlend (x11drv.@)
1588 BOOL CDECL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1589 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1590 BLENDFUNCTION blendfn)
1592 XRenderPictureAttributes pa;
1593 XRenderPictFormat *src_format;
1594 XRenderPictFormat argb32_templ = {
1595 0, /* id */
1596 PictTypeDirect, /* type */
1597 32, /* depth */
1598 { /* direct */
1599 16, /* direct.red */
1600 0xff, /* direct.redMask */
1601 8, /* direct.green */
1602 0xff, /* direct.greenMask */
1603 0, /* direct.blue */
1604 0xff, /* direct.blueMask */
1605 24, /* direct.alpha */
1606 0xff, /* direct.alphaMask */
1608 0, /* colormap */
1610 unsigned long argb32_templ_mask =
1611 PictFormatType |
1612 PictFormatDepth |
1613 PictFormatRed |
1614 PictFormatRedMask |
1615 PictFormatGreen |
1616 PictFormatGreenMask |
1617 PictFormatBlue |
1618 PictFormatBlueMask |
1619 PictFormatAlpha |
1620 PictFormatAlphaMask;
1622 Picture dst_pict, src_pict;
1623 Pixmap xpm;
1624 DIBSECTION dib;
1625 XImage *image;
1626 GC gc;
1627 XGCValues gcv;
1628 DWORD *dstbits, *data;
1629 int y, y2;
1630 POINT pts[2];
1631 BOOL top_down = FALSE;
1632 RGNDATA *rgndata;
1633 enum drawable_depth_type dst_depth_type = (devDst->depth == 1) ? mono_drawable : color_drawable;
1634 int repeat_src;
1636 if(!X11DRV_XRender_Installed) {
1637 FIXME("Unable to AlphaBlend without Xrender\n");
1638 return FALSE;
1640 pts[0].x = xDst;
1641 pts[0].y = yDst;
1642 pts[1].x = xDst + widthDst;
1643 pts[1].y = yDst + heightDst;
1644 LPtoDP(devDst->hdc, pts, 2);
1645 xDst = pts[0].x;
1646 yDst = pts[0].y;
1647 widthDst = pts[1].x - pts[0].x;
1648 heightDst = pts[1].y - pts[0].y;
1650 pts[0].x = xSrc;
1651 pts[0].y = ySrc;
1652 pts[1].x = xSrc + widthSrc;
1653 pts[1].y = ySrc + heightSrc;
1654 LPtoDP(devSrc->hdc, pts, 2);
1655 xSrc = pts[0].x;
1656 ySrc = pts[0].y;
1657 widthSrc = pts[1].x - pts[0].x;
1658 heightSrc = pts[1].y - pts[0].y;
1659 if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1661 /* If the source is a 1x1 bitmap, tiling is equivalent to stretching, but
1662 tiling is much faster. Therefore, we do no stretching in this case. */
1663 repeat_src = widthSrc == 1 && heightSrc == 1;
1665 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1666 if((widthDst != widthSrc || heightDst != heightSrc) && !repeat_src)
1667 #else
1668 if(!pXRenderSetPictureTransform && !repeat_src)
1669 #endif
1671 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1672 return FALSE;
1675 if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1677 static BOOL out = FALSE;
1678 if (!out)
1680 FIXME("not a dibsection\n");
1681 out = TRUE;
1683 return FALSE;
1686 if (xSrc < 0 || ySrc < 0 || widthSrc < 0 || heightSrc < 0 || xSrc + widthSrc > dib.dsBmih.biWidth
1687 || ySrc + heightSrc > abs(dib.dsBmih.biHeight))
1689 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc, ySrc, widthSrc, heightSrc);
1690 SetLastError(ERROR_INVALID_PARAMETER);
1691 return FALSE;
1694 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && blendfn.SourceConstantAlpha != 0xff)
1695 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn.SourceConstantAlpha);
1697 if(dib.dsBm.bmBitsPixel != 32) {
1698 FIXME("not a 32 bpp dibsection\n");
1699 return FALSE;
1701 dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1703 if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1704 top_down = TRUE;
1705 dstbits += widthSrc * (heightSrc - 1);
1706 y2 = ySrc;
1707 y = y2 + heightSrc - 1;
1709 else
1711 y = dib.dsBmih.biHeight - ySrc - 1;
1712 y2 = y - heightSrc + 1;
1715 if (blendfn.AlphaFormat & AC_SRC_ALPHA)
1717 for(; y >= y2; y--)
1719 memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1720 widthSrc * 4);
1721 dstbits += (top_down ? -1 : 1) * widthSrc;
1724 else
1726 DWORD source_alpha = (DWORD)blendfn.SourceConstantAlpha << 24;
1727 int x;
1729 for(; y >= y2; y--)
1731 DWORD *srcbits = (DWORD *)((char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes) + xSrc;
1732 for (x = 0; x < widthSrc; x++)
1734 DWORD argb = *srcbits++;
1735 argb = (argb & 0xffffff) | source_alpha;
1736 *dstbits++ = argb;
1738 if (top_down) /* we traversed the row forward so we should go back by two rows */
1739 dstbits -= 2 * widthSrc;
1744 rgndata = X11DRV_GetRegionData( devDst->region, 0 );
1746 wine_tsx11_lock();
1747 image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1748 (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1751 Avoid using XRenderFindStandardFormat as older libraries don't have it
1752 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1754 src_format = pXRenderFindFormat(gdi_display, argb32_templ_mask, &argb32_templ, 0);
1756 TRACE("src_format %p\n", src_format);
1758 pa.subwindow_mode = IncludeInferiors;
1759 pa.repeat = repeat_src ? RepeatNormal : RepeatNone;
1761 /* FIXME use devDst->xrender->pict ? */
1762 dst_pict = pXRenderCreatePicture(gdi_display,
1763 devDst->drawable,
1764 pict_formats[dst_depth_type],
1765 CPSubwindowMode, &pa);
1766 TRACE("dst_pict %08lx\n", dst_pict);
1767 TRACE("src_drawable = %08lx\n", devSrc->drawable);
1768 xpm = XCreatePixmap(gdi_display,
1769 root_window,
1770 widthSrc, heightSrc, 32);
1771 gcv.graphics_exposures = False;
1772 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1773 TRACE("xpm = %08lx\n", xpm);
1774 XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1776 src_pict = pXRenderCreatePicture(gdi_display,
1777 xpm, src_format,
1778 CPSubwindowMode|CPRepeat, &pa);
1779 TRACE("src_pict %08lx\n", src_pict);
1781 if (rgndata)
1783 pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
1784 devDst->dc_rect.left, devDst->dc_rect.top,
1785 (XRectangle *)rgndata->Buffer,
1786 rgndata->rdh.nCount );
1787 HeapFree( GetProcessHeap(), 0, rgndata );
1790 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1791 if(!repeat_src && (widthDst != widthSrc || heightDst != heightSrc)) {
1792 double xscale = widthSrc/(double)widthDst;
1793 double yscale = heightSrc/(double)heightDst;
1794 XTransform xform = {{
1795 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0) },
1796 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0) },
1797 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1799 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1801 #endif
1802 pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
1803 0, 0, 0, 0,
1804 xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
1807 pXRenderFreePicture(gdi_display, src_pict);
1808 XFreePixmap(gdi_display, xpm);
1809 XFreeGC(gdi_display, gc);
1810 pXRenderFreePicture(gdi_display, dst_pict);
1811 image->data = NULL;
1812 XDestroyImage(image);
1814 wine_tsx11_unlock();
1815 HeapFree(GetProcessHeap(), 0, data);
1816 return TRUE;
1819 #else /* SONAME_LIBXRENDER */
1821 void X11DRV_XRender_Init(void)
1823 TRACE("XRender support not compiled in.\n");
1824 return;
1827 void X11DRV_XRender_Finalize(void)
1831 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1833 assert(0);
1834 return FALSE;
1837 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1839 assert(0);
1840 return;
1843 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1844 const RECT *lprect, LPCWSTR wstr, UINT count,
1845 const INT *lpDx )
1847 assert(0);
1848 return FALSE;
1851 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1853 assert(0);
1854 return;
1857 /******************************************************************************
1858 * AlphaBlend (x11drv.@)
1860 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1861 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1862 BLENDFUNCTION blendfn)
1864 FIXME("not supported - XRENDER headers were missing at compile time\n");
1865 return FALSE;
1868 #endif /* SONAME_LIBXRENDER */