2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wine/port.h"
36 #include "wine/library.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
40 static BOOL X11DRV_XRender_Installed
= FALSE
;
41 int using_client_side_fonts
= FALSE
;
43 WINE_DEFAULT_DEBUG_CHANNEL(xrender
);
45 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
48 #include <X11/extensions/Xrender.h>
50 /* Older version of the Xrender headers don't define these */
51 #ifndef PictStandardARGB32
53 #define PictStandardARGB32 0
54 XRenderPictFormat
* XRenderFindStandardFormat (Display
*dpy
, int format
);
58 static XRenderPictFormat
*screen_format
; /* format of screen */
59 static XRenderPictFormat
*mono_format
; /* format of mono bitmap */
64 SIZE devsize
; /* size in device coords */
68 #define INITIAL_REALIZED_BUF_SIZE 128
70 typedef enum { AA_None
, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
} AA_Type
;
77 XRenderPictFormat
*font_format
;
92 COLORREF lastTextColor
;
96 static gsCacheEntry
*glyphsetCache
= NULL
;
97 static DWORD glyphsetCacheSize
= 0;
98 static INT lastfree
= -1;
101 #define INIT_CACHE_SIZE 10
103 static int antialias
= 1;
105 /* some default values just in case */
106 #ifndef SONAME_LIBX11
107 #define SONAME_LIBX11 "libX11.so"
109 #ifndef SONAME_LIBXEXT
110 #define SONAME_LIBXEXT "libXext.so"
112 #ifndef SONAME_LIBXRENDER
113 #define SONAME_LIBXRENDER "libXrender.so"
116 static void *xrender_handle
;
118 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
119 MAKE_FUNCPTR(XRenderAddGlyphs
)
120 MAKE_FUNCPTR(XRenderComposite
)
121 MAKE_FUNCPTR(XRenderCompositeString8
)
122 MAKE_FUNCPTR(XRenderCompositeString16
)
123 MAKE_FUNCPTR(XRenderCompositeString32
)
124 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
125 MAKE_FUNCPTR(XRenderCreatePicture
)
126 MAKE_FUNCPTR(XRenderFillRectangle
)
127 MAKE_FUNCPTR(XRenderFindFormat
)
128 MAKE_FUNCPTR(XRenderFindStandardFormat
)
129 MAKE_FUNCPTR(XRenderFindVisualFormat
)
130 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
131 MAKE_FUNCPTR(XRenderFreePicture
)
132 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
133 MAKE_FUNCPTR(XRenderQueryExtension
)
136 static CRITICAL_SECTION xrender_cs
;
137 static CRITICAL_SECTION_DEBUG critsect_debug
=
140 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
141 0, 0, { 0, (DWORD
)(__FILE__
": xrender_cs") }
143 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
146 /***********************************************************************
147 * X11DRV_XRender_Init
149 * Let's see if our XServer has the extension available
152 void X11DRV_XRender_Init(void)
154 int error_base
, event_base
, i
;
155 XRenderPictFormat pf
;
157 if (client_side_with_render
&&
158 wine_dlopen(SONAME_LIBX11
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
159 wine_dlopen(SONAME_LIBXEXT
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
160 (xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0)))
163 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
164 LOAD_FUNCPTR(XRenderAddGlyphs
)
165 LOAD_FUNCPTR(XRenderComposite
)
166 LOAD_FUNCPTR(XRenderCompositeString8
)
167 LOAD_FUNCPTR(XRenderCompositeString16
)
168 LOAD_FUNCPTR(XRenderCompositeString32
)
169 LOAD_FUNCPTR(XRenderCreateGlyphSet
)
170 LOAD_FUNCPTR(XRenderCreatePicture
)
171 LOAD_FUNCPTR(XRenderFillRectangle
)
172 LOAD_FUNCPTR(XRenderFindFormat
)
173 LOAD_FUNCPTR(XRenderFindStandardFormat
)
174 LOAD_FUNCPTR(XRenderFindVisualFormat
)
175 LOAD_FUNCPTR(XRenderFreeGlyphSet
)
176 LOAD_FUNCPTR(XRenderFreePicture
)
177 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
)
178 LOAD_FUNCPTR(XRenderQueryExtension
)
182 if(pXRenderQueryExtension(gdi_display
, &event_base
, &error_base
)) {
183 X11DRV_XRender_Installed
= TRUE
;
184 TRACE("Xrender is up and running error_base = %d\n", error_base
);
185 screen_format
= pXRenderFindVisualFormat(gdi_display
, visual
);
186 if(!screen_format
) { /* This fails in buggy versions of libXrender.so */
189 "Wine has detected that you probably have a buggy version\n"
190 "of libXrender.so . Because of this client side font rendering\n"
191 "will be disabled. Please upgrade this library.\n");
192 X11DRV_XRender_Installed
= FALSE
;
195 pf
.type
= PictTypeDirect
;
198 pf
.direct
.alphaMask
= 1;
199 mono_format
= pXRenderFindFormat(gdi_display
, PictFormatType
|
200 PictFormatDepth
| PictFormatAlpha
|
201 PictFormatAlphaMask
, &pf
, 0);
203 ERR("mono_format == NULL?\n");
204 X11DRV_XRender_Installed
= FALSE
;
211 if(X11DRV_XRender_Installed
|| client_side_with_core
)
213 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
214 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
216 glyphsetCacheSize
= INIT_CACHE_SIZE
;
218 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
219 glyphsetCache
[i
].next
= i
+ 1;
220 glyphsetCache
[i
].count
= -1;
222 glyphsetCache
[i
-1].next
= -1;
223 using_client_side_fonts
= 1;
225 if(!X11DRV_XRender_Installed
) {
226 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
227 if(screen_depth
<= 8 || !client_side_antialias_with_core
)
230 if(screen_depth
<= 8 || !client_side_antialias_with_render
)
234 else TRACE("Using X11 core fonts\n");
237 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
239 if(p1
->hash
!= p2
->hash
) return TRUE
;
240 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
241 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
242 return strcmpW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
246 static void walk_cache(void)
250 EnterCriticalSection(&xrender_cs
);
251 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
252 TRACE("item %d\n", i
);
253 LeaveCriticalSection(&xrender_cs
);
257 static int LookupEntry(LFANDSIZE
*plfsz
)
261 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
263 if(glyphsetCache
[i
].count
== -1) { /* reached free list so stop */
268 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
269 glyphsetCache
[i
].count
++;
271 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
272 glyphsetCache
[i
].next
= mru
;
275 TRACE("found font in cache %d\n", i
);
280 TRACE("font not in cache\n");
284 static void FreeEntry(int entry
)
288 if(glyphsetCache
[entry
].glyphset
) {
290 pXRenderFreeGlyphSet(gdi_display
, glyphsetCache
[entry
].glyphset
);
292 glyphsetCache
[entry
].glyphset
= 0;
294 if(glyphsetCache
[entry
].nrealized
) {
295 HeapFree(GetProcessHeap(), 0, glyphsetCache
[entry
].realized
);
296 glyphsetCache
[entry
].realized
= NULL
;
297 if(glyphsetCache
[entry
].bitmaps
) {
298 for(i
= 0; i
< glyphsetCache
[entry
].nrealized
; i
++)
299 if(glyphsetCache
[entry
].bitmaps
[i
])
300 HeapFree(GetProcessHeap(), 0, glyphsetCache
[entry
].bitmaps
[i
]);
301 HeapFree(GetProcessHeap(), 0, glyphsetCache
[entry
].bitmaps
);
302 glyphsetCache
[entry
].bitmaps
= NULL
;
303 HeapFree(GetProcessHeap(), 0, glyphsetCache
[entry
].gis
);
304 glyphsetCache
[entry
].gis
= NULL
;
306 glyphsetCache
[entry
].nrealized
= 0;
310 static int AllocEntry(void)
312 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
315 assert(glyphsetCache
[lastfree
].count
== -1);
316 glyphsetCache
[lastfree
].count
= 1;
318 lastfree
= glyphsetCache
[lastfree
].next
;
320 glyphsetCache
[best
].next
= mru
;
323 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
327 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
328 if(glyphsetCache
[i
].count
== 0) {
336 TRACE("freeing unused glyphset at cache %d\n", best
);
338 glyphsetCache
[best
].count
= 1;
340 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
341 glyphsetCache
[best
].next
= mru
;
349 TRACE("Growing cache\n");
352 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
354 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
355 * sizeof(*glyphsetCache
));
357 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
358 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
359 * sizeof(*glyphsetCache
));
361 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
363 glyphsetCache
[i
].next
= i
+ 1;
364 glyphsetCache
[i
].count
= -1;
366 glyphsetCache
[i
-1].next
= -1;
367 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
369 lastfree
= glyphsetCache
[best
].next
;
370 glyphsetCache
[best
].count
= 1;
371 glyphsetCache
[best
].next
= mru
;
373 TRACE("new free cache slot at %d\n", mru
);
377 static int GetCacheEntry(LFANDSIZE
*plfsz
)
382 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
385 entry
= glyphsetCache
+ ret
;
386 entry
->lfsz
= *plfsz
;
387 assert(entry
->nrealized
== 0);
394 entry
->font_format
= NULL
;
399 static void dec_ref_cache(int index
)
402 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
403 assert(glyphsetCache
[index
].count
> 0);
404 glyphsetCache
[index
].count
--;
407 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
409 DWORD hash
= 0, *ptr
;
412 hash
^= plfsz
->devsize
.cx
;
413 hash
^= plfsz
->devsize
.cy
;
414 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
416 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
417 WCHAR
*pwc
= (WCHAR
*)ptr
;
427 /***********************************************************************
428 * X11DRV_XRender_Finalize
430 void X11DRV_XRender_Finalize(void)
434 EnterCriticalSection(&xrender_cs
);
435 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
437 LeaveCriticalSection(&xrender_cs
);
441 /***********************************************************************
442 * X11DRV_XRender_SelectFont
444 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
448 GetObjectW(hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
449 TRACE("h=%ld w=%ld weight=%ld it=%d charset=%d name=%s\n",
450 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
451 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
452 lfsz
.devsize
.cx
= X11DRV_XWStoDS( physDev
, lfsz
.lf
.lfWidth
);
453 lfsz
.devsize
.cy
= X11DRV_YWStoDS( physDev
, lfsz
.lf
.lfHeight
);
454 lfsz_calc_hash(&lfsz
);
456 EnterCriticalSection(&xrender_cs
);
457 if(!physDev
->xrender
) {
458 physDev
->xrender
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
459 sizeof(*physDev
->xrender
));
460 physDev
->xrender
->cache_index
= -1;
462 else if(physDev
->xrender
->cache_index
!= -1)
463 dec_ref_cache(physDev
->xrender
->cache_index
);
464 physDev
->xrender
->cache_index
= GetCacheEntry(&lfsz
);
465 LeaveCriticalSection(&xrender_cs
);
469 /***********************************************************************
470 * X11DRV_XRender_DeleteDC
472 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
475 if(physDev
->xrender
->tile_pict
)
476 pXRenderFreePicture(gdi_display
, physDev
->xrender
->tile_pict
);
478 if(physDev
->xrender
->tile_xpm
)
479 XFreePixmap(gdi_display
, physDev
->xrender
->tile_xpm
);
481 if(physDev
->xrender
->pict
) {
482 TRACE("freeing pict = %lx dc = %p\n", physDev
->xrender
->pict
, physDev
->hdc
);
483 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
487 EnterCriticalSection(&xrender_cs
);
488 if(physDev
->xrender
->cache_index
!= -1)
489 dec_ref_cache(physDev
->xrender
->cache_index
);
490 LeaveCriticalSection(&xrender_cs
);
492 HeapFree(GetProcessHeap(), 0, physDev
->xrender
);
493 physDev
->xrender
= NULL
;
497 /***********************************************************************
498 * X11DRV_XRender_UpdateDrawable
500 * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
501 * It deletes the pict when the drawable changes.
503 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
505 if(physDev
->xrender
->pict
) {
506 TRACE("freeing pict %08lx from dc %p drawable %08lx\n", physDev
->xrender
->pict
,
507 physDev
->hdc
, physDev
->drawable
);
510 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
513 physDev
->xrender
->pict
= 0;
517 /************************************************************************
520 * Helper to ExtTextOut. Must be called inside xrender_cs
522 static BOOL
UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
)
529 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
530 UINT ggo_format
= GGO_GLYPH_INDEX
;
531 XRenderPictFormat pf
;
533 if(entry
->nrealized
<= glyph
) {
534 entry
->nrealized
= (glyph
/ 128 + 1) * 128;
537 entry
->realized
= HeapReAlloc(GetProcessHeap(),
540 entry
->nrealized
* sizeof(BOOL
));
542 entry
->realized
= HeapAlloc(GetProcessHeap(),
544 entry
->nrealized
* sizeof(BOOL
));
546 if(!X11DRV_XRender_Installed
) {
548 entry
->bitmaps
= HeapReAlloc(GetProcessHeap(),
551 entry
->nrealized
* sizeof(entry
->bitmaps
[0]));
553 entry
->bitmaps
= HeapAlloc(GetProcessHeap(),
555 entry
->nrealized
* sizeof(entry
->bitmaps
[0]));
558 entry
->gis
= HeapReAlloc(GetProcessHeap(),
561 entry
->nrealized
* sizeof(entry
->gis
[0]));
563 entry
->gis
= HeapAlloc(GetProcessHeap(),
565 entry
->nrealized
* sizeof(entry
->gis
[0]));
571 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
575 ERR("aa = %d - not implemented\n", entry
->aa
);
577 ggo_format
|= GGO_BITMAP
;
581 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
,
583 if(buflen
== GDI_ERROR
) {
584 if(entry
->aa
!= AA_None
) {
586 ggo_format
&= ~WINE_GGO_GRAY16_BITMAP
;
587 ggo_format
|= GGO_BITMAP
;
588 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
,
591 if(buflen
== GDI_ERROR
) {
592 ERR("GetGlyphOutlineW failed\n");
595 TRACE("Turning off antialiasing for this monochrome font\n");
598 if(entry
->glyphset
== 0 && X11DRV_XRender_Installed
) {
602 pf
.direct
.alphaMask
= 0xff;
606 ERR("aa = %d - not implemented\n", entry
->aa
);
609 pf
.direct
.alphaMask
= 1;
613 pf
.type
= PictTypeDirect
;
617 entry
->font_format
= pXRenderFindFormat(gdi_display
,
624 entry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, entry
->font_format
);
629 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
630 GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, NULL
);
631 entry
->realized
[glyph
] = TRUE
;
633 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%ld,%ld\n",
635 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
636 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
638 gi
.width
= gm
.gmBlackBoxX
;
639 gi
.height
= gm
.gmBlackBoxY
;
640 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
641 gi
.y
= gm
.gmptGlyphOrigin
.y
;
642 gi
.xOff
= gm
.gmCellIncX
;
643 gi
.yOff
= gm
.gmCellIncY
;
645 if(TRACE_ON(xrender
)) {
650 if(entry
->aa
== AA_None
) {
651 pitch
= ((gi
.width
+ 31) / 32) * 4;
652 for(i
= 0; i
< gi
.height
; i
++) {
653 line
= buf
+ i
* pitch
;
655 for(j
= 0; j
< pitch
* 8; j
++) {
656 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
658 strcat(output
, "\n");
662 static const char blks
[] = " .:;!o*#";
666 pitch
= ((gi
.width
+ 3) / 4) * 4;
667 for(i
= 0; i
< gi
.height
; i
++) {
668 line
= buf
+ i
* pitch
;
670 for(j
= 0; j
< pitch
; j
++) {
671 str
[0] = blks
[line
[j
] >> 5];
674 strcat(output
, "\n");
680 if(entry
->glyphset
) {
681 if(entry
->aa
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
682 unsigned char *byte
= buf
, c
;
688 /* magic to flip bit order */
689 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
690 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
691 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
698 pXRenderAddGlyphs(gdi_display
, entry
->glyphset
, &gid
, &gi
, 1,
701 HeapFree(GetProcessHeap(), 0, buf
);
703 entry
->bitmaps
[glyph
] = buf
;
704 memcpy(&entry
->gis
[glyph
], &gi
, sizeof(gi
));
709 static void SharpGlyphMono(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
710 void *bitmap
, XGlyphInfo
*gi
)
712 unsigned char *srcLine
= bitmap
, *src
;
713 unsigned char bits
, bitsMask
;
714 int width
= gi
->width
;
715 int stride
= ((width
+ 31) & ~31) >> 3;
716 int height
= gi
->height
;
720 TRACE("%d, %d\n", x
, y
);
729 bitsMask
= 0x80; /* FreeType is always MSB first */
743 bitsMask
= bitsMask
>> 1;
749 } while (bits
& bitsMask
);
750 XFillRectangle (gdi_display
, physDev
->drawable
,
751 physDev
->gc
, xspan
, y
, lenspan
, 1);
763 bitsMask
= bitsMask
>> 1;
769 } while (!(bits
& bitsMask
));
776 static void SharpGlyphGray(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
777 void *bitmap
, XGlyphInfo
*gi
)
779 unsigned char *srcLine
= bitmap
, *src
, bits
;
780 int width
= gi
->width
;
781 int stride
= ((width
+ 3) & ~3);
782 int height
= gi
->height
;
807 } while (bits
>= 0x80);
808 XFillRectangle (gdi_display
, physDev
->drawable
,
809 physDev
->gc
, xspan
, y
, lenspan
, 1);
822 } while (bits
< 0x80);
830 static void ExamineBitfield (DWORD mask
, int *shift
, int *len
)
835 while ((mask
& 1) == 0)
841 while ((mask
& 1) == 1)
850 static DWORD
GetField (DWORD pixel
, int shift
, int len
)
852 pixel
= pixel
& (((1 << (len
)) - 1) << shift
);
853 pixel
= pixel
<< (32 - (shift
+ len
)) >> 24;
856 pixel
|= (pixel
>> len
);
863 static DWORD
PutField (DWORD pixel
, int shift
, int len
)
865 shift
= shift
- (8 - len
);
867 pixel
&= (((1 << len
) - 1) << (8 - len
));
875 static void SmoothGlyphGray(XImage
*image
, int x
, int y
, void *bitmap
, XGlyphInfo
*gi
,
881 BYTE
*maskLine
, *mask
, m
;
886 BYTE src_r
, src_g
, src_b
;
888 src_r
= GetRValue(color
);
889 src_g
= GetGValue(color
);
890 src_b
= GetBValue(color
);
897 maskLine
= (unsigned char *) bitmap
;
898 maskStride
= (width
+ 3) & ~3;
900 ExamineBitfield (image
->red_mask
, &r_shift
, &r_len
);
901 ExamineBitfield (image
->green_mask
, &g_shift
, &g_len
);
902 ExamineBitfield (image
->blue_mask
, &b_shift
, &b_len
);
906 maskLine
+= maskStride
;
911 if(y
>= image
->height
) break;
915 if(tx
>= image
->width
) break;
922 pixel
= (PutField ((src_r
), r_shift
, r_len
) |
923 PutField ((src_g
), g_shift
, g_len
) |
924 PutField ((src_b
), b_shift
, b_len
));
925 XPutPixel (image
, tx
, y
, pixel
);
931 pixel
= XGetPixel (image
, tx
, y
);
933 r
= GetField(pixel
, r_shift
, r_len
);
934 r
= ((BYTE
)~m
* (WORD
)r
+ (BYTE
)m
* (WORD
)src_r
) >> 8;
935 g
= GetField(pixel
, g_shift
, g_len
);
936 g
= ((BYTE
)~m
* (WORD
)g
+ (BYTE
)m
* (WORD
)src_g
) >> 8;
937 b
= GetField(pixel
, b_shift
, b_len
);
938 b
= ((BYTE
)~m
* (WORD
)b
+ (BYTE
)m
* (WORD
)src_b
) >> 8;
940 pixel
= (PutField (r
, r_shift
, r_len
) |
941 PutField (g
, g_shift
, g_len
) |
942 PutField (b
, b_shift
, b_len
));
943 XPutPixel (image
, tx
, y
, pixel
);
949 static int XRenderErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
954 /***********************************************************************
955 * X11DRV_XRender_ExtTextOut
957 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
958 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
959 const INT
*lpDx
, INT breakExtra
)
967 BOOL done_extents
= FALSE
;
968 INT width
, xwidth
, ywidth
;
969 double cosEsc
, sinEsc
;
972 int render_op
= PictOpOver
;
977 HDC hdc
= physDev
->hdc
;
978 int textPixel
, backgroundPixel
;
981 HRGN saved_region
= 0;
982 UINT align
= GetTextAlign( hdc
);
983 COLORREF textColor
= GetTextColor( hdc
);
985 TRACE("%p, %d, %d, %08x, %p, %s, %d, %p)\n", hdc
, x
, y
, flags
,
986 lprect
, debugstr_wn(wstr
, count
), count
, lpDx
);
988 if(flags
& ETO_GLYPH_INDEX
)
989 glyphs
= (LPWORD
)wstr
;
991 glyphs
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(WCHAR
));
992 GetGlyphIndicesW(hdc
, wstr
, count
, glyphs
, 0);
996 TRACE("rect: %ld,%ld - %ld,%ld\n", lprect
->left
, lprect
->top
, lprect
->right
,
998 TRACE("align = %x bkmode = %x mapmode = %x\n", align
, GetBkMode(hdc
), GetMapMode(hdc
));
1000 if(align
& TA_UPDATECP
)
1002 GetCurrentPositionEx( hdc
, &pt
);
1007 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
1008 if(lf
.lfEscapement
!= 0) {
1009 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
1010 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
1016 if(flags
& (ETO_CLIPPED
| ETO_OPAQUE
)) {
1018 if(flags
& ETO_CLIPPED
) return FALSE
;
1019 GetTextExtentPointI(hdc
, glyphs
, count
, &sz
);
1020 done_extents
= TRUE
;
1023 rc
.right
= x
+ sz
.cx
;
1024 rc
.bottom
= y
+ sz
.cy
;
1029 LPtoDP(hdc
, (POINT
*)&rc
, 2);
1031 if(rc
.left
> rc
.right
) {INT tmp
= rc
.left
; rc
.left
= rc
.right
; rc
.right
= tmp
;}
1032 if(rc
.top
> rc
.bottom
) {INT tmp
= rc
.top
; rc
.top
= rc
.bottom
; rc
.bottom
= tmp
;}
1035 xgcval
.function
= GXcopy
;
1036 xgcval
.background
= physDev
->backgroundPixel
;
1037 xgcval
.fill_style
= FillSolid
;
1039 XChangeGC( gdi_display
, physDev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1040 wine_tsx11_unlock();
1042 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
, FALSE
);
1044 if(physDev
->depth
== 1) {
1045 if((textColor
& 0xffffff) == 0) {
1047 backgroundPixel
= 1;
1050 backgroundPixel
= 0;
1053 textPixel
= physDev
->textPixel
;
1054 backgroundPixel
= physDev
->backgroundPixel
;
1057 if(flags
& ETO_OPAQUE
) {
1059 XSetForeground( gdi_display
, physDev
->gc
, backgroundPixel
);
1060 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1061 physDev
->org
.x
+ rc
.left
, physDev
->org
.y
+ rc
.top
,
1062 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
1063 wine_tsx11_unlock();
1073 LPtoDP(hdc
, &pt
, 1);
1077 TRACE("real x,y %d,%d\n", x
, y
);
1079 if((char_extra
= GetTextCharacterExtra(hdc
)) != 0) {
1082 deltas
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(INT
));
1083 for(i
= 0; i
< count
; i
++) {
1085 deltas
[i
] = lpDx
[i
] + char_extra
;
1087 GetTextExtentPointI(hdc
, glyphs
+ i
, 1, &tmpsz
);
1088 deltas
[i
] = tmpsz
.cx
;
1092 deltas
= (INT
*)lpDx
;
1096 for(idx
= 0; idx
< count
; idx
++)
1097 width
+= deltas
[idx
];
1100 GetTextExtentPointI(hdc
, glyphs
, count
, &sz
);
1101 done_extents
= TRUE
;
1105 width
= X11DRV_XWStoDS(physDev
, width
);
1106 xwidth
= width
* cosEsc
;
1107 ywidth
= width
* sinEsc
;
1109 GetTextMetricsW(hdc
, &tm
);
1111 tm
.tmAscent
= abs(X11DRV_YWStoDS(physDev
, tm
.tmAscent
));
1112 tm
.tmDescent
= abs(X11DRV_YWStoDS(physDev
, tm
.tmDescent
));
1113 switch( align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
) ) {
1115 if (align
& TA_UPDATECP
) {
1118 DPtoLP(hdc
, &pt
, 1);
1119 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
1131 if (align
& TA_UPDATECP
) {
1134 DPtoLP(hdc
, &pt
, 1);
1135 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
1140 switch( align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
) ) {
1142 y
+= tm
.tmAscent
* cosEsc
;
1143 x
+= tm
.tmAscent
* sinEsc
;
1147 y
-= tm
.tmDescent
* cosEsc
;
1148 x
-= tm
.tmDescent
* sinEsc
;
1155 if (flags
& ETO_CLIPPED
)
1158 RECT clip_rect
= *lprect
;
1160 LPtoDP( hdc
, (POINT
*)&clip_rect
, 2 );
1161 clip_region
= CreateRectRgnIndirect( &clip_rect
);
1162 /* make a copy of the current device region */
1163 saved_region
= CreateRectRgn( 0, 0, 0, 0 );
1164 CombineRgn( saved_region
, physDev
->region
, 0, RGN_COPY
);
1165 X11DRV_SetDeviceClipping( physDev
, saved_region
, clip_region
);
1166 DeleteObject( clip_region
);
1169 if(X11DRV_XRender_Installed
) {
1170 if(!physDev
->xrender
->pict
) {
1171 XRenderPictureAttributes pa
;
1172 pa
.subwindow_mode
= IncludeInferiors
;
1175 physDev
->xrender
->pict
= pXRenderCreatePicture(gdi_display
,
1177 (physDev
->depth
== 1) ?
1178 mono_format
: screen_format
,
1179 CPSubwindowMode
, &pa
);
1180 wine_tsx11_unlock();
1182 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1183 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1185 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1186 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1189 if ((data
= X11DRV_GetRegionData( physDev
->region
, 0 )))
1192 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
1193 physDev
->org
.x
, physDev
->org
.y
,
1194 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
1195 wine_tsx11_unlock();
1196 HeapFree( GetProcessHeap(), 0, data
);
1200 if(GetBkMode(hdc
) != TRANSPARENT
) {
1201 if(!((flags
& ETO_CLIPPED
) && (flags
& ETO_OPAQUE
))) {
1202 if(!(flags
& ETO_OPAQUE
) || x
< rc
.left
|| x
+ width
>= rc
.right
||
1203 y
- tm
.tmAscent
< rc
.top
|| y
+ tm
.tmDescent
>= rc
.bottom
) {
1205 XSetForeground( gdi_display
, physDev
->gc
, backgroundPixel
);
1206 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1207 physDev
->org
.x
+ x
, physDev
->org
.y
+ y
- tm
.tmAscent
,
1208 width
, tm
.tmAscent
+ tm
.tmDescent
);
1209 wine_tsx11_unlock();
1214 if(X11DRV_XRender_Installed
) {
1215 /* Create a 1x1 pixmap to tile over the font mask */
1216 if(!physDev
->xrender
->tile_xpm
) {
1217 XRenderPictureAttributes pa
;
1219 XRenderPictFormat
*format
= (physDev
->depth
== 1) ? mono_format
: screen_format
;
1221 physDev
->xrender
->tile_xpm
= XCreatePixmap(gdi_display
,
1226 physDev
->xrender
->tile_pict
= pXRenderCreatePicture(gdi_display
,
1227 physDev
->xrender
->tile_xpm
,
1230 wine_tsx11_unlock();
1231 TRACE("Created pixmap of depth %d\n", format
->depth
);
1232 /* init lastTextColor to something different from textColor */
1233 physDev
->xrender
->lastTextColor
= ~textColor
;
1237 if(textColor
!= physDev
->xrender
->lastTextColor
) {
1238 if(physDev
->depth
!= 1) {
1239 /* Map 0 -- 0xff onto 0 -- 0xffff */
1240 col
.red
= GetRValue(textColor
);
1241 col
.red
|= col
.red
<< 8;
1242 col
.green
= GetGValue(textColor
);
1243 col
.green
|= col
.green
<< 8;
1244 col
.blue
= GetBValue(textColor
);
1245 col
.blue
|= col
.blue
<< 8;
1247 } else { /* for a 1bpp bitmap we always need a 1 in the tile */
1248 col
.red
= col
.green
= col
.blue
= 0;
1252 pXRenderFillRectangle(gdi_display
, PictOpSrc
,
1253 physDev
->xrender
->tile_pict
,
1255 wine_tsx11_unlock();
1256 physDev
->xrender
->lastTextColor
= textColor
;
1259 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1261 if((physDev
->depth
== 1) && (textPixel
== 0))
1262 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1265 EnterCriticalSection(&xrender_cs
);
1266 entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1268 for(idx
= 0; idx
< count
; idx
++) {
1269 if(glyphs
[idx
] >= entry
->nrealized
|| entry
->realized
[glyphs
[idx
]] == FALSE
) {
1270 UploadGlyph(physDev
, glyphs
[idx
]);
1275 TRACE("Writing %s at %ld,%ld\n", debugstr_wn(wstr
,count
),
1276 physDev
->org
.x
+ x
, physDev
->org
.y
+ y
);
1278 if(X11DRV_XRender_Installed
) {
1281 pXRenderCompositeString16(gdi_display
, render_op
,
1282 physDev
->xrender
->tile_pict
,
1283 physDev
->xrender
->pict
,
1284 entry
->font_format
, entry
->glyphset
,
1285 0, 0, physDev
->org
.x
+ x
, physDev
->org
.y
+ y
,
1289 INT offset
= 0, xoff
= 0, yoff
= 0;
1290 for(idx
= 0; idx
< count
; idx
++) {
1291 pXRenderCompositeString16(gdi_display
, render_op
,
1292 physDev
->xrender
->tile_pict
,
1293 physDev
->xrender
->pict
,
1294 entry
->font_format
, entry
->glyphset
,
1295 0, 0, physDev
->org
.x
+ x
+ xoff
,
1296 physDev
->org
.y
+ y
+ yoff
,
1298 offset
+= X11DRV_XWStoDS(physDev
, deltas
[idx
]);
1299 xoff
= offset
* cosEsc
;
1300 yoff
= offset
* -sinEsc
;
1303 wine_tsx11_unlock();
1306 INT offset
= 0, xoff
= 0, yoff
= 0;
1308 XSetForeground( gdi_display
, physDev
->gc
, textPixel
);
1310 if(entry
->aa
== AA_None
) {
1311 for(idx
= 0; idx
< count
; idx
++) {
1312 SharpGlyphMono(physDev
, physDev
->org
.x
+ x
+ xoff
,
1313 physDev
->org
.y
+ y
+ yoff
,
1314 entry
->bitmaps
[glyphs
[idx
]],
1315 &entry
->gis
[glyphs
[idx
]]);
1317 offset
+= X11DRV_XWStoDS(physDev
, deltas
[idx
]);
1318 xoff
= offset
* cosEsc
;
1319 yoff
= offset
* -sinEsc
;
1322 xoff
+= entry
->gis
[glyphs
[idx
]].xOff
;
1323 yoff
+= entry
->gis
[glyphs
[idx
]].yOff
;
1326 } else if(physDev
->depth
== 1) {
1327 for(idx
= 0; idx
< count
; idx
++) {
1328 SharpGlyphGray(physDev
, physDev
->org
.x
+ x
+ xoff
,
1329 physDev
->org
.y
+ y
+ yoff
,
1330 entry
->bitmaps
[glyphs
[idx
]],
1331 &entry
->gis
[glyphs
[idx
]]);
1333 offset
+= X11DRV_XWStoDS(physDev
, deltas
[idx
]);
1334 xoff
= offset
* cosEsc
;
1335 yoff
= offset
* -sinEsc
;
1338 xoff
+= entry
->gis
[glyphs
[idx
]].xOff
;
1339 yoff
+= entry
->gis
[glyphs
[idx
]].yOff
;
1345 unsigned int w
, h
, dummy_uint
;
1346 Window dummy_window
;
1348 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
1349 RECT extents
= {0, 0, 0, 0};
1353 XGetGeometry(gdi_display
, physDev
->drawable
, &dummy_window
, &dummy_int
, &dummy_int
,
1354 &w
, &h
, &dummy_uint
, &dummy_uint
);
1355 TRACE("drawable %dx%d\n", w
, h
);
1357 for(idx
= 0; idx
< count
; idx
++) {
1358 if(extents
.left
> cur
.x
- entry
->gis
[glyphs
[idx
]].x
)
1359 extents
.left
= cur
.x
- entry
->gis
[glyphs
[idx
]].x
;
1360 if(extents
.top
> cur
.y
- entry
->gis
[glyphs
[idx
]].y
)
1361 extents
.top
= cur
.y
- entry
->gis
[glyphs
[idx
]].y
;
1362 if(extents
.right
< cur
.x
- entry
->gis
[glyphs
[idx
]].x
+ entry
->gis
[glyphs
[idx
]].width
)
1363 extents
.right
= cur
.x
- entry
->gis
[glyphs
[idx
]].x
+ entry
->gis
[glyphs
[idx
]].width
;
1364 if(extents
.bottom
< cur
.y
- entry
->gis
[glyphs
[idx
]].y
+ entry
->gis
[glyphs
[idx
]].height
)
1365 extents
.bottom
= cur
.y
- entry
->gis
[glyphs
[idx
]].y
+ entry
->gis
[glyphs
[idx
]].height
;
1367 offset
+= X11DRV_XWStoDS(physDev
, deltas
[idx
]);
1368 cur
.x
= offset
* cosEsc
;
1369 cur
.y
= offset
* -sinEsc
;
1371 cur
.x
+= entry
->gis
[glyphs
[idx
]].xOff
;
1372 cur
.y
+= entry
->gis
[glyphs
[idx
]].yOff
;
1375 TRACE("glyph extents %ld,%ld - %ld,%ld drawable x,y %ld,%ld\n", extents
.left
, extents
.top
,
1376 extents
.right
, extents
.bottom
, physDev
->org
.x
+ x
, physDev
->org
.y
+ y
);
1378 if(physDev
->org
.x
+ x
+ extents
.left
>= 0) {
1379 image_x
= physDev
->org
.x
+ x
+ extents
.left
;
1383 image_off_x
= physDev
->org
.x
+ x
+ extents
.left
;
1385 if(physDev
->org
.y
+ y
+ extents
.top
>= 0) {
1386 image_y
= physDev
->org
.y
+ y
+ extents
.top
;
1390 image_off_y
= physDev
->org
.y
+ y
+ extents
.top
;
1392 if(physDev
->org
.x
+ x
+ extents
.right
< w
)
1393 image_w
= physDev
->org
.x
+ x
+ extents
.right
- image_x
;
1395 image_w
= w
- image_x
;
1396 if(physDev
->org
.y
+ y
+ extents
.bottom
< h
)
1397 image_h
= physDev
->org
.y
+ y
+ extents
.bottom
- image_y
;
1399 image_h
= h
- image_y
;
1401 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
1403 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1404 image
= XGetImage(gdi_display
, physDev
->drawable
,
1405 image_x
, image_y
, image_w
, image_h
,
1406 AllPlanes
, ZPixmap
);
1407 X11DRV_check_error();
1409 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1410 gdi_display
, (int)physDev
->drawable
, image_x
, image_y
,
1411 image_w
, image_h
, AllPlanes
, ZPixmap
,
1412 physDev
->depth
, image
);
1414 Pixmap xpm
= XCreatePixmap(gdi_display
, physDev
->drawable
, image_w
, image_h
,
1419 gcv
.graphics_exposures
= False
;
1420 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1421 XCopyArea(gdi_display
, physDev
->drawable
, xpm
, gc
, image_x
, image_y
,
1422 image_w
, image_h
, 0, 0);
1423 XFreeGC(gdi_display
, gc
);
1424 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1425 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
1427 X11DRV_check_error();
1428 XFreePixmap(gdi_display
, xpm
);
1430 if(!image
) goto no_image
;
1432 image
->red_mask
= visual
->red_mask
;
1433 image
->green_mask
= visual
->green_mask
;
1434 image
->blue_mask
= visual
->blue_mask
;
1436 offset
= xoff
= yoff
= 0;
1437 for(idx
= 0; idx
< count
; idx
++) {
1438 SmoothGlyphGray(image
, xoff
+ image_off_x
- extents
.left
,
1439 yoff
+ image_off_y
- extents
.top
,
1440 entry
->bitmaps
[glyphs
[idx
]],
1441 &entry
->gis
[glyphs
[idx
]],
1444 offset
+= X11DRV_XWStoDS(physDev
, deltas
[idx
]);
1445 xoff
= offset
* cosEsc
;
1446 yoff
= offset
* -sinEsc
;
1448 xoff
+= entry
->gis
[glyphs
[idx
]].xOff
;
1449 yoff
+= entry
->gis
[glyphs
[idx
]].yOff
;
1453 XPutImage(gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
1454 image_x
, image_y
, image_w
, image_h
);
1455 XDestroyImage(image
);
1458 wine_tsx11_unlock();
1460 LeaveCriticalSection(&xrender_cs
);
1462 if (lf
.lfUnderline
|| lf
.lfStrikeOut
) {
1464 unsigned int lineWidth
;
1465 UINT nMetricsSize
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
1466 OUTLINETEXTMETRICW
* otm
= HeapAlloc(GetProcessHeap(), 0, nMetricsSize
);
1467 if (!otm
) goto done
;
1469 GetOutlineTextMetricsW(hdc
, nMetricsSize
, otm
);
1472 XSetForeground( gdi_display
, physDev
->gc
, physDev
->textPixel
);
1474 if (lf
.lfUnderline
) {
1475 linePos
= X11DRV_YWStoDS(physDev
, otm
->otmsUnderscorePosition
);
1476 lineWidth
= X11DRV_YWStoDS(physDev
, otm
->otmsUnderscoreSize
);
1478 XSetLineAttributes( gdi_display
, physDev
->gc
, lineWidth
,
1479 LineSolid
, CapProjecting
, JoinBevel
);
1480 XDrawLine( gdi_display
, physDev
->drawable
, physDev
->gc
,
1481 physDev
->org
.x
+ x
- linePos
* sinEsc
,
1482 physDev
->org
.y
+ y
- linePos
* cosEsc
,
1483 physDev
->org
.x
+ x
+ width
* cosEsc
- linePos
* sinEsc
,
1484 physDev
->org
.y
+ y
- width
* sinEsc
- linePos
* cosEsc
);
1487 if (lf
.lfStrikeOut
) {
1488 linePos
= X11DRV_YWStoDS(physDev
, otm
->otmsStrikeoutPosition
);
1489 lineWidth
= X11DRV_YWStoDS(physDev
, otm
->otmsStrikeoutSize
);
1491 XSetLineAttributes( gdi_display
, physDev
->gc
, lineWidth
,
1492 LineSolid
, CapProjecting
, JoinBevel
);
1493 XDrawLine( gdi_display
, physDev
->drawable
, physDev
->gc
,
1494 physDev
->org
.x
+ x
, physDev
->org
.y
+ y
- linePos
,
1495 physDev
->org
.x
+ x
+ width
, physDev
->org
.y
+ y
- linePos
);
1497 wine_tsx11_unlock();
1498 HeapFree(GetProcessHeap(), 0, otm
);
1501 if(deltas
&& deltas
!= lpDx
)
1502 HeapFree(GetProcessHeap(), 0, deltas
);
1504 if (flags
& ETO_CLIPPED
)
1506 /* restore the device region */
1507 X11DRV_SetDeviceClipping( physDev
, saved_region
, 0 );
1508 DeleteObject( saved_region
);
1514 X11DRV_UnlockDIBSection( physDev
, TRUE
);
1515 if(glyphs
!= wstr
) HeapFree(GetProcessHeap(), 0, glyphs
);
1519 BOOL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1520 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1521 BLENDFUNCTION blendfn
)
1523 XRenderPictureAttributes pa
;
1524 XRenderPictFormat
*src_format
;
1525 Picture dst_pict
, src_pict
;
1532 char *dstbits
, *data
;
1535 BOOL top_down
= FALSE
;
1537 if(!X11DRV_XRender_Installed
) {
1538 FIXME("Unable to AlphaBlend without Xrender\n");
1543 pts
[1].x
= xDst
+ widthDst
;
1544 pts
[1].y
= yDst
+ heightDst
;
1545 LPtoDP(devDst
->hdc
, pts
, 2);
1548 widthDst
= pts
[1].x
- pts
[0].x
;
1549 heightDst
= pts
[1].y
- pts
[0].y
;
1553 pts
[1].x
= xSrc
+ widthSrc
;
1554 pts
[1].y
= ySrc
+ heightSrc
;
1555 LPtoDP(devSrc
->hdc
, pts
, 2);
1558 widthSrc
= pts
[1].x
- pts
[0].x
;
1559 heightSrc
= pts
[1].y
- pts
[0].y
;
1562 if(widthDst
!= widthSrc
|| heightDst
!= heightSrc
) {
1563 FIXME("Unable to Stretch\n");
1567 hBitmap
= GetCurrentObject( devSrc
->hdc
, OBJ_BITMAP
);
1568 bmp
= (BITMAPOBJ
*)GDI_GetObjPtr( hBitmap
, BITMAP_MAGIC
);
1569 if(!bmp
|| !bmp
->dib
) {
1570 FIXME("not a dibsection\n");
1571 GDI_ReleaseObj( hBitmap
);
1575 if(bmp
->dib
->dsBm
.bmBitsPixel
!= 32) {
1576 FIXME("not a 32 bpp dibsection\n");
1577 GDI_ReleaseObj( hBitmap
);
1580 dstbits
= data
= HeapAlloc(GetProcessHeap(), 0, heightSrc
* widthSrc
* 4);
1582 if(bmp
->dib
->dsBmih
.biHeight
< 0) { /* top-down dib */
1584 dstbits
+= widthSrc
* (heightSrc
- 1) * 4;
1586 for(y
= ySrc
+ heightSrc
- 1; y
>= ySrc
; y
--) {
1587 memcpy(dstbits
, (char *)bmp
->dib
->dsBm
.bmBits
+ y
* bmp
->dib
->dsBm
.bmWidthBytes
+ xSrc
* 4,
1589 dstbits
+= (top_down
? -1 : 1) * widthSrc
* 4;
1593 image
= XCreateImage(gdi_display
, visual
, 32, ZPixmap
, 0,
1594 data
, widthSrc
, heightSrc
, 32, widthSrc
* 4);
1596 src_format
= pXRenderFindStandardFormat(gdi_display
, PictStandardARGB32
);
1599 TRACE("src_format %p\n", src_format
);
1601 pa
.subwindow_mode
= IncludeInferiors
;
1603 /* FIXME use devDst->xrender->pict ? */
1604 dst_pict
= pXRenderCreatePicture(gdi_display
,
1606 (devDst
->depth
== 1) ?
1607 mono_format
: screen_format
,
1608 CPSubwindowMode
, &pa
);
1609 TRACE("dst_pict %08lx\n", dst_pict
);
1610 TRACE("src_drawable = %08lx\n", devSrc
->drawable
);
1611 xpm
= XCreatePixmap(gdi_display
,
1613 widthSrc
, heightSrc
, 32);
1614 gcv
.graphics_exposures
= False
;
1615 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1616 TRACE("xpm = %08lx\n", xpm
);
1617 XPutImage(gdi_display
, xpm
, gc
, image
, 0, 0, 0, 0, widthSrc
, heightSrc
);
1619 src_pict
= pXRenderCreatePicture(gdi_display
,
1621 CPSubwindowMode
, &pa
);
1622 TRACE("src_pict %08lx\n", src_pict
);
1624 pXRenderComposite(gdi_display
, PictOpOver
, src_pict
, 0, dst_pict
,
1626 xDst
+ devDst
->org
.x
, yDst
+ devDst
->org
.y
, widthSrc
, heightSrc
);
1629 pXRenderFreePicture(gdi_display
, src_pict
);
1630 XFreePixmap(gdi_display
, xpm
);
1631 XFreeGC(gdi_display
, gc
);
1632 pXRenderFreePicture(gdi_display
, dst_pict
);
1634 XDestroyImage(image
);
1636 wine_tsx11_unlock();
1637 HeapFree(GetProcessHeap(), 0, data
);
1638 GDI_ReleaseObj( hBitmap
);
1642 #else /* HAVE_X11_EXTENSIONS_XRENDER_H */
1644 void X11DRV_XRender_Init(void)
1646 TRACE("XRender support not compiled in.\n");
1650 void X11DRV_XRender_Finalize(void)
1654 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
1660 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
1666 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1667 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1668 const INT
*lpDx
, INT breakExtra
)
1674 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
1680 BOOL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1681 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1682 BLENDFUNCTION blendfn
)
1684 FIXME("not supported - XRENDER headers were missing at compile time\n");
1688 #endif /* HAVE_X11_EXTENSIONS_XRENDER_H */