ntprint: Implement PSetupEnumMonitor.
[wine/testsucceed.git] / dlls / winex11.drv / xrender.c
blob1e196a737a8032b3f2b0faa8f7cfe5dd164d2a56
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 static BOOL X11DRV_XRender_Installed = FALSE;
40 int using_client_side_fonts = FALSE;
42 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
44 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
46 #include <X11/Xlib.h>
47 #include <X11/extensions/Xrender.h>
49 static XRenderPictFormat *screen_format; /* format of screen */
50 static XRenderPictFormat *mono_format; /* format of mono bitmap */
52 typedef struct
54 LOGFONTW lf;
55 SIZE devsize; /* size in device coords */
56 DWORD hash;
57 } LFANDSIZE;
59 #define INITIAL_REALIZED_BUF_SIZE 128
61 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
63 typedef struct
65 GlyphSet glyphset;
66 XRenderPictFormat *font_format;
67 int nrealized;
68 BOOL *realized;
69 void **bitmaps;
70 XGlyphInfo *gis;
71 } gsCacheEntryFormat;
73 typedef struct
75 LFANDSIZE lfsz;
76 AA_Type aa_default;
77 gsCacheEntryFormat * format[AA_MAXVALUE];
78 INT count;
79 INT next;
80 } gsCacheEntry;
82 struct tagXRENDERINFO
84 int cache_index;
85 Picture pict;
86 Picture tile_pict;
87 Pixmap tile_xpm;
88 COLORREF lastTextColor;
92 static gsCacheEntry *glyphsetCache = NULL;
93 static DWORD glyphsetCacheSize = 0;
94 static INT lastfree = -1;
95 static INT mru = -1;
97 #define INIT_CACHE_SIZE 10
99 static int antialias = 1;
101 /* some default values just in case */
102 #ifndef SONAME_LIBX11
103 #define SONAME_LIBX11 "libX11.so"
104 #endif
105 #ifndef SONAME_LIBXEXT
106 #define SONAME_LIBXEXT "libXext.so"
107 #endif
108 #ifndef SONAME_LIBXRENDER
109 #define SONAME_LIBXRENDER "libXrender.so"
110 #endif
112 static void *xrender_handle;
114 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
115 MAKE_FUNCPTR(XRenderAddGlyphs)
116 MAKE_FUNCPTR(XRenderComposite)
117 MAKE_FUNCPTR(XRenderCompositeString8)
118 MAKE_FUNCPTR(XRenderCompositeString16)
119 MAKE_FUNCPTR(XRenderCompositeString32)
120 MAKE_FUNCPTR(XRenderCompositeText16)
121 MAKE_FUNCPTR(XRenderCreateGlyphSet)
122 MAKE_FUNCPTR(XRenderCreatePicture)
123 MAKE_FUNCPTR(XRenderFillRectangle)
124 MAKE_FUNCPTR(XRenderFindFormat)
125 MAKE_FUNCPTR(XRenderFindVisualFormat)
126 MAKE_FUNCPTR(XRenderFreeGlyphSet)
127 MAKE_FUNCPTR(XRenderFreePicture)
128 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
129 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
130 MAKE_FUNCPTR(XRenderSetPictureTransform)
131 #endif
132 MAKE_FUNCPTR(XRenderQueryExtension)
133 #undef MAKE_FUNCPTR
135 static CRITICAL_SECTION xrender_cs;
136 static CRITICAL_SECTION_DEBUG critsect_debug =
138 0, 0, &xrender_cs,
139 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
140 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
142 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
144 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
145 ( ( (ULONG)_x4 << 24 ) | \
146 ( (ULONG)_x3 << 16 ) | \
147 ( (ULONG)_x2 << 8 ) | \
148 (ULONG)_x1 )
150 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
152 #define GASP_GRIDFIT 0x01
153 #define GASP_DOGRAY 0x02
155 #ifdef WORDS_BIGENDIAN
156 #define get_be_word(x) (x)
157 #else
158 #define get_be_word(x) RtlUshortByteSwap(x)
159 #endif
161 /***********************************************************************
162 * X11DRV_XRender_Init
164 * Let's see if our XServer has the extension available
167 void X11DRV_XRender_Init(void)
169 int event_base, i;
170 XRenderPictFormat pf;
172 if (client_side_with_render &&
173 wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
174 wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
175 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
178 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
179 LOAD_FUNCPTR(XRenderAddGlyphs)
180 LOAD_FUNCPTR(XRenderComposite)
181 LOAD_FUNCPTR(XRenderCompositeString8)
182 LOAD_FUNCPTR(XRenderCompositeString16)
183 LOAD_FUNCPTR(XRenderCompositeString32)
184 LOAD_FUNCPTR(XRenderCompositeText16)
185 LOAD_FUNCPTR(XRenderCreateGlyphSet)
186 LOAD_FUNCPTR(XRenderCreatePicture)
187 LOAD_FUNCPTR(XRenderFillRectangle)
188 LOAD_FUNCPTR(XRenderFindFormat)
189 LOAD_FUNCPTR(XRenderFindVisualFormat)
190 LOAD_FUNCPTR(XRenderFreeGlyphSet)
191 LOAD_FUNCPTR(XRenderFreePicture)
192 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
193 LOAD_FUNCPTR(XRenderQueryExtension)
194 #undef LOAD_FUNCPTR
195 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
196 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
197 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
198 #undef LOAD_OPTIONAL_FUNCPTR
199 #endif
202 wine_tsx11_lock();
203 if(pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) {
204 X11DRV_XRender_Installed = TRUE;
205 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
206 screen_format = pXRenderFindVisualFormat(gdi_display, visual);
207 if(!screen_format)
209 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
210 if (visual->class == DirectColor)
212 XVisualInfo info;
213 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
214 screen_depth, TrueColor, &info ))
216 screen_format = pXRenderFindVisualFormat(gdi_display, info.visual);
217 if (screen_format) visual = info.visual;
221 if(!screen_format) /* This fails in buggy versions of libXrender.so */
223 wine_tsx11_unlock();
224 WINE_MESSAGE(
225 "Wine has detected that you probably have a buggy version\n"
226 "of libXrender.so . Because of this client side font rendering\n"
227 "will be disabled. Please upgrade this library.\n");
228 X11DRV_XRender_Installed = FALSE;
229 return;
231 pf.type = PictTypeDirect;
232 pf.depth = 1;
233 pf.direct.alpha = 0;
234 pf.direct.alphaMask = 1;
235 mono_format = pXRenderFindFormat(gdi_display, PictFormatType |
236 PictFormatDepth | PictFormatAlpha |
237 PictFormatAlphaMask, &pf, 0);
238 if(!mono_format) {
239 ERR("mono_format == NULL?\n");
240 X11DRV_XRender_Installed = FALSE;
242 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
243 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
244 X11DRV_XRender_Installed = FALSE;
247 wine_tsx11_unlock();
250 sym_not_found:
251 if(X11DRV_XRender_Installed || client_side_with_core)
253 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
254 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
256 glyphsetCacheSize = INIT_CACHE_SIZE;
257 lastfree = 0;
258 for(i = 0; i < INIT_CACHE_SIZE; i++) {
259 glyphsetCache[i].next = i + 1;
260 glyphsetCache[i].count = -1;
262 glyphsetCache[i-1].next = -1;
263 using_client_side_fonts = 1;
265 if(!X11DRV_XRender_Installed) {
266 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
267 if(screen_depth <= 8 || !client_side_antialias_with_core)
268 antialias = 0;
269 } else {
270 if(screen_depth <= 8 || !client_side_antialias_with_render)
271 antialias = 0;
274 else TRACE("Using X11 core fonts\n");
277 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
279 if(p1->hash != p2->hash) return TRUE;
280 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
281 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
282 return strcmpW(p1->lf.lfFaceName, p2->lf.lfFaceName);
285 #if 0
286 static void walk_cache(void)
288 int i;
290 EnterCriticalSection(&xrender_cs);
291 for(i=mru; i >= 0; i = glyphsetCache[i].next)
292 TRACE("item %d\n", i);
293 LeaveCriticalSection(&xrender_cs);
295 #endif
297 static int LookupEntry(LFANDSIZE *plfsz)
299 int i, prev_i = -1;
301 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
302 TRACE("%d\n", i);
303 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
304 i = -1;
305 break;
308 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
309 glyphsetCache[i].count++;
310 if(prev_i >= 0) {
311 glyphsetCache[prev_i].next = glyphsetCache[i].next;
312 glyphsetCache[i].next = mru;
313 mru = i;
315 TRACE("found font in cache %d\n", i);
316 return i;
318 prev_i = i;
320 TRACE("font not in cache\n");
321 return -1;
324 static void FreeEntry(int entry)
326 int i, format;
328 for(format = 0; format < AA_MAXVALUE; format++) {
329 gsCacheEntryFormat * formatEntry;
331 if( !glyphsetCache[entry].format[format] )
332 continue;
334 formatEntry = glyphsetCache[entry].format[format];
336 if(formatEntry->glyphset) {
337 wine_tsx11_lock();
338 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
339 wine_tsx11_unlock();
340 formatEntry->glyphset = 0;
342 if(formatEntry->nrealized) {
343 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
344 formatEntry->realized = NULL;
345 if(formatEntry->bitmaps) {
346 for(i = 0; i < formatEntry->nrealized; i++)
347 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
348 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
349 formatEntry->bitmaps = NULL;
351 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
352 formatEntry->gis = NULL;
353 formatEntry->nrealized = 0;
356 HeapFree(GetProcessHeap(), 0, formatEntry);
357 glyphsetCache[entry].format[format] = NULL;
361 static int AllocEntry(void)
363 int best = -1, prev_best = -1, i, prev_i = -1;
365 if(lastfree >= 0) {
366 assert(glyphsetCache[lastfree].count == -1);
367 glyphsetCache[lastfree].count = 1;
368 best = lastfree;
369 lastfree = glyphsetCache[lastfree].next;
370 assert(best != mru);
371 glyphsetCache[best].next = mru;
372 mru = best;
374 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
375 return mru;
378 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
379 if(glyphsetCache[i].count == 0) {
380 best = i;
381 prev_best = prev_i;
383 prev_i = i;
386 if(best >= 0) {
387 TRACE("freeing unused glyphset at cache %d\n", best);
388 FreeEntry(best);
389 glyphsetCache[best].count = 1;
390 if(prev_best >= 0) {
391 glyphsetCache[prev_best].next = glyphsetCache[best].next;
392 glyphsetCache[best].next = mru;
393 mru = best;
394 } else {
395 assert(mru == best);
397 return mru;
400 TRACE("Growing cache\n");
402 if (glyphsetCache)
403 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
404 glyphsetCache,
405 (glyphsetCacheSize + INIT_CACHE_SIZE)
406 * sizeof(*glyphsetCache));
407 else
408 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
409 (glyphsetCacheSize + INIT_CACHE_SIZE)
410 * sizeof(*glyphsetCache));
412 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
413 i++) {
414 glyphsetCache[i].next = i + 1;
415 glyphsetCache[i].count = -1;
417 glyphsetCache[i-1].next = -1;
418 glyphsetCacheSize += INIT_CACHE_SIZE;
420 lastfree = glyphsetCache[best].next;
421 glyphsetCache[best].count = 1;
422 glyphsetCache[best].next = mru;
423 mru = best;
424 TRACE("new free cache slot at %d\n", mru);
425 return mru;
428 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
430 DWORD size;
431 WORD *gasp, *buffer;
432 WORD num_recs;
433 DWORD ppem;
434 TEXTMETRICW tm;
436 *flags = 0;
438 size = GetFontData(physDev->hdc, MS_GASP_TAG, 0, NULL, 0);
439 if(size == GDI_ERROR)
440 return FALSE;
442 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
443 GetFontData(physDev->hdc, MS_GASP_TAG, 0, gasp, size);
445 GetTextMetricsW(physDev->hdc, &tm);
446 ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
448 gasp++;
449 num_recs = get_be_word(*gasp);
450 gasp++;
451 while(num_recs--)
453 *flags = get_be_word(*(gasp + 1));
454 if(ppem <= get_be_word(*gasp))
455 break;
456 gasp += 2;
458 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
460 HeapFree(GetProcessHeap(), 0, buffer);
461 return TRUE;
464 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
466 int ret;
467 int format;
468 gsCacheEntry *entry;
469 WORD flags;
470 static int hinter = -1;
472 if((ret = LookupEntry(plfsz)) != -1) return ret;
474 ret = AllocEntry();
475 entry = glyphsetCache + ret;
476 entry->lfsz = *plfsz;
477 for( format = 0; format < AA_MAXVALUE; format++ ) {
478 assert( !entry->format[format] );
481 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
483 if(hinter == -1)
485 RASTERIZER_STATUS status;
486 GetRasterizerCaps(&status, sizeof(status));
487 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
489 if(!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
490 entry->aa_default = AA_Grey;
491 else
492 entry->aa_default = AA_None;
494 else
495 entry->aa_default = AA_None;
497 return ret;
500 static void dec_ref_cache(int index)
502 assert(index >= 0);
503 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
504 assert(glyphsetCache[index].count > 0);
505 glyphsetCache[index].count--;
508 static void lfsz_calc_hash(LFANDSIZE *plfsz)
510 DWORD hash = 0, *ptr;
511 int i;
513 hash ^= plfsz->devsize.cx;
514 hash ^= plfsz->devsize.cy;
515 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
516 hash ^= *ptr;
517 for(i = 0, ptr = (DWORD*)&plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
518 WCHAR *pwc = (WCHAR *)ptr;
519 if(!*pwc) break;
520 hash ^= *ptr;
521 pwc++;
522 if(!*pwc) break;
524 plfsz->hash = hash;
525 return;
528 /***********************************************************************
529 * X11DRV_XRender_Finalize
531 void X11DRV_XRender_Finalize(void)
533 int i;
535 EnterCriticalSection(&xrender_cs);
536 for(i = mru; i >= 0; i = glyphsetCache[i].next)
537 FreeEntry(i);
538 LeaveCriticalSection(&xrender_cs);
542 /***********************************************************************
543 * X11DRV_XRender_SelectFont
545 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
547 LFANDSIZE lfsz;
549 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
550 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
551 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
552 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
553 lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
554 lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
555 lfsz_calc_hash(&lfsz);
557 EnterCriticalSection(&xrender_cs);
558 if(!physDev->xrender) {
559 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
560 sizeof(*physDev->xrender));
561 physDev->xrender->cache_index = -1;
563 else if(physDev->xrender->cache_index != -1)
564 dec_ref_cache(physDev->xrender->cache_index);
565 physDev->xrender->cache_index = GetCacheEntry(physDev, &lfsz);
566 LeaveCriticalSection(&xrender_cs);
567 return 0;
570 /***********************************************************************
571 * X11DRV_XRender_DeleteDC
573 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
575 X11DRV_XRender_UpdateDrawable(physDev);
577 EnterCriticalSection(&xrender_cs);
578 if(physDev->xrender->cache_index != -1)
579 dec_ref_cache(physDev->xrender->cache_index);
580 LeaveCriticalSection(&xrender_cs);
582 HeapFree(GetProcessHeap(), 0, physDev->xrender);
583 physDev->xrender = NULL;
584 return;
587 /***********************************************************************
588 * X11DRV_XRender_UpdateDrawable
590 * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
591 * It deletes the pict and tile when the drawable changes.
593 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
595 wine_tsx11_lock();
597 if(physDev->xrender->pict)
599 TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
600 XFlush(gdi_display);
601 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
602 physDev->xrender->pict = 0;
604 if(physDev->xrender->tile_pict)
606 pXRenderFreePicture(gdi_display, physDev->xrender->tile_pict);
607 physDev->xrender->tile_pict = 0;
609 if(physDev->xrender->tile_xpm)
611 XFreePixmap(gdi_display, physDev->xrender->tile_xpm);
612 physDev->xrender->tile_xpm = 0;
615 wine_tsx11_unlock();
617 return;
620 /************************************************************************
621 * UploadGlyph
623 * Helper to ExtTextOut. Must be called inside xrender_cs
625 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
627 unsigned int buflen;
628 char *buf;
629 Glyph gid;
630 GLYPHMETRICS gm;
631 XGlyphInfo gi;
632 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
633 gsCacheEntryFormat *formatEntry;
634 UINT ggo_format = GGO_GLYPH_INDEX;
635 XRenderPictFormat pf;
636 static const char zero[4];
638 switch(format) {
639 case AA_Grey:
640 ggo_format |= WINE_GGO_GRAY16_BITMAP;
641 break;
643 default:
644 ERR("aa = %d - not implemented\n", format);
645 case AA_None:
646 ggo_format |= GGO_BITMAP;
647 break;
650 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
651 NULL);
652 if(buflen == GDI_ERROR) {
653 if(format != AA_None) {
654 format = AA_None;
655 entry->aa_default = AA_None;
656 ggo_format &= ~WINE_GGO_GRAY16_BITMAP;
657 ggo_format |= GGO_BITMAP;
658 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
659 NULL);
661 if(buflen == GDI_ERROR) {
662 WARN("GetGlyphOutlineW failed\n");
663 return FALSE;
665 TRACE("Turning off antialiasing for this monochrome font\n");
668 /* If there is nothing for the current type, we create the entry. */
669 if( !entry->format[format] ) {
670 entry->format[format] = HeapAlloc(GetProcessHeap(),
671 HEAP_ZERO_MEMORY,
672 sizeof(gsCacheEntryFormat));
674 formatEntry = entry->format[format];
676 if(formatEntry->nrealized <= glyph) {
677 formatEntry->nrealized = (glyph / 128 + 1) * 128;
679 if (formatEntry->realized)
680 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
681 HEAP_ZERO_MEMORY,
682 formatEntry->realized,
683 formatEntry->nrealized * sizeof(BOOL));
684 else
685 formatEntry->realized = HeapAlloc(GetProcessHeap(),
686 HEAP_ZERO_MEMORY,
687 formatEntry->nrealized * sizeof(BOOL));
689 if(!X11DRV_XRender_Installed) {
690 if (formatEntry->bitmaps)
691 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
692 HEAP_ZERO_MEMORY,
693 formatEntry->bitmaps,
694 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
695 else
696 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
697 HEAP_ZERO_MEMORY,
698 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
700 if (formatEntry->gis)
701 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
702 HEAP_ZERO_MEMORY,
703 formatEntry->gis,
704 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
705 else
706 formatEntry->gis = HeapAlloc(GetProcessHeap(),
707 HEAP_ZERO_MEMORY,
708 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
712 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
713 switch(format) {
714 case AA_Grey:
715 pf.depth = 8;
716 pf.direct.alphaMask = 0xff;
717 break;
719 default:
720 ERR("aa = %d - not implemented\n", format);
721 case AA_None:
722 pf.depth = 1;
723 pf.direct.alphaMask = 1;
724 break;
727 pf.type = PictTypeDirect;
728 pf.direct.alpha = 0;
730 wine_tsx11_lock();
731 formatEntry->font_format = pXRenderFindFormat(gdi_display,
732 PictFormatType |
733 PictFormatDepth |
734 PictFormatAlpha |
735 PictFormatAlphaMask,
736 &pf, 0);
738 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
739 wine_tsx11_unlock();
743 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
744 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, NULL);
745 formatEntry->realized[glyph] = TRUE;
747 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
748 buflen,
749 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
750 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
752 gi.width = gm.gmBlackBoxX;
753 gi.height = gm.gmBlackBoxY;
754 gi.x = -gm.gmptGlyphOrigin.x;
755 gi.y = gm.gmptGlyphOrigin.y;
756 gi.xOff = gm.gmCellIncX;
757 gi.yOff = gm.gmCellIncY;
759 if(TRACE_ON(xrender)) {
760 int pitch, i, j;
761 char output[300];
762 unsigned char *line;
764 if(format == AA_None) {
765 pitch = ((gi.width + 31) / 32) * 4;
766 for(i = 0; i < gi.height; i++) {
767 line = (unsigned char*) buf + i * pitch;
768 output[0] = '\0';
769 for(j = 0; j < pitch * 8; j++) {
770 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
772 strcat(output, "\n");
773 TRACE(output);
775 } else {
776 static const char blks[] = " .:;!o*#";
777 char str[2];
779 str[1] = '\0';
780 pitch = ((gi.width + 3) / 4) * 4;
781 for(i = 0; i < gi.height; i++) {
782 line = (unsigned char*) buf + i * pitch;
783 output[0] = '\0';
784 for(j = 0; j < pitch; j++) {
785 str[0] = blks[line[j] >> 5];
786 strcat(output, str);
788 strcat(output, "\n");
789 TRACE(output);
795 if(formatEntry->glyphset) {
796 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
797 unsigned char *byte = (unsigned char*) buf, c;
798 int i = buflen;
800 while(i--) {
801 c = *byte;
803 /* magic to flip bit order */
804 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
805 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
806 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
808 *byte++ = c;
811 gid = glyph;
814 XRenderCompositeText seems to ignore 0x0 glyphs when
815 AA_None, which means we lose the advance width of glyphs
816 like the space. We'll pretend that such glyphs are 1x1
817 bitmaps.
820 if(buflen == 0)
821 gi.width = gi.height = 1;
823 wine_tsx11_lock();
824 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
825 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
826 wine_tsx11_unlock();
827 HeapFree(GetProcessHeap(), 0, buf);
828 } else {
829 formatEntry->bitmaps[glyph] = buf;
832 memcpy(&formatEntry->gis[glyph], &gi, sizeof(gi));
834 return TRUE;
837 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
838 void *bitmap, XGlyphInfo *gi)
840 unsigned char *srcLine = bitmap, *src;
841 unsigned char bits, bitsMask;
842 int width = gi->width;
843 int stride = ((width + 31) & ~31) >> 3;
844 int height = gi->height;
845 int w;
846 int xspan, lenspan;
848 TRACE("%d, %d\n", x, y);
849 x -= gi->x;
850 y -= gi->y;
851 while (height--)
853 src = srcLine;
854 srcLine += stride;
855 w = width;
857 bitsMask = 0x80; /* FreeType is always MSB first */
858 bits = *src++;
860 xspan = x;
861 while (w)
863 if (bits & bitsMask)
865 lenspan = 0;
868 lenspan++;
869 if (lenspan == w)
870 break;
871 bitsMask = bitsMask >> 1;
872 if (!bitsMask)
874 bits = *src++;
875 bitsMask = 0x80;
877 } while (bits & bitsMask);
878 XFillRectangle (gdi_display, physDev->drawable,
879 physDev->gc, xspan, y, lenspan, 1);
880 xspan += lenspan;
881 w -= lenspan;
883 else
887 w--;
888 xspan++;
889 if (!w)
890 break;
891 bitsMask = bitsMask >> 1;
892 if (!bitsMask)
894 bits = *src++;
895 bitsMask = 0x80;
897 } while (!(bits & bitsMask));
900 y++;
904 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
905 void *bitmap, XGlyphInfo *gi)
907 unsigned char *srcLine = bitmap, *src, bits;
908 int width = gi->width;
909 int stride = ((width + 3) & ~3);
910 int height = gi->height;
911 int w;
912 int xspan, lenspan;
914 x -= gi->x;
915 y -= gi->y;
916 while (height--)
918 src = srcLine;
919 srcLine += stride;
920 w = width;
922 bits = *src++;
923 xspan = x;
924 while (w)
926 if (bits >= 0x80)
928 lenspan = 0;
931 lenspan++;
932 if (lenspan == w)
933 break;
934 bits = *src++;
935 } while (bits >= 0x80);
936 XFillRectangle (gdi_display, physDev->drawable,
937 physDev->gc, xspan, y, lenspan, 1);
938 xspan += lenspan;
939 w -= lenspan;
941 else
945 w--;
946 xspan++;
947 if (!w)
948 break;
949 bits = *src++;
950 } while (bits < 0x80);
953 y++;
958 static void ExamineBitfield (DWORD mask, int *shift, int *len)
960 int s, l;
962 s = 0;
963 while ((mask & 1) == 0)
965 mask >>= 1;
966 s++;
968 l = 0;
969 while ((mask & 1) == 1)
971 mask >>= 1;
972 l++;
974 *shift = s;
975 *len = l;
978 static DWORD GetField (DWORD pixel, int shift, int len)
980 pixel = pixel & (((1 << (len)) - 1) << shift);
981 pixel = pixel << (32 - (shift + len)) >> 24;
982 while (len < 8)
984 pixel |= (pixel >> len);
985 len <<= 1;
987 return pixel;
991 static DWORD PutField (DWORD pixel, int shift, int len)
993 shift = shift - (8 - len);
994 if (len <= 8)
995 pixel &= (((1 << len) - 1) << (8 - len));
996 if (shift < 0)
997 pixel >>= -shift;
998 else
999 pixel <<= shift;
1000 return pixel;
1003 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1004 int color)
1006 int r_shift, r_len;
1007 int g_shift, g_len;
1008 int b_shift, b_len;
1009 BYTE *maskLine, *mask, m;
1010 int maskStride;
1011 DWORD pixel;
1012 int width, height;
1013 int w, tx;
1014 BYTE src_r, src_g, src_b;
1016 x -= gi->x;
1017 y -= gi->y;
1018 width = gi->width;
1019 height = gi->height;
1021 maskLine = (unsigned char *) bitmap;
1022 maskStride = (width + 3) & ~3;
1024 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1025 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1026 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1028 src_r = GetField(color, r_shift, r_len);
1029 src_g = GetField(color, g_shift, g_len);
1030 src_b = GetField(color, b_shift, b_len);
1032 for(; height--; y++)
1034 mask = maskLine;
1035 maskLine += maskStride;
1036 w = width;
1037 tx = x;
1039 if(y < 0) continue;
1040 if(y >= image->height) break;
1042 for(; w--; tx++)
1044 if(tx >= image->width) break;
1046 m = *mask++;
1047 if(tx < 0) continue;
1049 if (m == 0xff)
1050 XPutPixel (image, tx, y, color);
1051 else if (m)
1053 BYTE r, g, b;
1055 pixel = XGetPixel (image, tx, y);
1057 r = GetField(pixel, r_shift, r_len);
1058 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1059 g = GetField(pixel, g_shift, g_len);
1060 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1061 b = GetField(pixel, b_shift, b_len);
1062 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1064 pixel = (PutField (r, r_shift, r_len) |
1065 PutField (g, g_shift, g_len) |
1066 PutField (b, b_shift, b_len));
1067 XPutPixel (image, tx, y, pixel);
1073 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1075 return 1;
1078 /***********************************************************************
1079 * X11DRV_XRender_ExtTextOut
1081 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1082 const RECT *lprect, LPCWSTR wstr, UINT count,
1083 const INT *lpDx )
1085 XRenderColor col;
1086 RGNDATA *data;
1087 XGCValues xgcval;
1088 int render_op = PictOpOver;
1089 gsCacheEntry *entry;
1090 gsCacheEntryFormat *formatEntry;
1091 BOOL retv = FALSE;
1092 HDC hdc = physDev->hdc;
1093 int textPixel, backgroundPixel;
1094 HRGN saved_region = 0;
1095 BOOL disable_antialias = FALSE;
1096 AA_Type aa_type = AA_None;
1097 DIBSECTION bmp;
1098 unsigned int idx;
1099 double cosEsc, sinEsc;
1100 LOGFONTW lf;
1102 /* Do we need to disable antialiasing because of palette mode? */
1103 if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1104 TRACE("bitmap is not a DIB\n");
1106 else if (bmp.dsBmih.biBitCount <= 8) {
1107 TRACE("Disabling antialiasing\n");
1108 disable_antialias = TRUE;
1111 xgcval.function = GXcopy;
1112 xgcval.background = physDev->backgroundPixel;
1113 xgcval.fill_style = FillSolid;
1114 wine_tsx11_lock();
1115 XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1116 wine_tsx11_unlock();
1118 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1120 if(physDev->depth == 1) {
1121 if((physDev->textPixel & 0xffffff) == 0) {
1122 textPixel = 0;
1123 backgroundPixel = 1;
1124 } else {
1125 textPixel = 1;
1126 backgroundPixel = 0;
1128 } else {
1129 textPixel = physDev->textPixel;
1130 backgroundPixel = physDev->backgroundPixel;
1133 if(flags & ETO_OPAQUE)
1135 wine_tsx11_lock();
1136 XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1137 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1138 physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1139 lprect->right - lprect->left, lprect->bottom - lprect->top );
1140 wine_tsx11_unlock();
1143 if(count == 0)
1145 retv = TRUE;
1146 goto done_unlock;
1150 GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1151 if(lf.lfEscapement != 0) {
1152 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1153 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1154 } else {
1155 cosEsc = 1;
1156 sinEsc = 0;
1159 if (flags & ETO_CLIPPED)
1161 HRGN clip_region;
1163 clip_region = CreateRectRgnIndirect( lprect );
1164 /* make a copy of the current device region */
1165 saved_region = CreateRectRgn( 0, 0, 0, 0 );
1166 CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1167 X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1168 DeleteObject( clip_region );
1171 if(X11DRV_XRender_Installed) {
1172 if(!physDev->xrender->pict) {
1173 XRenderPictureAttributes pa;
1174 pa.subwindow_mode = IncludeInferiors;
1176 wine_tsx11_lock();
1177 physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1178 physDev->drawable,
1179 (physDev->depth == 1) ?
1180 mono_format : screen_format,
1181 CPSubwindowMode, &pa);
1182 wine_tsx11_unlock();
1184 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1185 physDev->xrender->pict, hdc, physDev->drawable);
1186 } else {
1187 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1188 physDev->xrender->pict, hdc, physDev->drawable);
1191 if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1193 wine_tsx11_lock();
1194 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1195 physDev->dc_rect.left, physDev->dc_rect.top,
1196 (XRectangle *)data->Buffer, data->rdh.nCount );
1197 wine_tsx11_unlock();
1198 HeapFree( GetProcessHeap(), 0, data );
1202 if(X11DRV_XRender_Installed) {
1203 /* Create a 1x1 pixmap to tile over the font mask */
1204 if(!physDev->xrender->tile_xpm) {
1205 XRenderPictureAttributes pa;
1207 XRenderPictFormat *format = (physDev->depth == 1) ? mono_format : screen_format;
1208 wine_tsx11_lock();
1209 physDev->xrender->tile_xpm = XCreatePixmap(gdi_display,
1210 physDev->drawable,
1211 1, 1,
1212 format->depth);
1213 pa.repeat = True;
1214 physDev->xrender->tile_pict = pXRenderCreatePicture(gdi_display,
1215 physDev->xrender->tile_xpm,
1216 format,
1217 CPRepeat, &pa);
1218 wine_tsx11_unlock();
1219 TRACE("Created pixmap of depth %d\n", format->depth);
1220 /* init lastTextColor to something different from textPixel */
1221 physDev->xrender->lastTextColor = ~physDev->textPixel;
1225 if(physDev->textPixel != physDev->xrender->lastTextColor) {
1226 if(physDev->depth != 1) {
1227 /* Map 0 -- 0xff onto 0 -- 0xffff */
1228 int r_shift, r_len;
1229 int g_shift, g_len;
1230 int b_shift, b_len;
1232 ExamineBitfield (visual->red_mask, &r_shift, &r_len );
1233 ExamineBitfield (visual->green_mask, &g_shift, &g_len);
1234 ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
1236 col.red = GetField(physDev->textPixel, r_shift, r_len);
1237 col.red |= col.red << 8;
1238 col.green = GetField(physDev->textPixel, g_shift, g_len);
1239 col.green |= col.green << 8;
1240 col.blue = GetField(physDev->textPixel, b_shift, b_len);
1241 col.blue |= col.blue << 8;
1242 col.alpha = 0x0;
1243 } else { /* for a 1bpp bitmap we always need a 1 in the tile */
1244 col.red = col.green = col.blue = 0;
1245 col.alpha = 0xffff;
1247 wine_tsx11_lock();
1248 pXRenderFillRectangle(gdi_display, PictOpSrc,
1249 physDev->xrender->tile_pict,
1250 &col, 0, 0, 1, 1);
1251 wine_tsx11_unlock();
1252 physDev->xrender->lastTextColor = physDev->textPixel;
1255 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1257 if((physDev->depth == 1) && (textPixel == 0))
1258 render_op = PictOpOutReverse; /* This gives us 'black' text */
1261 EnterCriticalSection(&xrender_cs);
1262 entry = glyphsetCache + physDev->xrender->cache_index;
1263 if( disable_antialias == FALSE )
1264 aa_type = entry->aa_default;
1265 formatEntry = entry->format[aa_type];
1267 for(idx = 0; idx < count; idx++) {
1268 if( !formatEntry ) {
1269 UploadGlyph(physDev, wstr[idx], aa_type);
1270 /* re-evaluate antialias since aa_default may have changed */
1271 if( disable_antialias == FALSE )
1272 aa_type = entry->aa_default;
1273 formatEntry = entry->format[aa_type];
1274 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1275 UploadGlyph(physDev, wstr[idx], aa_type);
1278 if (!formatEntry)
1280 WARN("could not upload requested glyphs\n");
1281 LeaveCriticalSection(&xrender_cs);
1282 goto done_unlock;
1285 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1286 physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1288 if(X11DRV_XRender_Installed)
1290 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1291 INT offset = 0;
1292 POINT desired, current;
1294 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1295 So we pass zeros to the function and move to our starting position using the first
1296 element of the elts array. */
1298 desired.x = physDev->dc_rect.left + x;
1299 desired.y = physDev->dc_rect.top + y;
1300 current.x = current.y = 0;
1302 for(idx = 0; idx < count; idx++)
1304 elts[idx].glyphset = formatEntry->glyphset;
1305 elts[idx].chars = wstr + idx;
1306 elts[idx].nchars = 1;
1307 elts[idx].xOff = desired.x - current.x;
1308 elts[idx].yOff = desired.y - current.y;
1310 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1311 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1313 if(!lpDx)
1315 desired.x += formatEntry->gis[wstr[idx]].xOff;
1316 desired.y += formatEntry->gis[wstr[idx]].yOff;
1318 else
1320 offset += lpDx[idx];
1321 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1322 desired.y = physDev->dc_rect.top + y - offset * sinEsc;
1325 wine_tsx11_lock();
1326 pXRenderCompositeText16(gdi_display, render_op,
1327 physDev->xrender->tile_pict,
1328 physDev->xrender->pict,
1329 formatEntry->font_format,
1330 0, 0, 0, 0, elts, count);
1331 wine_tsx11_unlock();
1332 HeapFree(GetProcessHeap(), 0, elts);
1333 } else {
1334 INT offset = 0, xoff = 0, yoff = 0;
1335 wine_tsx11_lock();
1336 XSetForeground( gdi_display, physDev->gc, textPixel );
1338 if(aa_type == AA_None || physDev->depth == 1)
1340 void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1342 if(aa_type == AA_None)
1343 sharp_glyph_fn = SharpGlyphMono;
1344 else
1345 sharp_glyph_fn = SharpGlyphGray;
1347 for(idx = 0; idx < count; idx++) {
1348 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1349 physDev->dc_rect.top + y + yoff,
1350 formatEntry->bitmaps[wstr[idx]],
1351 &formatEntry->gis[wstr[idx]]);
1352 if(lpDx) {
1353 offset += lpDx[idx];
1354 xoff = offset * cosEsc;
1355 yoff = offset * -sinEsc;
1356 } else {
1357 xoff += formatEntry->gis[wstr[idx]].xOff;
1358 yoff += formatEntry->gis[wstr[idx]].yOff;
1361 } else {
1362 XImage *image;
1363 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1364 RECT extents = {0, 0, 0, 0};
1365 POINT cur = {0, 0};
1366 int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1367 int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1369 TRACE("drawable %dx%d\n", w, h);
1371 for(idx = 0; idx < count; idx++) {
1372 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1373 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1374 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1375 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1376 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1377 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1378 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1379 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1380 if(lpDx) {
1381 offset += lpDx[idx];
1382 cur.x = offset * cosEsc;
1383 cur.y = offset * -sinEsc;
1384 } else {
1385 cur.x += formatEntry->gis[wstr[idx]].xOff;
1386 cur.y += formatEntry->gis[wstr[idx]].yOff;
1389 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1390 extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1392 if(physDev->dc_rect.left + x + extents.left >= 0) {
1393 image_x = physDev->dc_rect.left + x + extents.left;
1394 image_off_x = 0;
1395 } else {
1396 image_x = 0;
1397 image_off_x = physDev->dc_rect.left + x + extents.left;
1399 if(physDev->dc_rect.top + y + extents.top >= 0) {
1400 image_y = physDev->dc_rect.top + y + extents.top;
1401 image_off_y = 0;
1402 } else {
1403 image_y = 0;
1404 image_off_y = physDev->dc_rect.top + y + extents.top;
1406 if(physDev->dc_rect.left + x + extents.right < w)
1407 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1408 else
1409 image_w = w - image_x;
1410 if(physDev->dc_rect.top + y + extents.bottom < h)
1411 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1412 else
1413 image_h = h - image_y;
1415 if(image_w <= 0 || image_h <= 0) goto no_image;
1417 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1418 image = XGetImage(gdi_display, physDev->drawable,
1419 image_x, image_y, image_w, image_h,
1420 AllPlanes, ZPixmap);
1421 X11DRV_check_error();
1423 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1424 gdi_display, (int)physDev->drawable, image_x, image_y,
1425 image_w, image_h, AllPlanes, ZPixmap,
1426 physDev->depth, image);
1427 if(!image) {
1428 Pixmap xpm = XCreatePixmap(gdi_display, physDev->drawable, image_w, image_h,
1429 physDev->depth);
1430 GC gc;
1431 XGCValues gcv;
1433 gcv.graphics_exposures = False;
1434 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1435 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1436 image_w, image_h, 0, 0);
1437 XFreeGC(gdi_display, gc);
1438 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1439 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1440 ZPixmap);
1441 X11DRV_check_error();
1442 XFreePixmap(gdi_display, xpm);
1444 if(!image) goto no_image;
1446 image->red_mask = visual->red_mask;
1447 image->green_mask = visual->green_mask;
1448 image->blue_mask = visual->blue_mask;
1450 offset = xoff = yoff = 0;
1451 for(idx = 0; idx < count; idx++) {
1452 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1453 yoff + image_off_y - extents.top,
1454 formatEntry->bitmaps[wstr[idx]],
1455 &formatEntry->gis[wstr[idx]],
1456 physDev->textPixel);
1457 if(lpDx) {
1458 offset += lpDx[idx];
1459 xoff = offset * cosEsc;
1460 yoff = offset * -sinEsc;
1461 } else {
1462 xoff += formatEntry->gis[wstr[idx]].xOff;
1463 yoff += formatEntry->gis[wstr[idx]].yOff;
1466 XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1467 image_x, image_y, image_w, image_h);
1468 XDestroyImage(image);
1470 no_image:
1471 wine_tsx11_unlock();
1473 LeaveCriticalSection(&xrender_cs);
1475 if (flags & ETO_CLIPPED)
1477 /* restore the device region */
1478 X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1479 DeleteObject( saved_region );
1482 retv = TRUE;
1484 done_unlock:
1485 X11DRV_UnlockDIBSection( physDev, TRUE );
1486 return retv;
1489 /******************************************************************************
1490 * AlphaBlend (x11drv.@)
1492 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1493 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1494 BLENDFUNCTION blendfn)
1496 XRenderPictureAttributes pa;
1497 XRenderPictFormat *src_format;
1498 XRenderPictFormat argb32_templ = {
1499 0, /* id */
1500 PictTypeDirect, /* type */
1501 32, /* depth */
1502 { /* direct */
1503 16, /* direct.red */
1504 0xff, /* direct.redMask */
1505 8, /* direct.green */
1506 0xff, /* direct.greenMask */
1507 0, /* direct.blue */
1508 0xff, /* direct.blueMask */
1509 24, /* direct.alpha */
1510 0xff, /* direct.alphaMask */
1512 0, /* colormap */
1514 unsigned long argb32_templ_mask =
1515 PictFormatType |
1516 PictFormatDepth |
1517 PictFormatRed |
1518 PictFormatRedMask |
1519 PictFormatGreen |
1520 PictFormatGreenMask |
1521 PictFormatBlue |
1522 PictFormatBlueMask |
1523 PictFormatAlpha |
1524 PictFormatAlphaMask;
1526 Picture dst_pict, src_pict;
1527 Pixmap xpm;
1528 DIBSECTION dib;
1529 XImage *image;
1530 GC gc;
1531 XGCValues gcv;
1532 BYTE *dstbits, *data;
1533 int y, y2;
1534 POINT pts[2];
1535 BOOL top_down = FALSE;
1536 RGNDATA *rgndata;
1538 if(!X11DRV_XRender_Installed) {
1539 FIXME("Unable to AlphaBlend without Xrender\n");
1540 return FALSE;
1542 pts[0].x = xDst;
1543 pts[0].y = yDst;
1544 pts[1].x = xDst + widthDst;
1545 pts[1].y = yDst + heightDst;
1546 LPtoDP(devDst->hdc, pts, 2);
1547 xDst = pts[0].x;
1548 yDst = pts[0].y;
1549 widthDst = pts[1].x - pts[0].x;
1550 heightDst = pts[1].y - pts[0].y;
1552 pts[0].x = xSrc;
1553 pts[0].y = ySrc;
1554 pts[1].x = xSrc + widthSrc;
1555 pts[1].y = ySrc + heightSrc;
1556 LPtoDP(devSrc->hdc, pts, 2);
1557 xSrc = pts[0].x;
1558 ySrc = pts[0].y;
1559 widthSrc = pts[1].x - pts[0].x;
1560 heightSrc = pts[1].y - pts[0].y;
1561 if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1563 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1564 if(widthDst != widthSrc || heightDst != heightSrc)
1565 #else
1566 if(!pXRenderSetPictureTransform)
1567 #endif
1569 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1570 return FALSE;
1573 if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1575 FIXME("not a dibsection\n");
1576 return FALSE;
1579 if(dib.dsBm.bmBitsPixel != 32) {
1580 FIXME("not a 32 bpp dibsection\n");
1581 return FALSE;
1583 dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1585 if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1586 top_down = TRUE;
1587 dstbits += widthSrc * (heightSrc - 1) * 4;
1588 y2 = ySrc;
1589 y = y2 + heightSrc - 1;
1591 else
1593 y = dib.dsBmih.biHeight - ySrc - 1;
1594 y2 = y - heightSrc + 1;
1596 for(; y >= y2; y--) {
1597 memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1598 widthSrc * 4);
1599 dstbits += (top_down ? -1 : 1) * widthSrc * 4;
1602 wine_tsx11_lock();
1603 image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1604 (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1607 Avoid using XRenderFindStandardFormat as older libraries don't have it
1608 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1610 src_format = pXRenderFindFormat(gdi_display, argb32_templ_mask, &argb32_templ, 0);
1612 TRACE("src_format %p\n", src_format);
1614 pa.subwindow_mode = IncludeInferiors;
1616 /* FIXME use devDst->xrender->pict ? */
1617 dst_pict = pXRenderCreatePicture(gdi_display,
1618 devDst->drawable,
1619 (devDst->depth == 1) ?
1620 mono_format : screen_format,
1621 CPSubwindowMode, &pa);
1622 TRACE("dst_pict %08lx\n", dst_pict);
1623 TRACE("src_drawable = %08lx\n", devSrc->drawable);
1624 xpm = XCreatePixmap(gdi_display,
1625 devSrc->drawable,
1626 widthSrc, heightSrc, 32);
1627 gcv.graphics_exposures = False;
1628 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1629 TRACE("xpm = %08lx\n", xpm);
1630 XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1632 src_pict = pXRenderCreatePicture(gdi_display,
1633 xpm, src_format,
1634 CPSubwindowMode, &pa);
1635 TRACE("src_pict %08lx\n", src_pict);
1637 if ((rgndata = X11DRV_GetRegionData( devDst->region, 0 )))
1639 pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
1640 devDst->dc_rect.left, devDst->dc_rect.top,
1641 (XRectangle *)rgndata->Buffer,
1642 rgndata->rdh.nCount );
1643 HeapFree( GetProcessHeap(), 0, rgndata );
1646 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1647 if(widthDst != widthSrc || heightDst != heightSrc) {
1648 double xscale = widthSrc/(double)widthDst;
1649 double yscale = heightSrc/(double)heightDst;
1650 XTransform xform = {{
1651 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0) },
1652 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0) },
1653 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1655 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1657 #endif
1658 pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
1659 0, 0, 0, 0,
1660 xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
1663 pXRenderFreePicture(gdi_display, src_pict);
1664 XFreePixmap(gdi_display, xpm);
1665 XFreeGC(gdi_display, gc);
1666 pXRenderFreePicture(gdi_display, dst_pict);
1667 image->data = NULL;
1668 XDestroyImage(image);
1670 wine_tsx11_unlock();
1671 HeapFree(GetProcessHeap(), 0, data);
1672 return TRUE;
1675 #else /* HAVE_X11_EXTENSIONS_XRENDER_H */
1677 void X11DRV_XRender_Init(void)
1679 TRACE("XRender support not compiled in.\n");
1680 return;
1683 void X11DRV_XRender_Finalize(void)
1687 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1689 assert(0);
1690 return FALSE;
1693 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1695 assert(0);
1696 return;
1699 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1700 const RECT *lprect, LPCWSTR wstr, UINT count,
1701 const INT *lpDx )
1703 assert(0);
1704 return FALSE;
1707 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1709 assert(0);
1710 return;
1713 /******************************************************************************
1714 * AlphaBlend (x11drv.@)
1716 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1717 X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1718 BLENDFUNCTION blendfn)
1720 FIXME("not supported - XRENDER headers were missing at compile time\n");
1721 return FALSE;
1724 #endif /* HAVE_X11_EXTENSIONS_XRENDER_H */