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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
35 #include "wine/library.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 static BOOL X11DRV_XRender_Installed
= FALSE
;
40 int using_client_side_fonts
= FALSE
;
42 WINE_DEFAULT_DEBUG_CHANNEL(xrender
);
44 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
47 #include <X11/extensions/Xrender.h>
49 static XRenderPictFormat
*screen_format
; /* format of screen */
50 static XRenderPictFormat
*mono_format
; /* format of mono bitmap */
55 SIZE devsize
; /* size in device coords */
59 #define INITIAL_REALIZED_BUF_SIZE 128
61 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
66 XRenderPictFormat
*font_format
;
77 gsCacheEntryFormat
* format
[AA_MAXVALUE
];
88 COLORREF lastTextColor
;
92 static gsCacheEntry
*glyphsetCache
= NULL
;
93 static DWORD glyphsetCacheSize
= 0;
94 static INT lastfree
= -1;
97 #define INIT_CACHE_SIZE 10
99 static int antialias
= 1;
101 /* some default values just in case */
102 #ifndef SONAME_LIBX11
103 #define SONAME_LIBX11 "libX11.so"
105 #ifndef SONAME_LIBXEXT
106 #define SONAME_LIBXEXT "libXext.so"
108 #ifndef SONAME_LIBXRENDER
109 #define SONAME_LIBXRENDER "libXrender.so"
112 static void *xrender_handle
;
114 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
115 MAKE_FUNCPTR(XRenderAddGlyphs
)
116 MAKE_FUNCPTR(XRenderComposite
)
117 MAKE_FUNCPTR(XRenderCompositeString8
)
118 MAKE_FUNCPTR(XRenderCompositeString16
)
119 MAKE_FUNCPTR(XRenderCompositeString32
)
120 MAKE_FUNCPTR(XRenderCompositeText16
)
121 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
122 MAKE_FUNCPTR(XRenderCreatePicture
)
123 MAKE_FUNCPTR(XRenderFillRectangle
)
124 MAKE_FUNCPTR(XRenderFindFormat
)
125 MAKE_FUNCPTR(XRenderFindVisualFormat
)
126 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
127 MAKE_FUNCPTR(XRenderFreePicture
)
128 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
129 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
130 MAKE_FUNCPTR(XRenderSetPictureTransform
)
132 MAKE_FUNCPTR(XRenderQueryExtension
)
135 static CRITICAL_SECTION xrender_cs
;
136 static CRITICAL_SECTION_DEBUG critsect_debug
=
139 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
140 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
142 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
144 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
145 ( ( (ULONG)_x4 << 24 ) | \
146 ( (ULONG)_x3 << 16 ) | \
147 ( (ULONG)_x2 << 8 ) | \
150 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
152 #define GASP_GRIDFIT 0x01
153 #define GASP_DOGRAY 0x02
155 #ifdef WORDS_BIGENDIAN
156 #define get_be_word(x) (x)
158 #define get_be_word(x) RtlUshortByteSwap(x)
161 /***********************************************************************
162 * X11DRV_XRender_Init
164 * Let's see if our XServer has the extension available
167 void X11DRV_XRender_Init(void)
170 XRenderPictFormat pf
;
172 if (client_side_with_render
&&
173 wine_dlopen(SONAME_LIBX11
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
174 wine_dlopen(SONAME_LIBXEXT
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
175 (xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0)))
178 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
179 LOAD_FUNCPTR(XRenderAddGlyphs
)
180 LOAD_FUNCPTR(XRenderComposite
)
181 LOAD_FUNCPTR(XRenderCompositeString8
)
182 LOAD_FUNCPTR(XRenderCompositeString16
)
183 LOAD_FUNCPTR(XRenderCompositeString32
)
184 LOAD_FUNCPTR(XRenderCompositeText16
)
185 LOAD_FUNCPTR(XRenderCreateGlyphSet
)
186 LOAD_FUNCPTR(XRenderCreatePicture
)
187 LOAD_FUNCPTR(XRenderFillRectangle
)
188 LOAD_FUNCPTR(XRenderFindFormat
)
189 LOAD_FUNCPTR(XRenderFindVisualFormat
)
190 LOAD_FUNCPTR(XRenderFreeGlyphSet
)
191 LOAD_FUNCPTR(XRenderFreePicture
)
192 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
)
193 LOAD_FUNCPTR(XRenderQueryExtension
)
195 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
196 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
197 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
)
198 #undef LOAD_OPTIONAL_FUNCPTR
203 if(pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
)) {
204 X11DRV_XRender_Installed
= TRUE
;
205 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
206 screen_format
= pXRenderFindVisualFormat(gdi_display
, visual
);
209 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
210 if (visual
->class == DirectColor
)
213 if (XMatchVisualInfo( gdi_display
, DefaultScreen(gdi_display
),
214 screen_depth
, TrueColor
, &info
))
216 screen_format
= pXRenderFindVisualFormat(gdi_display
, info
.visual
);
217 if (screen_format
) visual
= info
.visual
;
221 if(!screen_format
) /* This fails in buggy versions of libXrender.so */
225 "Wine has detected that you probably have a buggy version\n"
226 "of libXrender.so . Because of this client side font rendering\n"
227 "will be disabled. Please upgrade this library.\n");
228 X11DRV_XRender_Installed
= FALSE
;
231 pf
.type
= PictTypeDirect
;
234 pf
.direct
.alphaMask
= 1;
235 mono_format
= pXRenderFindFormat(gdi_display
, PictFormatType
|
236 PictFormatDepth
| PictFormatAlpha
|
237 PictFormatAlphaMask
, &pf
, 0);
239 ERR("mono_format == NULL?\n");
240 X11DRV_XRender_Installed
= FALSE
;
242 if (!visual
->red_mask
|| !visual
->green_mask
|| !visual
->blue_mask
) {
243 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
244 X11DRV_XRender_Installed
= FALSE
;
251 if(X11DRV_XRender_Installed
|| client_side_with_core
)
253 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
254 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
256 glyphsetCacheSize
= INIT_CACHE_SIZE
;
258 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
259 glyphsetCache
[i
].next
= i
+ 1;
260 glyphsetCache
[i
].count
= -1;
262 glyphsetCache
[i
-1].next
= -1;
263 using_client_side_fonts
= 1;
265 if(!X11DRV_XRender_Installed
) {
266 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
267 if(screen_depth
<= 8 || !client_side_antialias_with_core
)
270 if(screen_depth
<= 8 || !client_side_antialias_with_render
)
274 else TRACE("Using X11 core fonts\n");
277 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
279 if(p1
->hash
!= p2
->hash
) return TRUE
;
280 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
281 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
282 return strcmpW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
286 static void walk_cache(void)
290 EnterCriticalSection(&xrender_cs
);
291 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
292 TRACE("item %d\n", i
);
293 LeaveCriticalSection(&xrender_cs
);
297 static int LookupEntry(LFANDSIZE
*plfsz
)
301 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
303 if(glyphsetCache
[i
].count
== -1) { /* reached free list so stop */
308 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
309 glyphsetCache
[i
].count
++;
311 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
312 glyphsetCache
[i
].next
= mru
;
315 TRACE("found font in cache %d\n", i
);
320 TRACE("font not in cache\n");
324 static void FreeEntry(int entry
)
328 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
329 gsCacheEntryFormat
* formatEntry
;
331 if( !glyphsetCache
[entry
].format
[format
] )
334 formatEntry
= glyphsetCache
[entry
].format
[format
];
336 if(formatEntry
->glyphset
) {
338 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
340 formatEntry
->glyphset
= 0;
342 if(formatEntry
->nrealized
) {
343 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
344 formatEntry
->realized
= NULL
;
345 if(formatEntry
->bitmaps
) {
346 for(i
= 0; i
< formatEntry
->nrealized
; i
++)
347 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
[i
]);
348 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
);
349 formatEntry
->bitmaps
= NULL
;
351 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
352 formatEntry
->gis
= NULL
;
353 formatEntry
->nrealized
= 0;
356 HeapFree(GetProcessHeap(), 0, formatEntry
);
357 glyphsetCache
[entry
].format
[format
] = NULL
;
361 static int AllocEntry(void)
363 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
366 assert(glyphsetCache
[lastfree
].count
== -1);
367 glyphsetCache
[lastfree
].count
= 1;
369 lastfree
= glyphsetCache
[lastfree
].next
;
371 glyphsetCache
[best
].next
= mru
;
374 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
378 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
379 if(glyphsetCache
[i
].count
== 0) {
387 TRACE("freeing unused glyphset at cache %d\n", best
);
389 glyphsetCache
[best
].count
= 1;
391 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
392 glyphsetCache
[best
].next
= mru
;
400 TRACE("Growing cache\n");
403 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
405 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
406 * sizeof(*glyphsetCache
));
408 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
409 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
410 * sizeof(*glyphsetCache
));
412 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
414 glyphsetCache
[i
].next
= i
+ 1;
415 glyphsetCache
[i
].count
= -1;
417 glyphsetCache
[i
-1].next
= -1;
418 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
420 lastfree
= glyphsetCache
[best
].next
;
421 glyphsetCache
[best
].count
= 1;
422 glyphsetCache
[best
].next
= mru
;
424 TRACE("new free cache slot at %d\n", mru
);
428 static BOOL
get_gasp_flags(X11DRV_PDEVICE
*physDev
, WORD
*flags
)
438 size
= GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, NULL
, 0);
439 if(size
== GDI_ERROR
)
442 gasp
= buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
443 GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, gasp
, size
);
445 GetTextMetricsW(physDev
->hdc
, &tm
);
446 ppem
= abs(X11DRV_YWStoDS(physDev
, tm
.tmAscent
+ tm
.tmDescent
- tm
.tmInternalLeading
));
449 num_recs
= get_be_word(*gasp
);
453 *flags
= get_be_word(*(gasp
+ 1));
454 if(ppem
<= get_be_word(*gasp
))
458 TRACE("got flags %04x for ppem %d\n", *flags
, ppem
);
460 HeapFree(GetProcessHeap(), 0, buffer
);
464 static int GetCacheEntry(X11DRV_PDEVICE
*physDev
, LFANDSIZE
*plfsz
)
470 static int hinter
= -1;
472 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
475 entry
= glyphsetCache
+ ret
;
476 entry
->lfsz
= *plfsz
;
477 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
478 assert( !entry
->format
[format
] );
481 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
485 RASTERIZER_STATUS status
;
486 GetRasterizerCaps(&status
, sizeof(status
));
487 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
489 if(!hinter
|| !get_gasp_flags(physDev
, &flags
) || flags
& GASP_DOGRAY
)
490 entry
->aa_default
= AA_Grey
;
492 entry
->aa_default
= AA_None
;
495 entry
->aa_default
= AA_None
;
500 static void dec_ref_cache(int index
)
503 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
504 assert(glyphsetCache
[index
].count
> 0);
505 glyphsetCache
[index
].count
--;
508 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
510 DWORD hash
= 0, *ptr
;
513 hash
^= plfsz
->devsize
.cx
;
514 hash
^= plfsz
->devsize
.cy
;
515 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
517 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
518 WCHAR
*pwc
= (WCHAR
*)ptr
;
528 /***********************************************************************
529 * X11DRV_XRender_Finalize
531 void X11DRV_XRender_Finalize(void)
535 EnterCriticalSection(&xrender_cs
);
536 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
538 LeaveCriticalSection(&xrender_cs
);
542 /***********************************************************************
543 * X11DRV_XRender_SelectFont
545 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
549 GetObjectW(hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
550 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
551 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
552 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
553 lfsz
.devsize
.cx
= X11DRV_XWStoDS( physDev
, lfsz
.lf
.lfWidth
);
554 lfsz
.devsize
.cy
= X11DRV_YWStoDS( physDev
, lfsz
.lf
.lfHeight
);
555 lfsz_calc_hash(&lfsz
);
557 EnterCriticalSection(&xrender_cs
);
558 if(!physDev
->xrender
) {
559 physDev
->xrender
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
560 sizeof(*physDev
->xrender
));
561 physDev
->xrender
->cache_index
= -1;
563 else if(physDev
->xrender
->cache_index
!= -1)
564 dec_ref_cache(physDev
->xrender
->cache_index
);
565 physDev
->xrender
->cache_index
= GetCacheEntry(physDev
, &lfsz
);
566 LeaveCriticalSection(&xrender_cs
);
570 /***********************************************************************
571 * X11DRV_XRender_DeleteDC
573 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
575 X11DRV_XRender_UpdateDrawable(physDev
);
577 EnterCriticalSection(&xrender_cs
);
578 if(physDev
->xrender
->cache_index
!= -1)
579 dec_ref_cache(physDev
->xrender
->cache_index
);
580 LeaveCriticalSection(&xrender_cs
);
582 HeapFree(GetProcessHeap(), 0, physDev
->xrender
);
583 physDev
->xrender
= NULL
;
587 /***********************************************************************
588 * X11DRV_XRender_UpdateDrawable
590 * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
591 * It deletes the pict and tile when the drawable changes.
593 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
597 if(physDev
->xrender
->pict
)
599 TRACE("freeing pict = %lx dc = %p\n", physDev
->xrender
->pict
, physDev
->hdc
);
601 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
602 physDev
->xrender
->pict
= 0;
604 if(physDev
->xrender
->tile_pict
)
606 pXRenderFreePicture(gdi_display
, physDev
->xrender
->tile_pict
);
607 physDev
->xrender
->tile_pict
= 0;
609 if(physDev
->xrender
->tile_xpm
)
611 XFreePixmap(gdi_display
, physDev
->xrender
->tile_xpm
);
612 physDev
->xrender
->tile_xpm
= 0;
620 /************************************************************************
623 * Helper to ExtTextOut. Must be called inside xrender_cs
625 static BOOL
UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
, AA_Type format
)
632 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
633 gsCacheEntryFormat
*formatEntry
;
634 UINT ggo_format
= GGO_GLYPH_INDEX
;
635 XRenderPictFormat pf
;
636 static const char zero
[4];
640 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
644 ERR("aa = %d - not implemented\n", format
);
646 ggo_format
|= GGO_BITMAP
;
650 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
,
652 if(buflen
== GDI_ERROR
) {
653 if(format
!= AA_None
) {
655 entry
->aa_default
= AA_None
;
656 ggo_format
&= ~WINE_GGO_GRAY16_BITMAP
;
657 ggo_format
|= GGO_BITMAP
;
658 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
,
661 if(buflen
== GDI_ERROR
) {
662 WARN("GetGlyphOutlineW failed\n");
665 TRACE("Turning off antialiasing for this monochrome font\n");
668 /* If there is nothing for the current type, we create the entry. */
669 if( !entry
->format
[format
] ) {
670 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
672 sizeof(gsCacheEntryFormat
));
674 formatEntry
= entry
->format
[format
];
676 if(formatEntry
->nrealized
<= glyph
) {
677 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
679 if (formatEntry
->realized
)
680 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
682 formatEntry
->realized
,
683 formatEntry
->nrealized
* sizeof(BOOL
));
685 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
687 formatEntry
->nrealized
* sizeof(BOOL
));
689 if(!X11DRV_XRender_Installed
) {
690 if (formatEntry
->bitmaps
)
691 formatEntry
->bitmaps
= HeapReAlloc(GetProcessHeap(),
693 formatEntry
->bitmaps
,
694 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
696 formatEntry
->bitmaps
= HeapAlloc(GetProcessHeap(),
698 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
700 if (formatEntry
->gis
)
701 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
704 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
706 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
708 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
712 if(formatEntry
->glyphset
== 0 && X11DRV_XRender_Installed
) {
716 pf
.direct
.alphaMask
= 0xff;
720 ERR("aa = %d - not implemented\n", format
);
723 pf
.direct
.alphaMask
= 1;
727 pf
.type
= PictTypeDirect
;
731 formatEntry
->font_format
= pXRenderFindFormat(gdi_display
,
738 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
743 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
744 GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, NULL
);
745 formatEntry
->realized
[glyph
] = TRUE
;
747 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
749 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
750 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
752 gi
.width
= gm
.gmBlackBoxX
;
753 gi
.height
= gm
.gmBlackBoxY
;
754 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
755 gi
.y
= gm
.gmptGlyphOrigin
.y
;
756 gi
.xOff
= gm
.gmCellIncX
;
757 gi
.yOff
= gm
.gmCellIncY
;
759 if(TRACE_ON(xrender
)) {
764 if(format
== AA_None
) {
765 pitch
= ((gi
.width
+ 31) / 32) * 4;
766 for(i
= 0; i
< gi
.height
; i
++) {
767 line
= (unsigned char*) buf
+ i
* pitch
;
769 for(j
= 0; j
< pitch
* 8; j
++) {
770 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
772 strcat(output
, "\n");
776 static const char blks
[] = " .:;!o*#";
780 pitch
= ((gi
.width
+ 3) / 4) * 4;
781 for(i
= 0; i
< gi
.height
; i
++) {
782 line
= (unsigned char*) buf
+ i
* pitch
;
784 for(j
= 0; j
< pitch
; j
++) {
785 str
[0] = blks
[line
[j
] >> 5];
788 strcat(output
, "\n");
795 if(formatEntry
->glyphset
) {
796 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
797 unsigned char *byte
= (unsigned char*) buf
, c
;
803 /* magic to flip bit order */
804 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
805 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
806 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
814 XRenderCompositeText seems to ignore 0x0 glyphs when
815 AA_None, which means we lose the advance width of glyphs
816 like the space. We'll pretend that such glyphs are 1x1
821 gi
.width
= gi
.height
= 1;
824 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
825 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
827 HeapFree(GetProcessHeap(), 0, buf
);
829 formatEntry
->bitmaps
[glyph
] = buf
;
832 memcpy(&formatEntry
->gis
[glyph
], &gi
, sizeof(gi
));
837 static void SharpGlyphMono(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
838 void *bitmap
, XGlyphInfo
*gi
)
840 unsigned char *srcLine
= bitmap
, *src
;
841 unsigned char bits
, bitsMask
;
842 int width
= gi
->width
;
843 int stride
= ((width
+ 31) & ~31) >> 3;
844 int height
= gi
->height
;
848 TRACE("%d, %d\n", x
, y
);
857 bitsMask
= 0x80; /* FreeType is always MSB first */
871 bitsMask
= bitsMask
>> 1;
877 } while (bits
& bitsMask
);
878 XFillRectangle (gdi_display
, physDev
->drawable
,
879 physDev
->gc
, xspan
, y
, lenspan
, 1);
891 bitsMask
= bitsMask
>> 1;
897 } while (!(bits
& bitsMask
));
904 static void SharpGlyphGray(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
905 void *bitmap
, XGlyphInfo
*gi
)
907 unsigned char *srcLine
= bitmap
, *src
, bits
;
908 int width
= gi
->width
;
909 int stride
= ((width
+ 3) & ~3);
910 int height
= gi
->height
;
935 } while (bits
>= 0x80);
936 XFillRectangle (gdi_display
, physDev
->drawable
,
937 physDev
->gc
, xspan
, y
, lenspan
, 1);
950 } while (bits
< 0x80);
958 static void ExamineBitfield (DWORD mask
, int *shift
, int *len
)
963 while ((mask
& 1) == 0)
969 while ((mask
& 1) == 1)
978 static DWORD
GetField (DWORD pixel
, int shift
, int len
)
980 pixel
= pixel
& (((1 << (len
)) - 1) << shift
);
981 pixel
= pixel
<< (32 - (shift
+ len
)) >> 24;
984 pixel
|= (pixel
>> len
);
991 static DWORD
PutField (DWORD pixel
, int shift
, int len
)
993 shift
= shift
- (8 - len
);
995 pixel
&= (((1 << len
) - 1) << (8 - len
));
1003 static void SmoothGlyphGray(XImage
*image
, int x
, int y
, void *bitmap
, XGlyphInfo
*gi
,
1009 BYTE
*maskLine
, *mask
, m
;
1014 BYTE src_r
, src_g
, src_b
;
1019 height
= gi
->height
;
1021 maskLine
= (unsigned char *) bitmap
;
1022 maskStride
= (width
+ 3) & ~3;
1024 ExamineBitfield (image
->red_mask
, &r_shift
, &r_len
);
1025 ExamineBitfield (image
->green_mask
, &g_shift
, &g_len
);
1026 ExamineBitfield (image
->blue_mask
, &b_shift
, &b_len
);
1028 src_r
= GetField(color
, r_shift
, r_len
);
1029 src_g
= GetField(color
, g_shift
, g_len
);
1030 src_b
= GetField(color
, b_shift
, b_len
);
1032 for(; height
--; y
++)
1035 maskLine
+= maskStride
;
1040 if(y
>= image
->height
) break;
1044 if(tx
>= image
->width
) break;
1047 if(tx
< 0) continue;
1050 XPutPixel (image
, tx
, y
, color
);
1055 pixel
= XGetPixel (image
, tx
, y
);
1057 r
= GetField(pixel
, r_shift
, r_len
);
1058 r
= ((BYTE
)~m
* (WORD
)r
+ (BYTE
)m
* (WORD
)src_r
) >> 8;
1059 g
= GetField(pixel
, g_shift
, g_len
);
1060 g
= ((BYTE
)~m
* (WORD
)g
+ (BYTE
)m
* (WORD
)src_g
) >> 8;
1061 b
= GetField(pixel
, b_shift
, b_len
);
1062 b
= ((BYTE
)~m
* (WORD
)b
+ (BYTE
)m
* (WORD
)src_b
) >> 8;
1064 pixel
= (PutField (r
, r_shift
, r_len
) |
1065 PutField (g
, g_shift
, g_len
) |
1066 PutField (b
, b_shift
, b_len
));
1067 XPutPixel (image
, tx
, y
, pixel
);
1073 static int XRenderErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
1078 /***********************************************************************
1079 * X11DRV_XRender_ExtTextOut
1081 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1082 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1088 int render_op
= PictOpOver
;
1089 gsCacheEntry
*entry
;
1090 gsCacheEntryFormat
*formatEntry
;
1092 HDC hdc
= physDev
->hdc
;
1093 int textPixel
, backgroundPixel
;
1094 HRGN saved_region
= 0;
1095 BOOL disable_antialias
= FALSE
;
1096 AA_Type aa_type
= AA_None
;
1099 double cosEsc
, sinEsc
;
1102 /* Do we need to disable antialiasing because of palette mode? */
1103 if( !physDev
->bitmap
|| GetObjectW( physDev
->bitmap
->hbitmap
, sizeof(bmp
), &bmp
) != sizeof(bmp
) ) {
1104 TRACE("bitmap is not a DIB\n");
1106 else if (bmp
.dsBmih
.biBitCount
<= 8) {
1107 TRACE("Disabling antialiasing\n");
1108 disable_antialias
= TRUE
;
1111 xgcval
.function
= GXcopy
;
1112 xgcval
.background
= physDev
->backgroundPixel
;
1113 xgcval
.fill_style
= FillSolid
;
1115 XChangeGC( gdi_display
, physDev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1116 wine_tsx11_unlock();
1118 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
, FALSE
);
1120 if(physDev
->depth
== 1) {
1121 if((physDev
->textPixel
& 0xffffff) == 0) {
1123 backgroundPixel
= 1;
1126 backgroundPixel
= 0;
1129 textPixel
= physDev
->textPixel
;
1130 backgroundPixel
= physDev
->backgroundPixel
;
1133 if(flags
& ETO_OPAQUE
)
1136 XSetForeground( gdi_display
, physDev
->gc
, backgroundPixel
);
1137 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1138 physDev
->dc_rect
.left
+ lprect
->left
, physDev
->dc_rect
.top
+ lprect
->top
,
1139 lprect
->right
- lprect
->left
, lprect
->bottom
- lprect
->top
);
1140 wine_tsx11_unlock();
1150 GetObjectW(GetCurrentObject(physDev
->hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
1151 if(lf
.lfEscapement
!= 0) {
1152 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
1153 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
1159 if (flags
& ETO_CLIPPED
)
1163 clip_region
= CreateRectRgnIndirect( lprect
);
1164 /* make a copy of the current device region */
1165 saved_region
= CreateRectRgn( 0, 0, 0, 0 );
1166 CombineRgn( saved_region
, physDev
->region
, 0, RGN_COPY
);
1167 X11DRV_SetDeviceClipping( physDev
, saved_region
, clip_region
);
1168 DeleteObject( clip_region
);
1171 if(X11DRV_XRender_Installed
) {
1172 if(!physDev
->xrender
->pict
) {
1173 XRenderPictureAttributes pa
;
1174 pa
.subwindow_mode
= IncludeInferiors
;
1177 physDev
->xrender
->pict
= pXRenderCreatePicture(gdi_display
,
1179 (physDev
->depth
== 1) ?
1180 mono_format
: screen_format
,
1181 CPSubwindowMode
, &pa
);
1182 wine_tsx11_unlock();
1184 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1185 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1187 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1188 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1191 if ((data
= X11DRV_GetRegionData( physDev
->region
, 0 )))
1194 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
1195 physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
1196 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
1197 wine_tsx11_unlock();
1198 HeapFree( GetProcessHeap(), 0, data
);
1202 if(X11DRV_XRender_Installed
) {
1203 /* Create a 1x1 pixmap to tile over the font mask */
1204 if(!physDev
->xrender
->tile_xpm
) {
1205 XRenderPictureAttributes pa
;
1207 XRenderPictFormat
*format
= (physDev
->depth
== 1) ? mono_format
: screen_format
;
1209 physDev
->xrender
->tile_xpm
= XCreatePixmap(gdi_display
,
1214 physDev
->xrender
->tile_pict
= pXRenderCreatePicture(gdi_display
,
1215 physDev
->xrender
->tile_xpm
,
1218 wine_tsx11_unlock();
1219 TRACE("Created pixmap of depth %d\n", format
->depth
);
1220 /* init lastTextColor to something different from textPixel */
1221 physDev
->xrender
->lastTextColor
= ~physDev
->textPixel
;
1225 if(physDev
->textPixel
!= physDev
->xrender
->lastTextColor
) {
1226 if(physDev
->depth
!= 1) {
1227 /* Map 0 -- 0xff onto 0 -- 0xffff */
1232 ExamineBitfield (visual
->red_mask
, &r_shift
, &r_len
);
1233 ExamineBitfield (visual
->green_mask
, &g_shift
, &g_len
);
1234 ExamineBitfield (visual
->blue_mask
, &b_shift
, &b_len
);
1236 col
.red
= GetField(physDev
->textPixel
, r_shift
, r_len
);
1237 col
.red
|= col
.red
<< 8;
1238 col
.green
= GetField(physDev
->textPixel
, g_shift
, g_len
);
1239 col
.green
|= col
.green
<< 8;
1240 col
.blue
= GetField(physDev
->textPixel
, b_shift
, b_len
);
1241 col
.blue
|= col
.blue
<< 8;
1243 } else { /* for a 1bpp bitmap we always need a 1 in the tile */
1244 col
.red
= col
.green
= col
.blue
= 0;
1248 pXRenderFillRectangle(gdi_display
, PictOpSrc
,
1249 physDev
->xrender
->tile_pict
,
1251 wine_tsx11_unlock();
1252 physDev
->xrender
->lastTextColor
= physDev
->textPixel
;
1255 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1257 if((physDev
->depth
== 1) && (textPixel
== 0))
1258 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1261 EnterCriticalSection(&xrender_cs
);
1262 entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1263 if( disable_antialias
== FALSE
)
1264 aa_type
= entry
->aa_default
;
1265 formatEntry
= entry
->format
[aa_type
];
1267 for(idx
= 0; idx
< count
; idx
++) {
1268 if( !formatEntry
) {
1269 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1270 /* re-evaluate antialias since aa_default may have changed */
1271 if( disable_antialias
== FALSE
)
1272 aa_type
= entry
->aa_default
;
1273 formatEntry
= entry
->format
[aa_type
];
1274 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1275 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1280 WARN("could not upload requested glyphs\n");
1281 LeaveCriticalSection(&xrender_cs
);
1285 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1286 physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1288 if(X11DRV_XRender_Installed
)
1290 XGlyphElt16
*elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1292 POINT desired
, current
;
1294 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1295 So we pass zeros to the function and move to our starting position using the first
1296 element of the elts array. */
1298 desired
.x
= physDev
->dc_rect
.left
+ x
;
1299 desired
.y
= physDev
->dc_rect
.top
+ y
;
1300 current
.x
= current
.y
= 0;
1302 for(idx
= 0; idx
< count
; idx
++)
1304 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1305 elts
[idx
].chars
= wstr
+ idx
;
1306 elts
[idx
].nchars
= 1;
1307 elts
[idx
].xOff
= desired
.x
- current
.x
;
1308 elts
[idx
].yOff
= desired
.y
- current
.y
;
1310 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1311 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1315 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1316 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1320 offset
+= lpDx
[idx
];
1321 desired
.x
= physDev
->dc_rect
.left
+ x
+ offset
* cosEsc
;
1322 desired
.y
= physDev
->dc_rect
.top
+ y
- offset
* sinEsc
;
1326 pXRenderCompositeText16(gdi_display
, render_op
,
1327 physDev
->xrender
->tile_pict
,
1328 physDev
->xrender
->pict
,
1329 formatEntry
->font_format
,
1330 0, 0, 0, 0, elts
, count
);
1331 wine_tsx11_unlock();
1332 HeapFree(GetProcessHeap(), 0, elts
);
1334 INT offset
= 0, xoff
= 0, yoff
= 0;
1336 XSetForeground( gdi_display
, physDev
->gc
, textPixel
);
1338 if(aa_type
== AA_None
|| physDev
->depth
== 1)
1340 void (* sharp_glyph_fn
)(X11DRV_PDEVICE
*, INT
, INT
, void *, XGlyphInfo
*);
1342 if(aa_type
== AA_None
)
1343 sharp_glyph_fn
= SharpGlyphMono
;
1345 sharp_glyph_fn
= SharpGlyphGray
;
1347 for(idx
= 0; idx
< count
; idx
++) {
1348 sharp_glyph_fn(physDev
, physDev
->dc_rect
.left
+ x
+ xoff
,
1349 physDev
->dc_rect
.top
+ y
+ yoff
,
1350 formatEntry
->bitmaps
[wstr
[idx
]],
1351 &formatEntry
->gis
[wstr
[idx
]]);
1353 offset
+= lpDx
[idx
];
1354 xoff
= offset
* cosEsc
;
1355 yoff
= offset
* -sinEsc
;
1357 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1358 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1363 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
1364 RECT extents
= {0, 0, 0, 0};
1366 int w
= physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
;
1367 int h
= physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
;
1369 TRACE("drawable %dx%d\n", w
, h
);
1371 for(idx
= 0; idx
< count
; idx
++) {
1372 if(extents
.left
> cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
)
1373 extents
.left
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
;
1374 if(extents
.top
> cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
)
1375 extents
.top
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
;
1376 if(extents
.right
< cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
)
1377 extents
.right
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
;
1378 if(extents
.bottom
< cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
)
1379 extents
.bottom
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
;
1381 offset
+= lpDx
[idx
];
1382 cur
.x
= offset
* cosEsc
;
1383 cur
.y
= offset
* -sinEsc
;
1385 cur
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1386 cur
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1389 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents
.left
, extents
.top
,
1390 extents
.right
, extents
.bottom
, physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1392 if(physDev
->dc_rect
.left
+ x
+ extents
.left
>= 0) {
1393 image_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1397 image_off_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1399 if(physDev
->dc_rect
.top
+ y
+ extents
.top
>= 0) {
1400 image_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1404 image_off_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1406 if(physDev
->dc_rect
.left
+ x
+ extents
.right
< w
)
1407 image_w
= physDev
->dc_rect
.left
+ x
+ extents
.right
- image_x
;
1409 image_w
= w
- image_x
;
1410 if(physDev
->dc_rect
.top
+ y
+ extents
.bottom
< h
)
1411 image_h
= physDev
->dc_rect
.top
+ y
+ extents
.bottom
- image_y
;
1413 image_h
= h
- image_y
;
1415 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
1417 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1418 image
= XGetImage(gdi_display
, physDev
->drawable
,
1419 image_x
, image_y
, image_w
, image_h
,
1420 AllPlanes
, ZPixmap
);
1421 X11DRV_check_error();
1423 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1424 gdi_display
, (int)physDev
->drawable
, image_x
, image_y
,
1425 image_w
, image_h
, AllPlanes
, ZPixmap
,
1426 physDev
->depth
, image
);
1428 Pixmap xpm
= XCreatePixmap(gdi_display
, physDev
->drawable
, image_w
, image_h
,
1433 gcv
.graphics_exposures
= False
;
1434 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1435 XCopyArea(gdi_display
, physDev
->drawable
, xpm
, gc
, image_x
, image_y
,
1436 image_w
, image_h
, 0, 0);
1437 XFreeGC(gdi_display
, gc
);
1438 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1439 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
1441 X11DRV_check_error();
1442 XFreePixmap(gdi_display
, xpm
);
1444 if(!image
) goto no_image
;
1446 image
->red_mask
= visual
->red_mask
;
1447 image
->green_mask
= visual
->green_mask
;
1448 image
->blue_mask
= visual
->blue_mask
;
1450 offset
= xoff
= yoff
= 0;
1451 for(idx
= 0; idx
< count
; idx
++) {
1452 SmoothGlyphGray(image
, xoff
+ image_off_x
- extents
.left
,
1453 yoff
+ image_off_y
- extents
.top
,
1454 formatEntry
->bitmaps
[wstr
[idx
]],
1455 &formatEntry
->gis
[wstr
[idx
]],
1456 physDev
->textPixel
);
1458 offset
+= lpDx
[idx
];
1459 xoff
= offset
* cosEsc
;
1460 yoff
= offset
* -sinEsc
;
1462 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1463 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1466 XPutImage(gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
1467 image_x
, image_y
, image_w
, image_h
);
1468 XDestroyImage(image
);
1471 wine_tsx11_unlock();
1473 LeaveCriticalSection(&xrender_cs
);
1475 if (flags
& ETO_CLIPPED
)
1477 /* restore the device region */
1478 X11DRV_SetDeviceClipping( physDev
, saved_region
, 0 );
1479 DeleteObject( saved_region
);
1485 X11DRV_UnlockDIBSection( physDev
, TRUE
);
1489 /******************************************************************************
1490 * AlphaBlend (x11drv.@)
1492 BOOL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1493 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1494 BLENDFUNCTION blendfn
)
1496 XRenderPictureAttributes pa
;
1497 XRenderPictFormat
*src_format
;
1498 XRenderPictFormat argb32_templ
= {
1500 PictTypeDirect
, /* type */
1503 16, /* direct.red */
1504 0xff, /* direct.redMask */
1505 8, /* direct.green */
1506 0xff, /* direct.greenMask */
1507 0, /* direct.blue */
1508 0xff, /* direct.blueMask */
1509 24, /* direct.alpha */
1510 0xff, /* direct.alphaMask */
1514 unsigned long argb32_templ_mask
=
1520 PictFormatGreenMask
|
1522 PictFormatBlueMask
|
1524 PictFormatAlphaMask
;
1526 Picture dst_pict
, src_pict
;
1532 BYTE
*dstbits
, *data
;
1535 BOOL top_down
= FALSE
;
1538 if(!X11DRV_XRender_Installed
) {
1539 FIXME("Unable to AlphaBlend without Xrender\n");
1544 pts
[1].x
= xDst
+ widthDst
;
1545 pts
[1].y
= yDst
+ heightDst
;
1546 LPtoDP(devDst
->hdc
, pts
, 2);
1549 widthDst
= pts
[1].x
- pts
[0].x
;
1550 heightDst
= pts
[1].y
- pts
[0].y
;
1554 pts
[1].x
= xSrc
+ widthSrc
;
1555 pts
[1].y
= ySrc
+ heightSrc
;
1556 LPtoDP(devSrc
->hdc
, pts
, 2);
1559 widthSrc
= pts
[1].x
- pts
[0].x
;
1560 heightSrc
= pts
[1].y
- pts
[0].y
;
1561 if (!widthDst
|| !heightDst
|| !widthSrc
|| !heightSrc
) return TRUE
;
1563 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1564 if(widthDst
!= widthSrc
|| heightDst
!= heightSrc
)
1566 if(!pXRenderSetPictureTransform
)
1569 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1573 if (!devSrc
->bitmap
|| GetObjectW( devSrc
->bitmap
->hbitmap
, sizeof(dib
), &dib
) != sizeof(dib
))
1575 FIXME("not a dibsection\n");
1579 if(dib
.dsBm
.bmBitsPixel
!= 32) {
1580 FIXME("not a 32 bpp dibsection\n");
1583 dstbits
= data
= HeapAlloc(GetProcessHeap(), 0, heightSrc
* widthSrc
* 4);
1585 if(dib
.dsBmih
.biHeight
< 0) { /* top-down dib */
1587 dstbits
+= widthSrc
* (heightSrc
- 1) * 4;
1589 y
= y2
+ heightSrc
- 1;
1593 y
= dib
.dsBmih
.biHeight
- ySrc
- 1;
1594 y2
= y
- heightSrc
+ 1;
1596 for(; y
>= y2
; y
--) {
1597 memcpy(dstbits
, (char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
+ xSrc
* 4,
1599 dstbits
+= (top_down
? -1 : 1) * widthSrc
* 4;
1603 image
= XCreateImage(gdi_display
, visual
, 32, ZPixmap
, 0,
1604 (char*) data
, widthSrc
, heightSrc
, 32, widthSrc
* 4);
1607 Avoid using XRenderFindStandardFormat as older libraries don't have it
1608 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1610 src_format
= pXRenderFindFormat(gdi_display
, argb32_templ_mask
, &argb32_templ
, 0);
1612 TRACE("src_format %p\n", src_format
);
1614 pa
.subwindow_mode
= IncludeInferiors
;
1616 /* FIXME use devDst->xrender->pict ? */
1617 dst_pict
= pXRenderCreatePicture(gdi_display
,
1619 (devDst
->depth
== 1) ?
1620 mono_format
: screen_format
,
1621 CPSubwindowMode
, &pa
);
1622 TRACE("dst_pict %08lx\n", dst_pict
);
1623 TRACE("src_drawable = %08lx\n", devSrc
->drawable
);
1624 xpm
= XCreatePixmap(gdi_display
,
1626 widthSrc
, heightSrc
, 32);
1627 gcv
.graphics_exposures
= False
;
1628 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1629 TRACE("xpm = %08lx\n", xpm
);
1630 XPutImage(gdi_display
, xpm
, gc
, image
, 0, 0, 0, 0, widthSrc
, heightSrc
);
1632 src_pict
= pXRenderCreatePicture(gdi_display
,
1634 CPSubwindowMode
, &pa
);
1635 TRACE("src_pict %08lx\n", src_pict
);
1637 if ((rgndata
= X11DRV_GetRegionData( devDst
->region
, 0 )))
1639 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
,
1640 devDst
->dc_rect
.left
, devDst
->dc_rect
.top
,
1641 (XRectangle
*)rgndata
->Buffer
,
1642 rgndata
->rdh
.nCount
);
1643 HeapFree( GetProcessHeap(), 0, rgndata
);
1646 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1647 if(widthDst
!= widthSrc
|| heightDst
!= heightSrc
) {
1648 double xscale
= widthSrc
/(double)widthDst
;
1649 double yscale
= heightSrc
/(double)heightDst
;
1650 XTransform xform
= {{
1651 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(0) },
1652 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(0) },
1653 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1655 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
1658 pXRenderComposite(gdi_display
, PictOpOver
, src_pict
, 0, dst_pict
,
1660 xDst
+ devDst
->dc_rect
.left
, yDst
+ devDst
->dc_rect
.top
, widthDst
, heightDst
);
1663 pXRenderFreePicture(gdi_display
, src_pict
);
1664 XFreePixmap(gdi_display
, xpm
);
1665 XFreeGC(gdi_display
, gc
);
1666 pXRenderFreePicture(gdi_display
, dst_pict
);
1668 XDestroyImage(image
);
1670 wine_tsx11_unlock();
1671 HeapFree(GetProcessHeap(), 0, data
);
1675 #else /* HAVE_X11_EXTENSIONS_XRENDER_H */
1677 void X11DRV_XRender_Init(void)
1679 TRACE("XRender support not compiled in.\n");
1683 void X11DRV_XRender_Finalize(void)
1687 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
1693 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
1699 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1700 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1707 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
1713 /******************************************************************************
1714 * AlphaBlend (x11drv.@)
1716 BOOL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1717 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1718 BLENDFUNCTION blendfn
)
1720 FIXME("not supported - XRENDER headers were missing at compile time\n");
1724 #endif /* HAVE_X11_EXTENSIONS_XRENDER_H */