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>
50 #ifndef RepeatNone /* added in 0.10 */
52 #define RepeatNormal 1
54 #define RepeatReflect 3
57 enum drawable_depth_type
{mono_drawable
, color_drawable
};
58 static XRenderPictFormat
*pict_formats
[2];
64 SIZE devsize
; /* size in device coords */
68 #define INITIAL_REALIZED_BUF_SIZE 128
70 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
75 XRenderPictFormat
*font_format
;
86 gsCacheEntryFormat
* format
[AA_MAXVALUE
];
98 static gsCacheEntry
*glyphsetCache
= NULL
;
99 static DWORD glyphsetCacheSize
= 0;
100 static INT lastfree
= -1;
103 #define INIT_CACHE_SIZE 10
105 static int antialias
= 1;
107 static void *xrender_handle
;
109 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
110 MAKE_FUNCPTR(XRenderAddGlyphs
)
111 MAKE_FUNCPTR(XRenderComposite
)
112 MAKE_FUNCPTR(XRenderCompositeString8
)
113 MAKE_FUNCPTR(XRenderCompositeString16
)
114 MAKE_FUNCPTR(XRenderCompositeString32
)
115 MAKE_FUNCPTR(XRenderCompositeText16
)
116 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
117 MAKE_FUNCPTR(XRenderCreatePicture
)
118 MAKE_FUNCPTR(XRenderFillRectangle
)
119 MAKE_FUNCPTR(XRenderFindFormat
)
120 MAKE_FUNCPTR(XRenderFindVisualFormat
)
121 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
122 MAKE_FUNCPTR(XRenderFreePicture
)
123 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
124 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
125 MAKE_FUNCPTR(XRenderSetPictureTransform
)
127 MAKE_FUNCPTR(XRenderQueryExtension
)
130 static CRITICAL_SECTION xrender_cs
;
131 static CRITICAL_SECTION_DEBUG critsect_debug
=
134 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
135 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
137 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
139 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
140 ( ( (ULONG)_x4 << 24 ) | \
141 ( (ULONG)_x3 << 16 ) | \
142 ( (ULONG)_x2 << 8 ) | \
145 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
147 #define GASP_GRIDFIT 0x01
148 #define GASP_DOGRAY 0x02
150 #ifdef WORDS_BIGENDIAN
151 #define get_be_word(x) (x)
152 #define NATIVE_BYTE_ORDER MSBFirst
154 #define get_be_word(x) RtlUshortByteSwap(x)
155 #define NATIVE_BYTE_ORDER LSBFirst
158 /***********************************************************************
159 * X11DRV_XRender_Init
161 * Let's see if our XServer has the extension available
164 void X11DRV_XRender_Init(void)
167 XRenderPictFormat pf
;
169 if (client_side_with_render
&&
170 wine_dlopen(SONAME_LIBX11
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
171 wine_dlopen(SONAME_LIBXEXT
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
172 (xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0)))
175 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
176 LOAD_FUNCPTR(XRenderAddGlyphs
)
177 LOAD_FUNCPTR(XRenderComposite
)
178 LOAD_FUNCPTR(XRenderCompositeString8
)
179 LOAD_FUNCPTR(XRenderCompositeString16
)
180 LOAD_FUNCPTR(XRenderCompositeString32
)
181 LOAD_FUNCPTR(XRenderCompositeText16
)
182 LOAD_FUNCPTR(XRenderCreateGlyphSet
)
183 LOAD_FUNCPTR(XRenderCreatePicture
)
184 LOAD_FUNCPTR(XRenderFillRectangle
)
185 LOAD_FUNCPTR(XRenderFindFormat
)
186 LOAD_FUNCPTR(XRenderFindVisualFormat
)
187 LOAD_FUNCPTR(XRenderFreeGlyphSet
)
188 LOAD_FUNCPTR(XRenderFreePicture
)
189 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
)
190 LOAD_FUNCPTR(XRenderQueryExtension
)
192 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
193 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
194 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
)
195 #undef LOAD_OPTIONAL_FUNCPTR
200 if(pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
)) {
201 X11DRV_XRender_Installed
= TRUE
;
202 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
203 pict_formats
[color_drawable
] = pXRenderFindVisualFormat(gdi_display
, visual
);
204 if(!pict_formats
[color_drawable
])
206 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
207 if (visual
->class == DirectColor
)
210 if (XMatchVisualInfo( gdi_display
, DefaultScreen(gdi_display
),
211 screen_depth
, TrueColor
, &info
))
213 pict_formats
[color_drawable
] = pXRenderFindVisualFormat(gdi_display
, info
.visual
);
214 if (pict_formats
[color_drawable
]) visual
= info
.visual
;
218 if(!pict_formats
[color_drawable
]) /* This fails in buggy versions of libXrender.so */
222 "Wine has detected that you probably have a buggy version\n"
223 "of libXrender.so . Because of this client side font rendering\n"
224 "will be disabled. Please upgrade this library.\n");
225 X11DRV_XRender_Installed
= FALSE
;
228 pf
.type
= PictTypeDirect
;
231 pf
.direct
.alphaMask
= 1;
232 pict_formats
[mono_drawable
] = pXRenderFindFormat(gdi_display
, PictFormatType
|
233 PictFormatDepth
| PictFormatAlpha
|
234 PictFormatAlphaMask
, &pf
, 0);
235 if(!pict_formats
[mono_drawable
]) {
236 ERR("mono_format == NULL?\n");
237 X11DRV_XRender_Installed
= FALSE
;
239 if (!visual
->red_mask
|| !visual
->green_mask
|| !visual
->blue_mask
) {
240 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
241 X11DRV_XRender_Installed
= FALSE
;
248 if(X11DRV_XRender_Installed
|| client_side_with_core
)
250 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
251 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
253 glyphsetCacheSize
= INIT_CACHE_SIZE
;
255 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
256 glyphsetCache
[i
].next
= i
+ 1;
257 glyphsetCache
[i
].count
= -1;
259 glyphsetCache
[i
-1].next
= -1;
260 using_client_side_fonts
= 1;
262 if(!X11DRV_XRender_Installed
) {
263 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
264 if(screen_depth
<= 8 || !client_side_antialias_with_core
)
267 if(screen_depth
<= 8 || !client_side_antialias_with_render
)
271 else TRACE("Using X11 core fonts\n");
274 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
276 if(p1
->hash
!= p2
->hash
) return TRUE
;
277 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
278 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
279 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
280 return strcmpiW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
284 static void walk_cache(void)
288 EnterCriticalSection(&xrender_cs
);
289 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
290 TRACE("item %d\n", i
);
291 LeaveCriticalSection(&xrender_cs
);
295 static int LookupEntry(LFANDSIZE
*plfsz
)
299 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
301 if(glyphsetCache
[i
].count
== -1) { /* reached free list so stop */
306 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
307 glyphsetCache
[i
].count
++;
309 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
310 glyphsetCache
[i
].next
= mru
;
313 TRACE("found font in cache %d\n", i
);
318 TRACE("font not in cache\n");
322 static void FreeEntry(int entry
)
326 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
327 gsCacheEntryFormat
* formatEntry
;
329 if( !glyphsetCache
[entry
].format
[format
] )
332 formatEntry
= glyphsetCache
[entry
].format
[format
];
334 if(formatEntry
->glyphset
) {
336 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
338 formatEntry
->glyphset
= 0;
340 if(formatEntry
->nrealized
) {
341 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
342 formatEntry
->realized
= NULL
;
343 if(formatEntry
->bitmaps
) {
344 for(i
= 0; i
< formatEntry
->nrealized
; i
++)
345 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
[i
]);
346 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
);
347 formatEntry
->bitmaps
= NULL
;
349 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
350 formatEntry
->gis
= NULL
;
351 formatEntry
->nrealized
= 0;
354 HeapFree(GetProcessHeap(), 0, formatEntry
);
355 glyphsetCache
[entry
].format
[format
] = NULL
;
359 static int AllocEntry(void)
361 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
364 assert(glyphsetCache
[lastfree
].count
== -1);
365 glyphsetCache
[lastfree
].count
= 1;
367 lastfree
= glyphsetCache
[lastfree
].next
;
369 glyphsetCache
[best
].next
= mru
;
372 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
376 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
377 if(glyphsetCache
[i
].count
== 0) {
385 TRACE("freeing unused glyphset at cache %d\n", best
);
387 glyphsetCache
[best
].count
= 1;
389 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
390 glyphsetCache
[best
].next
= mru
;
398 TRACE("Growing cache\n");
401 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
403 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
404 * sizeof(*glyphsetCache
));
406 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
407 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
408 * sizeof(*glyphsetCache
));
410 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
412 glyphsetCache
[i
].next
= i
+ 1;
413 glyphsetCache
[i
].count
= -1;
415 glyphsetCache
[i
-1].next
= -1;
416 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
418 lastfree
= glyphsetCache
[best
].next
;
419 glyphsetCache
[best
].count
= 1;
420 glyphsetCache
[best
].next
= mru
;
422 TRACE("new free cache slot at %d\n", mru
);
426 static BOOL
get_gasp_flags(X11DRV_PDEVICE
*physDev
, WORD
*flags
)
436 size
= GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, NULL
, 0);
437 if(size
== GDI_ERROR
)
440 gasp
= buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
441 GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, gasp
, size
);
443 GetTextMetricsW(physDev
->hdc
, &tm
);
444 ppem
= abs(X11DRV_YWStoDS(physDev
, tm
.tmAscent
+ tm
.tmDescent
- tm
.tmInternalLeading
));
447 num_recs
= get_be_word(*gasp
);
451 *flags
= get_be_word(*(gasp
+ 1));
452 if(ppem
<= get_be_word(*gasp
))
456 TRACE("got flags %04x for ppem %d\n", *flags
, ppem
);
458 HeapFree(GetProcessHeap(), 0, buffer
);
462 static AA_Type
get_antialias_type( X11DRV_PDEVICE
*physDev
, BOOL subpixel
, BOOL hinter
)
466 UINT font_smoothing_type
, font_smoothing_orientation
;
468 if (X11DRV_XRender_Installed
&& subpixel
&&
469 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE
, 0, &font_smoothing_type
, 0) &&
470 font_smoothing_type
== FE_FONTSMOOTHINGCLEARTYPE
)
472 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION
, 0,
473 &font_smoothing_orientation
, 0) &&
474 font_smoothing_orientation
== FE_FONTSMOOTHINGORIENTATIONBGR
)
481 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
482 But, Wine's subpixel rendering can support the portrait mode.
485 else if (!hinter
|| !get_gasp_flags(physDev
, &flags
) || flags
& GASP_DOGRAY
)
493 static int GetCacheEntry(X11DRV_PDEVICE
*physDev
, LFANDSIZE
*plfsz
)
498 static int hinter
= -1;
499 static int subpixel
= -1;
502 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
505 entry
= glyphsetCache
+ ret
;
506 entry
->lfsz
= *plfsz
;
507 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
508 assert( !entry
->format
[format
] );
511 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
513 if(hinter
== -1 || subpixel
== -1)
515 RASTERIZER_STATUS status
;
516 GetRasterizerCaps(&status
, sizeof(status
));
517 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
518 subpixel
= status
.wFlags
& WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
521 switch (plfsz
->lf
.lfQuality
)
523 case ANTIALIASED_QUALITY
:
524 entry
->aa_default
= get_antialias_type( physDev
, FALSE
, hinter
);
526 case CLEARTYPE_QUALITY
:
527 case CLEARTYPE_NATURAL_QUALITY
:
528 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
530 case DEFAULT_QUALITY
:
534 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING
, 0, &font_smoothing
, 0) &&
537 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
540 entry
->aa_default
= AA_None
;
545 entry
->aa_default
= AA_None
;
550 static void dec_ref_cache(int index
)
553 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
554 assert(glyphsetCache
[index
].count
> 0);
555 glyphsetCache
[index
].count
--;
558 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
560 DWORD hash
= 0, *ptr
, two_chars
;
564 hash
^= plfsz
->devsize
.cx
;
565 hash
^= plfsz
->devsize
.cy
;
566 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
568 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
570 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
572 pwc
= (WCHAR
*)&two_chars
;
574 *pwc
= toupperW(*pwc
);
576 *pwc
= toupperW(*pwc
);
584 /***********************************************************************
585 * X11DRV_XRender_Finalize
587 void X11DRV_XRender_Finalize(void)
591 EnterCriticalSection(&xrender_cs
);
592 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
594 LeaveCriticalSection(&xrender_cs
);
598 /***********************************************************************
599 * X11DRV_XRender_SelectFont
601 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
605 GetObjectW(hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
606 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
607 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
608 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
609 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
610 lfsz
.devsize
.cx
= X11DRV_XWStoDS( physDev
, lfsz
.lf
.lfWidth
);
611 lfsz
.devsize
.cy
= X11DRV_YWStoDS( physDev
, lfsz
.lf
.lfHeight
);
612 GetWorldTransform( physDev
->hdc
, &lfsz
.xform
);
613 lfsz_calc_hash(&lfsz
);
615 EnterCriticalSection(&xrender_cs
);
616 if(!physDev
->xrender
) {
617 physDev
->xrender
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
618 sizeof(*physDev
->xrender
));
619 physDev
->xrender
->cache_index
= -1;
621 else if(physDev
->xrender
->cache_index
!= -1)
622 dec_ref_cache(physDev
->xrender
->cache_index
);
623 physDev
->xrender
->cache_index
= GetCacheEntry(physDev
, &lfsz
);
624 LeaveCriticalSection(&xrender_cs
);
628 /***********************************************************************
629 * X11DRV_XRender_DeleteDC
631 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
633 X11DRV_XRender_UpdateDrawable(physDev
);
635 EnterCriticalSection(&xrender_cs
);
636 if(physDev
->xrender
->cache_index
!= -1)
637 dec_ref_cache(physDev
->xrender
->cache_index
);
638 LeaveCriticalSection(&xrender_cs
);
640 HeapFree(GetProcessHeap(), 0, physDev
->xrender
);
641 physDev
->xrender
= NULL
;
645 /***********************************************************************
646 * X11DRV_XRender_UpdateDrawable
648 * Deletes the pict and tile when the drawable changes.
650 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
654 if(physDev
->xrender
->pict
)
656 TRACE("freeing pict = %lx dc = %p\n", physDev
->xrender
->pict
, physDev
->hdc
);
658 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
659 physDev
->xrender
->pict
= 0;
666 /************************************************************************
669 * Helper to ExtTextOut. Must be called inside xrender_cs
671 static BOOL
UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
, AA_Type format
)
678 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
679 gsCacheEntryFormat
*formatEntry
;
680 UINT ggo_format
= GGO_GLYPH_INDEX
;
681 XRenderPictFormat pf
;
682 unsigned long pf_mask
;
683 static const char zero
[4];
684 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
688 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
691 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
694 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
697 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
700 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
704 ERR("aa = %d - not implemented\n", format
);
706 ggo_format
|= GGO_BITMAP
;
710 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
711 if(buflen
== GDI_ERROR
) {
712 if(format
!= AA_None
) {
714 entry
->aa_default
= AA_None
;
715 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
716 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
718 if(buflen
== GDI_ERROR
) {
719 WARN("GetGlyphOutlineW failed\n");
722 TRACE("Turning off antialiasing for this monochrome font\n");
725 /* If there is nothing for the current type, we create the entry. */
726 if( !entry
->format
[format
] ) {
727 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
729 sizeof(gsCacheEntryFormat
));
731 formatEntry
= entry
->format
[format
];
733 if(formatEntry
->nrealized
<= glyph
) {
734 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
736 if (formatEntry
->realized
)
737 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
739 formatEntry
->realized
,
740 formatEntry
->nrealized
* sizeof(BOOL
));
742 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
744 formatEntry
->nrealized
* sizeof(BOOL
));
746 if(!X11DRV_XRender_Installed
) {
747 if (formatEntry
->bitmaps
)
748 formatEntry
->bitmaps
= HeapReAlloc(GetProcessHeap(),
750 formatEntry
->bitmaps
,
751 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
753 formatEntry
->bitmaps
= HeapAlloc(GetProcessHeap(),
755 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
757 if (formatEntry
->gis
)
758 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
761 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
763 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
765 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
769 if(formatEntry
->glyphset
== 0 && X11DRV_XRender_Installed
) {
772 pf_mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
,
773 pf
.type
= PictTypeDirect
;
776 pf
.direct
.alphaMask
= 0xff;
783 pf_mask
= PictFormatType
| PictFormatDepth
| PictFormatRed
| PictFormatRedMask
|
784 PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
|
785 PictFormatBlueMask
| PictFormatAlpha
| PictFormatAlphaMask
;
786 pf
.type
= PictTypeDirect
;
789 pf
.direct
.redMask
= 0xff;
791 pf
.direct
.greenMask
= 0xff;
793 pf
.direct
.blueMask
= 0xff;
794 pf
.direct
.alpha
= 24;
795 pf
.direct
.alphaMask
= 0xff;
799 ERR("aa = %d - not implemented\n", format
);
801 pf_mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
,
802 pf
.type
= PictTypeDirect
;
805 pf
.direct
.alphaMask
= 1;
810 formatEntry
->font_format
= pXRenderFindFormat(gdi_display
, pf_mask
, &pf
, 0);
811 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
816 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
817 GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
818 formatEntry
->realized
[glyph
] = TRUE
;
820 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
822 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
823 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
825 gi
.width
= gm
.gmBlackBoxX
;
826 gi
.height
= gm
.gmBlackBoxY
;
827 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
828 gi
.y
= gm
.gmptGlyphOrigin
.y
;
829 gi
.xOff
= gm
.gmCellIncX
;
830 gi
.yOff
= gm
.gmCellIncY
;
832 if(TRACE_ON(xrender
)) {
837 if(format
== AA_None
) {
838 pitch
= ((gi
.width
+ 31) / 32) * 4;
839 for(i
= 0; i
< gi
.height
; i
++) {
840 line
= (unsigned char*) buf
+ i
* pitch
;
842 for(j
= 0; j
< pitch
* 8; j
++) {
843 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
845 TRACE("%s\n", output
);
848 static const char blks
[] = " .:;!o*#";
852 pitch
= ((gi
.width
+ 3) / 4) * 4;
853 for(i
= 0; i
< gi
.height
; i
++) {
854 line
= (unsigned char*) buf
+ i
* pitch
;
856 for(j
= 0; j
< pitch
; j
++) {
857 str
[0] = blks
[line
[j
] >> 5];
860 TRACE("%s\n", output
);
866 if(formatEntry
->glyphset
) {
867 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
868 unsigned char *byte
= (unsigned char*) buf
, c
;
874 /* magic to flip bit order */
875 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
876 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
877 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
882 else if ( format
!= AA_Grey
&&
883 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
885 unsigned int i
, *data
= (unsigned int *)buf
;
886 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
891 XRenderCompositeText seems to ignore 0x0 glyphs when
892 AA_None, which means we lose the advance width of glyphs
893 like the space. We'll pretend that such glyphs are 1x1
898 gi
.width
= gi
.height
= 1;
901 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
902 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
904 HeapFree(GetProcessHeap(), 0, buf
);
906 formatEntry
->bitmaps
[glyph
] = buf
;
909 formatEntry
->gis
[glyph
] = gi
;
914 static void SharpGlyphMono(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
915 void *bitmap
, XGlyphInfo
*gi
)
917 unsigned char *srcLine
= bitmap
, *src
;
918 unsigned char bits
, bitsMask
;
919 int width
= gi
->width
;
920 int stride
= ((width
+ 31) & ~31) >> 3;
921 int height
= gi
->height
;
925 TRACE("%d, %d\n", x
, y
);
934 bitsMask
= 0x80; /* FreeType is always MSB first */
948 bitsMask
= bitsMask
>> 1;
954 } while (bits
& bitsMask
);
955 XFillRectangle (gdi_display
, physDev
->drawable
,
956 physDev
->gc
, xspan
, y
, lenspan
, 1);
968 bitsMask
= bitsMask
>> 1;
974 } while (!(bits
& bitsMask
));
981 static void SharpGlyphGray(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
982 void *bitmap
, XGlyphInfo
*gi
)
984 unsigned char *srcLine
= bitmap
, *src
, bits
;
985 int width
= gi
->width
;
986 int stride
= ((width
+ 3) & ~3);
987 int height
= gi
->height
;
1012 } while (bits
>= 0x80);
1013 XFillRectangle (gdi_display
, physDev
->drawable
,
1014 physDev
->gc
, xspan
, y
, lenspan
, 1);
1027 } while (bits
< 0x80);
1035 static void ExamineBitfield (DWORD mask
, int *shift
, int *len
)
1040 while ((mask
& 1) == 0)
1046 while ((mask
& 1) == 1)
1055 static DWORD
GetField (DWORD pixel
, int shift
, int len
)
1057 pixel
= pixel
& (((1 << (len
)) - 1) << shift
);
1058 pixel
= pixel
<< (32 - (shift
+ len
)) >> 24;
1061 pixel
|= (pixel
>> len
);
1068 static DWORD
PutField (DWORD pixel
, int shift
, int len
)
1070 shift
= shift
- (8 - len
);
1072 pixel
&= (((1 << len
) - 1) << (8 - len
));
1080 static void SmoothGlyphGray(XImage
*image
, int x
, int y
, void *bitmap
, XGlyphInfo
*gi
,
1086 BYTE
*maskLine
, *mask
, m
;
1091 BYTE src_r
, src_g
, src_b
;
1096 height
= gi
->height
;
1099 maskStride
= (width
+ 3) & ~3;
1101 ExamineBitfield (image
->red_mask
, &r_shift
, &r_len
);
1102 ExamineBitfield (image
->green_mask
, &g_shift
, &g_len
);
1103 ExamineBitfield (image
->blue_mask
, &b_shift
, &b_len
);
1105 src_r
= GetField(color
, r_shift
, r_len
);
1106 src_g
= GetField(color
, g_shift
, g_len
);
1107 src_b
= GetField(color
, b_shift
, b_len
);
1109 for(; height
--; y
++)
1112 maskLine
+= maskStride
;
1117 if(y
>= image
->height
) break;
1121 if(tx
>= image
->width
) break;
1124 if(tx
< 0) continue;
1127 XPutPixel (image
, tx
, y
, color
);
1132 pixel
= XGetPixel (image
, tx
, y
);
1134 r
= GetField(pixel
, r_shift
, r_len
);
1135 r
= ((BYTE
)~m
* (WORD
)r
+ (BYTE
)m
* (WORD
)src_r
) >> 8;
1136 g
= GetField(pixel
, g_shift
, g_len
);
1137 g
= ((BYTE
)~m
* (WORD
)g
+ (BYTE
)m
* (WORD
)src_g
) >> 8;
1138 b
= GetField(pixel
, b_shift
, b_len
);
1139 b
= ((BYTE
)~m
* (WORD
)b
+ (BYTE
)m
* (WORD
)src_b
) >> 8;
1141 pixel
= (PutField (r
, r_shift
, r_len
) |
1142 PutField (g
, g_shift
, g_len
) |
1143 PutField (b
, b_shift
, b_len
));
1144 XPutPixel (image
, tx
, y
, pixel
);
1150 /*************************************************************
1153 * Returns an appropriate Picture for tiling the text colour.
1154 * Call and use result within the xrender_cs
1156 static Picture
get_tile_pict(enum drawable_depth_type type
, int text_pixel
)
1166 tile
= &tiles
[type
];
1170 XRenderPictureAttributes pa
;
1173 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_formats
[type
]->depth
);
1175 pa
.repeat
= RepeatNormal
;
1176 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_formats
[type
], CPRepeat
, &pa
);
1177 wine_tsx11_unlock();
1179 /* init current_color to something different from text_pixel */
1180 tile
->current_color
= ~text_pixel
;
1182 if(type
== mono_drawable
)
1184 /* for a 1bpp bitmap we always need a 1 in the tile */
1185 col
.red
= col
.green
= col
.blue
= 0;
1188 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1189 wine_tsx11_unlock();
1193 if(text_pixel
!= tile
->current_color
&& type
== color_drawable
)
1195 /* Map 0 -- 0xff onto 0 -- 0xffff */
1200 ExamineBitfield (visual
->red_mask
, &r_shift
, &r_len
);
1201 ExamineBitfield (visual
->green_mask
, &g_shift
, &g_len
);
1202 ExamineBitfield (visual
->blue_mask
, &b_shift
, &b_len
);
1204 col
.red
= GetField(text_pixel
, r_shift
, r_len
);
1205 col
.red
|= col
.red
<< 8;
1206 col
.green
= GetField(text_pixel
, g_shift
, g_len
);
1207 col
.green
|= col
.green
<< 8;
1208 col
.blue
= GetField(text_pixel
, b_shift
, b_len
);
1209 col
.blue
|= col
.blue
<< 8;
1213 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1214 wine_tsx11_unlock();
1215 tile
->current_color
= text_pixel
;
1220 static int XRenderErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
1225 /***********************************************************************
1226 * X11DRV_XRender_ExtTextOut
1228 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1229 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1234 gsCacheEntry
*entry
;
1235 gsCacheEntryFormat
*formatEntry
;
1237 HDC hdc
= physDev
->hdc
;
1238 int textPixel
, backgroundPixel
;
1239 HRGN saved_region
= 0;
1240 BOOL disable_antialias
= FALSE
;
1241 AA_Type aa_type
= AA_None
;
1244 double cosEsc
, sinEsc
;
1246 enum drawable_depth_type depth_type
= (physDev
->depth
== 1) ? mono_drawable
: color_drawable
;
1247 Picture tile_pict
= 0;
1249 /* Do we need to disable antialiasing because of palette mode? */
1250 if( !physDev
->bitmap
|| GetObjectW( physDev
->bitmap
->hbitmap
, sizeof(bmp
), &bmp
) != sizeof(bmp
) ) {
1251 TRACE("bitmap is not a DIB\n");
1253 else if (bmp
.dsBmih
.biBitCount
<= 8) {
1254 TRACE("Disabling antialiasing\n");
1255 disable_antialias
= TRUE
;
1258 xgcval
.function
= GXcopy
;
1259 xgcval
.background
= physDev
->backgroundPixel
;
1260 xgcval
.fill_style
= FillSolid
;
1262 XChangeGC( gdi_display
, physDev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1263 wine_tsx11_unlock();
1265 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
);
1267 if(physDev
->depth
== 1) {
1268 if((physDev
->textPixel
& 0xffffff) == 0) {
1270 backgroundPixel
= 1;
1273 backgroundPixel
= 0;
1276 textPixel
= physDev
->textPixel
;
1277 backgroundPixel
= physDev
->backgroundPixel
;
1280 if(flags
& ETO_OPAQUE
)
1283 XSetForeground( gdi_display
, physDev
->gc
, backgroundPixel
);
1284 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1285 physDev
->dc_rect
.left
+ lprect
->left
, physDev
->dc_rect
.top
+ lprect
->top
,
1286 lprect
->right
- lprect
->left
, lprect
->bottom
- lprect
->top
);
1287 wine_tsx11_unlock();
1297 GetObjectW(GetCurrentObject(physDev
->hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
1298 if(lf
.lfEscapement
!= 0) {
1299 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
1300 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
1306 if (flags
& ETO_CLIPPED
)
1310 clip_region
= CreateRectRgnIndirect( lprect
);
1311 /* make a copy of the current device region */
1312 saved_region
= CreateRectRgn( 0, 0, 0, 0 );
1313 CombineRgn( saved_region
, physDev
->region
, 0, RGN_COPY
);
1314 X11DRV_SetDeviceClipping( physDev
, saved_region
, clip_region
);
1315 DeleteObject( clip_region
);
1318 if(X11DRV_XRender_Installed
) {
1319 if(!physDev
->xrender
->pict
) {
1320 XRenderPictureAttributes pa
;
1321 pa
.subwindow_mode
= IncludeInferiors
;
1324 physDev
->xrender
->pict
= pXRenderCreatePicture(gdi_display
,
1326 pict_formats
[depth_type
],
1327 CPSubwindowMode
, &pa
);
1328 wine_tsx11_unlock();
1330 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1331 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1333 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1334 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1337 if ((data
= X11DRV_GetRegionData( physDev
->region
, 0 )))
1340 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
1341 physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
1342 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
1343 wine_tsx11_unlock();
1344 HeapFree( GetProcessHeap(), 0, data
);
1348 EnterCriticalSection(&xrender_cs
);
1350 entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1351 if( disable_antialias
== FALSE
)
1352 aa_type
= entry
->aa_default
;
1353 formatEntry
= entry
->format
[aa_type
];
1355 for(idx
= 0; idx
< count
; idx
++) {
1356 if( !formatEntry
) {
1357 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1358 /* re-evaluate antialias since aa_default may have changed */
1359 if( disable_antialias
== FALSE
)
1360 aa_type
= entry
->aa_default
;
1361 formatEntry
= entry
->format
[aa_type
];
1362 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1363 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1368 WARN("could not upload requested glyphs\n");
1369 LeaveCriticalSection(&xrender_cs
);
1373 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1374 physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1376 if(X11DRV_XRender_Installed
)
1378 XGlyphElt16
*elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1380 POINT desired
, current
;
1381 int render_op
= PictOpOver
;
1383 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1384 So we pass zeros to the function and move to our starting position using the first
1385 element of the elts array. */
1387 desired
.x
= physDev
->dc_rect
.left
+ x
;
1388 desired
.y
= physDev
->dc_rect
.top
+ y
;
1389 current
.x
= current
.y
= 0;
1391 tile_pict
= get_tile_pict(depth_type
, physDev
->textPixel
);
1393 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1395 if((depth_type
== mono_drawable
) && (textPixel
== 0))
1396 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1398 for(idx
= 0; idx
< count
; idx
++)
1400 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1401 elts
[idx
].chars
= wstr
+ idx
;
1402 elts
[idx
].nchars
= 1;
1403 elts
[idx
].xOff
= desired
.x
- current
.x
;
1404 elts
[idx
].yOff
= desired
.y
- current
.y
;
1406 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1407 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1411 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1412 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1416 offset
+= lpDx
[idx
];
1417 desired
.x
= physDev
->dc_rect
.left
+ x
+ offset
* cosEsc
;
1418 desired
.y
= physDev
->dc_rect
.top
+ y
- offset
* sinEsc
;
1422 pXRenderCompositeText16(gdi_display
, render_op
,
1424 physDev
->xrender
->pict
,
1425 formatEntry
->font_format
,
1426 0, 0, 0, 0, elts
, count
);
1427 wine_tsx11_unlock();
1428 HeapFree(GetProcessHeap(), 0, elts
);
1430 INT offset
= 0, xoff
= 0, yoff
= 0;
1432 XSetForeground( gdi_display
, physDev
->gc
, textPixel
);
1434 if(aa_type
== AA_None
|| physDev
->depth
== 1)
1436 void (* sharp_glyph_fn
)(X11DRV_PDEVICE
*, INT
, INT
, void *, XGlyphInfo
*);
1438 if(aa_type
== AA_None
)
1439 sharp_glyph_fn
= SharpGlyphMono
;
1441 sharp_glyph_fn
= SharpGlyphGray
;
1443 for(idx
= 0; idx
< count
; idx
++) {
1444 sharp_glyph_fn(physDev
, physDev
->dc_rect
.left
+ x
+ xoff
,
1445 physDev
->dc_rect
.top
+ y
+ yoff
,
1446 formatEntry
->bitmaps
[wstr
[idx
]],
1447 &formatEntry
->gis
[wstr
[idx
]]);
1449 offset
+= lpDx
[idx
];
1450 xoff
= offset
* cosEsc
;
1451 yoff
= offset
* -sinEsc
;
1453 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1454 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1459 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
1460 RECT extents
= {0, 0, 0, 0};
1462 int w
= physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
;
1463 int h
= physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
;
1465 TRACE("drawable %dx%d\n", w
, h
);
1467 for(idx
= 0; idx
< count
; idx
++) {
1468 if(extents
.left
> cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
)
1469 extents
.left
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
;
1470 if(extents
.top
> cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
)
1471 extents
.top
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
;
1472 if(extents
.right
< cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
)
1473 extents
.right
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
;
1474 if(extents
.bottom
< cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
)
1475 extents
.bottom
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
;
1477 offset
+= lpDx
[idx
];
1478 cur
.x
= offset
* cosEsc
;
1479 cur
.y
= offset
* -sinEsc
;
1481 cur
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1482 cur
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1485 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents
.left
, extents
.top
,
1486 extents
.right
, extents
.bottom
, physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1488 if(physDev
->dc_rect
.left
+ x
+ extents
.left
>= 0) {
1489 image_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1493 image_off_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1495 if(physDev
->dc_rect
.top
+ y
+ extents
.top
>= 0) {
1496 image_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1500 image_off_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1502 if(physDev
->dc_rect
.left
+ x
+ extents
.right
< w
)
1503 image_w
= physDev
->dc_rect
.left
+ x
+ extents
.right
- image_x
;
1505 image_w
= w
- image_x
;
1506 if(physDev
->dc_rect
.top
+ y
+ extents
.bottom
< h
)
1507 image_h
= physDev
->dc_rect
.top
+ y
+ extents
.bottom
- image_y
;
1509 image_h
= h
- image_y
;
1511 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
1513 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1514 image
= XGetImage(gdi_display
, physDev
->drawable
,
1515 image_x
, image_y
, image_w
, image_h
,
1516 AllPlanes
, ZPixmap
);
1517 X11DRV_check_error();
1519 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1520 gdi_display
, (int)physDev
->drawable
, image_x
, image_y
,
1521 image_w
, image_h
, AllPlanes
, ZPixmap
,
1522 physDev
->depth
, image
);
1524 Pixmap xpm
= XCreatePixmap(gdi_display
, root_window
, image_w
, image_h
,
1529 gcv
.graphics_exposures
= False
;
1530 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1531 XCopyArea(gdi_display
, physDev
->drawable
, xpm
, gc
, image_x
, image_y
,
1532 image_w
, image_h
, 0, 0);
1533 XFreeGC(gdi_display
, gc
);
1534 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1535 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
1537 X11DRV_check_error();
1538 XFreePixmap(gdi_display
, xpm
);
1540 if(!image
) goto no_image
;
1542 image
->red_mask
= visual
->red_mask
;
1543 image
->green_mask
= visual
->green_mask
;
1544 image
->blue_mask
= visual
->blue_mask
;
1546 offset
= xoff
= yoff
= 0;
1547 for(idx
= 0; idx
< count
; idx
++) {
1548 SmoothGlyphGray(image
, xoff
+ image_off_x
- extents
.left
,
1549 yoff
+ image_off_y
- extents
.top
,
1550 formatEntry
->bitmaps
[wstr
[idx
]],
1551 &formatEntry
->gis
[wstr
[idx
]],
1552 physDev
->textPixel
);
1554 offset
+= lpDx
[idx
];
1555 xoff
= offset
* cosEsc
;
1556 yoff
= offset
* -sinEsc
;
1558 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1559 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1562 XPutImage(gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
1563 image_x
, image_y
, image_w
, image_h
);
1564 XDestroyImage(image
);
1567 wine_tsx11_unlock();
1569 LeaveCriticalSection(&xrender_cs
);
1571 if (flags
& ETO_CLIPPED
)
1573 /* restore the device region */
1574 X11DRV_SetDeviceClipping( physDev
, saved_region
, 0 );
1575 DeleteObject( saved_region
);
1581 X11DRV_UnlockDIBSection( physDev
, TRUE
);
1585 /******************************************************************************
1586 * AlphaBlend (x11drv.@)
1588 BOOL CDECL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1589 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1590 BLENDFUNCTION blendfn
)
1592 XRenderPictureAttributes pa
;
1593 XRenderPictFormat
*src_format
;
1594 XRenderPictFormat argb32_templ
= {
1596 PictTypeDirect
, /* type */
1599 16, /* direct.red */
1600 0xff, /* direct.redMask */
1601 8, /* direct.green */
1602 0xff, /* direct.greenMask */
1603 0, /* direct.blue */
1604 0xff, /* direct.blueMask */
1605 24, /* direct.alpha */
1606 0xff, /* direct.alphaMask */
1610 unsigned long argb32_templ_mask
=
1616 PictFormatGreenMask
|
1618 PictFormatBlueMask
|
1620 PictFormatAlphaMask
;
1622 Picture dst_pict
, src_pict
;
1628 DWORD
*dstbits
, *data
;
1631 BOOL top_down
= FALSE
;
1633 enum drawable_depth_type dst_depth_type
= (devDst
->depth
== 1) ? mono_drawable
: color_drawable
;
1636 if(!X11DRV_XRender_Installed
) {
1637 FIXME("Unable to AlphaBlend without Xrender\n");
1642 pts
[1].x
= xDst
+ widthDst
;
1643 pts
[1].y
= yDst
+ heightDst
;
1644 LPtoDP(devDst
->hdc
, pts
, 2);
1647 widthDst
= pts
[1].x
- pts
[0].x
;
1648 heightDst
= pts
[1].y
- pts
[0].y
;
1652 pts
[1].x
= xSrc
+ widthSrc
;
1653 pts
[1].y
= ySrc
+ heightSrc
;
1654 LPtoDP(devSrc
->hdc
, pts
, 2);
1657 widthSrc
= pts
[1].x
- pts
[0].x
;
1658 heightSrc
= pts
[1].y
- pts
[0].y
;
1659 if (!widthDst
|| !heightDst
|| !widthSrc
|| !heightSrc
) return TRUE
;
1661 /* If the source is a 1x1 bitmap, tiling is equivalent to stretching, but
1662 tiling is much faster. Therefore, we do no stretching in this case. */
1663 repeat_src
= widthSrc
== 1 && heightSrc
== 1;
1665 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1666 if((widthDst
!= widthSrc
|| heightDst
!= heightSrc
) && !repeat_src
)
1668 if(!pXRenderSetPictureTransform
&& !repeat_src
)
1671 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1675 if (!devSrc
->bitmap
|| GetObjectW( devSrc
->bitmap
->hbitmap
, sizeof(dib
), &dib
) != sizeof(dib
))
1677 static BOOL out
= FALSE
;
1680 FIXME("not a dibsection\n");
1686 if (xSrc
< 0 || ySrc
< 0 || widthSrc
< 0 || heightSrc
< 0 || xSrc
+ widthSrc
> dib
.dsBmih
.biWidth
1687 || ySrc
+ heightSrc
> abs(dib
.dsBmih
.biHeight
))
1689 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc
, ySrc
, widthSrc
, heightSrc
);
1690 SetLastError(ERROR_INVALID_PARAMETER
);
1694 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && blendfn
.SourceConstantAlpha
!= 0xff)
1695 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn
.SourceConstantAlpha
);
1697 if(dib
.dsBm
.bmBitsPixel
!= 32) {
1698 FIXME("not a 32 bpp dibsection\n");
1701 dstbits
= data
= HeapAlloc(GetProcessHeap(), 0, heightSrc
* widthSrc
* 4);
1703 if(dib
.dsBmih
.biHeight
< 0) { /* top-down dib */
1705 dstbits
+= widthSrc
* (heightSrc
- 1);
1707 y
= y2
+ heightSrc
- 1;
1711 y
= dib
.dsBmih
.biHeight
- ySrc
- 1;
1712 y2
= y
- heightSrc
+ 1;
1715 if (blendfn
.AlphaFormat
& AC_SRC_ALPHA
)
1719 memcpy(dstbits
, (char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
+ xSrc
* 4,
1721 dstbits
+= (top_down
? -1 : 1) * widthSrc
;
1726 DWORD source_alpha
= (DWORD
)blendfn
.SourceConstantAlpha
<< 24;
1731 DWORD
*srcbits
= (DWORD
*)((char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
) + xSrc
;
1732 for (x
= 0; x
< widthSrc
; x
++)
1734 DWORD argb
= *srcbits
++;
1735 argb
= (argb
& 0xffffff) | source_alpha
;
1738 if (top_down
) /* we traversed the row forward so we should go back by two rows */
1739 dstbits
-= 2 * widthSrc
;
1744 rgndata
= X11DRV_GetRegionData( devDst
->region
, 0 );
1747 image
= XCreateImage(gdi_display
, visual
, 32, ZPixmap
, 0,
1748 (char*) data
, widthSrc
, heightSrc
, 32, widthSrc
* 4);
1751 Avoid using XRenderFindStandardFormat as older libraries don't have it
1752 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1754 src_format
= pXRenderFindFormat(gdi_display
, argb32_templ_mask
, &argb32_templ
, 0);
1756 TRACE("src_format %p\n", src_format
);
1758 pa
.subwindow_mode
= IncludeInferiors
;
1759 pa
.repeat
= repeat_src
? RepeatNormal
: RepeatNone
;
1761 /* FIXME use devDst->xrender->pict ? */
1762 dst_pict
= pXRenderCreatePicture(gdi_display
,
1764 pict_formats
[dst_depth_type
],
1765 CPSubwindowMode
, &pa
);
1766 TRACE("dst_pict %08lx\n", dst_pict
);
1767 TRACE("src_drawable = %08lx\n", devSrc
->drawable
);
1768 xpm
= XCreatePixmap(gdi_display
,
1770 widthSrc
, heightSrc
, 32);
1771 gcv
.graphics_exposures
= False
;
1772 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1773 TRACE("xpm = %08lx\n", xpm
);
1774 XPutImage(gdi_display
, xpm
, gc
, image
, 0, 0, 0, 0, widthSrc
, heightSrc
);
1776 src_pict
= pXRenderCreatePicture(gdi_display
,
1778 CPSubwindowMode
|CPRepeat
, &pa
);
1779 TRACE("src_pict %08lx\n", src_pict
);
1783 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
,
1784 devDst
->dc_rect
.left
, devDst
->dc_rect
.top
,
1785 (XRectangle
*)rgndata
->Buffer
,
1786 rgndata
->rdh
.nCount
);
1787 HeapFree( GetProcessHeap(), 0, rgndata
);
1790 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1791 if(!repeat_src
&& (widthDst
!= widthSrc
|| heightDst
!= heightSrc
)) {
1792 double xscale
= widthSrc
/(double)widthDst
;
1793 double yscale
= heightSrc
/(double)heightDst
;
1794 XTransform xform
= {{
1795 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(0) },
1796 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(0) },
1797 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1799 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
1802 pXRenderComposite(gdi_display
, PictOpOver
, src_pict
, 0, dst_pict
,
1804 xDst
+ devDst
->dc_rect
.left
, yDst
+ devDst
->dc_rect
.top
, widthDst
, heightDst
);
1807 pXRenderFreePicture(gdi_display
, src_pict
);
1808 XFreePixmap(gdi_display
, xpm
);
1809 XFreeGC(gdi_display
, gc
);
1810 pXRenderFreePicture(gdi_display
, dst_pict
);
1812 XDestroyImage(image
);
1814 wine_tsx11_unlock();
1815 HeapFree(GetProcessHeap(), 0, data
);
1819 #else /* SONAME_LIBXRENDER */
1821 void X11DRV_XRender_Init(void)
1823 TRACE("XRender support not compiled in.\n");
1827 void X11DRV_XRender_Finalize(void)
1831 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
1837 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
1843 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1844 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1851 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
1857 /******************************************************************************
1858 * AlphaBlend (x11drv.@)
1860 BOOL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1861 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1862 BLENDFUNCTION blendfn
)
1864 FIXME("not supported - XRENDER headers were missing at compile time\n");
1868 #endif /* SONAME_LIBXRENDER */