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];
58 SIZE devsize
; /* size in device coords */
62 #define INITIAL_REALIZED_BUF_SIZE 128
64 typedef enum { AA_None
= 0, AA_Grey
, AA_RGB
, AA_BGR
, AA_VRGB
, AA_VBGR
, AA_MAXVALUE
} AA_Type
;
69 XRenderPictFormat
*font_format
;
80 gsCacheEntryFormat
* format
[AA_MAXVALUE
];
92 static gsCacheEntry
*glyphsetCache
= NULL
;
93 static DWORD glyphsetCacheSize
= 0;
94 static INT lastfree
= -1;
97 #define INIT_CACHE_SIZE 10
99 static int antialias
= 1;
101 static void *xrender_handle
;
103 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
104 MAKE_FUNCPTR(XRenderAddGlyphs
)
105 MAKE_FUNCPTR(XRenderComposite
)
106 MAKE_FUNCPTR(XRenderCompositeString8
)
107 MAKE_FUNCPTR(XRenderCompositeString16
)
108 MAKE_FUNCPTR(XRenderCompositeString32
)
109 MAKE_FUNCPTR(XRenderCompositeText16
)
110 MAKE_FUNCPTR(XRenderCreateGlyphSet
)
111 MAKE_FUNCPTR(XRenderCreatePicture
)
112 MAKE_FUNCPTR(XRenderFillRectangle
)
113 MAKE_FUNCPTR(XRenderFindFormat
)
114 MAKE_FUNCPTR(XRenderFindVisualFormat
)
115 MAKE_FUNCPTR(XRenderFreeGlyphSet
)
116 MAKE_FUNCPTR(XRenderFreePicture
)
117 MAKE_FUNCPTR(XRenderSetPictureClipRectangles
)
118 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
119 MAKE_FUNCPTR(XRenderSetPictureTransform
)
121 MAKE_FUNCPTR(XRenderQueryExtension
)
124 static CRITICAL_SECTION xrender_cs
;
125 static CRITICAL_SECTION_DEBUG critsect_debug
=
128 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
129 0, 0, { (DWORD_PTR
)(__FILE__
": xrender_cs") }
131 static CRITICAL_SECTION xrender_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
133 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
134 ( ( (ULONG)_x4 << 24 ) | \
135 ( (ULONG)_x3 << 16 ) | \
136 ( (ULONG)_x2 << 8 ) | \
139 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
141 #define GASP_GRIDFIT 0x01
142 #define GASP_DOGRAY 0x02
144 #ifdef WORDS_BIGENDIAN
145 #define get_be_word(x) (x)
146 #define NATIVE_BYTE_ORDER MSBFirst
148 #define get_be_word(x) RtlUshortByteSwap(x)
149 #define NATIVE_BYTE_ORDER LSBFirst
152 /***********************************************************************
153 * X11DRV_XRender_Init
155 * Let's see if our XServer has the extension available
158 void X11DRV_XRender_Init(void)
161 XRenderPictFormat pf
;
163 if (client_side_with_render
&&
164 wine_dlopen(SONAME_LIBX11
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
165 wine_dlopen(SONAME_LIBXEXT
, RTLD_NOW
|RTLD_GLOBAL
, NULL
, 0) &&
166 (xrender_handle
= wine_dlopen(SONAME_LIBXRENDER
, RTLD_NOW
, NULL
, 0)))
169 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
170 LOAD_FUNCPTR(XRenderAddGlyphs
)
171 LOAD_FUNCPTR(XRenderComposite
)
172 LOAD_FUNCPTR(XRenderCompositeString8
)
173 LOAD_FUNCPTR(XRenderCompositeString16
)
174 LOAD_FUNCPTR(XRenderCompositeString32
)
175 LOAD_FUNCPTR(XRenderCompositeText16
)
176 LOAD_FUNCPTR(XRenderCreateGlyphSet
)
177 LOAD_FUNCPTR(XRenderCreatePicture
)
178 LOAD_FUNCPTR(XRenderFillRectangle
)
179 LOAD_FUNCPTR(XRenderFindFormat
)
180 LOAD_FUNCPTR(XRenderFindVisualFormat
)
181 LOAD_FUNCPTR(XRenderFreeGlyphSet
)
182 LOAD_FUNCPTR(XRenderFreePicture
)
183 LOAD_FUNCPTR(XRenderSetPictureClipRectangles
)
184 LOAD_FUNCPTR(XRenderQueryExtension
)
186 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
187 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
188 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform
)
189 #undef LOAD_OPTIONAL_FUNCPTR
194 if(pXRenderQueryExtension(gdi_display
, &event_base
, &xrender_error_base
)) {
195 X11DRV_XRender_Installed
= TRUE
;
196 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base
);
197 pict_formats
[color_drawable
] = pXRenderFindVisualFormat(gdi_display
, visual
);
198 if(!pict_formats
[color_drawable
])
200 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
201 if (visual
->class == DirectColor
)
204 if (XMatchVisualInfo( gdi_display
, DefaultScreen(gdi_display
),
205 screen_depth
, TrueColor
, &info
))
207 pict_formats
[color_drawable
] = pXRenderFindVisualFormat(gdi_display
, info
.visual
);
208 if (pict_formats
[color_drawable
]) visual
= info
.visual
;
212 if(!pict_formats
[color_drawable
]) /* This fails in buggy versions of libXrender.so */
216 "Wine has detected that you probably have a buggy version\n"
217 "of libXrender.so . Because of this client side font rendering\n"
218 "will be disabled. Please upgrade this library.\n");
219 X11DRV_XRender_Installed
= FALSE
;
222 pf
.type
= PictTypeDirect
;
225 pf
.direct
.alphaMask
= 1;
226 pict_formats
[mono_drawable
] = pXRenderFindFormat(gdi_display
, PictFormatType
|
227 PictFormatDepth
| PictFormatAlpha
|
228 PictFormatAlphaMask
, &pf
, 0);
229 if(!pict_formats
[mono_drawable
]) {
230 ERR("mono_format == NULL?\n");
231 X11DRV_XRender_Installed
= FALSE
;
233 if (!visual
->red_mask
|| !visual
->green_mask
|| !visual
->blue_mask
) {
234 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
235 X11DRV_XRender_Installed
= FALSE
;
242 if(X11DRV_XRender_Installed
|| client_side_with_core
)
244 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
245 sizeof(*glyphsetCache
) * INIT_CACHE_SIZE
);
247 glyphsetCacheSize
= INIT_CACHE_SIZE
;
249 for(i
= 0; i
< INIT_CACHE_SIZE
; i
++) {
250 glyphsetCache
[i
].next
= i
+ 1;
251 glyphsetCache
[i
].count
= -1;
253 glyphsetCache
[i
-1].next
= -1;
254 using_client_side_fonts
= 1;
256 if(!X11DRV_XRender_Installed
) {
257 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
258 if(screen_depth
<= 8 || !client_side_antialias_with_core
)
261 if(screen_depth
<= 8 || !client_side_antialias_with_render
)
265 else TRACE("Using X11 core fonts\n");
268 static BOOL
fontcmp(LFANDSIZE
*p1
, LFANDSIZE
*p2
)
270 if(p1
->hash
!= p2
->hash
) return TRUE
;
271 if(memcmp(&p1
->devsize
, &p2
->devsize
, sizeof(p1
->devsize
))) return TRUE
;
272 if(memcmp(&p1
->xform
, &p2
->xform
, sizeof(p1
->xform
))) return TRUE
;
273 if(memcmp(&p1
->lf
, &p2
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
274 return strcmpiW(p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
278 static void walk_cache(void)
282 EnterCriticalSection(&xrender_cs
);
283 for(i
=mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
284 TRACE("item %d\n", i
);
285 LeaveCriticalSection(&xrender_cs
);
289 static int LookupEntry(LFANDSIZE
*plfsz
)
293 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
295 if(glyphsetCache
[i
].count
== -1) { /* reached free list so stop */
300 if(!fontcmp(&glyphsetCache
[i
].lfsz
, plfsz
)) {
301 glyphsetCache
[i
].count
++;
303 glyphsetCache
[prev_i
].next
= glyphsetCache
[i
].next
;
304 glyphsetCache
[i
].next
= mru
;
307 TRACE("found font in cache %d\n", i
);
312 TRACE("font not in cache\n");
316 static void FreeEntry(int entry
)
320 for(format
= 0; format
< AA_MAXVALUE
; format
++) {
321 gsCacheEntryFormat
* formatEntry
;
323 if( !glyphsetCache
[entry
].format
[format
] )
326 formatEntry
= glyphsetCache
[entry
].format
[format
];
328 if(formatEntry
->glyphset
) {
330 pXRenderFreeGlyphSet(gdi_display
, formatEntry
->glyphset
);
332 formatEntry
->glyphset
= 0;
334 if(formatEntry
->nrealized
) {
335 HeapFree(GetProcessHeap(), 0, formatEntry
->realized
);
336 formatEntry
->realized
= NULL
;
337 if(formatEntry
->bitmaps
) {
338 for(i
= 0; i
< formatEntry
->nrealized
; i
++)
339 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
[i
]);
340 HeapFree(GetProcessHeap(), 0, formatEntry
->bitmaps
);
341 formatEntry
->bitmaps
= NULL
;
343 HeapFree(GetProcessHeap(), 0, formatEntry
->gis
);
344 formatEntry
->gis
= NULL
;
345 formatEntry
->nrealized
= 0;
348 HeapFree(GetProcessHeap(), 0, formatEntry
);
349 glyphsetCache
[entry
].format
[format
] = NULL
;
353 static int AllocEntry(void)
355 int best
= -1, prev_best
= -1, i
, prev_i
= -1;
358 assert(glyphsetCache
[lastfree
].count
== -1);
359 glyphsetCache
[lastfree
].count
= 1;
361 lastfree
= glyphsetCache
[lastfree
].next
;
363 glyphsetCache
[best
].next
= mru
;
366 TRACE("empty space at %d, next lastfree = %d\n", mru
, lastfree
);
370 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
) {
371 if(glyphsetCache
[i
].count
== 0) {
379 TRACE("freeing unused glyphset at cache %d\n", best
);
381 glyphsetCache
[best
].count
= 1;
383 glyphsetCache
[prev_best
].next
= glyphsetCache
[best
].next
;
384 glyphsetCache
[best
].next
= mru
;
392 TRACE("Growing cache\n");
395 glyphsetCache
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
397 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
398 * sizeof(*glyphsetCache
));
400 glyphsetCache
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
401 (glyphsetCacheSize
+ INIT_CACHE_SIZE
)
402 * sizeof(*glyphsetCache
));
404 for(best
= i
= glyphsetCacheSize
; i
< glyphsetCacheSize
+ INIT_CACHE_SIZE
;
406 glyphsetCache
[i
].next
= i
+ 1;
407 glyphsetCache
[i
].count
= -1;
409 glyphsetCache
[i
-1].next
= -1;
410 glyphsetCacheSize
+= INIT_CACHE_SIZE
;
412 lastfree
= glyphsetCache
[best
].next
;
413 glyphsetCache
[best
].count
= 1;
414 glyphsetCache
[best
].next
= mru
;
416 TRACE("new free cache slot at %d\n", mru
);
420 static BOOL
get_gasp_flags(X11DRV_PDEVICE
*physDev
, WORD
*flags
)
430 size
= GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, NULL
, 0);
431 if(size
== GDI_ERROR
)
434 gasp
= buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
435 GetFontData(physDev
->hdc
, MS_GASP_TAG
, 0, gasp
, size
);
437 GetTextMetricsW(physDev
->hdc
, &tm
);
438 ppem
= abs(X11DRV_YWStoDS(physDev
, tm
.tmAscent
+ tm
.tmDescent
- tm
.tmInternalLeading
));
441 num_recs
= get_be_word(*gasp
);
445 *flags
= get_be_word(*(gasp
+ 1));
446 if(ppem
<= get_be_word(*gasp
))
450 TRACE("got flags %04x for ppem %d\n", *flags
, ppem
);
452 HeapFree(GetProcessHeap(), 0, buffer
);
456 static AA_Type
get_antialias_type( X11DRV_PDEVICE
*physDev
, BOOL subpixel
, BOOL hinter
)
460 UINT font_smoothing_type
, font_smoothing_orientation
;
462 if (X11DRV_XRender_Installed
&& subpixel
&&
463 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE
, 0, &font_smoothing_type
, 0) &&
464 font_smoothing_type
== FE_FONTSMOOTHINGCLEARTYPE
)
466 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION
, 0,
467 &font_smoothing_orientation
, 0) &&
468 font_smoothing_orientation
== FE_FONTSMOOTHINGORIENTATIONBGR
)
475 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
476 But, Wine's subpixel rendering can support the portrait mode.
479 else if (!hinter
|| !get_gasp_flags(physDev
, &flags
) || flags
& GASP_DOGRAY
)
487 static int GetCacheEntry(X11DRV_PDEVICE
*physDev
, LFANDSIZE
*plfsz
)
492 static int hinter
= -1;
493 static int subpixel
= -1;
496 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
499 entry
= glyphsetCache
+ ret
;
500 entry
->lfsz
= *plfsz
;
501 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
502 assert( !entry
->format
[format
] );
505 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
507 if(hinter
== -1 || subpixel
== -1)
509 RASTERIZER_STATUS status
;
510 GetRasterizerCaps(&status
, sizeof(status
));
511 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
512 subpixel
= status
.wFlags
& WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
515 switch (plfsz
->lf
.lfQuality
)
517 case ANTIALIASED_QUALITY
:
518 entry
->aa_default
= get_antialias_type( physDev
, FALSE
, hinter
);
520 case CLEARTYPE_QUALITY
:
521 case CLEARTYPE_NATURAL_QUALITY
:
522 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
524 case DEFAULT_QUALITY
:
528 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING
, 0, &font_smoothing
, 0) &&
531 entry
->aa_default
= get_antialias_type( physDev
, subpixel
, hinter
);
534 entry
->aa_default
= AA_None
;
539 entry
->aa_default
= AA_None
;
544 static void dec_ref_cache(int index
)
547 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
548 assert(glyphsetCache
[index
].count
> 0);
549 glyphsetCache
[index
].count
--;
552 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
554 DWORD hash
= 0, *ptr
, two_chars
;
558 hash
^= plfsz
->devsize
.cx
;
559 hash
^= plfsz
->devsize
.cy
;
560 for(i
= 0, ptr
= (DWORD
*)&plfsz
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
562 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
564 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
566 pwc
= (WCHAR
*)&two_chars
;
568 *pwc
= toupperW(*pwc
);
570 *pwc
= toupperW(*pwc
);
578 /***********************************************************************
579 * X11DRV_XRender_Finalize
581 void X11DRV_XRender_Finalize(void)
585 EnterCriticalSection(&xrender_cs
);
586 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
588 LeaveCriticalSection(&xrender_cs
);
592 /***********************************************************************
593 * X11DRV_XRender_SelectFont
595 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
599 GetObjectW(hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
600 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
601 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
602 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
603 lfsz
.lf
.lfWidth
= abs( lfsz
.lf
.lfWidth
);
604 lfsz
.devsize
.cx
= X11DRV_XWStoDS( physDev
, lfsz
.lf
.lfWidth
);
605 lfsz
.devsize
.cy
= X11DRV_YWStoDS( physDev
, lfsz
.lf
.lfHeight
);
606 GetWorldTransform( physDev
->hdc
, &lfsz
.xform
);
607 lfsz_calc_hash(&lfsz
);
609 EnterCriticalSection(&xrender_cs
);
610 if(!physDev
->xrender
) {
611 physDev
->xrender
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
612 sizeof(*physDev
->xrender
));
613 physDev
->xrender
->cache_index
= -1;
615 else if(physDev
->xrender
->cache_index
!= -1)
616 dec_ref_cache(physDev
->xrender
->cache_index
);
617 physDev
->xrender
->cache_index
= GetCacheEntry(physDev
, &lfsz
);
618 LeaveCriticalSection(&xrender_cs
);
622 /***********************************************************************
623 * X11DRV_XRender_DeleteDC
625 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
627 X11DRV_XRender_UpdateDrawable(physDev
);
629 EnterCriticalSection(&xrender_cs
);
630 if(physDev
->xrender
->cache_index
!= -1)
631 dec_ref_cache(physDev
->xrender
->cache_index
);
632 LeaveCriticalSection(&xrender_cs
);
634 HeapFree(GetProcessHeap(), 0, physDev
->xrender
);
635 physDev
->xrender
= NULL
;
639 /***********************************************************************
640 * X11DRV_XRender_UpdateDrawable
642 * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
643 * It deletes the pict and tile when the drawable changes.
645 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
649 if(physDev
->xrender
->pict
)
651 TRACE("freeing pict = %lx dc = %p\n", physDev
->xrender
->pict
, physDev
->hdc
);
653 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
654 physDev
->xrender
->pict
= 0;
661 /************************************************************************
664 * Helper to ExtTextOut. Must be called inside xrender_cs
666 static BOOL
UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
, AA_Type format
)
673 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
674 gsCacheEntryFormat
*formatEntry
;
675 UINT ggo_format
= GGO_GLYPH_INDEX
;
676 XRenderPictFormat pf
;
677 unsigned long pf_mask
;
678 static const char zero
[4];
679 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
683 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
686 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
689 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
692 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
695 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
699 ERR("aa = %d - not implemented\n", format
);
701 ggo_format
|= GGO_BITMAP
;
705 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
706 if(buflen
== GDI_ERROR
) {
707 if(format
!= AA_None
) {
709 entry
->aa_default
= AA_None
;
710 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
711 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
, &identity
);
713 if(buflen
== GDI_ERROR
) {
714 WARN("GetGlyphOutlineW failed\n");
717 TRACE("Turning off antialiasing for this monochrome font\n");
720 /* If there is nothing for the current type, we create the entry. */
721 if( !entry
->format
[format
] ) {
722 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
724 sizeof(gsCacheEntryFormat
));
726 formatEntry
= entry
->format
[format
];
728 if(formatEntry
->nrealized
<= glyph
) {
729 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
731 if (formatEntry
->realized
)
732 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
734 formatEntry
->realized
,
735 formatEntry
->nrealized
* sizeof(BOOL
));
737 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
739 formatEntry
->nrealized
* sizeof(BOOL
));
741 if(!X11DRV_XRender_Installed
) {
742 if (formatEntry
->bitmaps
)
743 formatEntry
->bitmaps
= HeapReAlloc(GetProcessHeap(),
745 formatEntry
->bitmaps
,
746 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
748 formatEntry
->bitmaps
= HeapAlloc(GetProcessHeap(),
750 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
752 if (formatEntry
->gis
)
753 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
756 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
758 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
760 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
764 if(formatEntry
->glyphset
== 0 && X11DRV_XRender_Installed
) {
767 pf_mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
,
768 pf
.type
= PictTypeDirect
;
771 pf
.direct
.alphaMask
= 0xff;
778 pf_mask
= PictFormatType
| PictFormatDepth
| PictFormatRed
| PictFormatRedMask
|
779 PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
|
780 PictFormatBlueMask
| PictFormatAlpha
| PictFormatAlphaMask
;
781 pf
.type
= PictTypeDirect
;
784 pf
.direct
.redMask
= 0xff;
786 pf
.direct
.greenMask
= 0xff;
788 pf
.direct
.blueMask
= 0xff;
789 pf
.direct
.alpha
= 24;
790 pf
.direct
.alphaMask
= 0xff;
794 ERR("aa = %d - not implemented\n", format
);
796 pf_mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
,
797 pf
.type
= PictTypeDirect
;
800 pf
.direct
.alphaMask
= 1;
805 formatEntry
->font_format
= pXRenderFindFormat(gdi_display
, pf_mask
, &pf
, 0);
806 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
811 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
812 GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, &identity
);
813 formatEntry
->realized
[glyph
] = TRUE
;
815 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
817 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
818 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
820 gi
.width
= gm
.gmBlackBoxX
;
821 gi
.height
= gm
.gmBlackBoxY
;
822 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
823 gi
.y
= gm
.gmptGlyphOrigin
.y
;
824 gi
.xOff
= gm
.gmCellIncX
;
825 gi
.yOff
= gm
.gmCellIncY
;
827 if(TRACE_ON(xrender
)) {
832 if(format
== AA_None
) {
833 pitch
= ((gi
.width
+ 31) / 32) * 4;
834 for(i
= 0; i
< gi
.height
; i
++) {
835 line
= (unsigned char*) buf
+ i
* pitch
;
837 for(j
= 0; j
< pitch
* 8; j
++) {
838 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
840 TRACE("%s\n", output
);
843 static const char blks
[] = " .:;!o*#";
847 pitch
= ((gi
.width
+ 3) / 4) * 4;
848 for(i
= 0; i
< gi
.height
; i
++) {
849 line
= (unsigned char*) buf
+ i
* pitch
;
851 for(j
= 0; j
< pitch
; j
++) {
852 str
[0] = blks
[line
[j
] >> 5];
855 TRACE("%s\n", output
);
861 if(formatEntry
->glyphset
) {
862 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
863 unsigned char *byte
= (unsigned char*) buf
, c
;
869 /* magic to flip bit order */
870 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
871 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
872 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
877 else if ( format
!= AA_Grey
&&
878 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
880 unsigned int i
, *data
= (unsigned int *)buf
;
881 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
886 XRenderCompositeText seems to ignore 0x0 glyphs when
887 AA_None, which means we lose the advance width of glyphs
888 like the space. We'll pretend that such glyphs are 1x1
893 gi
.width
= gi
.height
= 1;
896 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
897 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
899 HeapFree(GetProcessHeap(), 0, buf
);
901 formatEntry
->bitmaps
[glyph
] = buf
;
904 formatEntry
->gis
[glyph
] = gi
;
909 static void SharpGlyphMono(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
910 void *bitmap
, XGlyphInfo
*gi
)
912 unsigned char *srcLine
= bitmap
, *src
;
913 unsigned char bits
, bitsMask
;
914 int width
= gi
->width
;
915 int stride
= ((width
+ 31) & ~31) >> 3;
916 int height
= gi
->height
;
920 TRACE("%d, %d\n", x
, y
);
929 bitsMask
= 0x80; /* FreeType is always MSB first */
943 bitsMask
= bitsMask
>> 1;
949 } while (bits
& bitsMask
);
950 XFillRectangle (gdi_display
, physDev
->drawable
,
951 physDev
->gc
, xspan
, y
, lenspan
, 1);
963 bitsMask
= bitsMask
>> 1;
969 } while (!(bits
& bitsMask
));
976 static void SharpGlyphGray(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
977 void *bitmap
, XGlyphInfo
*gi
)
979 unsigned char *srcLine
= bitmap
, *src
, bits
;
980 int width
= gi
->width
;
981 int stride
= ((width
+ 3) & ~3);
982 int height
= gi
->height
;
1007 } while (bits
>= 0x80);
1008 XFillRectangle (gdi_display
, physDev
->drawable
,
1009 physDev
->gc
, xspan
, y
, lenspan
, 1);
1022 } while (bits
< 0x80);
1030 static void ExamineBitfield (DWORD mask
, int *shift
, int *len
)
1035 while ((mask
& 1) == 0)
1041 while ((mask
& 1) == 1)
1050 static DWORD
GetField (DWORD pixel
, int shift
, int len
)
1052 pixel
= pixel
& (((1 << (len
)) - 1) << shift
);
1053 pixel
= pixel
<< (32 - (shift
+ len
)) >> 24;
1056 pixel
|= (pixel
>> len
);
1063 static DWORD
PutField (DWORD pixel
, int shift
, int len
)
1065 shift
= shift
- (8 - len
);
1067 pixel
&= (((1 << len
) - 1) << (8 - len
));
1075 static void SmoothGlyphGray(XImage
*image
, int x
, int y
, void *bitmap
, XGlyphInfo
*gi
,
1081 BYTE
*maskLine
, *mask
, m
;
1086 BYTE src_r
, src_g
, src_b
;
1091 height
= gi
->height
;
1094 maskStride
= (width
+ 3) & ~3;
1096 ExamineBitfield (image
->red_mask
, &r_shift
, &r_len
);
1097 ExamineBitfield (image
->green_mask
, &g_shift
, &g_len
);
1098 ExamineBitfield (image
->blue_mask
, &b_shift
, &b_len
);
1100 src_r
= GetField(color
, r_shift
, r_len
);
1101 src_g
= GetField(color
, g_shift
, g_len
);
1102 src_b
= GetField(color
, b_shift
, b_len
);
1104 for(; height
--; y
++)
1107 maskLine
+= maskStride
;
1112 if(y
>= image
->height
) break;
1116 if(tx
>= image
->width
) break;
1119 if(tx
< 0) continue;
1122 XPutPixel (image
, tx
, y
, color
);
1127 pixel
= XGetPixel (image
, tx
, y
);
1129 r
= GetField(pixel
, r_shift
, r_len
);
1130 r
= ((BYTE
)~m
* (WORD
)r
+ (BYTE
)m
* (WORD
)src_r
) >> 8;
1131 g
= GetField(pixel
, g_shift
, g_len
);
1132 g
= ((BYTE
)~m
* (WORD
)g
+ (BYTE
)m
* (WORD
)src_g
) >> 8;
1133 b
= GetField(pixel
, b_shift
, b_len
);
1134 b
= ((BYTE
)~m
* (WORD
)b
+ (BYTE
)m
* (WORD
)src_b
) >> 8;
1136 pixel
= (PutField (r
, r_shift
, r_len
) |
1137 PutField (g
, g_shift
, g_len
) |
1138 PutField (b
, b_shift
, b_len
));
1139 XPutPixel (image
, tx
, y
, pixel
);
1145 /*************************************************************
1148 * Returns an appropriate Picture for tiling the text colour.
1149 * Call and use result within the xrender_cs
1151 static Picture
get_tile_pict(enum drawable_depth_type type
, int text_pixel
)
1161 tile
= &tiles
[type
];
1165 XRenderPictureAttributes pa
;
1168 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_formats
[type
]->depth
);
1171 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_formats
[type
], CPRepeat
, &pa
);
1172 wine_tsx11_unlock();
1174 /* init current_color to something different from text_pixel */
1175 tile
->current_color
= ~text_pixel
;
1177 if(type
== mono_drawable
)
1179 /* for a 1bpp bitmap we always need a 1 in the tile */
1180 col
.red
= col
.green
= col
.blue
= 0;
1183 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1184 wine_tsx11_unlock();
1188 if(text_pixel
!= tile
->current_color
&& type
== color_drawable
)
1190 /* Map 0 -- 0xff onto 0 -- 0xffff */
1195 ExamineBitfield (visual
->red_mask
, &r_shift
, &r_len
);
1196 ExamineBitfield (visual
->green_mask
, &g_shift
, &g_len
);
1197 ExamineBitfield (visual
->blue_mask
, &b_shift
, &b_len
);
1199 col
.red
= GetField(text_pixel
, r_shift
, r_len
);
1200 col
.red
|= col
.red
<< 8;
1201 col
.green
= GetField(text_pixel
, g_shift
, g_len
);
1202 col
.green
|= col
.green
<< 8;
1203 col
.blue
= GetField(text_pixel
, b_shift
, b_len
);
1204 col
.blue
|= col
.blue
<< 8;
1208 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1209 wine_tsx11_unlock();
1210 tile
->current_color
= text_pixel
;
1215 static int XRenderErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
1220 /***********************************************************************
1221 * X11DRV_XRender_ExtTextOut
1223 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1224 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1229 gsCacheEntry
*entry
;
1230 gsCacheEntryFormat
*formatEntry
;
1232 HDC hdc
= physDev
->hdc
;
1233 int textPixel
, backgroundPixel
;
1234 HRGN saved_region
= 0;
1235 BOOL disable_antialias
= FALSE
;
1236 AA_Type aa_type
= AA_None
;
1239 double cosEsc
, sinEsc
;
1241 enum drawable_depth_type depth_type
= (physDev
->depth
== 1) ? mono_drawable
: color_drawable
;
1242 Picture tile_pict
= 0;
1244 /* Do we need to disable antialiasing because of palette mode? */
1245 if( !physDev
->bitmap
|| GetObjectW( physDev
->bitmap
->hbitmap
, sizeof(bmp
), &bmp
) != sizeof(bmp
) ) {
1246 TRACE("bitmap is not a DIB\n");
1248 else if (bmp
.dsBmih
.biBitCount
<= 8) {
1249 TRACE("Disabling antialiasing\n");
1250 disable_antialias
= TRUE
;
1253 xgcval
.function
= GXcopy
;
1254 xgcval
.background
= physDev
->backgroundPixel
;
1255 xgcval
.fill_style
= FillSolid
;
1257 XChangeGC( gdi_display
, physDev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1258 wine_tsx11_unlock();
1260 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
);
1262 if(physDev
->depth
== 1) {
1263 if((physDev
->textPixel
& 0xffffff) == 0) {
1265 backgroundPixel
= 1;
1268 backgroundPixel
= 0;
1271 textPixel
= physDev
->textPixel
;
1272 backgroundPixel
= physDev
->backgroundPixel
;
1275 if(flags
& ETO_OPAQUE
)
1278 XSetForeground( gdi_display
, physDev
->gc
, backgroundPixel
);
1279 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1280 physDev
->dc_rect
.left
+ lprect
->left
, physDev
->dc_rect
.top
+ lprect
->top
,
1281 lprect
->right
- lprect
->left
, lprect
->bottom
- lprect
->top
);
1282 wine_tsx11_unlock();
1292 GetObjectW(GetCurrentObject(physDev
->hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
1293 if(lf
.lfEscapement
!= 0) {
1294 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
1295 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
1301 if (flags
& ETO_CLIPPED
)
1305 clip_region
= CreateRectRgnIndirect( lprect
);
1306 /* make a copy of the current device region */
1307 saved_region
= CreateRectRgn( 0, 0, 0, 0 );
1308 CombineRgn( saved_region
, physDev
->region
, 0, RGN_COPY
);
1309 X11DRV_SetDeviceClipping( physDev
, saved_region
, clip_region
);
1310 DeleteObject( clip_region
);
1313 if(X11DRV_XRender_Installed
) {
1314 if(!physDev
->xrender
->pict
) {
1315 XRenderPictureAttributes pa
;
1316 pa
.subwindow_mode
= IncludeInferiors
;
1319 physDev
->xrender
->pict
= pXRenderCreatePicture(gdi_display
,
1321 pict_formats
[depth_type
],
1322 CPSubwindowMode
, &pa
);
1323 wine_tsx11_unlock();
1325 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1326 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1328 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1329 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1332 if ((data
= X11DRV_GetRegionData( physDev
->region
, 0 )))
1335 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
1336 physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
1337 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
1338 wine_tsx11_unlock();
1339 HeapFree( GetProcessHeap(), 0, data
);
1343 EnterCriticalSection(&xrender_cs
);
1345 entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1346 if( disable_antialias
== FALSE
)
1347 aa_type
= entry
->aa_default
;
1348 formatEntry
= entry
->format
[aa_type
];
1350 for(idx
= 0; idx
< count
; idx
++) {
1351 if( !formatEntry
) {
1352 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1353 /* re-evaluate antialias since aa_default may have changed */
1354 if( disable_antialias
== FALSE
)
1355 aa_type
= entry
->aa_default
;
1356 formatEntry
= entry
->format
[aa_type
];
1357 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1358 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1363 WARN("could not upload requested glyphs\n");
1364 LeaveCriticalSection(&xrender_cs
);
1368 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1369 physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1371 if(X11DRV_XRender_Installed
)
1373 XGlyphElt16
*elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1375 POINT desired
, current
;
1376 int render_op
= PictOpOver
;
1378 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1379 So we pass zeros to the function and move to our starting position using the first
1380 element of the elts array. */
1382 desired
.x
= physDev
->dc_rect
.left
+ x
;
1383 desired
.y
= physDev
->dc_rect
.top
+ y
;
1384 current
.x
= current
.y
= 0;
1386 tile_pict
= get_tile_pict(depth_type
, physDev
->textPixel
);
1388 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1390 if((depth_type
== mono_drawable
) && (textPixel
== 0))
1391 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1393 for(idx
= 0; idx
< count
; idx
++)
1395 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1396 elts
[idx
].chars
= wstr
+ idx
;
1397 elts
[idx
].nchars
= 1;
1398 elts
[idx
].xOff
= desired
.x
- current
.x
;
1399 elts
[idx
].yOff
= desired
.y
- current
.y
;
1401 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1402 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1406 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1407 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1411 offset
+= lpDx
[idx
];
1412 desired
.x
= physDev
->dc_rect
.left
+ x
+ offset
* cosEsc
;
1413 desired
.y
= physDev
->dc_rect
.top
+ y
- offset
* sinEsc
;
1417 pXRenderCompositeText16(gdi_display
, render_op
,
1419 physDev
->xrender
->pict
,
1420 formatEntry
->font_format
,
1421 0, 0, 0, 0, elts
, count
);
1422 wine_tsx11_unlock();
1423 HeapFree(GetProcessHeap(), 0, elts
);
1425 INT offset
= 0, xoff
= 0, yoff
= 0;
1427 XSetForeground( gdi_display
, physDev
->gc
, textPixel
);
1429 if(aa_type
== AA_None
|| physDev
->depth
== 1)
1431 void (* sharp_glyph_fn
)(X11DRV_PDEVICE
*, INT
, INT
, void *, XGlyphInfo
*);
1433 if(aa_type
== AA_None
)
1434 sharp_glyph_fn
= SharpGlyphMono
;
1436 sharp_glyph_fn
= SharpGlyphGray
;
1438 for(idx
= 0; idx
< count
; idx
++) {
1439 sharp_glyph_fn(physDev
, physDev
->dc_rect
.left
+ x
+ xoff
,
1440 physDev
->dc_rect
.top
+ y
+ yoff
,
1441 formatEntry
->bitmaps
[wstr
[idx
]],
1442 &formatEntry
->gis
[wstr
[idx
]]);
1444 offset
+= lpDx
[idx
];
1445 xoff
= offset
* cosEsc
;
1446 yoff
= offset
* -sinEsc
;
1448 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1449 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1454 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
1455 RECT extents
= {0, 0, 0, 0};
1457 int w
= physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
;
1458 int h
= physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
;
1460 TRACE("drawable %dx%d\n", w
, h
);
1462 for(idx
= 0; idx
< count
; idx
++) {
1463 if(extents
.left
> cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
)
1464 extents
.left
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
;
1465 if(extents
.top
> cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
)
1466 extents
.top
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
;
1467 if(extents
.right
< cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
)
1468 extents
.right
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
;
1469 if(extents
.bottom
< cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
)
1470 extents
.bottom
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
;
1472 offset
+= lpDx
[idx
];
1473 cur
.x
= offset
* cosEsc
;
1474 cur
.y
= offset
* -sinEsc
;
1476 cur
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1477 cur
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1480 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents
.left
, extents
.top
,
1481 extents
.right
, extents
.bottom
, physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1483 if(physDev
->dc_rect
.left
+ x
+ extents
.left
>= 0) {
1484 image_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1488 image_off_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1490 if(physDev
->dc_rect
.top
+ y
+ extents
.top
>= 0) {
1491 image_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1495 image_off_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1497 if(physDev
->dc_rect
.left
+ x
+ extents
.right
< w
)
1498 image_w
= physDev
->dc_rect
.left
+ x
+ extents
.right
- image_x
;
1500 image_w
= w
- image_x
;
1501 if(physDev
->dc_rect
.top
+ y
+ extents
.bottom
< h
)
1502 image_h
= physDev
->dc_rect
.top
+ y
+ extents
.bottom
- image_y
;
1504 image_h
= h
- image_y
;
1506 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
1508 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1509 image
= XGetImage(gdi_display
, physDev
->drawable
,
1510 image_x
, image_y
, image_w
, image_h
,
1511 AllPlanes
, ZPixmap
);
1512 X11DRV_check_error();
1514 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1515 gdi_display
, (int)physDev
->drawable
, image_x
, image_y
,
1516 image_w
, image_h
, AllPlanes
, ZPixmap
,
1517 physDev
->depth
, image
);
1519 Pixmap xpm
= XCreatePixmap(gdi_display
, root_window
, image_w
, image_h
,
1524 gcv
.graphics_exposures
= False
;
1525 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1526 XCopyArea(gdi_display
, physDev
->drawable
, xpm
, gc
, image_x
, image_y
,
1527 image_w
, image_h
, 0, 0);
1528 XFreeGC(gdi_display
, gc
);
1529 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1530 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
1532 X11DRV_check_error();
1533 XFreePixmap(gdi_display
, xpm
);
1535 if(!image
) goto no_image
;
1537 image
->red_mask
= visual
->red_mask
;
1538 image
->green_mask
= visual
->green_mask
;
1539 image
->blue_mask
= visual
->blue_mask
;
1541 offset
= xoff
= yoff
= 0;
1542 for(idx
= 0; idx
< count
; idx
++) {
1543 SmoothGlyphGray(image
, xoff
+ image_off_x
- extents
.left
,
1544 yoff
+ image_off_y
- extents
.top
,
1545 formatEntry
->bitmaps
[wstr
[idx
]],
1546 &formatEntry
->gis
[wstr
[idx
]],
1547 physDev
->textPixel
);
1549 offset
+= lpDx
[idx
];
1550 xoff
= offset
* cosEsc
;
1551 yoff
= offset
* -sinEsc
;
1553 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1554 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1557 XPutImage(gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
1558 image_x
, image_y
, image_w
, image_h
);
1559 XDestroyImage(image
);
1562 wine_tsx11_unlock();
1564 LeaveCriticalSection(&xrender_cs
);
1566 if (flags
& ETO_CLIPPED
)
1568 /* restore the device region */
1569 X11DRV_SetDeviceClipping( physDev
, saved_region
, 0 );
1570 DeleteObject( saved_region
);
1576 X11DRV_UnlockDIBSection( physDev
, TRUE
);
1580 /******************************************************************************
1581 * AlphaBlend (x11drv.@)
1583 BOOL CDECL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1584 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1585 BLENDFUNCTION blendfn
)
1587 XRenderPictureAttributes pa
;
1588 XRenderPictFormat
*src_format
;
1589 XRenderPictFormat argb32_templ
= {
1591 PictTypeDirect
, /* type */
1594 16, /* direct.red */
1595 0xff, /* direct.redMask */
1596 8, /* direct.green */
1597 0xff, /* direct.greenMask */
1598 0, /* direct.blue */
1599 0xff, /* direct.blueMask */
1600 24, /* direct.alpha */
1601 0xff, /* direct.alphaMask */
1605 unsigned long argb32_templ_mask
=
1611 PictFormatGreenMask
|
1613 PictFormatBlueMask
|
1615 PictFormatAlphaMask
;
1617 Picture dst_pict
, src_pict
;
1623 DWORD
*dstbits
, *data
;
1626 BOOL top_down
= FALSE
;
1628 enum drawable_depth_type dst_depth_type
= (devDst
->depth
== 1) ? mono_drawable
: color_drawable
;
1630 if(!X11DRV_XRender_Installed
) {
1631 FIXME("Unable to AlphaBlend without Xrender\n");
1636 pts
[1].x
= xDst
+ widthDst
;
1637 pts
[1].y
= yDst
+ heightDst
;
1638 LPtoDP(devDst
->hdc
, pts
, 2);
1641 widthDst
= pts
[1].x
- pts
[0].x
;
1642 heightDst
= pts
[1].y
- pts
[0].y
;
1646 pts
[1].x
= xSrc
+ widthSrc
;
1647 pts
[1].y
= ySrc
+ heightSrc
;
1648 LPtoDP(devSrc
->hdc
, pts
, 2);
1651 widthSrc
= pts
[1].x
- pts
[0].x
;
1652 heightSrc
= pts
[1].y
- pts
[0].y
;
1653 if (!widthDst
|| !heightDst
|| !widthSrc
|| !heightSrc
) return TRUE
;
1655 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1656 if(widthDst
!= widthSrc
|| heightDst
!= heightSrc
)
1658 if(!pXRenderSetPictureTransform
)
1661 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1665 if (!devSrc
->bitmap
|| GetObjectW( devSrc
->bitmap
->hbitmap
, sizeof(dib
), &dib
) != sizeof(dib
))
1667 static BOOL out
= FALSE
;
1670 FIXME("not a dibsection\n");
1676 if (xSrc
< 0 || ySrc
< 0 || widthSrc
< 0 || heightSrc
< 0 || xSrc
+ widthSrc
> dib
.dsBmih
.biWidth
1677 || ySrc
+ heightSrc
> abs(dib
.dsBmih
.biHeight
))
1679 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc
, ySrc
, widthSrc
, heightSrc
);
1680 SetLastError(ERROR_INVALID_PARAMETER
);
1684 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && blendfn
.SourceConstantAlpha
!= 0xff)
1685 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn
.SourceConstantAlpha
);
1687 if(dib
.dsBm
.bmBitsPixel
!= 32) {
1688 FIXME("not a 32 bpp dibsection\n");
1691 dstbits
= data
= HeapAlloc(GetProcessHeap(), 0, heightSrc
* widthSrc
* 4);
1693 if(dib
.dsBmih
.biHeight
< 0) { /* top-down dib */
1695 dstbits
+= widthSrc
* (heightSrc
- 1);
1697 y
= y2
+ heightSrc
- 1;
1701 y
= dib
.dsBmih
.biHeight
- ySrc
- 1;
1702 y2
= y
- heightSrc
+ 1;
1705 if (blendfn
.AlphaFormat
& AC_SRC_ALPHA
)
1709 memcpy(dstbits
, (char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
+ xSrc
* 4,
1711 dstbits
+= (top_down
? -1 : 1) * widthSrc
;
1716 DWORD source_alpha
= (DWORD
)blendfn
.SourceConstantAlpha
<< 24;
1721 DWORD
*srcbits
= (DWORD
*)((char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
) + xSrc
;
1722 for (x
= 0; x
< widthSrc
; x
++)
1724 DWORD argb
= *srcbits
++;
1725 argb
= (argb
& 0xffffff) | source_alpha
;
1728 if (top_down
) /* we traversed the row forward so we should go back by two rows */
1729 dstbits
-= 2 * widthSrc
;
1734 rgndata
= X11DRV_GetRegionData( devDst
->region
, 0 );
1737 image
= XCreateImage(gdi_display
, visual
, 32, ZPixmap
, 0,
1738 (char*) data
, widthSrc
, heightSrc
, 32, widthSrc
* 4);
1741 Avoid using XRenderFindStandardFormat as older libraries don't have it
1742 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1744 src_format
= pXRenderFindFormat(gdi_display
, argb32_templ_mask
, &argb32_templ
, 0);
1746 TRACE("src_format %p\n", src_format
);
1748 pa
.subwindow_mode
= IncludeInferiors
;
1750 /* FIXME use devDst->xrender->pict ? */
1751 dst_pict
= pXRenderCreatePicture(gdi_display
,
1753 pict_formats
[dst_depth_type
],
1754 CPSubwindowMode
, &pa
);
1755 TRACE("dst_pict %08lx\n", dst_pict
);
1756 TRACE("src_drawable = %08lx\n", devSrc
->drawable
);
1757 xpm
= XCreatePixmap(gdi_display
,
1759 widthSrc
, heightSrc
, 32);
1760 gcv
.graphics_exposures
= False
;
1761 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1762 TRACE("xpm = %08lx\n", xpm
);
1763 XPutImage(gdi_display
, xpm
, gc
, image
, 0, 0, 0, 0, widthSrc
, heightSrc
);
1765 src_pict
= pXRenderCreatePicture(gdi_display
,
1767 CPSubwindowMode
, &pa
);
1768 TRACE("src_pict %08lx\n", src_pict
);
1772 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
,
1773 devDst
->dc_rect
.left
, devDst
->dc_rect
.top
,
1774 (XRectangle
*)rgndata
->Buffer
,
1775 rgndata
->rdh
.nCount
);
1776 HeapFree( GetProcessHeap(), 0, rgndata
);
1779 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1780 if(widthDst
!= widthSrc
|| heightDst
!= heightSrc
) {
1781 double xscale
= widthSrc
/(double)widthDst
;
1782 double yscale
= heightSrc
/(double)heightDst
;
1783 XTransform xform
= {{
1784 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(0) },
1785 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(0) },
1786 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1788 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
1791 pXRenderComposite(gdi_display
, PictOpOver
, src_pict
, 0, dst_pict
,
1793 xDst
+ devDst
->dc_rect
.left
, yDst
+ devDst
->dc_rect
.top
, widthDst
, heightDst
);
1796 pXRenderFreePicture(gdi_display
, src_pict
);
1797 XFreePixmap(gdi_display
, xpm
);
1798 XFreeGC(gdi_display
, gc
);
1799 pXRenderFreePicture(gdi_display
, dst_pict
);
1801 XDestroyImage(image
);
1803 wine_tsx11_unlock();
1804 HeapFree(GetProcessHeap(), 0, data
);
1808 #else /* SONAME_LIBXRENDER */
1810 void X11DRV_XRender_Init(void)
1812 TRACE("XRender support not compiled in.\n");
1816 void X11DRV_XRender_Finalize(void)
1820 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
1826 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
1832 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1833 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1840 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
1846 /******************************************************************************
1847 * AlphaBlend (x11drv.@)
1849 BOOL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1850 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1851 BLENDFUNCTION blendfn
)
1853 FIXME("not supported - XRENDER headers were missing at compile time\n");
1857 #endif /* SONAME_LIBXRENDER */