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 int using_client_side_fonts
= FALSE
;
41 WINE_DEFAULT_DEBUG_CHANNEL(xrender
);
43 #ifdef SONAME_LIBXRENDER
45 static BOOL X11DRV_XRender_Installed
= FALSE
;
48 #include <X11/extensions/Xrender.h>
51 enum drawable_depth_type
{mono_drawable
, color_drawable
};
52 static XRenderPictFormat
*pict_formats
[2];
57 SIZE devsize
; /* size in device coords */
61 #define INITIAL_REALIZED_BUF_SIZE 128
63 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
68 XRenderPictFormat
*font_format
;
79 gsCacheEntryFormat
* format
[AA_MAXVALUE
];
91 static gsCacheEntry
*glyphsetCache
= NULL
;
92 static DWORD glyphsetCacheSize
= 0;
93 static INT lastfree
= -1;
96 #define INIT_CACHE_SIZE 10
98 static int antialias
= 1;
100 static void *xrender_handle
;
102 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
103 MAKE_FUNCPTR(XRenderAddGlyphs
)
104 MAKE_FUNCPTR(XRenderComposite
)
105 MAKE_FUNCPTR(XRenderCompositeString8
)
106 MAKE_FUNCPTR(XRenderCompositeString16
)
107 MAKE_FUNCPTR(XRenderCompositeString32
)
108 MAKE_FUNCPTR(XRenderCompositeText16
)
109 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
110 MAKE_FUNCPTR(XRenderCreatePicture
)
111 MAKE_FUNCPTR(XRenderFillRectangle
)
112 MAKE_FUNCPTR(XRenderFindFormat
)
113 MAKE_FUNCPTR(XRenderFindVisualFormat
)
114 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
115 MAKE_FUNCPTR(XRenderFreePicture
)
116 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
117 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
118 MAKE_FUNCPTR(XRenderSetPictureTransform
)
120 MAKE_FUNCPTR(XRenderQueryExtension
)
123 static CRITICAL_SECTION xrender_cs
;
124 static CRITICAL_SECTION_DEBUG critsect_debug
=
127 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
128 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
130 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
132 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
133 ( ( (ULONG)_x4 << 24 ) | \
134 ( (ULONG)_x3 << 16 ) | \
135 ( (ULONG)_x2 << 8 ) | \
138 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
140 #define GASP_GRIDFIT 0x01
141 #define GASP_DOGRAY 0x02
143 #ifdef WORDS_BIGENDIAN
144 #define get_be_word(x) (x)
146 #define get_be_word(x) RtlUshortByteSwap(x)
149 /***********************************************************************
150 * X11DRV_XRender_Init
152 * Let's see if our XServer has the extension available
155 void X11DRV_XRender_Init(void)
158 XRenderPictFormat pf
;
160 if (client_side_with_render
&&
161 wine_dlopen(SONAME_LIBX11
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
162 wine_dlopen(SONAME_LIBXEXT
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
163 (xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0)))
166 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
167 LOAD_FUNCPTR(XRenderAddGlyphs
)
168 LOAD_FUNCPTR(XRenderComposite
)
169 LOAD_FUNCPTR(XRenderCompositeString8
)
170 LOAD_FUNCPTR(XRenderCompositeString16
)
171 LOAD_FUNCPTR(XRenderCompositeString32
)
172 LOAD_FUNCPTR(XRenderCompositeText16
)
173 LOAD_FUNCPTR(XRenderCreateGlyphSet
)
174 LOAD_FUNCPTR(XRenderCreatePicture
)
175 LOAD_FUNCPTR(XRenderFillRectangle
)
176 LOAD_FUNCPTR(XRenderFindFormat
)
177 LOAD_FUNCPTR(XRenderFindVisualFormat
)
178 LOAD_FUNCPTR(XRenderFreeGlyphSet
)
179 LOAD_FUNCPTR(XRenderFreePicture
)
180 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
)
181 LOAD_FUNCPTR(XRenderQueryExtension
)
183 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
184 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
185 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
)
186 #undef LOAD_OPTIONAL_FUNCPTR
191 if(pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
)) {
192 X11DRV_XRender_Installed
= TRUE
;
193 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
194 pict_formats
[color_drawable
] = pXRenderFindVisualFormat(gdi_display
, visual
);
195 if(!pict_formats
[color_drawable
])
197 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
198 if (visual
->class == DirectColor
)
201 if (XMatchVisualInfo( gdi_display
, DefaultScreen(gdi_display
),
202 screen_depth
, TrueColor
, &info
))
204 pict_formats
[color_drawable
] = pXRenderFindVisualFormat(gdi_display
, info
.visual
);
205 if (pict_formats
[color_drawable
]) visual
= info
.visual
;
209 if(!pict_formats
[color_drawable
]) /* This fails in buggy versions of libXrender.so */
213 "Wine has detected that you probably have a buggy version\n"
214 "of libXrender.so . Because of this client side font rendering\n"
215 "will be disabled. Please upgrade this library.\n");
216 X11DRV_XRender_Installed
= FALSE
;
219 pf
.type
= PictTypeDirect
;
222 pf
.direct
.alphaMask
= 1;
223 pict_formats
[mono_drawable
] = pXRenderFindFormat(gdi_display
, PictFormatType
|
224 PictFormatDepth
| PictFormatAlpha
|
225 PictFormatAlphaMask
, &pf
, 0);
226 if(!pict_formats
[mono_drawable
]) {
227 ERR("mono_format == NULL?\n");
228 X11DRV_XRender_Installed
= FALSE
;
230 if (!visual
->red_mask
|| !visual
->green_mask
|| !visual
->blue_mask
) {
231 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
232 X11DRV_XRender_Installed
= FALSE
;
239 if(X11DRV_XRender_Installed
|| client_side_with_core
)
241 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
242 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
244 glyphsetCacheSize
= INIT_CACHE_SIZE
;
246 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
247 glyphsetCache
[i
].next
= i
+ 1;
248 glyphsetCache
[i
].count
= -1;
250 glyphsetCache
[i
-1].next
= -1;
251 using_client_side_fonts
= 1;
253 if(!X11DRV_XRender_Installed
) {
254 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
255 if(screen_depth
<= 8 || !client_side_antialias_with_core
)
258 if(screen_depth
<= 8 || !client_side_antialias_with_render
)
262 else TRACE("Using X11 core fonts\n");
265 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
267 if(p1
->hash
!= p2
->hash
) return TRUE
;
268 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
269 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
270 return strcmpW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
274 static void walk_cache(void)
278 EnterCriticalSection(&xrender_cs
);
279 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
280 TRACE("item %d\n", i
);
281 LeaveCriticalSection(&xrender_cs
);
285 static int LookupEntry(LFANDSIZE
*plfsz
)
289 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
291 if(glyphsetCache
[i
].count
== -1) { /* reached free list so stop */
296 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
297 glyphsetCache
[i
].count
++;
299 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
300 glyphsetCache
[i
].next
= mru
;
303 TRACE("found font in cache %d\n", i
);
308 TRACE("font not in cache\n");
312 static void FreeEntry(int entry
)
316 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
317 gsCacheEntryFormat
* formatEntry
;
319 if( !glyphsetCache
[entry
].format
[format
] )
322 formatEntry
= glyphsetCache
[entry
].format
[format
];
324 if(formatEntry
->glyphset
) {
326 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
328 formatEntry
->glyphset
= 0;
330 if(formatEntry
->nrealized
) {
331 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
332 formatEntry
->realized
= NULL
;
333 if(formatEntry
->bitmaps
) {
334 for(i
= 0; i
< formatEntry
->nrealized
; i
++)
335 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
[i
]);
336 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
);
337 formatEntry
->bitmaps
= NULL
;
339 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
340 formatEntry
->gis
= NULL
;
341 formatEntry
->nrealized
= 0;
344 HeapFree(GetProcessHeap(), 0, formatEntry
);
345 glyphsetCache
[entry
].format
[format
] = NULL
;
349 static int AllocEntry(void)
351 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
354 assert(glyphsetCache
[lastfree
].count
== -1);
355 glyphsetCache
[lastfree
].count
= 1;
357 lastfree
= glyphsetCache
[lastfree
].next
;
359 glyphsetCache
[best
].next
= mru
;
362 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
366 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
367 if(glyphsetCache
[i
].count
== 0) {
375 TRACE("freeing unused glyphset at cache %d\n", best
);
377 glyphsetCache
[best
].count
= 1;
379 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
380 glyphsetCache
[best
].next
= mru
;
388 TRACE("Growing cache\n");
391 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
393 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
394 * sizeof(*glyphsetCache
));
396 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
397 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
398 * sizeof(*glyphsetCache
));
400 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
402 glyphsetCache
[i
].next
= i
+ 1;
403 glyphsetCache
[i
].count
= -1;
405 glyphsetCache
[i
-1].next
= -1;
406 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
408 lastfree
= glyphsetCache
[best
].next
;
409 glyphsetCache
[best
].count
= 1;
410 glyphsetCache
[best
].next
= mru
;
412 TRACE("new free cache slot at %d\n", mru
);
416 static BOOL
get_gasp_flags(X11DRV_PDEVICE
*physDev
, WORD
*flags
)
426 size
= GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, NULL
, 0);
427 if(size
== GDI_ERROR
)
430 gasp
= buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
431 GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, gasp
, size
);
433 GetTextMetricsW(physDev
->hdc
, &tm
);
434 ppem
= abs(X11DRV_YWStoDS(physDev
, tm
.tmAscent
+ tm
.tmDescent
- tm
.tmInternalLeading
));
437 num_recs
= get_be_word(*gasp
);
441 *flags
= get_be_word(*(gasp
+ 1));
442 if(ppem
<= get_be_word(*gasp
))
446 TRACE("got flags %04x for ppem %d\n", *flags
, ppem
);
448 HeapFree(GetProcessHeap(), 0, buffer
);
452 static int GetCacheEntry(X11DRV_PDEVICE
*physDev
, LFANDSIZE
*plfsz
)
458 static int hinter
= -1;
460 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
463 entry
= glyphsetCache
+ ret
;
464 entry
->lfsz
= *plfsz
;
465 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
466 assert( !entry
->format
[format
] );
469 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
473 RASTERIZER_STATUS status
;
474 GetRasterizerCaps(&status
, sizeof(status
));
475 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
477 if(!hinter
|| !get_gasp_flags(physDev
, &flags
) || flags
& GASP_DOGRAY
)
478 entry
->aa_default
= AA_Grey
;
480 entry
->aa_default
= AA_None
;
483 entry
->aa_default
= AA_None
;
488 static void dec_ref_cache(int index
)
491 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
492 assert(glyphsetCache
[index
].count
> 0);
493 glyphsetCache
[index
].count
--;
496 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
498 DWORD hash
= 0, *ptr
;
501 hash
^= plfsz
->devsize
.cx
;
502 hash
^= plfsz
->devsize
.cy
;
503 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
505 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
506 WCHAR
*pwc
= (WCHAR
*)ptr
;
516 /***********************************************************************
517 * X11DRV_XRender_Finalize
519 void X11DRV_XRender_Finalize(void)
523 EnterCriticalSection(&xrender_cs
);
524 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
526 LeaveCriticalSection(&xrender_cs
);
530 /***********************************************************************
531 * X11DRV_XRender_SelectFont
533 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
537 GetObjectW(hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
538 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
539 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
540 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
541 lfsz
.devsize
.cx
= X11DRV_XWStoDS( physDev
, lfsz
.lf
.lfWidth
);
542 lfsz
.devsize
.cy
= X11DRV_YWStoDS( physDev
, lfsz
.lf
.lfHeight
);
543 lfsz_calc_hash(&lfsz
);
545 EnterCriticalSection(&xrender_cs
);
546 if(!physDev
->xrender
) {
547 physDev
->xrender
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
548 sizeof(*physDev
->xrender
));
549 physDev
->xrender
->cache_index
= -1;
551 else if(physDev
->xrender
->cache_index
!= -1)
552 dec_ref_cache(physDev
->xrender
->cache_index
);
553 physDev
->xrender
->cache_index
= GetCacheEntry(physDev
, &lfsz
);
554 LeaveCriticalSection(&xrender_cs
);
558 /***********************************************************************
559 * X11DRV_XRender_DeleteDC
561 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
563 X11DRV_XRender_UpdateDrawable(physDev
);
565 EnterCriticalSection(&xrender_cs
);
566 if(physDev
->xrender
->cache_index
!= -1)
567 dec_ref_cache(physDev
->xrender
->cache_index
);
568 LeaveCriticalSection(&xrender_cs
);
570 HeapFree(GetProcessHeap(), 0, physDev
->xrender
);
571 physDev
->xrender
= NULL
;
575 /***********************************************************************
576 * X11DRV_XRender_UpdateDrawable
578 * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
579 * It deletes the pict and tile when the drawable changes.
581 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
585 if(physDev
->xrender
->pict
)
587 TRACE("freeing pict = %lx dc = %p\n", physDev
->xrender
->pict
, physDev
->hdc
);
589 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
590 physDev
->xrender
->pict
= 0;
597 /************************************************************************
600 * Helper to ExtTextOut. Must be called inside xrender_cs
602 static BOOL
UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
, AA_Type format
)
609 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
610 gsCacheEntryFormat
*formatEntry
;
611 UINT ggo_format
= GGO_GLYPH_INDEX
;
612 XRenderPictFormat pf
;
613 static const char zero
[4];
617 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
621 ERR("aa = %d - not implemented\n", format
);
623 ggo_format
|= GGO_BITMAP
;
627 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
,
629 if(buflen
== GDI_ERROR
) {
630 if(format
!= AA_None
) {
632 entry
->aa_default
= AA_None
;
633 ggo_format
&= ~WINE_GGO_GRAY16_BITMAP
;
634 ggo_format
|= GGO_BITMAP
;
635 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
,
638 if(buflen
== GDI_ERROR
) {
639 WARN("GetGlyphOutlineW failed\n");
642 TRACE("Turning off antialiasing for this monochrome font\n");
645 /* If there is nothing for the current type, we create the entry. */
646 if( !entry
->format
[format
] ) {
647 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
649 sizeof(gsCacheEntryFormat
));
651 formatEntry
= entry
->format
[format
];
653 if(formatEntry
->nrealized
<= glyph
) {
654 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
656 if (formatEntry
->realized
)
657 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
659 formatEntry
->realized
,
660 formatEntry
->nrealized
* sizeof(BOOL
));
662 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
664 formatEntry
->nrealized
* sizeof(BOOL
));
666 if(!X11DRV_XRender_Installed
) {
667 if (formatEntry
->bitmaps
)
668 formatEntry
->bitmaps
= HeapReAlloc(GetProcessHeap(),
670 formatEntry
->bitmaps
,
671 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
673 formatEntry
->bitmaps
= HeapAlloc(GetProcessHeap(),
675 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
677 if (formatEntry
->gis
)
678 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
681 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
683 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
685 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
689 if(formatEntry
->glyphset
== 0 && X11DRV_XRender_Installed
) {
693 pf
.direct
.alphaMask
= 0xff;
697 ERR("aa = %d - not implemented\n", format
);
700 pf
.direct
.alphaMask
= 1;
704 pf
.type
= PictTypeDirect
;
708 formatEntry
->font_format
= pXRenderFindFormat(gdi_display
,
715 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
720 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
721 GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, NULL
);
722 formatEntry
->realized
[glyph
] = TRUE
;
724 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
726 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
727 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
729 gi
.width
= gm
.gmBlackBoxX
;
730 gi
.height
= gm
.gmBlackBoxY
;
731 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
732 gi
.y
= gm
.gmptGlyphOrigin
.y
;
733 gi
.xOff
= gm
.gmCellIncX
;
734 gi
.yOff
= gm
.gmCellIncY
;
736 if(TRACE_ON(xrender
)) {
741 if(format
== AA_None
) {
742 pitch
= ((gi
.width
+ 31) / 32) * 4;
743 for(i
= 0; i
< gi
.height
; i
++) {
744 line
= (unsigned char*) buf
+ i
* pitch
;
746 for(j
= 0; j
< pitch
* 8; j
++) {
747 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
749 TRACE("%s\n", output
);
752 static const char blks
[] = " .:;!o*#";
756 pitch
= ((gi
.width
+ 3) / 4) * 4;
757 for(i
= 0; i
< gi
.height
; i
++) {
758 line
= (unsigned char*) buf
+ i
* pitch
;
760 for(j
= 0; j
< pitch
; j
++) {
761 str
[0] = blks
[line
[j
] >> 5];
764 TRACE("%s\n", output
);
770 if(formatEntry
->glyphset
) {
771 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
772 unsigned char *byte
= (unsigned char*) buf
, c
;
778 /* magic to flip bit order */
779 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
780 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
781 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
789 XRenderCompositeText seems to ignore 0x0 glyphs when
790 AA_None, which means we lose the advance width of glyphs
791 like the space. We'll pretend that such glyphs are 1x1
796 gi
.width
= gi
.height
= 1;
799 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
800 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
802 HeapFree(GetProcessHeap(), 0, buf
);
804 formatEntry
->bitmaps
[glyph
] = buf
;
807 formatEntry
->gis
[glyph
] = gi
;
812 static void SharpGlyphMono(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
813 void *bitmap
, XGlyphInfo
*gi
)
815 unsigned char *srcLine
= bitmap
, *src
;
816 unsigned char bits
, bitsMask
;
817 int width
= gi
->width
;
818 int stride
= ((width
+ 31) & ~31) >> 3;
819 int height
= gi
->height
;
823 TRACE("%d, %d\n", x
, y
);
832 bitsMask
= 0x80; /* FreeType is always MSB first */
846 bitsMask
= bitsMask
>> 1;
852 } while (bits
& bitsMask
);
853 XFillRectangle (gdi_display
, physDev
->drawable
,
854 physDev
->gc
, xspan
, y
, lenspan
, 1);
866 bitsMask
= bitsMask
>> 1;
872 } while (!(bits
& bitsMask
));
879 static void SharpGlyphGray(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
880 void *bitmap
, XGlyphInfo
*gi
)
882 unsigned char *srcLine
= bitmap
, *src
, bits
;
883 int width
= gi
->width
;
884 int stride
= ((width
+ 3) & ~3);
885 int height
= gi
->height
;
910 } while (bits
>= 0x80);
911 XFillRectangle (gdi_display
, physDev
->drawable
,
912 physDev
->gc
, xspan
, y
, lenspan
, 1);
925 } while (bits
< 0x80);
933 static void ExamineBitfield (DWORD mask
, int *shift
, int *len
)
938 while ((mask
& 1) == 0)
944 while ((mask
& 1) == 1)
953 static DWORD
GetField (DWORD pixel
, int shift
, int len
)
955 pixel
= pixel
& (((1 << (len
)) - 1) << shift
);
956 pixel
= pixel
<< (32 - (shift
+ len
)) >> 24;
959 pixel
|= (pixel
>> len
);
966 static DWORD
PutField (DWORD pixel
, int shift
, int len
)
968 shift
= shift
- (8 - len
);
970 pixel
&= (((1 << len
) - 1) << (8 - len
));
978 static void SmoothGlyphGray(XImage
*image
, int x
, int y
, void *bitmap
, XGlyphInfo
*gi
,
984 BYTE
*maskLine
, *mask
, m
;
989 BYTE src_r
, src_g
, src_b
;
996 maskLine
= (unsigned char *) bitmap
;
997 maskStride
= (width
+ 3) & ~3;
999 ExamineBitfield (image
->red_mask
, &r_shift
, &r_len
);
1000 ExamineBitfield (image
->green_mask
, &g_shift
, &g_len
);
1001 ExamineBitfield (image
->blue_mask
, &b_shift
, &b_len
);
1003 src_r
= GetField(color
, r_shift
, r_len
);
1004 src_g
= GetField(color
, g_shift
, g_len
);
1005 src_b
= GetField(color
, b_shift
, b_len
);
1007 for(; height
--; y
++)
1010 maskLine
+= maskStride
;
1015 if(y
>= image
->height
) break;
1019 if(tx
>= image
->width
) break;
1022 if(tx
< 0) continue;
1025 XPutPixel (image
, tx
, y
, color
);
1030 pixel
= XGetPixel (image
, tx
, y
);
1032 r
= GetField(pixel
, r_shift
, r_len
);
1033 r
= ((BYTE
)~m
* (WORD
)r
+ (BYTE
)m
* (WORD
)src_r
) >> 8;
1034 g
= GetField(pixel
, g_shift
, g_len
);
1035 g
= ((BYTE
)~m
* (WORD
)g
+ (BYTE
)m
* (WORD
)src_g
) >> 8;
1036 b
= GetField(pixel
, b_shift
, b_len
);
1037 b
= ((BYTE
)~m
* (WORD
)b
+ (BYTE
)m
* (WORD
)src_b
) >> 8;
1039 pixel
= (PutField (r
, r_shift
, r_len
) |
1040 PutField (g
, g_shift
, g_len
) |
1041 PutField (b
, b_shift
, b_len
));
1042 XPutPixel (image
, tx
, y
, pixel
);
1048 /*************************************************************
1051 * Returns an appropriate Picture for tiling the text colour.
1052 * Call and use result within the xrender_cs
1054 static Picture
get_tile_pict(enum drawable_depth_type type
, int text_pixel
)
1064 tile
= &tiles
[type
];
1068 XRenderPictureAttributes pa
;
1071 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_formats
[type
]->depth
);
1074 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_formats
[type
], CPRepeat
, &pa
);
1075 wine_tsx11_unlock();
1077 /* init current_color to something different from text_pixel */
1078 tile
->current_color
= ~text_pixel
;
1080 if(type
== mono_drawable
)
1082 /* for a 1bpp bitmap we always need a 1 in the tile */
1083 col
.red
= col
.green
= col
.blue
= 0;
1086 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1087 wine_tsx11_unlock();
1091 if(text_pixel
!= tile
->current_color
&& type
== color_drawable
)
1093 /* Map 0 -- 0xff onto 0 -- 0xffff */
1098 ExamineBitfield (visual
->red_mask
, &r_shift
, &r_len
);
1099 ExamineBitfield (visual
->green_mask
, &g_shift
, &g_len
);
1100 ExamineBitfield (visual
->blue_mask
, &b_shift
, &b_len
);
1102 col
.red
= GetField(text_pixel
, r_shift
, r_len
);
1103 col
.red
|= col
.red
<< 8;
1104 col
.green
= GetField(text_pixel
, g_shift
, g_len
);
1105 col
.green
|= col
.green
<< 8;
1106 col
.blue
= GetField(text_pixel
, b_shift
, b_len
);
1107 col
.blue
|= col
.blue
<< 8;
1111 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1112 wine_tsx11_unlock();
1113 tile
->current_color
= text_pixel
;
1118 static int XRenderErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
1123 /***********************************************************************
1124 * X11DRV_XRender_ExtTextOut
1126 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1127 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1132 gsCacheEntry
*entry
;
1133 gsCacheEntryFormat
*formatEntry
;
1135 HDC hdc
= physDev
->hdc
;
1136 int textPixel
, backgroundPixel
;
1137 HRGN saved_region
= 0;
1138 BOOL disable_antialias
= FALSE
;
1139 AA_Type aa_type
= AA_None
;
1142 double cosEsc
, sinEsc
;
1144 enum drawable_depth_type depth_type
= (physDev
->depth
== 1) ? mono_drawable
: color_drawable
;
1145 Picture tile_pict
= 0;
1147 /* Do we need to disable antialiasing because of palette mode? */
1148 if( !physDev
->bitmap
|| GetObjectW( physDev
->bitmap
->hbitmap
, sizeof(bmp
), &bmp
) != sizeof(bmp
) ) {
1149 TRACE("bitmap is not a DIB\n");
1151 else if (bmp
.dsBmih
.biBitCount
<= 8) {
1152 TRACE("Disabling antialiasing\n");
1153 disable_antialias
= TRUE
;
1156 xgcval
.function
= GXcopy
;
1157 xgcval
.background
= physDev
->backgroundPixel
;
1158 xgcval
.fill_style
= FillSolid
;
1160 XChangeGC( gdi_display
, physDev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1161 wine_tsx11_unlock();
1163 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
);
1165 if(physDev
->depth
== 1) {
1166 if((physDev
->textPixel
& 0xffffff) == 0) {
1168 backgroundPixel
= 1;
1171 backgroundPixel
= 0;
1174 textPixel
= physDev
->textPixel
;
1175 backgroundPixel
= physDev
->backgroundPixel
;
1178 if(flags
& ETO_OPAQUE
)
1181 XSetForeground( gdi_display
, physDev
->gc
, backgroundPixel
);
1182 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1183 physDev
->dc_rect
.left
+ lprect
->left
, physDev
->dc_rect
.top
+ lprect
->top
,
1184 lprect
->right
- lprect
->left
, lprect
->bottom
- lprect
->top
);
1185 wine_tsx11_unlock();
1195 GetObjectW(GetCurrentObject(physDev
->hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
1196 if(lf
.lfEscapement
!= 0) {
1197 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
1198 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
1204 if (flags
& ETO_CLIPPED
)
1208 clip_region
= CreateRectRgnIndirect( lprect
);
1209 /* make a copy of the current device region */
1210 saved_region
= CreateRectRgn( 0, 0, 0, 0 );
1211 CombineRgn( saved_region
, physDev
->region
, 0, RGN_COPY
);
1212 X11DRV_SetDeviceClipping( physDev
, saved_region
, clip_region
);
1213 DeleteObject( clip_region
);
1216 if(X11DRV_XRender_Installed
) {
1217 if(!physDev
->xrender
->pict
) {
1218 XRenderPictureAttributes pa
;
1219 pa
.subwindow_mode
= IncludeInferiors
;
1222 physDev
->xrender
->pict
= pXRenderCreatePicture(gdi_display
,
1224 pict_formats
[depth_type
],
1225 CPSubwindowMode
, &pa
);
1226 wine_tsx11_unlock();
1228 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1229 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1231 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1232 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1235 if ((data
= X11DRV_GetRegionData( physDev
->region
, 0 )))
1238 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
1239 physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
1240 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
1241 wine_tsx11_unlock();
1242 HeapFree( GetProcessHeap(), 0, data
);
1246 EnterCriticalSection(&xrender_cs
);
1248 entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1249 if( disable_antialias
== FALSE
)
1250 aa_type
= entry
->aa_default
;
1251 formatEntry
= entry
->format
[aa_type
];
1253 for(idx
= 0; idx
< count
; idx
++) {
1254 if( !formatEntry
) {
1255 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1256 /* re-evaluate antialias since aa_default may have changed */
1257 if( disable_antialias
== FALSE
)
1258 aa_type
= entry
->aa_default
;
1259 formatEntry
= entry
->format
[aa_type
];
1260 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1261 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1266 WARN("could not upload requested glyphs\n");
1267 LeaveCriticalSection(&xrender_cs
);
1271 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1272 physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1274 if(X11DRV_XRender_Installed
)
1276 XGlyphElt16
*elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1278 POINT desired
, current
;
1279 int render_op
= PictOpOver
;
1281 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1282 So we pass zeros to the function and move to our starting position using the first
1283 element of the elts array. */
1285 desired
.x
= physDev
->dc_rect
.left
+ x
;
1286 desired
.y
= physDev
->dc_rect
.top
+ y
;
1287 current
.x
= current
.y
= 0;
1289 tile_pict
= get_tile_pict(depth_type
, physDev
->textPixel
);
1291 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1293 if((depth_type
== mono_drawable
) && (textPixel
== 0))
1294 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1296 for(idx
= 0; idx
< count
; idx
++)
1298 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1299 elts
[idx
].chars
= wstr
+ idx
;
1300 elts
[idx
].nchars
= 1;
1301 elts
[idx
].xOff
= desired
.x
- current
.x
;
1302 elts
[idx
].yOff
= desired
.y
- current
.y
;
1304 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1305 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1309 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1310 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1314 offset
+= lpDx
[idx
];
1315 desired
.x
= physDev
->dc_rect
.left
+ x
+ offset
* cosEsc
;
1316 desired
.y
= physDev
->dc_rect
.top
+ y
- offset
* sinEsc
;
1320 pXRenderCompositeText16(gdi_display
, render_op
,
1322 physDev
->xrender
->pict
,
1323 formatEntry
->font_format
,
1324 0, 0, 0, 0, elts
, count
);
1325 wine_tsx11_unlock();
1326 HeapFree(GetProcessHeap(), 0, elts
);
1328 INT offset
= 0, xoff
= 0, yoff
= 0;
1330 XSetForeground( gdi_display
, physDev
->gc
, textPixel
);
1332 if(aa_type
== AA_None
|| physDev
->depth
== 1)
1334 void (* sharp_glyph_fn
)(X11DRV_PDEVICE
*, INT
, INT
, void *, XGlyphInfo
*);
1336 if(aa_type
== AA_None
)
1337 sharp_glyph_fn
= SharpGlyphMono
;
1339 sharp_glyph_fn
= SharpGlyphGray
;
1341 for(idx
= 0; idx
< count
; idx
++) {
1342 sharp_glyph_fn(physDev
, physDev
->dc_rect
.left
+ x
+ xoff
,
1343 physDev
->dc_rect
.top
+ y
+ yoff
,
1344 formatEntry
->bitmaps
[wstr
[idx
]],
1345 &formatEntry
->gis
[wstr
[idx
]]);
1347 offset
+= lpDx
[idx
];
1348 xoff
= offset
* cosEsc
;
1349 yoff
= offset
* -sinEsc
;
1351 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1352 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1357 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
1358 RECT extents
= {0, 0, 0, 0};
1360 int w
= physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
;
1361 int h
= physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
;
1363 TRACE("drawable %dx%d\n", w
, h
);
1365 for(idx
= 0; idx
< count
; idx
++) {
1366 if(extents
.left
> cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
)
1367 extents
.left
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
;
1368 if(extents
.top
> cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
)
1369 extents
.top
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
;
1370 if(extents
.right
< cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
)
1371 extents
.right
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
;
1372 if(extents
.bottom
< cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
)
1373 extents
.bottom
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
;
1375 offset
+= lpDx
[idx
];
1376 cur
.x
= offset
* cosEsc
;
1377 cur
.y
= offset
* -sinEsc
;
1379 cur
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1380 cur
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1383 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents
.left
, extents
.top
,
1384 extents
.right
, extents
.bottom
, physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1386 if(physDev
->dc_rect
.left
+ x
+ extents
.left
>= 0) {
1387 image_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1391 image_off_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1393 if(physDev
->dc_rect
.top
+ y
+ extents
.top
>= 0) {
1394 image_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1398 image_off_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1400 if(physDev
->dc_rect
.left
+ x
+ extents
.right
< w
)
1401 image_w
= physDev
->dc_rect
.left
+ x
+ extents
.right
- image_x
;
1403 image_w
= w
- image_x
;
1404 if(physDev
->dc_rect
.top
+ y
+ extents
.bottom
< h
)
1405 image_h
= physDev
->dc_rect
.top
+ y
+ extents
.bottom
- image_y
;
1407 image_h
= h
- image_y
;
1409 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
1411 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1412 image
= XGetImage(gdi_display
, physDev
->drawable
,
1413 image_x
, image_y
, image_w
, image_h
,
1414 AllPlanes
, ZPixmap
);
1415 X11DRV_check_error();
1417 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1418 gdi_display
, (int)physDev
->drawable
, image_x
, image_y
,
1419 image_w
, image_h
, AllPlanes
, ZPixmap
,
1420 physDev
->depth
, image
);
1422 Pixmap xpm
= XCreatePixmap(gdi_display
, root_window
, image_w
, image_h
,
1427 gcv
.graphics_exposures
= False
;
1428 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1429 XCopyArea(gdi_display
, physDev
->drawable
, xpm
, gc
, image_x
, image_y
,
1430 image_w
, image_h
, 0, 0);
1431 XFreeGC(gdi_display
, gc
);
1432 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1433 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
1435 X11DRV_check_error();
1436 XFreePixmap(gdi_display
, xpm
);
1438 if(!image
) goto no_image
;
1440 image
->red_mask
= visual
->red_mask
;
1441 image
->green_mask
= visual
->green_mask
;
1442 image
->blue_mask
= visual
->blue_mask
;
1444 offset
= xoff
= yoff
= 0;
1445 for(idx
= 0; idx
< count
; idx
++) {
1446 SmoothGlyphGray(image
, xoff
+ image_off_x
- extents
.left
,
1447 yoff
+ image_off_y
- extents
.top
,
1448 formatEntry
->bitmaps
[wstr
[idx
]],
1449 &formatEntry
->gis
[wstr
[idx
]],
1450 physDev
->textPixel
);
1452 offset
+= lpDx
[idx
];
1453 xoff
= offset
* cosEsc
;
1454 yoff
= offset
* -sinEsc
;
1456 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1457 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1460 XPutImage(gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
1461 image_x
, image_y
, image_w
, image_h
);
1462 XDestroyImage(image
);
1465 wine_tsx11_unlock();
1467 LeaveCriticalSection(&xrender_cs
);
1469 if (flags
& ETO_CLIPPED
)
1471 /* restore the device region */
1472 X11DRV_SetDeviceClipping( physDev
, saved_region
, 0 );
1473 DeleteObject( saved_region
);
1479 X11DRV_UnlockDIBSection( physDev
, TRUE
);
1483 /******************************************************************************
1484 * AlphaBlend (x11drv.@)
1486 BOOL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1487 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1488 BLENDFUNCTION blendfn
)
1490 XRenderPictureAttributes pa
;
1491 XRenderPictFormat
*src_format
;
1492 XRenderPictFormat argb32_templ
= {
1494 PictTypeDirect
, /* type */
1497 16, /* direct.red */
1498 0xff, /* direct.redMask */
1499 8, /* direct.green */
1500 0xff, /* direct.greenMask */
1501 0, /* direct.blue */
1502 0xff, /* direct.blueMask */
1503 24, /* direct.alpha */
1504 0xff, /* direct.alphaMask */
1508 unsigned long argb32_templ_mask
=
1514 PictFormatGreenMask
|
1516 PictFormatBlueMask
|
1518 PictFormatAlphaMask
;
1520 Picture dst_pict
, src_pict
;
1526 DWORD
*dstbits
, *data
;
1529 BOOL top_down
= FALSE
;
1531 enum drawable_depth_type dst_depth_type
= (devDst
->depth
== 1) ? mono_drawable
: color_drawable
;
1533 if(!X11DRV_XRender_Installed
) {
1534 FIXME("Unable to AlphaBlend without Xrender\n");
1539 pts
[1].x
= xDst
+ widthDst
;
1540 pts
[1].y
= yDst
+ heightDst
;
1541 LPtoDP(devDst
->hdc
, pts
, 2);
1544 widthDst
= pts
[1].x
- pts
[0].x
;
1545 heightDst
= pts
[1].y
- pts
[0].y
;
1549 pts
[1].x
= xSrc
+ widthSrc
;
1550 pts
[1].y
= ySrc
+ heightSrc
;
1551 LPtoDP(devSrc
->hdc
, pts
, 2);
1554 widthSrc
= pts
[1].x
- pts
[0].x
;
1555 heightSrc
= pts
[1].y
- pts
[0].y
;
1556 if (!widthDst
|| !heightDst
|| !widthSrc
|| !heightSrc
) return TRUE
;
1558 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1559 if(widthDst
!= widthSrc
|| heightDst
!= heightSrc
)
1561 if(!pXRenderSetPictureTransform
)
1564 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1568 if (!devSrc
->bitmap
|| GetObjectW( devSrc
->bitmap
->hbitmap
, sizeof(dib
), &dib
) != sizeof(dib
))
1570 static BOOL out
= FALSE
;
1573 FIXME("not a dibsection\n");
1579 if (xSrc
< 0 || ySrc
< 0 || widthSrc
< 0 || heightSrc
< 0 || xSrc
+ widthSrc
> dib
.dsBmih
.biWidth
1580 || ySrc
+ heightSrc
> abs(dib
.dsBmih
.biHeight
))
1582 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc
, ySrc
, widthSrc
, heightSrc
);
1583 SetLastError(ERROR_INVALID_PARAMETER
);
1587 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && blendfn
.SourceConstantAlpha
!= 0xff)
1588 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn
.SourceConstantAlpha
);
1590 if(dib
.dsBm
.bmBitsPixel
!= 32) {
1591 FIXME("not a 32 bpp dibsection\n");
1594 dstbits
= data
= HeapAlloc(GetProcessHeap(), 0, heightSrc
* widthSrc
* 4);
1596 if(dib
.dsBmih
.biHeight
< 0) { /* top-down dib */
1598 dstbits
+= widthSrc
* (heightSrc
- 1);
1600 y
= y2
+ heightSrc
- 1;
1604 y
= dib
.dsBmih
.biHeight
- ySrc
- 1;
1605 y2
= y
- heightSrc
+ 1;
1608 if (blendfn
.AlphaFormat
& AC_SRC_ALPHA
)
1612 memcpy(dstbits
, (char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
+ xSrc
* 4,
1614 dstbits
+= (top_down
? -1 : 1) * widthSrc
;
1619 DWORD source_alpha
= (DWORD
)blendfn
.SourceConstantAlpha
<< 24;
1624 DWORD
*srcbits
= (DWORD
*)((char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
) + xSrc
;
1625 for (x
= 0; x
< widthSrc
; x
++)
1627 DWORD argb
= *srcbits
++;
1628 argb
= (argb
& 0xffffff) | source_alpha
;
1631 if (top_down
) /* we traversed the row forward so we should go back by two rows */
1632 dstbits
-= 2 * widthSrc
;
1637 rgndata
= X11DRV_GetRegionData( devDst
->region
, 0 );
1640 image
= XCreateImage(gdi_display
, visual
, 32, ZPixmap
, 0,
1641 (char*) data
, widthSrc
, heightSrc
, 32, widthSrc
* 4);
1644 Avoid using XRenderFindStandardFormat as older libraries don't have it
1645 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1647 src_format
= pXRenderFindFormat(gdi_display
, argb32_templ_mask
, &argb32_templ
, 0);
1649 TRACE("src_format %p\n", src_format
);
1651 pa
.subwindow_mode
= IncludeInferiors
;
1653 /* FIXME use devDst->xrender->pict ? */
1654 dst_pict
= pXRenderCreatePicture(gdi_display
,
1656 pict_formats
[dst_depth_type
],
1657 CPSubwindowMode
, &pa
);
1658 TRACE("dst_pict %08lx\n", dst_pict
);
1659 TRACE("src_drawable = %08lx\n", devSrc
->drawable
);
1660 xpm
= XCreatePixmap(gdi_display
,
1662 widthSrc
, heightSrc
, 32);
1663 gcv
.graphics_exposures
= False
;
1664 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1665 TRACE("xpm = %08lx\n", xpm
);
1666 XPutImage(gdi_display
, xpm
, gc
, image
, 0, 0, 0, 0, widthSrc
, heightSrc
);
1668 src_pict
= pXRenderCreatePicture(gdi_display
,
1670 CPSubwindowMode
, &pa
);
1671 TRACE("src_pict %08lx\n", src_pict
);
1675 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
,
1676 devDst
->dc_rect
.left
, devDst
->dc_rect
.top
,
1677 (XRectangle
*)rgndata
->Buffer
,
1678 rgndata
->rdh
.nCount
);
1679 HeapFree( GetProcessHeap(), 0, rgndata
);
1682 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1683 if(widthDst
!= widthSrc
|| heightDst
!= heightSrc
) {
1684 double xscale
= widthSrc
/(double)widthDst
;
1685 double yscale
= heightSrc
/(double)heightDst
;
1686 XTransform xform
= {{
1687 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(0) },
1688 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(0) },
1689 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1691 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
1694 pXRenderComposite(gdi_display
, PictOpOver
, src_pict
, 0, dst_pict
,
1696 xDst
+ devDst
->dc_rect
.left
, yDst
+ devDst
->dc_rect
.top
, widthDst
, heightDst
);
1699 pXRenderFreePicture(gdi_display
, src_pict
);
1700 XFreePixmap(gdi_display
, xpm
);
1701 XFreeGC(gdi_display
, gc
);
1702 pXRenderFreePicture(gdi_display
, dst_pict
);
1704 XDestroyImage(image
);
1706 wine_tsx11_unlock();
1707 HeapFree(GetProcessHeap(), 0, data
);
1711 #else /* SONAME_LIBXRENDER */
1713 void X11DRV_XRender_Init(void)
1715 TRACE("XRender support not compiled in.\n");
1719 void X11DRV_XRender_Finalize(void)
1723 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
1729 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
1735 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1736 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1743 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
1749 /******************************************************************************
1750 * AlphaBlend (x11drv.@)
1752 BOOL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1753 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1754 BLENDFUNCTION blendfn
)
1756 FIXME("not supported - XRENDER headers were missing at compile time\n");
1760 #endif /* SONAME_LIBXRENDER */