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"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
33 BOOL X11DRV_XRender_Installed
= FALSE
;
34 WINE_DEFAULT_DEBUG_CHANNEL(xrender
);
36 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
39 #include <X11/extensions/Xrender.h>
41 static XRenderPictFormat
*screen_format
; /* format of screen */
42 static XRenderPictFormat
*mono_format
; /* format of mono bitmap */
47 XFORM xform
; /* this is dum as we don't care about offsets */
51 #define INITIAL_REALIZED_BUF_SIZE 128
58 XRenderPictFormat
*font_format
;
67 gsCacheEntry
*cacheEntry
;
71 COLORREF lastTextColor
;
75 static gsCacheEntry
*glyphsetCache
= NULL
;
76 static DWORD glyphsetCacheSize
= 0;
77 static INT lastfree
= -1;
80 #define INIT_CACHE_SIZE 10
82 static int antialias
= 1;
84 /* some default values just in case */
86 #define SONAME_LIBX11 "libX11.so"
88 #ifndef SONAME_LIBXEXT
89 #define SONAME_LIBXEXT "libXext.so"
91 #ifndef SONAME_LIBXRENDER
92 #define SONAME_LIBXRENDER "libXrender.so"
95 static void *xrender_handle
;
97 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
98 MAKE_FUNCPTR(XRenderAddGlyphs
)
99 MAKE_FUNCPTR(XRenderCompositeString8
)
100 MAKE_FUNCPTR(XRenderCompositeString16
)
101 MAKE_FUNCPTR(XRenderCompositeString32
)
102 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
103 MAKE_FUNCPTR(XRenderCreatePicture
)
104 MAKE_FUNCPTR(XRenderFillRectangle
)
105 MAKE_FUNCPTR(XRenderFindFormat
)
106 MAKE_FUNCPTR(XRenderFindVisualFormat
)
107 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
108 MAKE_FUNCPTR(XRenderFreePicture
)
109 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
110 MAKE_FUNCPTR(XRenderQueryExtension
)
113 /***********************************************************************
114 * X11DRV_XRender_Init
116 * Let's see if our XServer has the extension available
119 void X11DRV_XRender_Init(void)
121 int error_base
, event_base
, i
;
122 XRenderPictFormat pf
;
124 if (!wine_dlopen(SONAME_LIBX11
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0)) return;
125 if (!wine_dlopen(SONAME_LIBXEXT
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0)) return;
126 xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0);
127 if(!xrender_handle
) return;
129 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
130 LOAD_FUNCPTR(XRenderAddGlyphs
)
131 LOAD_FUNCPTR(XRenderCompositeString8
)
132 LOAD_FUNCPTR(XRenderCompositeString16
)
133 LOAD_FUNCPTR(XRenderCompositeString32
)
134 LOAD_FUNCPTR(XRenderCreateGlyphSet
)
135 LOAD_FUNCPTR(XRenderCreatePicture
)
136 LOAD_FUNCPTR(XRenderFillRectangle
)
137 LOAD_FUNCPTR(XRenderFindFormat
)
138 LOAD_FUNCPTR(XRenderFindVisualFormat
)
139 LOAD_FUNCPTR(XRenderFreeGlyphSet
)
140 LOAD_FUNCPTR(XRenderFreePicture
)
141 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
)
142 LOAD_FUNCPTR(XRenderQueryExtension
)
146 if(pXRenderQueryExtension(gdi_display
, &event_base
, &error_base
)) {
147 X11DRV_XRender_Installed
= TRUE
;
148 TRACE("Xrender is up and running error_base = %d\n", error_base
);
149 screen_format
= pXRenderFindVisualFormat(gdi_display
, visual
);
150 if(!screen_format
) { /* This fails in buggy versions of libXrender.so */
153 "Wine has detected that you probably have a buggy version\n"
154 "of libXrender.so . Because of this client side font rendering\n"
155 "will be disabled. Please upgrade this library.\n");
156 X11DRV_XRender_Installed
= FALSE
;
159 pf
.type
= PictTypeDirect
;
162 pf
.direct
.alphaMask
= 1;
163 mono_format
= pXRenderFindFormat(gdi_display
, PictFormatType
|
164 PictFormatDepth
| PictFormatAlpha
|
165 PictFormatAlphaMask
, &pf
, 0);
168 ERR("mono_format == NULL?\n");
169 X11DRV_XRender_Installed
= FALSE
;
172 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
173 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
175 glyphsetCacheSize
= INIT_CACHE_SIZE
;
177 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
178 glyphsetCache
[i
].next
= i
+ 1;
179 glyphsetCache
[i
].count
= -1;
181 glyphsetCache
[i
-1].next
= -1;
183 TRACE("Xrender is not available on this server\n");
189 wine_dlclose(xrender_handle
, NULL
, 0);
190 xrender_handle
= NULL
;
193 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
195 if(p1
->hash
!= p2
->hash
) return TRUE
;
196 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
197 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
198 return strcmpW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
202 static void walk_cache(void)
206 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
207 TRACE("item %d\n", i
);
211 static gsCacheEntry
*LookupEntry(LFANDSIZE
*plfsz
)
215 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
217 if(glyphsetCache
[i
].count
== -1) { /* reached free list so stop */
222 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
223 glyphsetCache
[i
].count
++;
225 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
226 glyphsetCache
[i
].next
= mru
;
229 TRACE("found font in cache %d\n", i
);
230 return glyphsetCache
+ i
;
234 TRACE("font not in cache\n");
238 static gsCacheEntry
*AllocEntry(void)
240 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
243 assert(glyphsetCache
[lastfree
].count
== -1);
244 glyphsetCache
[lastfree
].count
= 1;
246 lastfree
= glyphsetCache
[lastfree
].next
;
248 glyphsetCache
[best
].next
= mru
;
251 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
252 return glyphsetCache
+ mru
;
255 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
256 if(glyphsetCache
[i
].count
== 0) {
264 TRACE("freeing unused glyphset at cache %d\n", best
);
266 pXRenderFreeGlyphSet(gdi_display
, glyphsetCache
[best
].glyphset
);
268 glyphsetCache
[best
].glyphset
= 0;
269 if(glyphsetCache
[best
].nrealized
) { /* do we really want to do this? */
270 HeapFree(GetProcessHeap(), 0, glyphsetCache
[best
].realized
);
271 glyphsetCache
[best
].realized
= NULL
;
272 glyphsetCache
[best
].nrealized
= 0;
274 glyphsetCache
[best
].count
= 1;
276 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
277 glyphsetCache
[best
].next
= mru
;
282 return glyphsetCache
+ mru
;
285 TRACE("Growing cache\n");
286 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
288 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
289 * sizeof(*glyphsetCache
));
290 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
292 glyphsetCache
[i
].next
= i
+ 1;
293 glyphsetCache
[i
].count
= -1;
295 glyphsetCache
[i
-1].next
= -1;
296 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
298 lastfree
= glyphsetCache
[best
].next
;
299 glyphsetCache
[best
].count
= 1;
300 glyphsetCache
[best
].next
= mru
;
302 TRACE("new free cache slot at %d\n", mru
);
303 return glyphsetCache
+ mru
;
306 static gsCacheEntry
*GetCacheEntry(LFANDSIZE
*plfsz
)
308 XRenderPictFormat pf
;
311 if((ret
= LookupEntry(plfsz
)) != NULL
) return ret
;
315 assert(ret
->nrealized
== 0);
318 if(antialias
&& abs(plfsz
->lf
.lfHeight
) > 16) {
320 pf
.direct
.alphaMask
= 0xff;
323 pf
.direct
.alphaMask
= 1;
325 pf
.type
= PictTypeDirect
;
329 ret
->font_format
= pXRenderFindFormat(gdi_display
,
336 ret
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, ret
->font_format
);
341 static void dec_ref_cache(gsCacheEntry
*entry
)
343 TRACE("dec'ing entry %d to %d\n", entry
- glyphsetCache
, entry
->count
- 1);
344 assert(entry
->count
> 0);
348 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
350 DWORD hash
= 0, *ptr
;
353 for(ptr
= (DWORD
*)&plfsz
->xform
; ptr
< (DWORD
*)(&plfsz
->xform
+ 1); ptr
++)
355 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
357 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
358 WCHAR
*pwc
= (WCHAR
*)ptr
;
368 /***********************************************************************
369 * X11DRV_XRender_Finalize
371 void X11DRV_XRender_Finalize(void)
373 FIXME("Free cached glyphsets\n");
374 if (xrender_handle
) wine_dlclose(xrender_handle
, NULL
, 0);
375 xrender_handle
= NULL
;
379 /***********************************************************************
380 * X11DRV_XRender_SelectFont
382 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
386 GetObjectW(hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
387 TRACE("h=%ld w=%ld weight=%ld it=%d charset=%d name=%s\n",
388 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
389 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
390 lfsz
.xform
= physDev
->dc
->xformWorld2Vport
;
391 lfsz_calc_hash(&lfsz
);
393 if(!physDev
->xrender
)
394 physDev
->xrender
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
395 sizeof(*physDev
->xrender
));
397 else if(physDev
->xrender
->cacheEntry
)
398 dec_ref_cache(physDev
->xrender
->cacheEntry
);
399 physDev
->xrender
->cacheEntry
= GetCacheEntry(&lfsz
);
403 /***********************************************************************
404 * X11DRV_XRender_DeleteDC
406 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
409 if(physDev
->xrender
->tile_pict
)
410 pXRenderFreePicture(gdi_display
, physDev
->xrender
->tile_pict
);
412 if(physDev
->xrender
->tile_xpm
)
413 XFreePixmap(gdi_display
, physDev
->xrender
->tile_xpm
);
415 if(physDev
->xrender
->pict
) {
416 TRACE("freeing pict = %lx dc = %p\n", physDev
->xrender
->pict
, physDev
->dc
);
417 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
421 if(physDev
->xrender
->cacheEntry
)
422 dec_ref_cache(physDev
->xrender
->cacheEntry
);
424 HeapFree(GetProcessHeap(), 0, physDev
->xrender
);
425 physDev
->xrender
= NULL
;
429 /***********************************************************************
430 * X11DRV_XRender_UpdateDrawable
432 * This gets called from X11DRV_SetDrawable and deletes the pict when the
433 * drawable changes. However at the moment we delete the pict at the end of
434 * every ExtTextOut so this is basically a NOP.
436 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
438 if(physDev
->xrender
->pict
) {
439 TRACE("freeing pict %08lx from dc %p\n", physDev
->xrender
->pict
, physDev
->dc
);
441 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
444 physDev
->xrender
->pict
= 0;
448 static BOOL
UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
)
455 gsCacheEntry
*entry
= physDev
->xrender
->cacheEntry
;
456 UINT ggo_format
= GGO_GLYPH_INDEX
;
459 if(entry
->nrealized
<= glyph
) {
460 entry
->nrealized
= (glyph
/ 128 + 1) * 128;
461 entry
->realized
= HeapReAlloc(GetProcessHeap(),
464 entry
->nrealized
* sizeof(BOOL
));
466 entry
->realized
[glyph
] = TRUE
;
468 if(entry
->font_format
->depth
== 8) {
470 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
473 ggo_format
|= GGO_BITMAP
;
476 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
,
478 if(buflen
== GDI_ERROR
)
481 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
482 GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, NULL
);
484 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%ld,%ld\n",
486 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
487 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
489 gi
.width
= gm
.gmBlackBoxX
;
490 gi
.height
= gm
.gmBlackBoxY
;
491 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
492 gi
.y
= gm
.gmptGlyphOrigin
.y
;
493 gi
.xOff
= gm
.gmCellIncX
;
494 gi
.yOff
= gm
.gmCellIncY
;
496 if(TRACE_ON(xrender
)) {
502 pitch
= ((gi
.width
+ 31) / 32) * 4;
503 for(i
= 0; i
< gi
.height
; i
++) {
504 line
= buf
+ i
* pitch
;
506 for(j
= 0; j
< pitch
* 8; j
++) {
507 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
509 strcat(output
, "\n");
513 char blks
[] = " .:;!o*#";
517 pitch
= ((gi
.width
+ 3) / 4) * 4;
518 for(i
= 0; i
< gi
.height
; i
++) {
519 line
= buf
+ i
* pitch
;
521 for(j
= 0; j
< pitch
; j
++) {
522 str
[0] = blks
[line
[j
] >> 5];
525 strcat(output
, "\n");
531 if(!aa
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
532 unsigned char *byte
= buf
, c
;
538 /* magic to flip bit order */
539 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
540 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
541 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
548 pXRenderAddGlyphs(gdi_display
, entry
->glyphset
, &gid
, &gi
, 1,
551 HeapFree(GetProcessHeap(), 0, buf
);
555 /***********************************************************************
556 * X11DRV_XRender_ExtTextOut
558 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
559 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
568 BOOL done_extents
= FALSE
;
569 INT width
, xwidth
, ywidth
;
570 double cosEsc
, sinEsc
;
573 int render_op
= PictOpOver
;
575 HDC hdc
= physDev
->hdc
;
576 DC
*dc
= physDev
->dc
;
578 TRACE("%04x, %d, %d, %08x, %p, %s, %d, %p)\n", hdc
, x
, y
, flags
,
579 lprect
, debugstr_wn(wstr
, count
), count
, lpDx
);
581 if(flags
& ETO_GLYPH_INDEX
)
582 glyphs
= (LPWORD
)wstr
;
584 glyphs
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(WCHAR
));
585 GetGlyphIndicesW(hdc
, wstr
, count
, glyphs
, 0);
589 TRACE("rect: %d,%d - %d,%d\n", lprect
->left
, lprect
->top
, lprect
->right
,
591 TRACE("align = %x bkmode = %x mapmode = %x\n", dc
->textAlign
, GetBkMode(hdc
), dc
->MapMode
);
593 if(dc
->textAlign
& TA_UPDATECP
) {
598 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
599 if(lf
.lfEscapement
!= 0) {
600 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
601 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
607 if(flags
& (ETO_CLIPPED
| ETO_OPAQUE
)) {
609 if(flags
& ETO_CLIPPED
) return FALSE
;
610 GetTextExtentPointI(hdc
, glyphs
, count
, &sz
);
614 rc
.right
= x
+ sz
.cx
;
615 rc
.bottom
= y
+ sz
.cy
;
620 rc
.left
= INTERNAL_XWPTODP(dc
, rc
.left
, rc
.top
);
621 rc
.top
= INTERNAL_YWPTODP(dc
, rc
.left
, rc
.top
);
622 rc
.right
= INTERNAL_XWPTODP(dc
, rc
.right
, rc
.bottom
);
623 rc
.bottom
= INTERNAL_YWPTODP(dc
, rc
.right
, rc
.bottom
);
625 if(rc
.left
> rc
.right
) {INT tmp
= rc
.left
; rc
.left
= rc
.right
; rc
.right
= tmp
;}
626 if(rc
.top
> rc
.bottom
) {INT tmp
= rc
.top
; rc
.top
= rc
.bottom
; rc
.bottom
= tmp
;}
629 xgcval
.function
= GXcopy
;
630 xgcval
.background
= physDev
->backgroundPixel
;
631 xgcval
.fill_style
= FillSolid
;
632 TSXChangeGC( gdi_display
, physDev
->gc
,
633 GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
635 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
, FALSE
);
637 if(flags
& ETO_OPAQUE
) {
638 TSXSetForeground( gdi_display
, physDev
->gc
, physDev
->backgroundPixel
);
639 TSXFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
640 physDev
->org
.x
+ rc
.left
, physDev
->org
.y
+ rc
.top
,
641 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
645 X11DRV_UnlockDIBSection( physDev
, TRUE
);
649 x
= INTERNAL_XWPTODP( dc
, x
, y
);
650 y
= INTERNAL_YWPTODP( dc
, x
, y
);
652 TRACE("real x,y %d,%d\n", x
, y
);
656 for(idx
= 0; idx
< count
; idx
++)
660 GetTextExtentPointI(hdc
, glyphs
, count
, &sz
);
665 width
= INTERNAL_XWSTODS(dc
, width
);
666 xwidth
= width
* cosEsc
;
667 ywidth
= width
* sinEsc
;
669 GetTextMetricsW(hdc
, &tm
);
671 tm
.tmAscent
= INTERNAL_YWSTODS(dc
, tm
.tmAscent
);
672 tm
.tmDescent
= INTERNAL_YWSTODS(dc
, tm
.tmDescent
);
673 switch( dc
->textAlign
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
) ) {
675 if (dc
->textAlign
& TA_UPDATECP
) {
676 dc
->CursPosX
= INTERNAL_XDPTOWP( dc
, x
+ xwidth
, y
- ywidth
);
677 dc
->CursPosY
= INTERNAL_YDPTOWP( dc
, x
+ xwidth
, y
- ywidth
);
689 if (dc
->textAlign
& TA_UPDATECP
) {
690 dc
->CursPosX
= INTERNAL_XDPTOWP( dc
, x
+ xwidth
, y
- ywidth
);
691 dc
->CursPosY
= INTERNAL_YDPTOWP( dc
, x
+ xwidth
, y
- ywidth
);
696 switch( dc
->textAlign
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
) ) {
698 y
+= tm
.tmAscent
* cosEsc
;
699 x
+= tm
.tmAscent
* sinEsc
;
703 y
-= tm
.tmDescent
* cosEsc
;
704 x
-= tm
.tmDescent
* sinEsc
;
711 if (flags
& ETO_CLIPPED
)
714 IntersectVisRect16( dc
->hSelf
, lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
717 if(!physDev
->xrender
->pict
) {
718 XRenderPictureAttributes pa
;
719 pa
.subwindow_mode
= IncludeInferiors
;
722 physDev
->xrender
->pict
= pXRenderCreatePicture(gdi_display
,
724 (dc
->bitsPerPixel
== 1) ?
725 mono_format
: screen_format
,
726 CPSubwindowMode
, &pa
);
729 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n", physDev
->xrender
->pict
, dc
, physDev
->drawable
);
731 TRACE("using existing pict = %lx dc = %p\n", physDev
->xrender
->pict
, dc
);
734 if ((data
= X11DRV_GetRegionData( dc
->hGCClipRgn
, 0 )))
737 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
738 physDev
->org
.x
, physDev
->org
.y
,
739 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
741 HeapFree( GetProcessHeap(), 0, data
);
744 if(GetBkMode(hdc
) != TRANSPARENT
) {
745 if(!((flags
& ETO_CLIPPED
) && (flags
& ETO_OPAQUE
))) {
746 if(!(flags
& ETO_OPAQUE
) || x
< rc
.left
|| x
+ width
>= rc
.right
||
747 y
- tm
.tmAscent
< rc
.top
|| y
+ tm
.tmDescent
>= rc
.bottom
) {
748 TSXSetForeground( gdi_display
, physDev
->gc
, physDev
->backgroundPixel
);
749 TSXFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
750 physDev
->org
.x
+ x
, physDev
->org
.y
+ y
- tm
.tmAscent
,
751 width
, tm
.tmAscent
+ tm
.tmDescent
);
756 /* Create a 1x1 pixmap to tile over the font mask */
757 if(!physDev
->xrender
->tile_xpm
) {
758 XRenderPictureAttributes pa
;
760 XRenderPictFormat
*format
= (dc
->bitsPerPixel
== 1) ? mono_format
: screen_format
;
762 physDev
->xrender
->tile_xpm
= XCreatePixmap(gdi_display
,
767 physDev
->xrender
->tile_pict
= pXRenderCreatePicture(gdi_display
,
768 physDev
->xrender
->tile_xpm
,
772 TRACE("Created pixmap of depth %d\n", format
->depth
);
773 /* init lastTextColor to something different from dc->textColor */
774 physDev
->xrender
->lastTextColor
= ~dc
->textColor
;
778 if(dc
->textColor
!= physDev
->xrender
->lastTextColor
) {
779 if(dc
->bitsPerPixel
!= 1) {
780 /* Map 0 -- 0xff onto 0 -- 0xffff */
781 col
.red
= GetRValue(dc
->textColor
);
782 col
.red
|= col
.red
<< 8;
783 col
.green
= GetGValue(dc
->textColor
);
784 col
.green
|= col
.green
<< 8;
785 col
.blue
= GetBValue(dc
->textColor
);
786 col
.blue
|= col
.blue
<< 8;
788 } else { /* for a 1bpp bitmap we always need a 1 in the tile */
789 col
.red
= col
.green
= col
.blue
= 0;
793 pXRenderFillRectangle(gdi_display
, PictOpSrc
,
794 physDev
->xrender
->tile_pict
,
797 physDev
->xrender
->lastTextColor
= dc
->textColor
;
800 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
802 if((dc
->bitsPerPixel
== 1) && ((dc
->textColor
& 0xffffff) == 0))
803 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
805 for(idx
= 0; idx
< count
; idx
++) {
806 if(glyphs
[idx
] >= physDev
->xrender
->cacheEntry
->nrealized
||
807 physDev
->xrender
->cacheEntry
->realized
[glyphs
[idx
]] == FALSE
) {
808 UploadGlyph(physDev
, glyphs
[idx
]);
813 TRACE("Writing %s at %ld,%ld\n", debugstr_wn(wstr
,count
),
814 physDev
->org
.x
+ x
, physDev
->org
.y
+ y
);
818 pXRenderCompositeString16(gdi_display
, render_op
,
819 physDev
->xrender
->tile_pict
,
820 physDev
->xrender
->pict
,
821 physDev
->xrender
->cacheEntry
->font_format
,
822 physDev
->xrender
->cacheEntry
->glyphset
,
823 0, 0, physDev
->org
.x
+ x
, physDev
->org
.y
+ y
,
827 INT offset
= 0, xoff
= 0, yoff
= 0;
828 for(idx
= 0; idx
< count
; idx
++) {
829 pXRenderCompositeString16(gdi_display
, render_op
,
830 physDev
->xrender
->tile_pict
,
831 physDev
->xrender
->pict
,
832 physDev
->xrender
->cacheEntry
->font_format
,
833 physDev
->xrender
->cacheEntry
->glyphset
,
834 0, 0, physDev
->org
.x
+ x
+ xoff
,
835 physDev
->org
.y
+ y
+ yoff
,
837 offset
+= INTERNAL_XWSTODS(dc
, lpDx
[idx
]);
838 xoff
= offset
* cosEsc
;
839 yoff
= offset
* -sinEsc
;
843 if(physDev
->xrender
->pict
) {
844 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
846 physDev
->xrender
->pict
= 0;
849 if (flags
& ETO_CLIPPED
)
850 RestoreVisRgn16( hdc
);
852 X11DRV_UnlockDIBSection( physDev
, TRUE
);
853 if(glyphs
!= wstr
) HeapFree(GetProcessHeap(), 0, glyphs
);
857 #else /* HAVE_X11_EXTENSIONS_XRENDER_H */
859 void X11DRV_XRender_Init(void)
861 TRACE("XRender support not compiled in.\n");
865 void X11DRV_XRender_Finalize(void)
869 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
875 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
881 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
882 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
889 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
895 #endif /* HAVE_X11_EXTENSIONS_XRENDER_H */