Fixed a number of -DSTRICT warnings.
[wine.git] / dlls / x11drv / xrender.c
blob273868613747ba1ee0d6e840ce4a74ad49f25830
1 /*
2 * Functions to use the XRender extension
4 * Copyright 2001 Huw D M Davies for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "config.h"
21 #include "wine/port.h"
23 #include <assert.h>
24 #include <string.h>
25 #include <stdlib.h>
27 #include "winnt.h"
28 #include "wownt32.h"
29 #include "x11drv.h"
30 #include "bitmap.h"
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
34 BOOL X11DRV_XRender_Installed = FALSE;
35 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
37 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
39 #include "ts_xlib.h"
40 #include <X11/extensions/Xrender.h>
42 static XRenderPictFormat *screen_format; /* format of screen */
43 static XRenderPictFormat *mono_format; /* format of mono bitmap */
45 typedef struct
47 LOGFONTW lf;
48 XFORM xform; /* this is dum as we don't care about offsets */
49 DWORD hash;
50 } LFANDSIZE;
52 #define INITIAL_REALIZED_BUF_SIZE 128
55 typedef struct
57 LFANDSIZE lfsz;
58 GlyphSet glyphset;
59 XRenderPictFormat *font_format;
60 int nrealized;
61 BOOL *realized;
62 UINT count;
63 INT next;
64 } gsCacheEntry;
66 struct tagXRENDERINFO
68 int cache_index;
69 Picture pict;
70 Picture tile_pict;
71 Pixmap tile_xpm;
72 COLORREF lastTextColor;
76 static gsCacheEntry *glyphsetCache = NULL;
77 static DWORD glyphsetCacheSize = 0;
78 static INT lastfree = -1;
79 static INT mru = -1;
81 #define INIT_CACHE_SIZE 10
83 static int antialias = 1;
85 /* some default values just in case */
86 #ifndef SONAME_LIBX11
87 #define SONAME_LIBX11 "libX11.so"
88 #endif
89 #ifndef SONAME_LIBXEXT
90 #define SONAME_LIBXEXT "libXext.so"
91 #endif
92 #ifndef SONAME_LIBXRENDER
93 #define SONAME_LIBXRENDER "libXrender.so"
94 #endif
96 static void *xrender_handle;
98 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
99 MAKE_FUNCPTR(XRenderAddGlyphs)
100 MAKE_FUNCPTR(XRenderCompositeString8)
101 MAKE_FUNCPTR(XRenderCompositeString16)
102 MAKE_FUNCPTR(XRenderCompositeString32)
103 MAKE_FUNCPTR(XRenderCreateGlyphSet)
104 MAKE_FUNCPTR(XRenderCreatePicture)
105 MAKE_FUNCPTR(XRenderFillRectangle)
106 MAKE_FUNCPTR(XRenderFindFormat)
107 MAKE_FUNCPTR(XRenderFindVisualFormat)
108 MAKE_FUNCPTR(XRenderFreeGlyphSet)
109 MAKE_FUNCPTR(XRenderFreePicture)
110 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
111 MAKE_FUNCPTR(XRenderQueryExtension)
112 #undef MAKE_FUNCPTR
114 static CRITICAL_SECTION xrender_cs = CRITICAL_SECTION_INIT("xrender_cs");
117 /***********************************************************************
118 * X11DRV_XRender_Init
120 * Let's see if our XServer has the extension available
123 void X11DRV_XRender_Init(void)
125 int error_base, event_base, i;
126 XRenderPictFormat pf;
128 if (!wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0)) return;
129 if (!wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0)) return;
130 xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0);
131 if(!xrender_handle) return;
133 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
134 LOAD_FUNCPTR(XRenderAddGlyphs)
135 LOAD_FUNCPTR(XRenderCompositeString8)
136 LOAD_FUNCPTR(XRenderCompositeString16)
137 LOAD_FUNCPTR(XRenderCompositeString32)
138 LOAD_FUNCPTR(XRenderCreateGlyphSet)
139 LOAD_FUNCPTR(XRenderCreatePicture)
140 LOAD_FUNCPTR(XRenderFillRectangle)
141 LOAD_FUNCPTR(XRenderFindFormat)
142 LOAD_FUNCPTR(XRenderFindVisualFormat)
143 LOAD_FUNCPTR(XRenderFreeGlyphSet)
144 LOAD_FUNCPTR(XRenderFreePicture)
145 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
146 LOAD_FUNCPTR(XRenderQueryExtension)
147 #undef LOAD_FUNCPTR
149 wine_tsx11_lock();
150 if(pXRenderQueryExtension(gdi_display, &event_base, &error_base)) {
151 X11DRV_XRender_Installed = TRUE;
152 TRACE("Xrender is up and running error_base = %d\n", error_base);
153 screen_format = pXRenderFindVisualFormat(gdi_display, visual);
154 if(!screen_format) { /* This fails in buggy versions of libXrender.so */
155 wine_tsx11_unlock();
156 WINE_MESSAGE(
157 "Wine has detected that you probably have a buggy version\n"
158 "of libXrender.so . Because of this client side font rendering\n"
159 "will be disabled. Please upgrade this library.\n");
160 X11DRV_XRender_Installed = FALSE;
161 return;
163 pf.type = PictTypeDirect;
164 pf.depth = 1;
165 pf.direct.alpha = 0;
166 pf.direct.alphaMask = 1;
167 mono_format = pXRenderFindFormat(gdi_display, PictFormatType |
168 PictFormatDepth | PictFormatAlpha |
169 PictFormatAlphaMask, &pf, 0);
170 if(!mono_format) {
171 wine_tsx11_unlock();
172 ERR("mono_format == NULL?\n");
173 X11DRV_XRender_Installed = FALSE;
174 return;
176 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
177 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
179 glyphsetCacheSize = INIT_CACHE_SIZE;
180 lastfree = 0;
181 for(i = 0; i < INIT_CACHE_SIZE; i++) {
182 glyphsetCache[i].next = i + 1;
183 glyphsetCache[i].count = -1;
185 glyphsetCache[i-1].next = -1;
186 } else {
187 TRACE("Xrender is not available on this server\n");
189 wine_tsx11_unlock();
190 return;
192 sym_not_found:
193 wine_dlclose(xrender_handle, NULL, 0);
194 xrender_handle = NULL;
197 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
199 if(p1->hash != p2->hash) return TRUE;
200 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
201 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
202 return strcmpW(p1->lf.lfFaceName, p2->lf.lfFaceName);
205 #if 0
206 static void walk_cache(void)
208 int i;
210 EnterCriticalSection(&xrender_cs);
211 for(i=mru; i >= 0; i = glyphsetCache[i].next)
212 TRACE("item %d\n", i);
213 LeaveCriticalSection(&xrender_cs);
215 #endif
217 static int LookupEntry(LFANDSIZE *plfsz)
219 int i, prev_i = -1;
221 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
222 TRACE("%d\n", i);
223 if(glyphsetCache[i].count == -1) { /* reached free list so stop */
224 i = -1;
225 break;
228 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
229 glyphsetCache[i].count++;
230 if(prev_i >= 0) {
231 glyphsetCache[prev_i].next = glyphsetCache[i].next;
232 glyphsetCache[i].next = mru;
233 mru = i;
235 TRACE("found font in cache %d\n", i);
236 return i;
238 prev_i = i;
240 TRACE("font not in cache\n");
241 return -1;
244 static int AllocEntry(void)
246 int best = -1, prev_best = -1, i, prev_i = -1;
248 if(lastfree >= 0) {
249 assert(glyphsetCache[lastfree].count == -1);
250 glyphsetCache[lastfree].count = 1;
251 best = lastfree;
252 lastfree = glyphsetCache[lastfree].next;
253 assert(best != mru);
254 glyphsetCache[best].next = mru;
255 mru = best;
257 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
258 return mru;
261 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
262 if(glyphsetCache[i].count == 0) {
263 best = i;
264 prev_best = prev_i;
266 prev_i = i;
269 if(best >= 0) {
270 TRACE("freeing unused glyphset at cache %d\n", best);
271 wine_tsx11_lock();
272 pXRenderFreeGlyphSet(gdi_display, glyphsetCache[best].glyphset);
273 wine_tsx11_unlock();
274 glyphsetCache[best].glyphset = 0;
275 if(glyphsetCache[best].nrealized) { /* do we really want to do this? */
276 HeapFree(GetProcessHeap(), 0, glyphsetCache[best].realized);
277 glyphsetCache[best].realized = NULL;
278 glyphsetCache[best].nrealized = 0;
280 glyphsetCache[best].count = 1;
281 if(prev_best >= 0) {
282 glyphsetCache[prev_best].next = glyphsetCache[best].next;
283 glyphsetCache[best].next = mru;
284 mru = best;
285 } else {
286 assert(mru == best);
288 return mru;
291 TRACE("Growing cache\n");
292 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
293 glyphsetCache,
294 (glyphsetCacheSize + INIT_CACHE_SIZE)
295 * sizeof(*glyphsetCache));
296 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
297 i++) {
298 glyphsetCache[i].next = i + 1;
299 glyphsetCache[i].count = -1;
301 glyphsetCache[i-1].next = -1;
302 glyphsetCacheSize += INIT_CACHE_SIZE;
304 lastfree = glyphsetCache[best].next;
305 glyphsetCache[best].count = 1;
306 glyphsetCache[best].next = mru;
307 mru = best;
308 TRACE("new free cache slot at %d\n", mru);
309 return mru;
312 static int GetCacheEntry(LFANDSIZE *plfsz)
314 XRenderPictFormat pf;
315 int ret;
316 gsCacheEntry *entry;
318 if((ret = LookupEntry(plfsz)) != -1) return ret;
320 ret = AllocEntry();
321 entry = glyphsetCache + ret;
322 entry->lfsz = *plfsz;
323 assert(entry->nrealized == 0);
326 if(antialias) {
327 pf.depth = 8;
328 pf.direct.alphaMask = 0xff;
329 } else {
330 pf.depth = 1;
331 pf.direct.alphaMask = 1;
333 pf.type = PictTypeDirect;
334 pf.direct.alpha = 0;
336 wine_tsx11_lock();
337 entry->font_format = pXRenderFindFormat(gdi_display,
338 PictFormatType |
339 PictFormatDepth |
340 PictFormatAlpha |
341 PictFormatAlphaMask,
342 &pf, 0);
344 entry->glyphset = pXRenderCreateGlyphSet(gdi_display, entry->font_format);
345 wine_tsx11_unlock();
346 return ret;
349 static void dec_ref_cache(int index)
351 assert(index >= 0);
352 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
353 assert(glyphsetCache[index].count > 0);
354 glyphsetCache[index].count--;
357 static void lfsz_calc_hash(LFANDSIZE *plfsz)
359 DWORD hash = 0, *ptr;
360 int i;
362 for(ptr = (DWORD*)&plfsz->xform; ptr < (DWORD*)(&plfsz->xform + 1); ptr++)
363 hash ^= *ptr;
364 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
365 hash ^= *ptr;
366 for(i = 0, ptr = (DWORD*)&plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
367 WCHAR *pwc = (WCHAR *)ptr;
368 if(!*pwc) break;
369 hash ^= *ptr;
370 pwc++;
371 if(!*pwc) break;
373 plfsz->hash = hash;
374 return;
377 /***********************************************************************
378 * X11DRV_XRender_Finalize
380 void X11DRV_XRender_Finalize(void)
382 FIXME("Free cached glyphsets\n");
383 #if 0
384 if (xrender_handle) wine_dlclose(xrender_handle, NULL, 0);
385 xrender_handle = NULL;
386 #endif
390 /***********************************************************************
391 * X11DRV_XRender_SelectFont
393 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
395 LFANDSIZE lfsz;
397 GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
398 TRACE("h=%ld w=%ld weight=%ld it=%d charset=%d name=%s\n",
399 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
400 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
401 lfsz.xform = physDev->dc->xformWorld2Vport;
402 lfsz_calc_hash(&lfsz);
404 EnterCriticalSection(&xrender_cs);
405 if(!physDev->xrender) {
406 physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
407 sizeof(*physDev->xrender));
408 physDev->xrender->cache_index = -1;
410 else if(physDev->xrender->cache_index != -1)
411 dec_ref_cache(physDev->xrender->cache_index);
412 physDev->xrender->cache_index = GetCacheEntry(&lfsz);
413 LeaveCriticalSection(&xrender_cs);
414 return 0;
417 /***********************************************************************
418 * X11DRV_XRender_DeleteDC
420 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
422 wine_tsx11_lock();
423 if(physDev->xrender->tile_pict)
424 pXRenderFreePicture(gdi_display, physDev->xrender->tile_pict);
426 if(physDev->xrender->tile_xpm)
427 XFreePixmap(gdi_display, physDev->xrender->tile_xpm);
429 if(physDev->xrender->pict) {
430 TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->dc);
431 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
433 wine_tsx11_unlock();
435 EnterCriticalSection(&xrender_cs);
436 if(physDev->xrender->cache_index != -1)
437 dec_ref_cache(physDev->xrender->cache_index);
438 LeaveCriticalSection(&xrender_cs);
440 HeapFree(GetProcessHeap(), 0, physDev->xrender);
441 physDev->xrender = NULL;
442 return;
445 /***********************************************************************
446 * X11DRV_XRender_UpdateDrawable
448 * This gets called from X11DRV_SetDrawable and deletes the pict when the
449 * drawable changes. However at the moment we delete the pict at the end of
450 * every ExtTextOut so this is basically a NOP.
452 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
454 if(physDev->xrender->pict) {
455 TRACE("freeing pict %08lx from dc %p\n", physDev->xrender->pict, physDev->dc);
456 wine_tsx11_lock();
457 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
458 wine_tsx11_unlock();
460 physDev->xrender->pict = 0;
461 return;
464 /************************************************************************
465 * UploadGlyph
467 * Helper to ExtTextOut. Must be called inside xrender_cs
469 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph)
471 int buflen;
472 char *buf;
473 Glyph gid;
474 GLYPHMETRICS gm;
475 XGlyphInfo gi;
476 gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
477 UINT ggo_format = GGO_GLYPH_INDEX;
478 BOOL aa;
480 if(entry->nrealized <= glyph) {
481 entry->nrealized = (glyph / 128 + 1) * 128;
482 entry->realized = HeapReAlloc(GetProcessHeap(),
483 HEAP_ZERO_MEMORY,
484 entry->realized,
485 entry->nrealized * sizeof(BOOL));
488 if(entry->font_format->depth == 8) {
489 aa = TRUE;
490 ggo_format |= WINE_GGO_GRAY16_BITMAP;
491 } else {
492 aa = FALSE;
493 ggo_format |= GGO_BITMAP;
496 buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL,
497 NULL);
498 if(buflen == GDI_ERROR) {
499 LeaveCriticalSection(&xrender_cs);
500 return FALSE;
503 entry->realized[glyph] = TRUE;
505 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
506 GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, NULL);
508 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%ld,%ld\n",
509 buflen,
510 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
511 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
513 gi.width = gm.gmBlackBoxX;
514 gi.height = gm.gmBlackBoxY;
515 gi.x = -gm.gmptGlyphOrigin.x;
516 gi.y = gm.gmptGlyphOrigin.y;
517 gi.xOff = gm.gmCellIncX;
518 gi.yOff = gm.gmCellIncY;
520 if(TRACE_ON(xrender)) {
521 int pitch, i, j;
522 char output[300];
523 unsigned char *line;
525 if(!aa) {
526 pitch = ((gi.width + 31) / 32) * 4;
527 for(i = 0; i < gi.height; i++) {
528 line = buf + i * pitch;
529 output[0] = '\0';
530 for(j = 0; j < pitch * 8; j++) {
531 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
533 strcat(output, "\n");
534 TRACE(output);
536 } else {
537 char blks[] = " .:;!o*#";
538 char str[2];
540 str[1] = '\0';
541 pitch = ((gi.width + 3) / 4) * 4;
542 for(i = 0; i < gi.height; i++) {
543 line = buf + i * pitch;
544 output[0] = '\0';
545 for(j = 0; j < pitch; j++) {
546 str[0] = blks[line[j] >> 5];
547 strcat(output, str);
549 strcat(output, "\n");
550 TRACE(output);
555 if(!aa && BitmapBitOrder(gdi_display) != MSBFirst) {
556 unsigned char *byte = buf, c;
557 int i = buflen;
559 while(i--) {
560 c = *byte;
562 /* magic to flip bit order */
563 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
564 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
565 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
567 *byte++ = c;
570 gid = glyph;
571 wine_tsx11_lock();
572 pXRenderAddGlyphs(gdi_display, entry->glyphset, &gid, &gi, 1,
573 buf, buflen);
574 wine_tsx11_unlock();
575 HeapFree(GetProcessHeap(), 0, buf);
576 return TRUE;
579 /***********************************************************************
580 * X11DRV_XRender_ExtTextOut
582 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
583 const RECT *lprect, LPCWSTR wstr, UINT count,
584 const INT *lpDx )
586 XRenderColor col;
587 int idx;
588 TEXTMETRICW tm;
589 RGNDATA *data;
590 SIZE sz;
591 RECT rc;
592 BOOL done_extents = FALSE;
593 INT width, xwidth, ywidth;
594 double cosEsc, sinEsc;
595 XGCValues xgcval;
596 LOGFONTW lf;
597 int render_op = PictOpOver;
598 WORD *glyphs;
599 POINT pt;
600 gsCacheEntry *entry;
601 BOOL retv = FALSE;
602 HDC hdc = physDev->hdc;
603 DC *dc = physDev->dc;
605 TRACE("%04x, %d, %d, %08x, %p, %s, %d, %p)\n", hdc, x, y, flags,
606 lprect, debugstr_wn(wstr, count), count, lpDx);
608 if(flags & ETO_GLYPH_INDEX)
609 glyphs = (LPWORD)wstr;
610 else {
611 glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
612 GetGlyphIndicesW(hdc, wstr, count, glyphs, 0);
615 if(lprect)
616 TRACE("rect: %d,%d - %d,%d\n", lprect->left, lprect->top, lprect->right,
617 lprect->bottom);
618 TRACE("align = %x bkmode = %x mapmode = %x\n", dc->textAlign, GetBkMode(hdc), dc->MapMode);
620 if(dc->textAlign & TA_UPDATECP) {
621 x = dc->CursPosX;
622 y = dc->CursPosY;
625 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
626 if(lf.lfEscapement != 0) {
627 cosEsc = cos(lf.lfEscapement * M_PI / 1800);
628 sinEsc = sin(lf.lfEscapement * M_PI / 1800);
629 } else {
630 cosEsc = 1;
631 sinEsc = 0;
634 if(flags & (ETO_CLIPPED | ETO_OPAQUE)) {
635 if(!lprect) {
636 if(flags & ETO_CLIPPED) return FALSE;
637 GetTextExtentPointI(hdc, glyphs, count, &sz);
638 done_extents = TRUE;
639 rc.left = x;
640 rc.top = y;
641 rc.right = x + sz.cx;
642 rc.bottom = y + sz.cy;
643 } else {
644 rc = *lprect;
647 LPtoDP(physDev->hdc, (POINT*)&rc, 2);
649 if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
650 if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
653 xgcval.function = GXcopy;
654 xgcval.background = physDev->backgroundPixel;
655 xgcval.fill_style = FillSolid;
656 TSXChangeGC( gdi_display, physDev->gc,
657 GCFunction | GCBackground | GCFillStyle, &xgcval );
659 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
661 if(flags & ETO_OPAQUE) {
662 TSXSetForeground( gdi_display, physDev->gc, physDev->backgroundPixel );
663 TSXFillRectangle( gdi_display, physDev->drawable, physDev->gc,
664 physDev->org.x + rc.left, physDev->org.y + rc.top,
665 rc.right - rc.left, rc.bottom - rc.top );
668 if(count == 0) {
669 retv = TRUE;
670 goto done;
673 pt.x = x;
674 pt.y = y;
675 LPtoDP(physDev->hdc, &pt, 1);
676 x = pt.x;
677 y = pt.y;
679 TRACE("real x,y %d,%d\n", x, y);
681 if(lpDx) {
682 width = 0;
683 for(idx = 0; idx < count; idx++)
684 width += lpDx[idx];
685 } else {
686 if(!done_extents) {
687 GetTextExtentPointI(hdc, glyphs, count, &sz);
688 done_extents = TRUE;
690 width = sz.cx;
692 width = INTERNAL_XWSTODS(dc, width);
693 xwidth = width * cosEsc;
694 ywidth = width * sinEsc;
696 GetTextMetricsW(hdc, &tm);
698 tm.tmAscent = INTERNAL_YWSTODS(dc, tm.tmAscent);
699 tm.tmDescent = INTERNAL_YWSTODS(dc, tm.tmDescent);
700 switch( dc->textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER) ) {
701 case TA_LEFT:
702 if (dc->textAlign & TA_UPDATECP) {
703 pt.x = x + xwidth;
704 pt.y = y - ywidth;
705 DPtoLP(physDev->hdc, &pt, 1);
706 dc->CursPosX = pt.x;
707 dc->CursPosY = pt.y;
709 break;
711 case TA_CENTER:
712 x -= xwidth / 2;
713 y += ywidth / 2;
714 break;
716 case TA_RIGHT:
717 x -= xwidth;
718 y += ywidth;
719 if (dc->textAlign & TA_UPDATECP) {
720 pt.x = x;
721 pt.y = y;
722 DPtoLP(physDev->hdc, &pt, 1);
723 dc->CursPosX = pt.x;
724 dc->CursPosY = pt.y;
726 break;
729 switch( dc->textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE) ) {
730 case TA_TOP:
731 y += tm.tmAscent * cosEsc;
732 x += tm.tmAscent * sinEsc;
733 break;
735 case TA_BOTTOM:
736 y -= tm.tmDescent * cosEsc;
737 x -= tm.tmDescent * sinEsc;
738 break;
740 case TA_BASELINE:
741 break;
744 if (flags & ETO_CLIPPED)
746 SaveVisRgn16( HDC_16(hdc) );
747 IntersectVisRect16( HDC_16(dc->hSelf), lprect->left, lprect->top, lprect->right, lprect->bottom );
750 if(!physDev->xrender->pict) {
751 XRenderPictureAttributes pa;
752 pa.subwindow_mode = IncludeInferiors;
754 wine_tsx11_lock();
755 physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
756 physDev->drawable,
757 (dc->bitsPerPixel == 1) ?
758 mono_format : screen_format,
759 CPSubwindowMode, &pa);
760 wine_tsx11_unlock();
762 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n", physDev->xrender->pict, dc, physDev->drawable);
763 } else {
764 TRACE("using existing pict = %lx dc = %p\n", physDev->xrender->pict, dc);
767 if ((data = X11DRV_GetRegionData( dc->hGCClipRgn, 0 )))
769 wine_tsx11_lock();
770 pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
771 physDev->org.x, physDev->org.y,
772 (XRectangle *)data->Buffer, data->rdh.nCount );
773 wine_tsx11_unlock();
774 HeapFree( GetProcessHeap(), 0, data );
777 if(GetBkMode(hdc) != TRANSPARENT) {
778 if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE))) {
779 if(!(flags & ETO_OPAQUE) || x < rc.left || x + width >= rc.right ||
780 y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom) {
781 TSXSetForeground( gdi_display, physDev->gc, physDev->backgroundPixel );
782 TSXFillRectangle( gdi_display, physDev->drawable, physDev->gc,
783 physDev->org.x + x, physDev->org.y + y - tm.tmAscent,
784 width, tm.tmAscent + tm.tmDescent );
789 /* Create a 1x1 pixmap to tile over the font mask */
790 if(!physDev->xrender->tile_xpm) {
791 XRenderPictureAttributes pa;
793 XRenderPictFormat *format = (dc->bitsPerPixel == 1) ? mono_format : screen_format;
794 wine_tsx11_lock();
795 physDev->xrender->tile_xpm = XCreatePixmap(gdi_display,
796 physDev->drawable,
797 1, 1,
798 format->depth);
799 pa.repeat = True;
800 physDev->xrender->tile_pict = pXRenderCreatePicture(gdi_display,
801 physDev->xrender->tile_xpm,
802 format,
803 CPRepeat, &pa);
804 wine_tsx11_unlock();
805 TRACE("Created pixmap of depth %d\n", format->depth);
806 /* init lastTextColor to something different from dc->textColor */
807 physDev->xrender->lastTextColor = ~dc->textColor;
811 if(dc->textColor != physDev->xrender->lastTextColor) {
812 if(dc->bitsPerPixel != 1) {
813 /* Map 0 -- 0xff onto 0 -- 0xffff */
814 col.red = GetRValue(dc->textColor);
815 col.red |= col.red << 8;
816 col.green = GetGValue(dc->textColor);
817 col.green |= col.green << 8;
818 col.blue = GetBValue(dc->textColor);
819 col.blue |= col.blue << 8;
820 col.alpha = 0x0;
821 } else { /* for a 1bpp bitmap we always need a 1 in the tile */
822 col.red = col.green = col.blue = 0;
823 col.alpha = 0xffff;
825 wine_tsx11_lock();
826 pXRenderFillRectangle(gdi_display, PictOpSrc,
827 physDev->xrender->tile_pict,
828 &col, 0, 0, 1, 1);
829 wine_tsx11_unlock();
830 physDev->xrender->lastTextColor = dc->textColor;
833 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
835 if((dc->bitsPerPixel == 1) && ((dc->textColor & 0xffffff) == 0))
836 render_op = PictOpOutReverse; /* This gives us 'black' text */
838 EnterCriticalSection(&xrender_cs);
839 entry = glyphsetCache + physDev->xrender->cache_index;
841 for(idx = 0; idx < count; idx++) {
842 if(glyphs[idx] >= entry->nrealized || entry->realized[glyphs[idx]] == FALSE) {
843 UploadGlyph(physDev, glyphs[idx]);
848 TRACE("Writing %s at %ld,%ld\n", debugstr_wn(wstr,count),
849 physDev->org.x + x, physDev->org.y + y);
851 wine_tsx11_lock();
852 if(!lpDx)
853 pXRenderCompositeString16(gdi_display, render_op,
854 physDev->xrender->tile_pict,
855 physDev->xrender->pict,
856 entry->font_format, entry->glyphset,
857 0, 0, physDev->org.x + x, physDev->org.y + y,
858 glyphs, count);
860 else {
861 INT offset = 0, xoff = 0, yoff = 0;
862 for(idx = 0; idx < count; idx++) {
863 pXRenderCompositeString16(gdi_display, render_op,
864 physDev->xrender->tile_pict,
865 physDev->xrender->pict,
866 entry->font_format, entry->glyphset,
867 0, 0, physDev->org.x + x + xoff,
868 physDev->org.y + y + yoff,
869 glyphs + idx, 1);
870 offset += INTERNAL_XWSTODS(dc, lpDx[idx]);
871 xoff = offset * cosEsc;
872 yoff = offset * -sinEsc;
876 LeaveCriticalSection(&xrender_cs);
878 if(physDev->xrender->pict) {
879 pXRenderFreePicture(gdi_display, physDev->xrender->pict);
881 physDev->xrender->pict = 0;
882 wine_tsx11_unlock();
884 if (flags & ETO_CLIPPED)
885 RestoreVisRgn16( HDC_16(hdc) );
887 retv = TRUE;
889 done:
890 X11DRV_UnlockDIBSection( physDev, TRUE );
891 if(glyphs != wstr) HeapFree(GetProcessHeap(), 0, glyphs);
892 return retv;
895 #else /* HAVE_X11_EXTENSIONS_XRENDER_H */
897 void X11DRV_XRender_Init(void)
899 TRACE("XRender support not compiled in.\n");
900 return;
903 void X11DRV_XRender_Finalize(void)
907 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
909 assert(0);
910 return FALSE;
913 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
915 assert(0);
916 return;
919 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
920 const RECT *lprect, LPCWSTR wstr, UINT count,
921 const INT *lpDx )
923 assert(0);
924 return FALSE;
927 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
929 assert(0);
930 return;
933 #endif /* HAVE_X11_EXTENSIONS_XRENDER_H */