user32: Fix bogus "if (!x & y)" code.
[wine/testsucceed.git] / dlls / winex11.drv / xrender.c
blobfd405beff63b276257174661566f6ca3138ad789
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>
51 enum drawable_depth_type {mono_drawable, color_drawable};
52 static XRenderPictFormat *pict_formats[2];
54 typedef struct
56 LOGFONTW lf;
57 SIZE devsize; /* size in device coords */
58 DWORD hash;
59 } LFANDSIZE;
61 #define INITIAL_REALIZED_BUF_SIZE 128
63 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
65 typedef struct
67 GlyphSet glyphset;
68 XRenderPictFormat *font_format;
69 int nrealized;
70 BOOL *realized;
71 void **bitmaps;
72 XGlyphInfo *gis;
73 } gsCacheEntryFormat;
75 typedef struct
77 LFANDSIZE lfsz;
78 AA_Type aa_default;
79 gsCacheEntryFormat * format[AA_MAXVALUE];
80 INT count;
81 INT next;
82 } gsCacheEntry;
84 struct tagXRENDERINFO
86 int cache_index;
87 Picture pict;
91 static gsCacheEntry *glyphsetCache = NULL;
92 static DWORD glyphsetCacheSize = 0;
93 static INT lastfree = -1;
94 static INT mru = -1;
96 #define INIT_CACHE_SIZE 10
98 static int antialias = 1;
100 static void *xrender_handle;
102 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
103 MAKE_FUNCPTR(XRenderAddGlyphs)
104 MAKE_FUNCPTR(XRenderComposite)
105 MAKE_FUNCPTR(XRenderCompositeString8)
106 MAKE_FUNCPTR(XRenderCompositeString16)
107 MAKE_FUNCPTR(XRenderCompositeString32)
108 MAKE_FUNCPTR(XRenderCompositeText16)
109 MAKE_FUNCPTR(XRenderCreateGlyphSet)
110 MAKE_FUNCPTR(XRenderCreatePicture)
111 MAKE_FUNCPTR(XRenderFillRectangle)
112 MAKE_FUNCPTR(XRenderFindFormat)
113 MAKE_FUNCPTR(XRenderFindVisualFormat)
114 MAKE_FUNCPTR(XRenderFreeGlyphSet)
115 MAKE_FUNCPTR(XRenderFreePicture)
116 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
117 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
118 MAKE_FUNCPTR(XRenderSetPictureTransform)
119 #endif
120 MAKE_FUNCPTR(XRenderQueryExtension)
121 #undef MAKE_FUNCPTR
123 static CRITICAL_SECTION xrender_cs;
124 static CRITICAL_SECTION_DEBUG critsect_debug =
126 0, 0, &xrender_cs,
127 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
128 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
130 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
132 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
133 ( ( (ULONG)_x4 << 24 ) | \
134 ( (ULONG)_x3 << 16 ) | \
135 ( (ULONG)_x2 << 8 ) | \
136 (ULONG)_x1 )
138 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
140 #define GASP_GRIDFIT 0x01
141 #define GASP_DOGRAY 0x02
143 #ifdef WORDS_BIGENDIAN
144 #define get_be_word(x) (x)
145 #define NATIVE_BYTE_ORDER MSBFirst
146 #else
147 #define get_be_word(x) RtlUshortByteSwap(x)
148 #define NATIVE_BYTE_ORDER LSBFirst
149 #endif
151 /***********************************************************************
152 * X11DRV_XRender_Init
154 * Let's see if our XServer has the extension available
157 void X11DRV_XRender_Init(void)
159 int event_base, i;
160 XRenderPictFormat pf;
162 if (client_side_with_render &&
163 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
164 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
165 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
168 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
169 LOAD_FUNCPTR(XRenderAddGlyphs)
170 LOAD_FUNCPTR(XRenderComposite)
171 LOAD_FUNCPTR(XRenderCompositeString8)
172 LOAD_FUNCPTR(XRenderCompositeString16)
173 LOAD_FUNCPTR(XRenderCompositeString32)
174 LOAD_FUNCPTR(XRenderCompositeText16)
175 LOAD_FUNCPTR(XRenderCreateGlyphSet)
176 LOAD_FUNCPTR(XRenderCreatePicture)
177 LOAD_FUNCPTR(XRenderFillRectangle)
178 LOAD_FUNCPTR(XRenderFindFormat)
179 LOAD_FUNCPTR(XRenderFindVisualFormat)
180 LOAD_FUNCPTR(XRenderFreeGlyphSet)
181 LOAD_FUNCPTR(XRenderFreePicture)
182 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
183 LOAD_FUNCPTR(XRenderQueryExtension)
184 #undef LOAD_FUNCPTR
185 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
186 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
187 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
188 #undef LOAD_OPTIONAL_FUNCPTR
189 #endif
192 wine_tsx11_lock();
193 if(pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) {
194 X11DRV_XRender_Installed = TRUE;
195 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
196 pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, visual);
197 if(!pict_formats[color_drawable])
199 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
200 if (visual->class == DirectColor)
202 XVisualInfo info;
203 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
204 screen_depth, TrueColor, &info ))
206 pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, info.visual);
207 if (pict_formats[color_drawable]) visual = info.visual;
211 if(!pict_formats[color_drawable]) /* This fails in buggy versions of libXrender.so */
213 wine_tsx11_unlock();
214 WINE_MESSAGE(
215 "Wine has detected that you probably have a buggy version\n"
216 "of libXrender.so . Because of this client side font rendering\n"
217 "will be disabled. Please upgrade this library.\n");
218 X11DRV_XRender_Installed = FALSE;
219 return;
221 pf.type = PictTypeDirect;
222 pf.depth = 1;
223 pf.direct.alpha = 0;
224 pf.direct.alphaMask = 1;
225 pict_formats[mono_drawable] = pXRenderFindFormat(gdi_display, PictFormatType |
226 PictFormatDepth | PictFormatAlpha |
227 PictFormatAlphaMask, &pf, 0);
228 if(!pict_formats[mono_drawable]) {
229 ERR("mono_format == NULL?\n");
230 X11DRV_XRender_Installed = FALSE;
232 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
233 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
234 X11DRV_XRender_Installed = FALSE;
237 wine_tsx11_unlock();
240 sym_not_found:
241 if(X11DRV_XRender_Installed || client_side_with_core)
243 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
244 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
246 glyphsetCacheSize = INIT_CACHE_SIZE;
247 lastfree = 0;
248 for(i = 0; i < INIT_CACHE_SIZE; i++) {
249 glyphsetCache[i].next = i + 1;
250 glyphsetCache[i].count = -1;
252 glyphsetCache[i-1].next = -1;
253 using_client_side_fonts = 1;
255 if(!X11DRV_XRender_Installed) {
256 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
257 if(screen_depth <= 8 || !client_side_antialias_with_core)
258 antialias = 0;
259 } else {
260 if(screen_depth <= 8 || !client_side_antialias_with_render)
261 antialias = 0;
264 else TRACE("Using X11 core fonts\n");
267 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
269 if(p1->hash != p2->hash) return TRUE;
270 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
271 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
272 return strcmpW(p1->lf.lfFaceName, p2->lf.lfFaceName);
275 #if 0
276 static void walk_cache(void)
278 int i;
280 EnterCriticalSection(&xrender_cs);
281 for(i=mru; i >= 0; i = glyphsetCache[i].next)
282 TRACE("item %d\n", i);
283 LeaveCriticalSection(&xrender_cs);
285 #endif
287 static int LookupEntry(LFANDSIZE *plfsz)
289 int i, prev_i = -1;
291 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
292 TRACE("%d\n", i);
293 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
294 i = -1;
295 break;
298 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
299 glyphsetCache[i].count++;
300 if(prev_i >= 0) {
301 glyphsetCache[prev_i].next = glyphsetCache[i].next;
302 glyphsetCache[i].next = mru;
303 mru = i;
305 TRACE("found font in cache %d\n", i);
306 return i;
308 prev_i = i;
310 TRACE("font not in cache\n");
311 return -1;
314 static void FreeEntry(int entry)
316 int i, format;
318 for(format = 0; format < AA_MAXVALUE; format++) {
319 gsCacheEntryFormat * formatEntry;
321 if( !glyphsetCache[entry].format[format] )
322 continue;
324 formatEntry = glyphsetCache[entry].format[format];
326 if(formatEntry->glyphset) {
327 wine_tsx11_lock();
328 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
329 wine_tsx11_unlock();
330 formatEntry->glyphset = 0;
332 if(formatEntry->nrealized) {
333 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
334 formatEntry->realized = NULL;
335 if(formatEntry->bitmaps) {
336 for(i = 0; i < formatEntry->nrealized; i++)
337 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
338 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
339 formatEntry->bitmaps = NULL;
341 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
342 formatEntry->gis = NULL;
343 formatEntry->nrealized = 0;
346 HeapFree(GetProcessHeap(), 0, formatEntry);
347 glyphsetCache[entry].format[format] = NULL;
351 static int AllocEntry(void)
353 int best = -1, prev_best = -1, i, prev_i = -1;
355 if(lastfree >= 0) {
356 assert(glyphsetCache[lastfree].count == -1);
357 glyphsetCache[lastfree].count = 1;
358 best = lastfree;
359 lastfree = glyphsetCache[lastfree].next;
360 assert(best != mru);
361 glyphsetCache[best].next = mru;
362 mru = best;
364 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
365 return mru;
368 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
369 if(glyphsetCache[i].count == 0) {
370 best = i;
371 prev_best = prev_i;
373 prev_i = i;
376 if(best >= 0) {
377 TRACE("freeing unused glyphset at cache %d\n", best);
378 FreeEntry(best);
379 glyphsetCache[best].count = 1;
380 if(prev_best >= 0) {
381 glyphsetCache[prev_best].next = glyphsetCache[best].next;
382 glyphsetCache[best].next = mru;
383 mru = best;
384 } else {
385 assert(mru == best);
387 return mru;
390 TRACE("Growing cache\n");
392 if (glyphsetCache)
393 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
394 glyphsetCache,
395 (glyphsetCacheSize + INIT_CACHE_SIZE)
396 * sizeof(*glyphsetCache));
397 else
398 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
399 (glyphsetCacheSize + INIT_CACHE_SIZE)
400 * sizeof(*glyphsetCache));
402 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
403 i++) {
404 glyphsetCache[i].next = i + 1;
405 glyphsetCache[i].count = -1;
407 glyphsetCache[i-1].next = -1;
408 glyphsetCacheSize += INIT_CACHE_SIZE;
410 lastfree = glyphsetCache[best].next;
411 glyphsetCache[best].count = 1;
412 glyphsetCache[best].next = mru;
413 mru = best;
414 TRACE("new free cache slot at %d\n", mru);
415 return mru;
418 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
420 DWORD size;
421 WORD *gasp, *buffer;
422 WORD num_recs;
423 DWORD ppem;
424 TEXTMETRICW tm;
426 *flags = 0;
428 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
429 if(size == GDI_ERROR)
430 return FALSE;
432 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
433 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
435 GetTextMetricsW(physDev->hdc, &tm);
436 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
438 gasp++;
439 num_recs = get_be_word(*gasp);
440 gasp++;
441 while(num_recs--)
443 *flags = get_be_word(*(gasp + 1));
444 if(ppem <= get_be_word(*gasp))
445 break;
446 gasp += 2;
448 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
450 HeapFree(GetProcessHeap(), 0, buffer);
451 return TRUE;
454 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
456 AA_Type ret;
457 WORD flags;
458 UINT font_smoothing_type, font_smoothing_orientation;
460 if (X11DRV_XRender_Installed && subpixel &&
461 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
462 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
464 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
465 &font_smoothing_orientation, 0) &&
466 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
468 ret = AA_BGR;
470 else
471 ret = AA_RGB;
472 /*FIXME
473 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
474 But, Wine's subpixel rendering can support the portrait mode.
477 else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
478 ret = AA_Grey;
479 else
480 ret = AA_None;
482 return ret;
485 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
487 int ret;
488 int format;
489 gsCacheEntry *entry;
490 static int hinter = -1;
491 static int subpixel = -1;
492 BOOL font_smoothing;
494 if((ret = LookupEntry(plfsz)) != -1) return ret;
496 ret = AllocEntry();
497 entry = glyphsetCache + ret;
498 entry->lfsz = *plfsz;
499 for( format = 0; format < AA_MAXVALUE; format++ ) {
500 assert( !entry->format[format] );
503 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
505 if(hinter == -1 || subpixel == -1)
507 RASTERIZER_STATUS status;
508 GetRasterizerCaps(&status, sizeof(status));
509 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
510 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
513 switch (plfsz->lf.lfQuality)
515 case ANTIALIASED_QUALITY:
516 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
517 break;
518 case CLEARTYPE_QUALITY:
519 case CLEARTYPE_NATURAL_QUALITY:
520 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
521 break;
522 case DEFAULT_QUALITY:
523 case DRAFT_QUALITY:
524 case PROOF_QUALITY:
525 default:
526 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
527 font_smoothing)
529 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
531 else
532 entry->aa_default = AA_None;
533 break;
536 else
537 entry->aa_default = AA_None;
539 return ret;
542 static void dec_ref_cache(int index)
544 assert(index >= 0);
545 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
546 assert(glyphsetCache[index].count > 0);
547 glyphsetCache[index].count--;
550 static void lfsz_calc_hash(LFANDSIZE *plfsz)
552 DWORD hash = 0, *ptr;
553 int i;
555 hash ^= plfsz->devsize.cx;
556 hash ^= plfsz->devsize.cy;
557 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
558 hash ^= *ptr;
559 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
560 WCHAR *pwc = (WCHAR *)ptr;
561 if(!*pwc) break;
562 hash ^= *ptr;
563 pwc++;
564 if(!*pwc) break;
566 plfsz->hash = hash;
567 return;
570 /***********************************************************************
571 * X11DRV_XRender_Finalize
573 void X11DRV_XRender_Finalize(void)
575 int i;
577 EnterCriticalSection(&xrender_cs);
578 for(i = mru; i >= 0; i = glyphsetCache[i].next)
579 FreeEntry(i);
580 LeaveCriticalSection(&xrender_cs);
584 /***********************************************************************
585 * X11DRV_XRender_SelectFont
587 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
589 LFANDSIZE lfsz;
591 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
592 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
593 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
594 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
595 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
596 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
597 lfsz_calc_hash(&lfsz);
599 EnterCriticalSection(&xrender_cs);
600 if(!physDev->xrender) {
601 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
602 sizeof(*physDev->xrender));
603 physDev->xrender->cache_index = -1;
605 else if(physDev->xrender->cache_index != -1)
606 dec_ref_cache(physDev->xrender->cache_index);
607 physDev->xrender->cache_index = GetCacheEntry(physDev, &lfsz);
608 LeaveCriticalSection(&xrender_cs);
609 return 0;
612 /***********************************************************************
613 * X11DRV_XRender_DeleteDC
615 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
617 X11DRV_XRender_UpdateDrawable(physDev);
619 EnterCriticalSection(&xrender_cs);
620 if(physDev->xrender->cache_index != -1)
621 dec_ref_cache(physDev->xrender->cache_index);
622 LeaveCriticalSection(&xrender_cs);
624 HeapFree(GetProcessHeap(), 0, physDev->xrender);
625 physDev->xrender = NULL;
626 return;
629 /***********************************************************************
630 * X11DRV_XRender_UpdateDrawable
632 * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
633 * It deletes the pict and tile when the drawable changes.
635 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
637 wine_tsx11_lock();
639 if(physDev->xrender->pict)
641 TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
642 XFlush(gdi_display);
643 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
644 physDev->xrender->pict = 0;
646 wine_tsx11_unlock();
648 return;
651 /************************************************************************
652 * UploadGlyph
654 * Helper to ExtTextOut. Must be called inside xrender_cs
656 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
658 unsigned int buflen;
659 char *buf;
660 Glyph gid;
661 GLYPHMETRICS gm;
662 XGlyphInfo gi;
663 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
664 gsCacheEntryFormat *formatEntry;
665 UINT ggo_format = GGO_GLYPH_INDEX;
666 XRenderPictFormat pf;
667 unsigned long pf_mask;
668 static const char zero[4];
670 switch(format) {
671 case AA_Grey:
672 ggo_format |= WINE_GGO_GRAY16_BITMAP;
673 break;
674 case AA_RGB:
675 ggo_format |= WINE_GGO_HRGB_BITMAP;
676 break;
677 case AA_BGR:
678 ggo_format |= WINE_GGO_HBGR_BITMAP;
679 break;
680 case AA_VRGB:
681 ggo_format |= WINE_GGO_VRGB_BITMAP;
682 break;
683 case AA_VBGR:
684 ggo_format |= WINE_GGO_VBGR_BITMAP;
685 break;
687 default:
688 ERR("aa = %d - not implemented\n", format);
689 case AA_None:
690 ggo_format |= GGO_BITMAP;
691 break;
694 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
695 NULL);
696 if(buflen == GDI_ERROR) {
697 if(format != AA_None) {
698 format = AA_None;
699 entry->aa_default = AA_None;
700 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
701 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
702 NULL);
704 if(buflen == GDI_ERROR) {
705 WARN("GetGlyphOutlineW failed\n");
706 return FALSE;
708 TRACE("Turning off antialiasing for this monochrome font\n");
711 /* If there is nothing for the current type, we create the entry. */
712 if( !entry->format[format] ) {
713 entry->format[format] = HeapAlloc(GetProcessHeap(),
714 HEAP_ZERO_MEMORY,
715 sizeof(gsCacheEntryFormat));
717 formatEntry = entry->format[format];
719 if(formatEntry->nrealized <= glyph) {
720 formatEntry->nrealized = (glyph / 128 + 1) * 128;
722 if (formatEntry->realized)
723 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
724 HEAP_ZERO_MEMORY,
725 formatEntry->realized,
726 formatEntry->nrealized * sizeof(BOOL));
727 else
728 formatEntry->realized = HeapAlloc(GetProcessHeap(),
729 HEAP_ZERO_MEMORY,
730 formatEntry->nrealized * sizeof(BOOL));
732 if(!X11DRV_XRender_Installed) {
733 if (formatEntry->bitmaps)
734 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
735 HEAP_ZERO_MEMORY,
736 formatEntry->bitmaps,
737 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
738 else
739 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
740 HEAP_ZERO_MEMORY,
741 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
743 if (formatEntry->gis)
744 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
745 HEAP_ZERO_MEMORY,
746 formatEntry->gis,
747 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
748 else
749 formatEntry->gis = HeapAlloc(GetProcessHeap(),
750 HEAP_ZERO_MEMORY,
751 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
755 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
756 switch(format) {
757 case AA_Grey:
758 pf_mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask,
759 pf.type = PictTypeDirect;
760 pf.depth = 8;
761 pf.direct.alpha = 0;
762 pf.direct.alphaMask = 0xff;
763 break;
765 case AA_RGB:
766 case AA_BGR:
767 case AA_VRGB:
768 case AA_VBGR:
769 pf_mask = PictFormatType | PictFormatDepth | PictFormatRed | PictFormatRedMask |
770 PictFormatGreen | PictFormatGreenMask | PictFormatBlue |
771 PictFormatBlueMask | PictFormatAlpha | PictFormatAlphaMask;
772 pf.type = PictTypeDirect;
773 pf.depth = 32;
774 pf.direct.red = 16;
775 pf.direct.redMask = 0xff;
776 pf.direct.green = 8;
777 pf.direct.greenMask = 0xff;
778 pf.direct.blue = 0;
779 pf.direct.blueMask = 0xff;
780 pf.direct.alpha = 24;
781 pf.direct.alphaMask = 0xff;
782 break;
784 default:
785 ERR("aa = %d - not implemented\n", format);
786 case AA_None:
787 pf_mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask,
788 pf.type = PictTypeDirect;
789 pf.depth = 1;
790 pf.direct.alpha = 0;
791 pf.direct.alphaMask = 1;
792 break;
795 wine_tsx11_lock();
796 formatEntry->font_format = pXRenderFindFormat(gdi_display, pf_mask, &pf, 0);
797 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
798 wine_tsx11_unlock();
802 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
803 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, NULL);
804 formatEntry->realized[glyph] = TRUE;
806 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
807 buflen,
808 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
809 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
811 gi.width = gm.gmBlackBoxX;
812 gi.height = gm.gmBlackBoxY;
813 gi.x = -gm.gmptGlyphOrigin.x;
814 gi.y = gm.gmptGlyphOrigin.y;
815 gi.xOff = gm.gmCellIncX;
816 gi.yOff = gm.gmCellIncY;
818 if(TRACE_ON(xrender)) {
819 int pitch, i, j;
820 char output[300];
821 unsigned char *line;
823 if(format == AA_None) {
824 pitch = ((gi.width + 31) / 32) * 4;
825 for(i = 0; i < gi.height; i++) {
826 line = (unsigned char*) buf + i * pitch;
827 output[0] = '\0';
828 for(j = 0; j < pitch * 8; j++) {
829 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
831 TRACE("%s\n", output);
833 } else {
834 static const char blks[] = " .:;!o*#";
835 char str[2];
837 str[1] = '\0';
838 pitch = ((gi.width + 3) / 4) * 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; j++) {
843 str[0] = blks[line[j] >> 5];
844 strcat(output, str);
846 TRACE("%s\n", output);
852 if(formatEntry->glyphset) {
853 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
854 unsigned char *byte = (unsigned char*) buf, c;
855 int i = buflen;
857 while(i--) {
858 c = *byte;
860 /* magic to flip bit order */
861 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
862 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
863 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
865 *byte++ = c;
868 else if ( format != AA_Grey &&
869 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
871 unsigned int i, *data = (unsigned int *)buf;
872 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
874 gid = glyph;
877 XRenderCompositeText seems to ignore 0x0 glyphs when
878 AA_None, which means we lose the advance width of glyphs
879 like the space. We'll pretend that such glyphs are 1x1
880 bitmaps.
883 if(buflen == 0)
884 gi.width = gi.height = 1;
886 wine_tsx11_lock();
887 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
888 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
889 wine_tsx11_unlock();
890 HeapFree(GetProcessHeap(), 0, buf);
891 } else {
892 formatEntry->bitmaps[glyph] = buf;
895 formatEntry->gis[glyph] = gi;
897 return TRUE;
900 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
901 void *bitmap, XGlyphInfo *gi)
903 unsigned char *srcLine = bitmap, *src;
904 unsigned char bits, bitsMask;
905 int width = gi->width;
906 int stride = ((width + 31) & ~31) >> 3;
907 int height = gi->height;
908 int w;
909 int xspan, lenspan;
911 TRACE("%d, %d\n", x, y);
912 x -= gi->x;
913 y -= gi->y;
914 while (height--)
916 src = srcLine;
917 srcLine += stride;
918 w = width;
920 bitsMask = 0x80; /* FreeType is always MSB first */
921 bits = *src++;
923 xspan = x;
924 while (w)
926 if (bits & bitsMask)
928 lenspan = 0;
931 lenspan++;
932 if (lenspan == w)
933 break;
934 bitsMask = bitsMask >> 1;
935 if (!bitsMask)
937 bits = *src++;
938 bitsMask = 0x80;
940 } while (bits & bitsMask);
941 XFillRectangle (gdi_display, physDev->drawable,
942 physDev->gc, xspan, y, lenspan, 1);
943 xspan += lenspan;
944 w -= lenspan;
946 else
950 w--;
951 xspan++;
952 if (!w)
953 break;
954 bitsMask = bitsMask >> 1;
955 if (!bitsMask)
957 bits = *src++;
958 bitsMask = 0x80;
960 } while (!(bits & bitsMask));
963 y++;
967 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
968 void *bitmap, XGlyphInfo *gi)
970 unsigned char *srcLine = bitmap, *src, bits;
971 int width = gi->width;
972 int stride = ((width + 3) & ~3);
973 int height = gi->height;
974 int w;
975 int xspan, lenspan;
977 x -= gi->x;
978 y -= gi->y;
979 while (height--)
981 src = srcLine;
982 srcLine += stride;
983 w = width;
985 bits = *src++;
986 xspan = x;
987 while (w)
989 if (bits >= 0x80)
991 lenspan = 0;
994 lenspan++;
995 if (lenspan == w)
996 break;
997 bits = *src++;
998 } while (bits >= 0x80);
999 XFillRectangle (gdi_display, physDev->drawable,
1000 physDev->gc, xspan, y, lenspan, 1);
1001 xspan += lenspan;
1002 w -= lenspan;
1004 else
1008 w--;
1009 xspan++;
1010 if (!w)
1011 break;
1012 bits = *src++;
1013 } while (bits < 0x80);
1016 y++;
1021 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1023 int s, l;
1025 s = 0;
1026 while ((mask & 1) == 0)
1028 mask >>= 1;
1029 s++;
1031 l = 0;
1032 while ((mask & 1) == 1)
1034 mask >>= 1;
1035 l++;
1037 *shift = s;
1038 *len = l;
1041 static DWORD GetField (DWORD pixel, int shift, int len)
1043 pixel = pixel & (((1 << (len)) - 1) << shift);
1044 pixel = pixel << (32 - (shift + len)) >> 24;
1045 while (len < 8)
1047 pixel |= (pixel >> len);
1048 len <<= 1;
1050 return pixel;
1054 static DWORD PutField (DWORD pixel, int shift, int len)
1056 shift = shift - (8 - len);
1057 if (len <= 8)
1058 pixel &= (((1 << len) - 1) << (8 - len));
1059 if (shift < 0)
1060 pixel >>= -shift;
1061 else
1062 pixel <<= shift;
1063 return pixel;
1066 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1067 int color)
1069 int r_shift, r_len;
1070 int g_shift, g_len;
1071 int b_shift, b_len;
1072 BYTE *maskLine, *mask, m;
1073 int maskStride;
1074 DWORD pixel;
1075 int width, height;
1076 int w, tx;
1077 BYTE src_r, src_g, src_b;
1079 x -= gi->x;
1080 y -= gi->y;
1081 width = gi->width;
1082 height = gi->height;
1084 maskLine = bitmap;
1085 maskStride = (width + 3) & ~3;
1087 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1088 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1089 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1091 src_r = GetField(color, r_shift, r_len);
1092 src_g = GetField(color, g_shift, g_len);
1093 src_b = GetField(color, b_shift, b_len);
1095 for(; height--; y++)
1097 mask = maskLine;
1098 maskLine += maskStride;
1099 w = width;
1100 tx = x;
1102 if(y < 0) continue;
1103 if(y >= image->height) break;
1105 for(; w--; tx++)
1107 if(tx >= image->width) break;
1109 m = *mask++;
1110 if(tx < 0) continue;
1112 if (m == 0xff)
1113 XPutPixel (image, tx, y, color);
1114 else if (m)
1116 BYTE r, g, b;
1118 pixel = XGetPixel (image, tx, y);
1120 r = GetField(pixel, r_shift, r_len);
1121 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1122 g = GetField(pixel, g_shift, g_len);
1123 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1124 b = GetField(pixel, b_shift, b_len);
1125 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1127 pixel = (PutField (r, r_shift, r_len) |
1128 PutField (g, g_shift, g_len) |
1129 PutField (b, b_shift, b_len));
1130 XPutPixel (image, tx, y, pixel);
1136 /*************************************************************
1137 * get_tile_pict
1139 * Returns an appropriate Picture for tiling the text colour.
1140 * Call and use result within the xrender_cs
1142 static Picture get_tile_pict(enum drawable_depth_type type, int text_pixel)
1144 static struct
1146 Pixmap xpm;
1147 Picture pict;
1148 int current_color;
1149 } tiles[2], *tile;
1150 XRenderColor col;
1152 tile = &tiles[type];
1154 if(!tile->xpm)
1156 XRenderPictureAttributes pa;
1158 wine_tsx11_lock();
1159 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_formats[type]->depth);
1161 pa.repeat = True;
1162 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_formats[type], CPRepeat, &pa);
1163 wine_tsx11_unlock();
1165 /* init current_color to something different from text_pixel */
1166 tile->current_color = ~text_pixel;
1168 if(type == mono_drawable)
1170 /* for a 1bpp bitmap we always need a 1 in the tile */
1171 col.red = col.green = col.blue = 0;
1172 col.alpha = 0xffff;
1173 wine_tsx11_lock();
1174 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1175 wine_tsx11_unlock();
1179 if(text_pixel != tile->current_color && type == color_drawable)
1181 /* Map 0 -- 0xff onto 0 -- 0xffff */
1182 int r_shift, r_len;
1183 int g_shift, g_len;
1184 int b_shift, b_len;
1186 ExamineBitfield (visual->red_mask, &r_shift, &r_len );
1187 ExamineBitfield (visual->green_mask, &g_shift, &g_len);
1188 ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
1190 col.red = GetField(text_pixel, r_shift, r_len);
1191 col.red |= col.red << 8;
1192 col.green = GetField(text_pixel, g_shift, g_len);
1193 col.green |= col.green << 8;
1194 col.blue = GetField(text_pixel, b_shift, b_len);
1195 col.blue |= col.blue << 8;
1196 col.alpha = 0xffff;
1198 wine_tsx11_lock();
1199 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1200 wine_tsx11_unlock();
1201 tile->current_color = text_pixel;
1203 return tile->pict;
1206 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1208 return 1;
1211 /***********************************************************************
1212 * X11DRV_XRender_ExtTextOut
1214 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1215 const RECT *lprect, LPCWSTR wstr, UINT count,
1216 const INT *lpDx )
1218 RGNDATA *data;
1219 XGCValues xgcval;
1220 gsCacheEntry *entry;
1221 gsCacheEntryFormat *formatEntry;
1222 BOOL retv = FALSE;
1223 HDC hdc = physDev->hdc;
1224 int textPixel, backgroundPixel;
1225 HRGN saved_region = 0;
1226 BOOL disable_antialias = FALSE;
1227 AA_Type aa_type = AA_None;
1228 DIBSECTION bmp;
1229 unsigned int idx;
1230 double cosEsc, sinEsc;
1231 LOGFONTW lf;
1232 enum drawable_depth_type depth_type = (physDev->depth == 1) ? mono_drawable : color_drawable;
1233 Picture tile_pict = 0;
1235 /* Do we need to disable antialiasing because of palette mode? */
1236 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1237 TRACE("bitmap is not a DIB\n");
1239 else if (bmp.dsBmih.biBitCount <= 8) {
1240 TRACE("Disabling antialiasing\n");
1241 disable_antialias = TRUE;
1244 xgcval.function = GXcopy;
1245 xgcval.background = physDev->backgroundPixel;
1246 xgcval.fill_style = FillSolid;
1247 wine_tsx11_lock();
1248 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1249 wine_tsx11_unlock();
1251 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1253 if(physDev->depth == 1) {
1254 if((physDev->textPixel & 0xffffff) == 0) {
1255 textPixel = 0;
1256 backgroundPixel = 1;
1257 } else {
1258 textPixel = 1;
1259 backgroundPixel = 0;
1261 } else {
1262 textPixel = physDev->textPixel;
1263 backgroundPixel = physDev->backgroundPixel;
1266 if(flags & ETO_OPAQUE)
1268 wine_tsx11_lock();
1269 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1270 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1271 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1272 lprect->right - lprect->left, lprect->bottom - lprect->top );
1273 wine_tsx11_unlock();
1276 if(count == 0)
1278 retv = TRUE;
1279 goto done_unlock;
1283 GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1284 if(lf.lfEscapement != 0) {
1285 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1286 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1287 } else {
1288 cosEsc = 1;
1289 sinEsc = 0;
1292 if (flags & ETO_CLIPPED)
1294 HRGN clip_region;
1296 clip_region = CreateRectRgnIndirect( lprect );
1297 /* make a copy of the current device region */
1298 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1299 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1300 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1301 DeleteObject( clip_region );
1304 if(X11DRV_XRender_Installed) {
1305 if(!physDev->xrender->pict) {
1306 XRenderPictureAttributes pa;
1307 pa.subwindow_mode = IncludeInferiors;
1309 wine_tsx11_lock();
1310 physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1311 physDev->drawable,
1312 pict_formats[depth_type],
1313 CPSubwindowMode, &pa);
1314 wine_tsx11_unlock();
1316 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1317 physDev->xrender->pict, hdc, physDev->drawable);
1318 } else {
1319 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1320 physDev->xrender->pict, hdc, physDev->drawable);
1323 if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1325 wine_tsx11_lock();
1326 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1327 physDev->dc_rect.left, physDev->dc_rect.top,
1328 (XRectangle *)data->Buffer, data->rdh.nCount );
1329 wine_tsx11_unlock();
1330 HeapFree( GetProcessHeap(), 0, data );
1334 EnterCriticalSection(&xrender_cs);
1336 entry = glyphsetCache + physDev->xrender->cache_index;
1337 if( disable_antialias == FALSE )
1338 aa_type = entry->aa_default;
1339 formatEntry = entry->format[aa_type];
1341 for(idx = 0; idx < count; idx++) {
1342 if( !formatEntry ) {
1343 UploadGlyph(physDev, wstr[idx], aa_type);
1344 /* re-evaluate antialias since aa_default may have changed */
1345 if( disable_antialias == FALSE )
1346 aa_type = entry->aa_default;
1347 formatEntry = entry->format[aa_type];
1348 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1349 UploadGlyph(physDev, wstr[idx], aa_type);
1352 if (!formatEntry)
1354 WARN("could not upload requested glyphs\n");
1355 LeaveCriticalSection(&xrender_cs);
1356 goto done_unlock;
1359 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1360 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1362 if(X11DRV_XRender_Installed)
1364 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1365 INT offset = 0;
1366 POINT desired, current;
1367 int render_op = PictOpOver;
1369 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1370 So we pass zeros to the function and move to our starting position using the first
1371 element of the elts array. */
1373 desired.x = physDev->dc_rect.left + x;
1374 desired.y = physDev->dc_rect.top + y;
1375 current.x = current.y = 0;
1377 tile_pict = get_tile_pict(depth_type, physDev->textPixel);
1379 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1381 if((depth_type == mono_drawable) && (textPixel == 0))
1382 render_op = PictOpOutReverse; /* This gives us 'black' text */
1384 for(idx = 0; idx < count; idx++)
1386 elts[idx].glyphset = formatEntry->glyphset;
1387 elts[idx].chars = wstr + idx;
1388 elts[idx].nchars = 1;
1389 elts[idx].xOff = desired.x - current.x;
1390 elts[idx].yOff = desired.y - current.y;
1392 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1393 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1395 if(!lpDx)
1397 desired.x += formatEntry->gis[wstr[idx]].xOff;
1398 desired.y += formatEntry->gis[wstr[idx]].yOff;
1400 else
1402 offset += lpDx[idx];
1403 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1404 desired.y = physDev->dc_rect.top + y - offset * sinEsc;
1407 wine_tsx11_lock();
1408 pXRenderCompositeText16(gdi_display, render_op,
1409 tile_pict,
1410 physDev->xrender->pict,
1411 formatEntry->font_format,
1412 0, 0, 0, 0, elts, count);
1413 wine_tsx11_unlock();
1414 HeapFree(GetProcessHeap(), 0, elts);
1415 } else {
1416 INT offset = 0, xoff = 0, yoff = 0;
1417 wine_tsx11_lock();
1418 XSetForeground( gdi_display, physDev->gc, textPixel );
1420 if(aa_type == AA_None || physDev->depth == 1)
1422 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1424 if(aa_type == AA_None)
1425 sharp_glyph_fn = SharpGlyphMono;
1426 else
1427 sharp_glyph_fn = SharpGlyphGray;
1429 for(idx = 0; idx < count; idx++) {
1430 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1431 physDev->dc_rect.top + y + yoff,
1432 formatEntry->bitmaps[wstr[idx]],
1433 &formatEntry->gis[wstr[idx]]);
1434 if(lpDx) {
1435 offset += lpDx[idx];
1436 xoff = offset * cosEsc;
1437 yoff = offset * -sinEsc;
1438 } else {
1439 xoff += formatEntry->gis[wstr[idx]].xOff;
1440 yoff += formatEntry->gis[wstr[idx]].yOff;
1443 } else {
1444 XImage *image;
1445 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1446 RECT extents = {0, 0, 0, 0};
1447 POINT cur = {0, 0};
1448 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1449 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1451 TRACE("drawable %dx%d\n", w, h);
1453 for(idx = 0; idx < count; idx++) {
1454 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1455 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1456 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1457 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1458 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1459 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1460 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1461 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1462 if(lpDx) {
1463 offset += lpDx[idx];
1464 cur.x = offset * cosEsc;
1465 cur.y = offset * -sinEsc;
1466 } else {
1467 cur.x += formatEntry->gis[wstr[idx]].xOff;
1468 cur.y += formatEntry->gis[wstr[idx]].yOff;
1471 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1472 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1474 if(physDev->dc_rect.left + x + extents.left >= 0) {
1475 image_x = physDev->dc_rect.left + x + extents.left;
1476 image_off_x = 0;
1477 } else {
1478 image_x = 0;
1479 image_off_x = physDev->dc_rect.left + x + extents.left;
1481 if(physDev->dc_rect.top + y + extents.top >= 0) {
1482 image_y = physDev->dc_rect.top + y + extents.top;
1483 image_off_y = 0;
1484 } else {
1485 image_y = 0;
1486 image_off_y = physDev->dc_rect.top + y + extents.top;
1488 if(physDev->dc_rect.left + x + extents.right < w)
1489 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1490 else
1491 image_w = w - image_x;
1492 if(physDev->dc_rect.top + y + extents.bottom < h)
1493 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1494 else
1495 image_h = h - image_y;
1497 if(image_w <= 0 || image_h <= 0) goto no_image;
1499 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1500 image = XGetImage(gdi_display, physDev->drawable,
1501 image_x, image_y, image_w, image_h,
1502 AllPlanes, ZPixmap);
1503 X11DRV_check_error();
1505 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1506 gdi_display, (int)physDev->drawable, image_x, image_y,
1507 image_w, image_h, AllPlanes, ZPixmap,
1508 physDev->depth, image);
1509 if(!image) {
1510 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
1511 physDev->depth);
1512 GC gc;
1513 XGCValues gcv;
1515 gcv.graphics_exposures = False;
1516 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1517 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1518 image_w, image_h, 0, 0);
1519 XFreeGC(gdi_display, gc);
1520 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1521 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1522 ZPixmap);
1523 X11DRV_check_error();
1524 XFreePixmap(gdi_display, xpm);
1526 if(!image) goto no_image;
1528 image->red_mask = visual->red_mask;
1529 image->green_mask = visual->green_mask;
1530 image->blue_mask = visual->blue_mask;
1532 offset = xoff = yoff = 0;
1533 for(idx = 0; idx < count; idx++) {
1534 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1535 yoff + image_off_y - extents.top,
1536 formatEntry->bitmaps[wstr[idx]],
1537 &formatEntry->gis[wstr[idx]],
1538 physDev->textPixel);
1539 if(lpDx) {
1540 offset += lpDx[idx];
1541 xoff = offset * cosEsc;
1542 yoff = offset * -sinEsc;
1543 } else {
1544 xoff += formatEntry->gis[wstr[idx]].xOff;
1545 yoff += formatEntry->gis[wstr[idx]].yOff;
1548 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1549 image_x, image_y, image_w, image_h);
1550 XDestroyImage(image);
1552 no_image:
1553 wine_tsx11_unlock();
1555 LeaveCriticalSection(&xrender_cs);
1557 if (flags & ETO_CLIPPED)
1559 /* restore the device region */
1560 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1561 DeleteObject( saved_region );
1564 retv = TRUE;
1566 done_unlock:
1567 X11DRV_UnlockDIBSection( physDev, TRUE );
1568 return retv;
1571 /******************************************************************************
1572 * AlphaBlend (x11drv.@)
1574 BOOL CDECL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1575 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1576 BLENDFUNCTION blendfn)
1578 XRenderPictureAttributes pa;
1579 XRenderPictFormat *src_format;
1580 XRenderPictFormat argb32_templ = {
1581 0, /* id */
1582 PictTypeDirect, /* type */
1583 32, /* depth */
1584 { /* direct */
1585 16, /* direct.red */
1586 0xff, /* direct.redMask */
1587 8, /* direct.green */
1588 0xff, /* direct.greenMask */
1589 0, /* direct.blue */
1590 0xff, /* direct.blueMask */
1591 24, /* direct.alpha */
1592 0xff, /* direct.alphaMask */
1594 0, /* colormap */
1596 unsigned long argb32_templ_mask =
1597 PictFormatType |
1598 PictFormatDepth |
1599 PictFormatRed |
1600 PictFormatRedMask |
1601 PictFormatGreen |
1602 PictFormatGreenMask |
1603 PictFormatBlue |
1604 PictFormatBlueMask |
1605 PictFormatAlpha |
1606 PictFormatAlphaMask;
1608 Picture dst_pict, src_pict;
1609 Pixmap xpm;
1610 DIBSECTION dib;
1611 XImage *image;
1612 GC gc;
1613 XGCValues gcv;
1614 DWORD *dstbits, *data;
1615 int y, y2;
1616 POINT pts[2];
1617 BOOL top_down = FALSE;
1618 RGNDATA *rgndata;
1619 enum drawable_depth_type dst_depth_type = (devDst->depth == 1) ? mono_drawable : color_drawable;
1621 if(!X11DRV_XRender_Installed) {
1622 FIXME("Unable to AlphaBlend without Xrender\n");
1623 return FALSE;
1625 pts[0].x = xDst;
1626 pts[0].y = yDst;
1627 pts[1].x = xDst + widthDst;
1628 pts[1].y = yDst + heightDst;
1629 LPtoDP(devDst->hdc, pts, 2);
1630 xDst = pts[0].x;
1631 yDst = pts[0].y;
1632 widthDst = pts[1].x - pts[0].x;
1633 heightDst = pts[1].y - pts[0].y;
1635 pts[0].x = xSrc;
1636 pts[0].y = ySrc;
1637 pts[1].x = xSrc + widthSrc;
1638 pts[1].y = ySrc + heightSrc;
1639 LPtoDP(devSrc->hdc, pts, 2);
1640 xSrc = pts[0].x;
1641 ySrc = pts[0].y;
1642 widthSrc = pts[1].x - pts[0].x;
1643 heightSrc = pts[1].y - pts[0].y;
1644 if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1646 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1647 if(widthDst != widthSrc || heightDst != heightSrc)
1648 #else
1649 if(!pXRenderSetPictureTransform)
1650 #endif
1652 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1653 return FALSE;
1656 if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1658 static BOOL out = FALSE;
1659 if (!out)
1661 FIXME("not a dibsection\n");
1662 out = TRUE;
1664 return FALSE;
1667 if (xSrc < 0 || ySrc < 0 || widthSrc < 0 || heightSrc < 0 || xSrc + widthSrc > dib.dsBmih.biWidth
1668 || ySrc + heightSrc > abs(dib.dsBmih.biHeight))
1670 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc, ySrc, widthSrc, heightSrc);
1671 SetLastError(ERROR_INVALID_PARAMETER);
1672 return FALSE;
1675 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && blendfn.SourceConstantAlpha != 0xff)
1676 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn.SourceConstantAlpha);
1678 if(dib.dsBm.bmBitsPixel != 32) {
1679 FIXME("not a 32 bpp dibsection\n");
1680 return FALSE;
1682 dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1684 if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1685 top_down = TRUE;
1686 dstbits += widthSrc * (heightSrc - 1);
1687 y2 = ySrc;
1688 y = y2 + heightSrc - 1;
1690 else
1692 y = dib.dsBmih.biHeight - ySrc - 1;
1693 y2 = y - heightSrc + 1;
1696 if (blendfn.AlphaFormat & AC_SRC_ALPHA)
1698 for(; y >= y2; y--)
1700 memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1701 widthSrc * 4);
1702 dstbits += (top_down ? -1 : 1) * widthSrc;
1705 else
1707 DWORD source_alpha = (DWORD)blendfn.SourceConstantAlpha << 24;
1708 int x;
1710 for(; y >= y2; y--)
1712 DWORD *srcbits = (DWORD *)((char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes) + xSrc;
1713 for (x = 0; x < widthSrc; x++)
1715 DWORD argb = *srcbits++;
1716 argb = (argb & 0xffffff) | source_alpha;
1717 *dstbits++ = argb;
1719 if (top_down) /* we traversed the row forward so we should go back by two rows */
1720 dstbits -= 2 * widthSrc;
1725 rgndata = X11DRV_GetRegionData( devDst->region, 0 );
1727 wine_tsx11_lock();
1728 image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1729 (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1732 Avoid using XRenderFindStandardFormat as older libraries don't have it
1733 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1735 src_format = pXRenderFindFormat(gdi_display, argb32_templ_mask, &argb32_templ, 0);
1737 TRACE("src_format %p\n", src_format);
1739 pa.subwindow_mode = IncludeInferiors;
1741 /* FIXME use devDst->xrender->pict ? */
1742 dst_pict = pXRenderCreatePicture(gdi_display,
1743 devDst->drawable,
1744 pict_formats[dst_depth_type],
1745 CPSubwindowMode, &pa);
1746 TRACE("dst_pict %08lx\n", dst_pict);
1747 TRACE("src_drawable = %08lx\n", devSrc->drawable);
1748 xpm = XCreatePixmap(gdi_display,
1749 root_window,
1750 widthSrc, heightSrc, 32);
1751 gcv.graphics_exposures = False;
1752 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1753 TRACE("xpm = %08lx\n", xpm);
1754 XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1756 src_pict = pXRenderCreatePicture(gdi_display,
1757 xpm, src_format,
1758 CPSubwindowMode, &pa);
1759 TRACE("src_pict %08lx\n", src_pict);
1761 if (rgndata)
1763 pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
1764 devDst->dc_rect.left, devDst->dc_rect.top,
1765 (XRectangle *)rgndata->Buffer,
1766 rgndata->rdh.nCount );
1767 HeapFree( GetProcessHeap(), 0, rgndata );
1770 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1771 if(widthDst != widthSrc || heightDst != heightSrc) {
1772 double xscale = widthSrc/(double)widthDst;
1773 double yscale = heightSrc/(double)heightDst;
1774 XTransform xform = {{
1775 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0) },
1776 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0) },
1777 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1779 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1781 #endif
1782 pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
1783 0, 0, 0, 0,
1784 xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
1787 pXRenderFreePicture(gdi_display, src_pict);
1788 XFreePixmap(gdi_display, xpm);
1789 XFreeGC(gdi_display, gc);
1790 pXRenderFreePicture(gdi_display, dst_pict);
1791 image->data = NULL;
1792 XDestroyImage(image);
1794 wine_tsx11_unlock();
1795 HeapFree(GetProcessHeap(), 0, data);
1796 return TRUE;
1799 #else /* SONAME_LIBXRENDER */
1801 void X11DRV_XRender_Init(void)
1803 TRACE("XRender support not compiled in.\n");
1804 return;
1807 void X11DRV_XRender_Finalize(void)
1811 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1813 assert(0);
1814 return FALSE;
1817 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1819 assert(0);
1820 return;
1823 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1824 const RECT *lprect, LPCWSTR wstr, UINT count,
1825 const INT *lpDx )
1827 assert(0);
1828 return FALSE;
1831 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1833 assert(0);
1834 return;
1837 /******************************************************************************
1838 * AlphaBlend (x11drv.@)
1840 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1841 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1842 BLENDFUNCTION blendfn)
1844 FIXME("not supported - XRENDER headers were missing at compile time\n");
1845 return FALSE;
1848 #endif /* SONAME_LIBXRENDER */