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
21 #include "wine/port.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
40 #include <X11/extensions/Xrender.h>
42 static XRenderPictFormat
*screen_format
; /* format of screen */
43 static XRenderPictFormat
*mono_format
; /* format of mono bitmap */
48 XFORM xform
; /* this is dum as we don't care about offsets */
52 #define INITIAL_REALIZED_BUF_SIZE 128
59 XRenderPictFormat
*font_format
;
72 COLORREF lastTextColor
;
76 static gsCacheEntry
*glyphsetCache
= NULL
;
77 static DWORD glyphsetCacheSize
= 0;
78 static INT lastfree
= -1;
81 #define INIT_CACHE_SIZE 10
83 static int antialias
= 1;
85 /* some default values just in case */
87 #define SONAME_LIBX11 "libX11.so"
89 #ifndef SONAME_LIBXEXT
90 #define SONAME_LIBXEXT "libXext.so"
92 #ifndef SONAME_LIBXRENDER
93 #define SONAME_LIBXRENDER "libXrender.so"
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
)
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
)
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 */
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
;
163 pf
.type
= PictTypeDirect
;
166 pf
.direct
.alphaMask
= 1;
167 mono_format
= pXRenderFindFormat(gdi_display
, PictFormatType
|
168 PictFormatDepth
| PictFormatAlpha
|
169 PictFormatAlphaMask
, &pf
, 0);
172 ERR("mono_format == NULL?\n");
173 X11DRV_XRender_Installed
= FALSE
;
176 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
177 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
179 glyphsetCacheSize
= INIT_CACHE_SIZE
;
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;
187 TRACE("Xrender is not available on this server\n");
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
);
206 static void walk_cache(void)
210 EnterCriticalSection(&xrender_cs
);
211 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
212 TRACE("item %d\n", i
);
213 LeaveCriticalSection(&xrender_cs
);
217 static int LookupEntry(LFANDSIZE
*plfsz
)
221 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
223 if(glyphsetCache
[i
].count
== -1) { /* reached free list so stop */
228 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
229 glyphsetCache
[i
].count
++;
231 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
232 glyphsetCache
[i
].next
= mru
;
235 TRACE("found font in cache %d\n", i
);
240 TRACE("font not in cache\n");
244 static int AllocEntry(void)
246 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
249 assert(glyphsetCache
[lastfree
].count
== -1);
250 glyphsetCache
[lastfree
].count
= 1;
252 lastfree
= glyphsetCache
[lastfree
].next
;
254 glyphsetCache
[best
].next
= mru
;
257 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
261 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
262 if(glyphsetCache
[i
].count
== 0) {
270 TRACE("freeing unused glyphset at cache %d\n", best
);
272 pXRenderFreeGlyphSet(gdi_display
, glyphsetCache
[best
].glyphset
);
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;
282 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
283 glyphsetCache
[best
].next
= mru
;
291 TRACE("Growing cache\n");
292 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
294 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
295 * sizeof(*glyphsetCache
));
296 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
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
;
308 TRACE("new free cache slot at %d\n", mru
);
312 static int GetCacheEntry(LFANDSIZE
*plfsz
)
314 XRenderPictFormat pf
;
318 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
321 entry
= glyphsetCache
+ ret
;
322 entry
->lfsz
= *plfsz
;
323 assert(entry
->nrealized
== 0);
328 pf
.direct
.alphaMask
= 0xff;
331 pf
.direct
.alphaMask
= 1;
333 pf
.type
= PictTypeDirect
;
337 entry
->font_format
= pXRenderFindFormat(gdi_display
,
344 entry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, entry
->font_format
);
349 static void dec_ref_cache(int index
)
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
;
362 for(ptr
= (DWORD
*)&plfsz
->xform
; ptr
< (DWORD
*)(&plfsz
->xform
+ 1); ptr
++)
364 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
366 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
367 WCHAR
*pwc
= (WCHAR
*)ptr
;
377 /***********************************************************************
378 * X11DRV_XRender_Finalize
380 void X11DRV_XRender_Finalize(void)
382 FIXME("Free cached glyphsets\n");
384 if (xrender_handle
) wine_dlclose(xrender_handle
, NULL
, 0);
385 xrender_handle
= NULL
;
390 /***********************************************************************
391 * X11DRV_XRender_SelectFont
393 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
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
);
417 /***********************************************************************
418 * X11DRV_XRender_DeleteDC
420 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
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
);
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
;
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
);
457 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
460 physDev
->xrender
->pict
= 0;
464 /************************************************************************
467 * Helper to ExtTextOut. Must be called inside xrender_cs
469 static BOOL
UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
)
476 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
477 UINT ggo_format
= GGO_GLYPH_INDEX
;
480 if(entry
->nrealized
<= glyph
) {
481 entry
->nrealized
= (glyph
/ 128 + 1) * 128;
482 entry
->realized
= HeapReAlloc(GetProcessHeap(),
485 entry
->nrealized
* sizeof(BOOL
));
488 if(entry
->font_format
->depth
== 8) {
490 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
493 ggo_format
|= GGO_BITMAP
;
496 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
,
498 if(buflen
== GDI_ERROR
) {
499 LeaveCriticalSection(&xrender_cs
);
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",
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
)) {
526 pitch
= ((gi
.width
+ 31) / 32) * 4;
527 for(i
= 0; i
< gi
.height
; i
++) {
528 line
= buf
+ i
* pitch
;
530 for(j
= 0; j
< pitch
* 8; j
++) {
531 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
533 strcat(output
, "\n");
537 char blks
[] = " .:;!o*#";
541 pitch
= ((gi
.width
+ 3) / 4) * 4;
542 for(i
= 0; i
< gi
.height
; i
++) {
543 line
= buf
+ i
* pitch
;
545 for(j
= 0; j
< pitch
; j
++) {
546 str
[0] = blks
[line
[j
] >> 5];
549 strcat(output
, "\n");
555 if(!aa
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
556 unsigned char *byte
= buf
, c
;
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);
572 pXRenderAddGlyphs(gdi_display
, entry
->glyphset
, &gid
, &gi
, 1,
575 HeapFree(GetProcessHeap(), 0, buf
);
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
,
592 BOOL done_extents
= FALSE
;
593 INT width
, xwidth
, ywidth
;
594 double cosEsc
, sinEsc
;
597 int render_op
= PictOpOver
;
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
;
611 glyphs
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(WCHAR
));
612 GetGlyphIndicesW(hdc
, wstr
, count
, glyphs
, 0);
616 TRACE("rect: %d,%d - %d,%d\n", lprect
->left
, lprect
->top
, lprect
->right
,
618 TRACE("align = %x bkmode = %x mapmode = %x\n", dc
->textAlign
, GetBkMode(hdc
), dc
->MapMode
);
620 if(dc
->textAlign
& TA_UPDATECP
) {
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);
634 if(flags
& (ETO_CLIPPED
| ETO_OPAQUE
)) {
636 if(flags
& ETO_CLIPPED
) return FALSE
;
637 GetTextExtentPointI(hdc
, glyphs
, count
, &sz
);
641 rc
.right
= x
+ sz
.cx
;
642 rc
.bottom
= y
+ sz
.cy
;
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
);
675 LPtoDP(physDev
->hdc
, &pt
, 1);
679 TRACE("real x,y %d,%d\n", x
, y
);
683 for(idx
= 0; idx
< count
; idx
++)
687 GetTextExtentPointI(hdc
, glyphs
, count
, &sz
);
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
) ) {
702 if (dc
->textAlign
& TA_UPDATECP
) {
705 DPtoLP(physDev
->hdc
, &pt
, 1);
719 if (dc
->textAlign
& TA_UPDATECP
) {
722 DPtoLP(physDev
->hdc
, &pt
, 1);
729 switch( dc
->textAlign
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
) ) {
731 y
+= tm
.tmAscent
* cosEsc
;
732 x
+= tm
.tmAscent
* sinEsc
;
736 y
-= tm
.tmDescent
* cosEsc
;
737 x
-= tm
.tmDescent
* sinEsc
;
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
;
755 physDev
->xrender
->pict
= pXRenderCreatePicture(gdi_display
,
757 (dc
->bitsPerPixel
== 1) ?
758 mono_format
: screen_format
,
759 CPSubwindowMode
, &pa
);
762 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n", physDev
->xrender
->pict
, dc
, physDev
->drawable
);
764 TRACE("using existing pict = %lx dc = %p\n", physDev
->xrender
->pict
, dc
);
767 if ((data
= X11DRV_GetRegionData( dc
->hGCClipRgn
, 0 )))
770 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
771 physDev
->org
.x
, physDev
->org
.y
,
772 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
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
;
795 physDev
->xrender
->tile_xpm
= XCreatePixmap(gdi_display
,
800 physDev
->xrender
->tile_pict
= pXRenderCreatePicture(gdi_display
,
801 physDev
->xrender
->tile_xpm
,
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;
821 } else { /* for a 1bpp bitmap we always need a 1 in the tile */
822 col
.red
= col
.green
= col
.blue
= 0;
826 pXRenderFillRectangle(gdi_display
, PictOpSrc
,
827 physDev
->xrender
->tile_pict
,
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
);
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
,
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
,
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;
884 if (flags
& ETO_CLIPPED
)
885 RestoreVisRgn16( HDC_16(hdc
) );
890 X11DRV_UnlockDIBSection( physDev
, TRUE
);
891 if(glyphs
!= wstr
) HeapFree(GetProcessHeap(), 0, glyphs
);
895 #else /* HAVE_X11_EXTENSIONS_XRENDER_H */
897 void X11DRV_XRender_Init(void)
899 TRACE("XRender support not compiled in.\n");
903 void X11DRV_XRender_Finalize(void)
907 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
913 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
919 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
920 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
927 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
933 #endif /* HAVE_X11_EXTENSIONS_XRENDER_H */