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)
145 #define NATIVE_BYTE_ORDER MSBFirst
147 #define get_be_word(x) RtlUshortByteSwap(x)
148 #define NATIVE_BYTE_ORDER LSBFirst
151 /***********************************************************************
152 * X11DRV_XRender_Init
154 * Let's see if our XServer has the extension available
157 void X11DRV_XRender_Init(void)
160 XRenderPictFormat pf
;
162 if (client_side_with_render
&&
163 wine_dlopen(SONAME_LIBX11
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
164 wine_dlopen(SONAME_LIBXEXT
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
165 (xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0)))
168 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
169 LOAD_FUNCPTR(XRenderAddGlyphs
)
170 LOAD_FUNCPTR(XRenderComposite
)
171 LOAD_FUNCPTR(XRenderCompositeString8
)
172 LOAD_FUNCPTR(XRenderCompositeString16
)
173 LOAD_FUNCPTR(XRenderCompositeString32
)
174 LOAD_FUNCPTR(XRenderCompositeText16
)
175 LOAD_FUNCPTR(XRenderCreateGlyphSet
)
176 LOAD_FUNCPTR(XRenderCreatePicture
)
177 LOAD_FUNCPTR(XRenderFillRectangle
)
178 LOAD_FUNCPTR(XRenderFindFormat
)
179 LOAD_FUNCPTR(XRenderFindVisualFormat
)
180 LOAD_FUNCPTR(XRenderFreeGlyphSet
)
181 LOAD_FUNCPTR(XRenderFreePicture
)
182 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
)
183 LOAD_FUNCPTR(XRenderQueryExtension
)
185 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
186 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
187 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
)
188 #undef LOAD_OPTIONAL_FUNCPTR
193 if(pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
)) {
194 X11DRV_XRender_Installed
= TRUE
;
195 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
196 pict_formats
[color_drawable
] = pXRenderFindVisualFormat(gdi_display
, visual
);
197 if(!pict_formats
[color_drawable
])
199 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
200 if (visual
->class == DirectColor
)
203 if (XMatchVisualInfo( gdi_display
, DefaultScreen(gdi_display
),
204 screen_depth
, TrueColor
, &info
))
206 pict_formats
[color_drawable
] = pXRenderFindVisualFormat(gdi_display
, info
.visual
);
207 if (pict_formats
[color_drawable
]) visual
= info
.visual
;
211 if(!pict_formats
[color_drawable
]) /* This fails in buggy versions of libXrender.so */
215 "Wine has detected that you probably have a buggy version\n"
216 "of libXrender.so . Because of this client side font rendering\n"
217 "will be disabled. Please upgrade this library.\n");
218 X11DRV_XRender_Installed
= FALSE
;
221 pf
.type
= PictTypeDirect
;
224 pf
.direct
.alphaMask
= 1;
225 pict_formats
[mono_drawable
] = pXRenderFindFormat(gdi_display
, PictFormatType
|
226 PictFormatDepth
| PictFormatAlpha
|
227 PictFormatAlphaMask
, &pf
, 0);
228 if(!pict_formats
[mono_drawable
]) {
229 ERR("mono_format == NULL?\n");
230 X11DRV_XRender_Installed
= FALSE
;
232 if (!visual
->red_mask
|| !visual
->green_mask
|| !visual
->blue_mask
) {
233 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
234 X11DRV_XRender_Installed
= FALSE
;
241 if(X11DRV_XRender_Installed
|| client_side_with_core
)
243 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
244 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
246 glyphsetCacheSize
= INIT_CACHE_SIZE
;
248 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
249 glyphsetCache
[i
].next
= i
+ 1;
250 glyphsetCache
[i
].count
= -1;
252 glyphsetCache
[i
-1].next
= -1;
253 using_client_side_fonts
= 1;
255 if(!X11DRV_XRender_Installed
) {
256 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
257 if(screen_depth
<= 8 || !client_side_antialias_with_core
)
260 if(screen_depth
<= 8 || !client_side_antialias_with_render
)
264 else TRACE("Using X11 core fonts\n");
267 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
269 if(p1
->hash
!= p2
->hash
) return TRUE
;
270 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
271 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
272 return strcmpW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
276 static void walk_cache(void)
280 EnterCriticalSection(&xrender_cs
);
281 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
282 TRACE("item %d\n", i
);
283 LeaveCriticalSection(&xrender_cs
);
287 static int LookupEntry(LFANDSIZE
*plfsz
)
291 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
293 if(glyphsetCache
[i
].count
== -1) { /* reached free list so stop */
298 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
299 glyphsetCache
[i
].count
++;
301 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
302 glyphsetCache
[i
].next
= mru
;
305 TRACE("found font in cache %d\n", i
);
310 TRACE("font not in cache\n");
314 static void FreeEntry(int entry
)
318 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
319 gsCacheEntryFormat
* formatEntry
;
321 if( !glyphsetCache
[entry
].format
[format
] )
324 formatEntry
= glyphsetCache
[entry
].format
[format
];
326 if(formatEntry
->glyphset
) {
328 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
330 formatEntry
->glyphset
= 0;
332 if(formatEntry
->nrealized
) {
333 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
334 formatEntry
->realized
= NULL
;
335 if(formatEntry
->bitmaps
) {
336 for(i
= 0; i
< formatEntry
->nrealized
; i
++)
337 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
[i
]);
338 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
);
339 formatEntry
->bitmaps
= NULL
;
341 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
342 formatEntry
->gis
= NULL
;
343 formatEntry
->nrealized
= 0;
346 HeapFree(GetProcessHeap(), 0, formatEntry
);
347 glyphsetCache
[entry
].format
[format
] = NULL
;
351 static int AllocEntry(void)
353 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
356 assert(glyphsetCache
[lastfree
].count
== -1);
357 glyphsetCache
[lastfree
].count
= 1;
359 lastfree
= glyphsetCache
[lastfree
].next
;
361 glyphsetCache
[best
].next
= mru
;
364 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
368 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
369 if(glyphsetCache
[i
].count
== 0) {
377 TRACE("freeing unused glyphset at cache %d\n", best
);
379 glyphsetCache
[best
].count
= 1;
381 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
382 glyphsetCache
[best
].next
= mru
;
390 TRACE("Growing cache\n");
393 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
395 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
396 * sizeof(*glyphsetCache
));
398 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
399 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
400 * sizeof(*glyphsetCache
));
402 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
404 glyphsetCache
[i
].next
= i
+ 1;
405 glyphsetCache
[i
].count
= -1;
407 glyphsetCache
[i
-1].next
= -1;
408 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
410 lastfree
= glyphsetCache
[best
].next
;
411 glyphsetCache
[best
].count
= 1;
412 glyphsetCache
[best
].next
= mru
;
414 TRACE("new free cache slot at %d\n", mru
);
418 static BOOL
get_gasp_flags(X11DRV_PDEVICE
*physDev
, WORD
*flags
)
428 size
= GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, NULL
, 0);
429 if(size
== GDI_ERROR
)
432 gasp
= buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
433 GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, gasp
, size
);
435 GetTextMetricsW(physDev
->hdc
, &tm
);
436 ppem
= abs(X11DRV_YWStoDS(physDev
, tm
.tmAscent
+ tm
.tmDescent
- tm
.tmInternalLeading
));
439 num_recs
= get_be_word(*gasp
);
443 *flags
= get_be_word(*(gasp
+ 1));
444 if(ppem
<= get_be_word(*gasp
))
448 TRACE("got flags %04x for ppem %d\n", *flags
, ppem
);
450 HeapFree(GetProcessHeap(), 0, buffer
);
454 static AA_Type
get_antialias_type( X11DRV_PDEVICE
*physDev
, BOOL subpixel
, BOOL hinter
)
458 UINT font_smoothing_type
, font_smoothing_orientation
;
460 if (X11DRV_XRender_Installed
&& subpixel
&&
461 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE
, 0, &font_smoothing_type
, 0) &&
462 font_smoothing_type
== FE_FONTSMOOTHINGCLEARTYPE
)
464 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION
, 0,
465 &font_smoothing_orientation
, 0) &&
466 font_smoothing_orientation
== FE_FONTSMOOTHINGORIENTATIONBGR
)
473 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
474 But, Wine's subpixel rendering can support the portrait mode.
477 else if (!hinter
|| !get_gasp_flags(physDev
, &flags
) || flags
& GASP_DOGRAY
)
485 static int GetCacheEntry(X11DRV_PDEVICE
*physDev
, LFANDSIZE
*plfsz
)
490 static int hinter
= -1;
491 static int subpixel
= -1;
494 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
497 entry
= glyphsetCache
+ ret
;
498 entry
->lfsz
= *plfsz
;
499 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
500 assert( !entry
->format
[format
] );
503 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
505 if(hinter
== -1 || subpixel
== -1)
507 RASTERIZER_STATUS status
;
508 GetRasterizerCaps(&status
, sizeof(status
));
509 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
510 subpixel
= status
.wFlags
& WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
513 switch (plfsz
->lf
.lfQuality
)
515 case ANTIALIASED_QUALITY
:
516 entry
->aa_default
= get_antialias_type( physDev
, FALSE
, hinter
);
518 case CLEARTYPE_QUALITY
:
519 case CLEARTYPE_NATURAL_QUALITY
:
520 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
522 case DEFAULT_QUALITY
:
526 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING
, 0, &font_smoothing
, 0) &&
529 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
532 entry
->aa_default
= AA_None
;
537 entry
->aa_default
= AA_None
;
542 static void dec_ref_cache(int index
)
545 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
546 assert(glyphsetCache
[index
].count
> 0);
547 glyphsetCache
[index
].count
--;
550 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
552 DWORD hash
= 0, *ptr
;
555 hash
^= plfsz
->devsize
.cx
;
556 hash
^= plfsz
->devsize
.cy
;
557 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
559 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
560 WCHAR
*pwc
= (WCHAR
*)ptr
;
570 /***********************************************************************
571 * X11DRV_XRender_Finalize
573 void X11DRV_XRender_Finalize(void)
577 EnterCriticalSection(&xrender_cs
);
578 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
580 LeaveCriticalSection(&xrender_cs
);
584 /***********************************************************************
585 * X11DRV_XRender_SelectFont
587 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
591 GetObjectW(hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
592 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
593 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
594 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
595 lfsz
.devsize
.cx
= X11DRV_XWStoDS( physDev
, lfsz
.lf
.lfWidth
);
596 lfsz
.devsize
.cy
= X11DRV_YWStoDS( physDev
, lfsz
.lf
.lfHeight
);
597 lfsz_calc_hash(&lfsz
);
599 EnterCriticalSection(&xrender_cs
);
600 if(!physDev
->xrender
) {
601 physDev
->xrender
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
602 sizeof(*physDev
->xrender
));
603 physDev
->xrender
->cache_index
= -1;
605 else if(physDev
->xrender
->cache_index
!= -1)
606 dec_ref_cache(physDev
->xrender
->cache_index
);
607 physDev
->xrender
->cache_index
= GetCacheEntry(physDev
, &lfsz
);
608 LeaveCriticalSection(&xrender_cs
);
612 /***********************************************************************
613 * X11DRV_XRender_DeleteDC
615 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
617 X11DRV_XRender_UpdateDrawable(physDev
);
619 EnterCriticalSection(&xrender_cs
);
620 if(physDev
->xrender
->cache_index
!= -1)
621 dec_ref_cache(physDev
->xrender
->cache_index
);
622 LeaveCriticalSection(&xrender_cs
);
624 HeapFree(GetProcessHeap(), 0, physDev
->xrender
);
625 physDev
->xrender
= NULL
;
629 /***********************************************************************
630 * X11DRV_XRender_UpdateDrawable
632 * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
633 * It deletes the pict and tile when the drawable changes.
635 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
639 if(physDev
->xrender
->pict
)
641 TRACE("freeing pict = %lx dc = %p\n", physDev
->xrender
->pict
, physDev
->hdc
);
643 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
644 physDev
->xrender
->pict
= 0;
651 /************************************************************************
654 * Helper to ExtTextOut. Must be called inside xrender_cs
656 static BOOL
UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
, AA_Type format
)
663 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
664 gsCacheEntryFormat
*formatEntry
;
665 UINT ggo_format
= GGO_GLYPH_INDEX
;
666 XRenderPictFormat pf
;
667 unsigned long pf_mask
;
668 static const char zero
[4];
669 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
673 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
676 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
679 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
682 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
685 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
689 ERR("aa = %d - not implemented\n", format
);
691 ggo_format
|= GGO_BITMAP
;
695 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
696 if(buflen
== GDI_ERROR
) {
697 if(format
!= AA_None
) {
699 entry
->aa_default
= AA_None
;
700 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
701 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
703 if(buflen
== GDI_ERROR
) {
704 WARN("GetGlyphOutlineW failed\n");
707 TRACE("Turning off antialiasing for this monochrome font\n");
710 /* If there is nothing for the current type, we create the entry. */
711 if( !entry
->format
[format
] ) {
712 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
714 sizeof(gsCacheEntryFormat
));
716 formatEntry
= entry
->format
[format
];
718 if(formatEntry
->nrealized
<= glyph
) {
719 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
721 if (formatEntry
->realized
)
722 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
724 formatEntry
->realized
,
725 formatEntry
->nrealized
* sizeof(BOOL
));
727 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
729 formatEntry
->nrealized
* sizeof(BOOL
));
731 if(!X11DRV_XRender_Installed
) {
732 if (formatEntry
->bitmaps
)
733 formatEntry
->bitmaps
= HeapReAlloc(GetProcessHeap(),
735 formatEntry
->bitmaps
,
736 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
738 formatEntry
->bitmaps
= HeapAlloc(GetProcessHeap(),
740 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
742 if (formatEntry
->gis
)
743 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
746 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
748 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
750 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
754 if(formatEntry
->glyphset
== 0 && X11DRV_XRender_Installed
) {
757 pf_mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
,
758 pf
.type
= PictTypeDirect
;
761 pf
.direct
.alphaMask
= 0xff;
768 pf_mask
= PictFormatType
| PictFormatDepth
| PictFormatRed
| PictFormatRedMask
|
769 PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
|
770 PictFormatBlueMask
| PictFormatAlpha
| PictFormatAlphaMask
;
771 pf
.type
= PictTypeDirect
;
774 pf
.direct
.redMask
= 0xff;
776 pf
.direct
.greenMask
= 0xff;
778 pf
.direct
.blueMask
= 0xff;
779 pf
.direct
.alpha
= 24;
780 pf
.direct
.alphaMask
= 0xff;
784 ERR("aa = %d - not implemented\n", format
);
786 pf_mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
,
787 pf
.type
= PictTypeDirect
;
790 pf
.direct
.alphaMask
= 1;
795 formatEntry
->font_format
= pXRenderFindFormat(gdi_display
, pf_mask
, &pf
, 0);
796 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
801 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
802 GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
803 formatEntry
->realized
[glyph
] = TRUE
;
805 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
807 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
808 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
810 gi
.width
= gm
.gmBlackBoxX
;
811 gi
.height
= gm
.gmBlackBoxY
;
812 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
813 gi
.y
= gm
.gmptGlyphOrigin
.y
;
814 gi
.xOff
= gm
.gmCellIncX
;
815 gi
.yOff
= gm
.gmCellIncY
;
817 if(TRACE_ON(xrender
)) {
822 if(format
== AA_None
) {
823 pitch
= ((gi
.width
+ 31) / 32) * 4;
824 for(i
= 0; i
< gi
.height
; i
++) {
825 line
= (unsigned char*) buf
+ i
* pitch
;
827 for(j
= 0; j
< pitch
* 8; j
++) {
828 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
830 TRACE("%s\n", output
);
833 static const char blks
[] = " .:;!o*#";
837 pitch
= ((gi
.width
+ 3) / 4) * 4;
838 for(i
= 0; i
< gi
.height
; i
++) {
839 line
= (unsigned char*) buf
+ i
* pitch
;
841 for(j
= 0; j
< pitch
; j
++) {
842 str
[0] = blks
[line
[j
] >> 5];
845 TRACE("%s\n", output
);
851 if(formatEntry
->glyphset
) {
852 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
853 unsigned char *byte
= (unsigned char*) buf
, c
;
859 /* magic to flip bit order */
860 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
861 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
862 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
867 else if ( format
!= AA_Grey
&&
868 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
870 unsigned int i
, *data
= (unsigned int *)buf
;
871 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
876 XRenderCompositeText seems to ignore 0x0 glyphs when
877 AA_None, which means we lose the advance width of glyphs
878 like the space. We'll pretend that such glyphs are 1x1
883 gi
.width
= gi
.height
= 1;
886 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
887 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
889 HeapFree(GetProcessHeap(), 0, buf
);
891 formatEntry
->bitmaps
[glyph
] = buf
;
894 formatEntry
->gis
[glyph
] = gi
;
899 static void SharpGlyphMono(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
900 void *bitmap
, XGlyphInfo
*gi
)
902 unsigned char *srcLine
= bitmap
, *src
;
903 unsigned char bits
, bitsMask
;
904 int width
= gi
->width
;
905 int stride
= ((width
+ 31) & ~31) >> 3;
906 int height
= gi
->height
;
910 TRACE("%d, %d\n", x
, y
);
919 bitsMask
= 0x80; /* FreeType is always MSB first */
933 bitsMask
= bitsMask
>> 1;
939 } while (bits
& bitsMask
);
940 XFillRectangle (gdi_display
, physDev
->drawable
,
941 physDev
->gc
, xspan
, y
, lenspan
, 1);
953 bitsMask
= bitsMask
>> 1;
959 } while (!(bits
& bitsMask
));
966 static void SharpGlyphGray(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
967 void *bitmap
, XGlyphInfo
*gi
)
969 unsigned char *srcLine
= bitmap
, *src
, bits
;
970 int width
= gi
->width
;
971 int stride
= ((width
+ 3) & ~3);
972 int height
= gi
->height
;
997 } while (bits
>= 0x80);
998 XFillRectangle (gdi_display
, physDev
->drawable
,
999 physDev
->gc
, xspan
, y
, lenspan
, 1);
1012 } while (bits
< 0x80);
1020 static void ExamineBitfield (DWORD mask
, int *shift
, int *len
)
1025 while ((mask
& 1) == 0)
1031 while ((mask
& 1) == 1)
1040 static DWORD
GetField (DWORD pixel
, int shift
, int len
)
1042 pixel
= pixel
& (((1 << (len
)) - 1) << shift
);
1043 pixel
= pixel
<< (32 - (shift
+ len
)) >> 24;
1046 pixel
|= (pixel
>> len
);
1053 static DWORD
PutField (DWORD pixel
, int shift
, int len
)
1055 shift
= shift
- (8 - len
);
1057 pixel
&= (((1 << len
) - 1) << (8 - len
));
1065 static void SmoothGlyphGray(XImage
*image
, int x
, int y
, void *bitmap
, XGlyphInfo
*gi
,
1071 BYTE
*maskLine
, *mask
, m
;
1076 BYTE src_r
, src_g
, src_b
;
1081 height
= gi
->height
;
1084 maskStride
= (width
+ 3) & ~3;
1086 ExamineBitfield (image
->red_mask
, &r_shift
, &r_len
);
1087 ExamineBitfield (image
->green_mask
, &g_shift
, &g_len
);
1088 ExamineBitfield (image
->blue_mask
, &b_shift
, &b_len
);
1090 src_r
= GetField(color
, r_shift
, r_len
);
1091 src_g
= GetField(color
, g_shift
, g_len
);
1092 src_b
= GetField(color
, b_shift
, b_len
);
1094 for(; height
--; y
++)
1097 maskLine
+= maskStride
;
1102 if(y
>= image
->height
) break;
1106 if(tx
>= image
->width
) break;
1109 if(tx
< 0) continue;
1112 XPutPixel (image
, tx
, y
, color
);
1117 pixel
= XGetPixel (image
, tx
, y
);
1119 r
= GetField(pixel
, r_shift
, r_len
);
1120 r
= ((BYTE
)~m
* (WORD
)r
+ (BYTE
)m
* (WORD
)src_r
) >> 8;
1121 g
= GetField(pixel
, g_shift
, g_len
);
1122 g
= ((BYTE
)~m
* (WORD
)g
+ (BYTE
)m
* (WORD
)src_g
) >> 8;
1123 b
= GetField(pixel
, b_shift
, b_len
);
1124 b
= ((BYTE
)~m
* (WORD
)b
+ (BYTE
)m
* (WORD
)src_b
) >> 8;
1126 pixel
= (PutField (r
, r_shift
, r_len
) |
1127 PutField (g
, g_shift
, g_len
) |
1128 PutField (b
, b_shift
, b_len
));
1129 XPutPixel (image
, tx
, y
, pixel
);
1135 /*************************************************************
1138 * Returns an appropriate Picture for tiling the text colour.
1139 * Call and use result within the xrender_cs
1141 static Picture
get_tile_pict(enum drawable_depth_type type
, int text_pixel
)
1151 tile
= &tiles
[type
];
1155 XRenderPictureAttributes pa
;
1158 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_formats
[type
]->depth
);
1161 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_formats
[type
], CPRepeat
, &pa
);
1162 wine_tsx11_unlock();
1164 /* init current_color to something different from text_pixel */
1165 tile
->current_color
= ~text_pixel
;
1167 if(type
== mono_drawable
)
1169 /* for a 1bpp bitmap we always need a 1 in the tile */
1170 col
.red
= col
.green
= col
.blue
= 0;
1173 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1174 wine_tsx11_unlock();
1178 if(text_pixel
!= tile
->current_color
&& type
== color_drawable
)
1180 /* Map 0 -- 0xff onto 0 -- 0xffff */
1185 ExamineBitfield (visual
->red_mask
, &r_shift
, &r_len
);
1186 ExamineBitfield (visual
->green_mask
, &g_shift
, &g_len
);
1187 ExamineBitfield (visual
->blue_mask
, &b_shift
, &b_len
);
1189 col
.red
= GetField(text_pixel
, r_shift
, r_len
);
1190 col
.red
|= col
.red
<< 8;
1191 col
.green
= GetField(text_pixel
, g_shift
, g_len
);
1192 col
.green
|= col
.green
<< 8;
1193 col
.blue
= GetField(text_pixel
, b_shift
, b_len
);
1194 col
.blue
|= col
.blue
<< 8;
1198 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1199 wine_tsx11_unlock();
1200 tile
->current_color
= text_pixel
;
1205 static int XRenderErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
1210 /***********************************************************************
1211 * X11DRV_XRender_ExtTextOut
1213 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1214 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1219 gsCacheEntry
*entry
;
1220 gsCacheEntryFormat
*formatEntry
;
1222 HDC hdc
= physDev
->hdc
;
1223 int textPixel
, backgroundPixel
;
1224 HRGN saved_region
= 0;
1225 BOOL disable_antialias
= FALSE
;
1226 AA_Type aa_type
= AA_None
;
1229 double cosEsc
, sinEsc
;
1231 enum drawable_depth_type depth_type
= (physDev
->depth
== 1) ? mono_drawable
: color_drawable
;
1232 Picture tile_pict
= 0;
1234 /* Do we need to disable antialiasing because of palette mode? */
1235 if( !physDev
->bitmap
|| GetObjectW( physDev
->bitmap
->hbitmap
, sizeof(bmp
), &bmp
) != sizeof(bmp
) ) {
1236 TRACE("bitmap is not a DIB\n");
1238 else if (bmp
.dsBmih
.biBitCount
<= 8) {
1239 TRACE("Disabling antialiasing\n");
1240 disable_antialias
= TRUE
;
1243 xgcval
.function
= GXcopy
;
1244 xgcval
.background
= physDev
->backgroundPixel
;
1245 xgcval
.fill_style
= FillSolid
;
1247 XChangeGC( gdi_display
, physDev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1248 wine_tsx11_unlock();
1250 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
);
1252 if(physDev
->depth
== 1) {
1253 if((physDev
->textPixel
& 0xffffff) == 0) {
1255 backgroundPixel
= 1;
1258 backgroundPixel
= 0;
1261 textPixel
= physDev
->textPixel
;
1262 backgroundPixel
= physDev
->backgroundPixel
;
1265 if(flags
& ETO_OPAQUE
)
1268 XSetForeground( gdi_display
, physDev
->gc
, backgroundPixel
);
1269 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1270 physDev
->dc_rect
.left
+ lprect
->left
, physDev
->dc_rect
.top
+ lprect
->top
,
1271 lprect
->right
- lprect
->left
, lprect
->bottom
- lprect
->top
);
1272 wine_tsx11_unlock();
1282 GetObjectW(GetCurrentObject(physDev
->hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
1283 if(lf
.lfEscapement
!= 0) {
1284 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
1285 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
1291 if (flags
& ETO_CLIPPED
)
1295 clip_region
= CreateRectRgnIndirect( lprect
);
1296 /* make a copy of the current device region */
1297 saved_region
= CreateRectRgn( 0, 0, 0, 0 );
1298 CombineRgn( saved_region
, physDev
->region
, 0, RGN_COPY
);
1299 X11DRV_SetDeviceClipping( physDev
, saved_region
, clip_region
);
1300 DeleteObject( clip_region
);
1303 if(X11DRV_XRender_Installed
) {
1304 if(!physDev
->xrender
->pict
) {
1305 XRenderPictureAttributes pa
;
1306 pa
.subwindow_mode
= IncludeInferiors
;
1309 physDev
->xrender
->pict
= pXRenderCreatePicture(gdi_display
,
1311 pict_formats
[depth_type
],
1312 CPSubwindowMode
, &pa
);
1313 wine_tsx11_unlock();
1315 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1316 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1318 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1319 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1322 if ((data
= X11DRV_GetRegionData( physDev
->region
, 0 )))
1325 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
1326 physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
1327 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
1328 wine_tsx11_unlock();
1329 HeapFree( GetProcessHeap(), 0, data
);
1333 EnterCriticalSection(&xrender_cs
);
1335 entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1336 if( disable_antialias
== FALSE
)
1337 aa_type
= entry
->aa_default
;
1338 formatEntry
= entry
->format
[aa_type
];
1340 for(idx
= 0; idx
< count
; idx
++) {
1341 if( !formatEntry
) {
1342 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1343 /* re-evaluate antialias since aa_default may have changed */
1344 if( disable_antialias
== FALSE
)
1345 aa_type
= entry
->aa_default
;
1346 formatEntry
= entry
->format
[aa_type
];
1347 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1348 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1353 WARN("could not upload requested glyphs\n");
1354 LeaveCriticalSection(&xrender_cs
);
1358 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1359 physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1361 if(X11DRV_XRender_Installed
)
1363 XGlyphElt16
*elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1365 POINT desired
, current
;
1366 int render_op
= PictOpOver
;
1368 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1369 So we pass zeros to the function and move to our starting position using the first
1370 element of the elts array. */
1372 desired
.x
= physDev
->dc_rect
.left
+ x
;
1373 desired
.y
= physDev
->dc_rect
.top
+ y
;
1374 current
.x
= current
.y
= 0;
1376 tile_pict
= get_tile_pict(depth_type
, physDev
->textPixel
);
1378 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1380 if((depth_type
== mono_drawable
) && (textPixel
== 0))
1381 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1383 for(idx
= 0; idx
< count
; idx
++)
1385 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1386 elts
[idx
].chars
= wstr
+ idx
;
1387 elts
[idx
].nchars
= 1;
1388 elts
[idx
].xOff
= desired
.x
- current
.x
;
1389 elts
[idx
].yOff
= desired
.y
- current
.y
;
1391 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1392 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1396 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1397 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1401 offset
+= lpDx
[idx
];
1402 desired
.x
= physDev
->dc_rect
.left
+ x
+ offset
* cosEsc
;
1403 desired
.y
= physDev
->dc_rect
.top
+ y
- offset
* sinEsc
;
1407 pXRenderCompositeText16(gdi_display
, render_op
,
1409 physDev
->xrender
->pict
,
1410 formatEntry
->font_format
,
1411 0, 0, 0, 0, elts
, count
);
1412 wine_tsx11_unlock();
1413 HeapFree(GetProcessHeap(), 0, elts
);
1415 INT offset
= 0, xoff
= 0, yoff
= 0;
1417 XSetForeground( gdi_display
, physDev
->gc
, textPixel
);
1419 if(aa_type
== AA_None
|| physDev
->depth
== 1)
1421 void (* sharp_glyph_fn
)(X11DRV_PDEVICE
*, INT
, INT
, void *, XGlyphInfo
*);
1423 if(aa_type
== AA_None
)
1424 sharp_glyph_fn
= SharpGlyphMono
;
1426 sharp_glyph_fn
= SharpGlyphGray
;
1428 for(idx
= 0; idx
< count
; idx
++) {
1429 sharp_glyph_fn(physDev
, physDev
->dc_rect
.left
+ x
+ xoff
,
1430 physDev
->dc_rect
.top
+ y
+ yoff
,
1431 formatEntry
->bitmaps
[wstr
[idx
]],
1432 &formatEntry
->gis
[wstr
[idx
]]);
1434 offset
+= lpDx
[idx
];
1435 xoff
= offset
* cosEsc
;
1436 yoff
= offset
* -sinEsc
;
1438 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1439 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1444 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
1445 RECT extents
= {0, 0, 0, 0};
1447 int w
= physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
;
1448 int h
= physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
;
1450 TRACE("drawable %dx%d\n", w
, h
);
1452 for(idx
= 0; idx
< count
; idx
++) {
1453 if(extents
.left
> cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
)
1454 extents
.left
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
;
1455 if(extents
.top
> cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
)
1456 extents
.top
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
;
1457 if(extents
.right
< cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
)
1458 extents
.right
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
;
1459 if(extents
.bottom
< cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
)
1460 extents
.bottom
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
;
1462 offset
+= lpDx
[idx
];
1463 cur
.x
= offset
* cosEsc
;
1464 cur
.y
= offset
* -sinEsc
;
1466 cur
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1467 cur
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1470 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents
.left
, extents
.top
,
1471 extents
.right
, extents
.bottom
, physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1473 if(physDev
->dc_rect
.left
+ x
+ extents
.left
>= 0) {
1474 image_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1478 image_off_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1480 if(physDev
->dc_rect
.top
+ y
+ extents
.top
>= 0) {
1481 image_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1485 image_off_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1487 if(physDev
->dc_rect
.left
+ x
+ extents
.right
< w
)
1488 image_w
= physDev
->dc_rect
.left
+ x
+ extents
.right
- image_x
;
1490 image_w
= w
- image_x
;
1491 if(physDev
->dc_rect
.top
+ y
+ extents
.bottom
< h
)
1492 image_h
= physDev
->dc_rect
.top
+ y
+ extents
.bottom
- image_y
;
1494 image_h
= h
- image_y
;
1496 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
1498 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1499 image
= XGetImage(gdi_display
, physDev
->drawable
,
1500 image_x
, image_y
, image_w
, image_h
,
1501 AllPlanes
, ZPixmap
);
1502 X11DRV_check_error();
1504 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1505 gdi_display
, (int)physDev
->drawable
, image_x
, image_y
,
1506 image_w
, image_h
, AllPlanes
, ZPixmap
,
1507 physDev
->depth
, image
);
1509 Pixmap xpm
= XCreatePixmap(gdi_display
, root_window
, image_w
, image_h
,
1514 gcv
.graphics_exposures
= False
;
1515 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1516 XCopyArea(gdi_display
, physDev
->drawable
, xpm
, gc
, image_x
, image_y
,
1517 image_w
, image_h
, 0, 0);
1518 XFreeGC(gdi_display
, gc
);
1519 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1520 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
1522 X11DRV_check_error();
1523 XFreePixmap(gdi_display
, xpm
);
1525 if(!image
) goto no_image
;
1527 image
->red_mask
= visual
->red_mask
;
1528 image
->green_mask
= visual
->green_mask
;
1529 image
->blue_mask
= visual
->blue_mask
;
1531 offset
= xoff
= yoff
= 0;
1532 for(idx
= 0; idx
< count
; idx
++) {
1533 SmoothGlyphGray(image
, xoff
+ image_off_x
- extents
.left
,
1534 yoff
+ image_off_y
- extents
.top
,
1535 formatEntry
->bitmaps
[wstr
[idx
]],
1536 &formatEntry
->gis
[wstr
[idx
]],
1537 physDev
->textPixel
);
1539 offset
+= lpDx
[idx
];
1540 xoff
= offset
* cosEsc
;
1541 yoff
= offset
* -sinEsc
;
1543 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1544 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1547 XPutImage(gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
1548 image_x
, image_y
, image_w
, image_h
);
1549 XDestroyImage(image
);
1552 wine_tsx11_unlock();
1554 LeaveCriticalSection(&xrender_cs
);
1556 if (flags
& ETO_CLIPPED
)
1558 /* restore the device region */
1559 X11DRV_SetDeviceClipping( physDev
, saved_region
, 0 );
1560 DeleteObject( saved_region
);
1566 X11DRV_UnlockDIBSection( physDev
, TRUE
);
1570 /******************************************************************************
1571 * AlphaBlend (x11drv.@)
1573 BOOL CDECL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1574 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1575 BLENDFUNCTION blendfn
)
1577 XRenderPictureAttributes pa
;
1578 XRenderPictFormat
*src_format
;
1579 XRenderPictFormat argb32_templ
= {
1581 PictTypeDirect
, /* type */
1584 16, /* direct.red */
1585 0xff, /* direct.redMask */
1586 8, /* direct.green */
1587 0xff, /* direct.greenMask */
1588 0, /* direct.blue */
1589 0xff, /* direct.blueMask */
1590 24, /* direct.alpha */
1591 0xff, /* direct.alphaMask */
1595 unsigned long argb32_templ_mask
=
1601 PictFormatGreenMask
|
1603 PictFormatBlueMask
|
1605 PictFormatAlphaMask
;
1607 Picture dst_pict
, src_pict
;
1613 DWORD
*dstbits
, *data
;
1616 BOOL top_down
= FALSE
;
1618 enum drawable_depth_type dst_depth_type
= (devDst
->depth
== 1) ? mono_drawable
: color_drawable
;
1620 if(!X11DRV_XRender_Installed
) {
1621 FIXME("Unable to AlphaBlend without Xrender\n");
1626 pts
[1].x
= xDst
+ widthDst
;
1627 pts
[1].y
= yDst
+ heightDst
;
1628 LPtoDP(devDst
->hdc
, pts
, 2);
1631 widthDst
= pts
[1].x
- pts
[0].x
;
1632 heightDst
= pts
[1].y
- pts
[0].y
;
1636 pts
[1].x
= xSrc
+ widthSrc
;
1637 pts
[1].y
= ySrc
+ heightSrc
;
1638 LPtoDP(devSrc
->hdc
, pts
, 2);
1641 widthSrc
= pts
[1].x
- pts
[0].x
;
1642 heightSrc
= pts
[1].y
- pts
[0].y
;
1643 if (!widthDst
|| !heightDst
|| !widthSrc
|| !heightSrc
) return TRUE
;
1645 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1646 if(widthDst
!= widthSrc
|| heightDst
!= heightSrc
)
1648 if(!pXRenderSetPictureTransform
)
1651 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1655 if (!devSrc
->bitmap
|| GetObjectW( devSrc
->bitmap
->hbitmap
, sizeof(dib
), &dib
) != sizeof(dib
))
1657 static BOOL out
= FALSE
;
1660 FIXME("not a dibsection\n");
1666 if (xSrc
< 0 || ySrc
< 0 || widthSrc
< 0 || heightSrc
< 0 || xSrc
+ widthSrc
> dib
.dsBmih
.biWidth
1667 || ySrc
+ heightSrc
> abs(dib
.dsBmih
.biHeight
))
1669 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc
, ySrc
, widthSrc
, heightSrc
);
1670 SetLastError(ERROR_INVALID_PARAMETER
);
1674 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && blendfn
.SourceConstantAlpha
!= 0xff)
1675 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn
.SourceConstantAlpha
);
1677 if(dib
.dsBm
.bmBitsPixel
!= 32) {
1678 FIXME("not a 32 bpp dibsection\n");
1681 dstbits
= data
= HeapAlloc(GetProcessHeap(), 0, heightSrc
* widthSrc
* 4);
1683 if(dib
.dsBmih
.biHeight
< 0) { /* top-down dib */
1685 dstbits
+= widthSrc
* (heightSrc
- 1);
1687 y
= y2
+ heightSrc
- 1;
1691 y
= dib
.dsBmih
.biHeight
- ySrc
- 1;
1692 y2
= y
- heightSrc
+ 1;
1695 if (blendfn
.AlphaFormat
& AC_SRC_ALPHA
)
1699 memcpy(dstbits
, (char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
+ xSrc
* 4,
1701 dstbits
+= (top_down
? -1 : 1) * widthSrc
;
1706 DWORD source_alpha
= (DWORD
)blendfn
.SourceConstantAlpha
<< 24;
1711 DWORD
*srcbits
= (DWORD
*)((char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
) + xSrc
;
1712 for (x
= 0; x
< widthSrc
; x
++)
1714 DWORD argb
= *srcbits
++;
1715 argb
= (argb
& 0xffffff) | source_alpha
;
1718 if (top_down
) /* we traversed the row forward so we should go back by two rows */
1719 dstbits
-= 2 * widthSrc
;
1724 rgndata
= X11DRV_GetRegionData( devDst
->region
, 0 );
1727 image
= XCreateImage(gdi_display
, visual
, 32, ZPixmap
, 0,
1728 (char*) data
, widthSrc
, heightSrc
, 32, widthSrc
* 4);
1731 Avoid using XRenderFindStandardFormat as older libraries don't have it
1732 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1734 src_format
= pXRenderFindFormat(gdi_display
, argb32_templ_mask
, &argb32_templ
, 0);
1736 TRACE("src_format %p\n", src_format
);
1738 pa
.subwindow_mode
= IncludeInferiors
;
1740 /* FIXME use devDst->xrender->pict ? */
1741 dst_pict
= pXRenderCreatePicture(gdi_display
,
1743 pict_formats
[dst_depth_type
],
1744 CPSubwindowMode
, &pa
);
1745 TRACE("dst_pict %08lx\n", dst_pict
);
1746 TRACE("src_drawable = %08lx\n", devSrc
->drawable
);
1747 xpm
= XCreatePixmap(gdi_display
,
1749 widthSrc
, heightSrc
, 32);
1750 gcv
.graphics_exposures
= False
;
1751 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1752 TRACE("xpm = %08lx\n", xpm
);
1753 XPutImage(gdi_display
, xpm
, gc
, image
, 0, 0, 0, 0, widthSrc
, heightSrc
);
1755 src_pict
= pXRenderCreatePicture(gdi_display
,
1757 CPSubwindowMode
, &pa
);
1758 TRACE("src_pict %08lx\n", src_pict
);
1762 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
,
1763 devDst
->dc_rect
.left
, devDst
->dc_rect
.top
,
1764 (XRectangle
*)rgndata
->Buffer
,
1765 rgndata
->rdh
.nCount
);
1766 HeapFree( GetProcessHeap(), 0, rgndata
);
1769 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1770 if(widthDst
!= widthSrc
|| heightDst
!= heightSrc
) {
1771 double xscale
= widthSrc
/(double)widthDst
;
1772 double yscale
= heightSrc
/(double)heightDst
;
1773 XTransform xform
= {{
1774 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(0) },
1775 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(0) },
1776 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1778 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
1781 pXRenderComposite(gdi_display
, PictOpOver
, src_pict
, 0, dst_pict
,
1783 xDst
+ devDst
->dc_rect
.left
, yDst
+ devDst
->dc_rect
.top
, widthDst
, heightDst
);
1786 pXRenderFreePicture(gdi_display
, src_pict
);
1787 XFreePixmap(gdi_display
, xpm
);
1788 XFreeGC(gdi_display
, gc
);
1789 pXRenderFreePicture(gdi_display
, dst_pict
);
1791 XDestroyImage(image
);
1793 wine_tsx11_unlock();
1794 HeapFree(GetProcessHeap(), 0, data
);
1798 #else /* SONAME_LIBXRENDER */
1800 void X11DRV_XRender_Init(void)
1802 TRACE("XRender support not compiled in.\n");
1806 void X11DRV_XRender_Finalize(void)
1810 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
1816 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
1822 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1823 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1830 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
1836 /******************************************************************************
1837 * AlphaBlend (x11drv.@)
1839 BOOL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1840 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1841 BLENDFUNCTION blendfn
)
1843 FIXME("not supported - XRENDER headers were missing at compile time\n");
1847 #endif /* SONAME_LIBXRENDER */