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 int GetCacheEntry(X11DRV_PDEVICE
*physDev
, LFANDSIZE
*plfsz
)
460 static int hinter
= -1;
461 static int subpixel
= -1;
463 if((ret
= LookupEntry(plfsz
)) != -1) return ret
;
466 entry
= glyphsetCache
+ ret
;
467 entry
->lfsz
= *plfsz
;
468 for( format
= 0; format
< AA_MAXVALUE
; format
++ ) {
469 assert( !entry
->format
[format
] );
472 if(antialias
&& plfsz
->lf
.lfQuality
!= NONANTIALIASED_QUALITY
)
474 if(hinter
== -1 || subpixel
== -1)
476 RASTERIZER_STATUS status
;
477 GetRasterizerCaps(&status
, sizeof(status
));
478 hinter
= status
.wFlags
& WINE_TT_HINTER_ENABLED
;
479 subpixel
= status
.wFlags
& WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
482 /* FIXME: Use the following registry information
483 [HKEY_CURRENT_USER\Control Panel\Desktop]
484 "FontSmoothing"="2" ; 0=>Off, 2=>On
485 "FontSmoothingType"=dword:00000002 ; 1=>Standard, 2=>Cleartype
486 "FontSmoothingOrientation"=dword:00000001 ; 0=>BGR, 1=>RGB
487 "FontSmoothingGamma"=dword:00000578
489 if ( subpixel
&& X11DRV_XRender_Installed
)
490 entry
->aa_default
= AA_RGB
;
491 else if(!hinter
|| !get_gasp_flags(physDev
, &flags
) || flags
& GASP_DOGRAY
)
492 entry
->aa_default
= AA_Grey
;
494 entry
->aa_default
= AA_None
;
497 entry
->aa_default
= AA_None
;
502 static void dec_ref_cache(int index
)
505 TRACE("dec'ing entry %d to %d\n", index
, glyphsetCache
[index
].count
- 1);
506 assert(glyphsetCache
[index
].count
> 0);
507 glyphsetCache
[index
].count
--;
510 static void lfsz_calc_hash(LFANDSIZE
*plfsz
)
512 DWORD hash
= 0, *ptr
;
515 hash
^= plfsz
->devsize
.cx
;
516 hash
^= plfsz
->devsize
.cy
;
517 for(i
= 0, ptr
= (DWORD
*)&plfsz
->lf
; i
< 7; i
++, ptr
++)
519 for(i
= 0, ptr
= (DWORD
*)plfsz
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
520 WCHAR
*pwc
= (WCHAR
*)ptr
;
530 /***********************************************************************
531 * X11DRV_XRender_Finalize
533 void X11DRV_XRender_Finalize(void)
537 EnterCriticalSection(&xrender_cs
);
538 for(i
= mru
; i
>= 0; i
= glyphsetCache
[i
].next
)
540 LeaveCriticalSection(&xrender_cs
);
544 /***********************************************************************
545 * X11DRV_XRender_SelectFont
547 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
551 GetObjectW(hfont
, sizeof(lfsz
.lf
), &lfsz
.lf
);
552 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
553 lfsz
.lf
.lfHeight
, lfsz
.lf
.lfWidth
, lfsz
.lf
.lfWeight
,
554 lfsz
.lf
.lfItalic
, lfsz
.lf
.lfCharSet
, debugstr_w(lfsz
.lf
.lfFaceName
));
555 lfsz
.devsize
.cx
= X11DRV_XWStoDS( physDev
, lfsz
.lf
.lfWidth
);
556 lfsz
.devsize
.cy
= X11DRV_YWStoDS( physDev
, lfsz
.lf
.lfHeight
);
557 lfsz_calc_hash(&lfsz
);
559 EnterCriticalSection(&xrender_cs
);
560 if(!physDev
->xrender
) {
561 physDev
->xrender
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
562 sizeof(*physDev
->xrender
));
563 physDev
->xrender
->cache_index
= -1;
565 else if(physDev
->xrender
->cache_index
!= -1)
566 dec_ref_cache(physDev
->xrender
->cache_index
);
567 physDev
->xrender
->cache_index
= GetCacheEntry(physDev
, &lfsz
);
568 LeaveCriticalSection(&xrender_cs
);
572 /***********************************************************************
573 * X11DRV_XRender_DeleteDC
575 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
577 X11DRV_XRender_UpdateDrawable(physDev
);
579 EnterCriticalSection(&xrender_cs
);
580 if(physDev
->xrender
->cache_index
!= -1)
581 dec_ref_cache(physDev
->xrender
->cache_index
);
582 LeaveCriticalSection(&xrender_cs
);
584 HeapFree(GetProcessHeap(), 0, physDev
->xrender
);
585 physDev
->xrender
= NULL
;
589 /***********************************************************************
590 * X11DRV_XRender_UpdateDrawable
592 * This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
593 * It deletes the pict and tile when the drawable changes.
595 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
599 if(physDev
->xrender
->pict
)
601 TRACE("freeing pict = %lx dc = %p\n", physDev
->xrender
->pict
, physDev
->hdc
);
603 pXRenderFreePicture(gdi_display
, physDev
->xrender
->pict
);
604 physDev
->xrender
->pict
= 0;
611 /************************************************************************
614 * Helper to ExtTextOut. Must be called inside xrender_cs
616 static BOOL
UploadGlyph(X11DRV_PDEVICE
*physDev
, int glyph
, AA_Type format
)
623 gsCacheEntry
*entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
624 gsCacheEntryFormat
*formatEntry
;
625 UINT ggo_format
= GGO_GLYPH_INDEX
;
626 XRenderPictFormat pf
;
627 unsigned long pf_mask
;
628 static const char zero
[4];
632 ggo_format
|= WINE_GGO_GRAY16_BITMAP
;
635 ggo_format
|= WINE_GGO_HRGB_BITMAP
;
638 ggo_format
|= WINE_GGO_HBGR_BITMAP
;
641 ggo_format
|= WINE_GGO_VRGB_BITMAP
;
644 ggo_format
|= WINE_GGO_VBGR_BITMAP
;
648 ERR("aa = %d - not implemented\n", format
);
650 ggo_format
|= GGO_BITMAP
;
654 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
,
656 if(buflen
== GDI_ERROR
) {
657 if(format
!= AA_None
) {
659 entry
->aa_default
= AA_None
;
660 ggo_format
= GGO_GLYPH_INDEX
| GGO_BITMAP
;
661 buflen
= GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, 0, NULL
,
664 if(buflen
== GDI_ERROR
) {
665 WARN("GetGlyphOutlineW failed\n");
668 TRACE("Turning off antialiasing for this monochrome font\n");
671 /* If there is nothing for the current type, we create the entry. */
672 if( !entry
->format
[format
] ) {
673 entry
->format
[format
] = HeapAlloc(GetProcessHeap(),
675 sizeof(gsCacheEntryFormat
));
677 formatEntry
= entry
->format
[format
];
679 if(formatEntry
->nrealized
<= glyph
) {
680 formatEntry
->nrealized
= (glyph
/ 128 + 1) * 128;
682 if (formatEntry
->realized
)
683 formatEntry
->realized
= HeapReAlloc(GetProcessHeap(),
685 formatEntry
->realized
,
686 formatEntry
->nrealized
* sizeof(BOOL
));
688 formatEntry
->realized
= HeapAlloc(GetProcessHeap(),
690 formatEntry
->nrealized
* sizeof(BOOL
));
692 if(!X11DRV_XRender_Installed
) {
693 if (formatEntry
->bitmaps
)
694 formatEntry
->bitmaps
= HeapReAlloc(GetProcessHeap(),
696 formatEntry
->bitmaps
,
697 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
699 formatEntry
->bitmaps
= HeapAlloc(GetProcessHeap(),
701 formatEntry
->nrealized
* sizeof(formatEntry
->bitmaps
[0]));
703 if (formatEntry
->gis
)
704 formatEntry
->gis
= HeapReAlloc(GetProcessHeap(),
707 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
709 formatEntry
->gis
= HeapAlloc(GetProcessHeap(),
711 formatEntry
->nrealized
* sizeof(formatEntry
->gis
[0]));
715 if(formatEntry
->glyphset
== 0 && X11DRV_XRender_Installed
) {
718 pf_mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
,
719 pf
.type
= PictTypeDirect
;
722 pf
.direct
.alphaMask
= 0xff;
729 pf_mask
= PictFormatType
| PictFormatDepth
| PictFormatRed
| PictFormatRedMask
|
730 PictFormatGreen
| PictFormatGreenMask
| PictFormatBlue
|
731 PictFormatBlueMask
| PictFormatAlpha
| PictFormatAlphaMask
;
732 pf
.type
= PictTypeDirect
;
735 pf
.direct
.redMask
= 0xff;
737 pf
.direct
.greenMask
= 0xff;
739 pf
.direct
.blueMask
= 0xff;
740 pf
.direct
.alpha
= 24;
741 pf
.direct
.alphaMask
= 0xff;
745 ERR("aa = %d - not implemented\n", format
);
747 pf_mask
= PictFormatType
| PictFormatDepth
| PictFormatAlpha
| PictFormatAlphaMask
,
748 pf
.type
= PictTypeDirect
;
751 pf
.direct
.alphaMask
= 1;
756 formatEntry
->font_format
= pXRenderFindFormat(gdi_display
, pf_mask
, &pf
, 0);
757 formatEntry
->glyphset
= pXRenderCreateGlyphSet(gdi_display
, formatEntry
->font_format
);
762 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, buflen
);
763 GetGlyphOutlineW(physDev
->hdc
, glyph
, ggo_format
, &gm
, buflen
, buf
, NULL
);
764 formatEntry
->realized
[glyph
] = TRUE
;
766 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
768 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
, gm
.gmCellIncX
, gm
.gmCellIncY
,
769 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
771 gi
.width
= gm
.gmBlackBoxX
;
772 gi
.height
= gm
.gmBlackBoxY
;
773 gi
.x
= -gm
.gmptGlyphOrigin
.x
;
774 gi
.y
= gm
.gmptGlyphOrigin
.y
;
775 gi
.xOff
= gm
.gmCellIncX
;
776 gi
.yOff
= gm
.gmCellIncY
;
778 if(TRACE_ON(xrender
)) {
783 if(format
== AA_None
) {
784 pitch
= ((gi
.width
+ 31) / 32) * 4;
785 for(i
= 0; i
< gi
.height
; i
++) {
786 line
= (unsigned char*) buf
+ i
* pitch
;
788 for(j
= 0; j
< pitch
* 8; j
++) {
789 strcat(output
, (line
[j
/ 8] & (1 << (7 - (j
% 8)))) ? "#" : " ");
791 TRACE("%s\n", output
);
794 static const char blks
[] = " .:;!o*#";
798 pitch
= ((gi
.width
+ 3) / 4) * 4;
799 for(i
= 0; i
< gi
.height
; i
++) {
800 line
= (unsigned char*) buf
+ i
* pitch
;
802 for(j
= 0; j
< pitch
; j
++) {
803 str
[0] = blks
[line
[j
] >> 5];
806 TRACE("%s\n", output
);
812 if(formatEntry
->glyphset
) {
813 if(format
== AA_None
&& BitmapBitOrder(gdi_display
) != MSBFirst
) {
814 unsigned char *byte
= (unsigned char*) buf
, c
;
820 /* magic to flip bit order */
821 c
= ((c
<< 1) & 0xaa) | ((c
>> 1) & 0x55);
822 c
= ((c
<< 2) & 0xcc) | ((c
>> 2) & 0x33);
823 c
= ((c
<< 4) & 0xf0) | ((c
>> 4) & 0x0f);
828 else if ( format
!= AA_Grey
&&
829 ImageByteOrder (gdi_display
) != NATIVE_BYTE_ORDER
)
831 unsigned int i
, *data
= (unsigned int *)buf
;
832 for (i
= buflen
/ sizeof(int); i
; i
--, data
++) *data
= RtlUlongByteSwap(*data
);
837 XRenderCompositeText seems to ignore 0x0 glyphs when
838 AA_None, which means we lose the advance width of glyphs
839 like the space. We'll pretend that such glyphs are 1x1
844 gi
.width
= gi
.height
= 1;
847 pXRenderAddGlyphs(gdi_display
, formatEntry
->glyphset
, &gid
, &gi
, 1,
848 buflen
? buf
: zero
, buflen
? buflen
: sizeof(zero
));
850 HeapFree(GetProcessHeap(), 0, buf
);
852 formatEntry
->bitmaps
[glyph
] = buf
;
855 formatEntry
->gis
[glyph
] = gi
;
860 static void SharpGlyphMono(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
861 void *bitmap
, XGlyphInfo
*gi
)
863 unsigned char *srcLine
= bitmap
, *src
;
864 unsigned char bits
, bitsMask
;
865 int width
= gi
->width
;
866 int stride
= ((width
+ 31) & ~31) >> 3;
867 int height
= gi
->height
;
871 TRACE("%d, %d\n", x
, y
);
880 bitsMask
= 0x80; /* FreeType is always MSB first */
894 bitsMask
= bitsMask
>> 1;
900 } while (bits
& bitsMask
);
901 XFillRectangle (gdi_display
, physDev
->drawable
,
902 physDev
->gc
, xspan
, y
, lenspan
, 1);
914 bitsMask
= bitsMask
>> 1;
920 } while (!(bits
& bitsMask
));
927 static void SharpGlyphGray(X11DRV_PDEVICE
*physDev
, INT x
, INT y
,
928 void *bitmap
, XGlyphInfo
*gi
)
930 unsigned char *srcLine
= bitmap
, *src
, bits
;
931 int width
= gi
->width
;
932 int stride
= ((width
+ 3) & ~3);
933 int height
= gi
->height
;
958 } while (bits
>= 0x80);
959 XFillRectangle (gdi_display
, physDev
->drawable
,
960 physDev
->gc
, xspan
, y
, lenspan
, 1);
973 } while (bits
< 0x80);
981 static void ExamineBitfield (DWORD mask
, int *shift
, int *len
)
986 while ((mask
& 1) == 0)
992 while ((mask
& 1) == 1)
1001 static DWORD
GetField (DWORD pixel
, int shift
, int len
)
1003 pixel
= pixel
& (((1 << (len
)) - 1) << shift
);
1004 pixel
= pixel
<< (32 - (shift
+ len
)) >> 24;
1007 pixel
|= (pixel
>> len
);
1014 static DWORD
PutField (DWORD pixel
, int shift
, int len
)
1016 shift
= shift
- (8 - len
);
1018 pixel
&= (((1 << len
) - 1) << (8 - len
));
1026 static void SmoothGlyphGray(XImage
*image
, int x
, int y
, void *bitmap
, XGlyphInfo
*gi
,
1032 BYTE
*maskLine
, *mask
, m
;
1037 BYTE src_r
, src_g
, src_b
;
1042 height
= gi
->height
;
1044 maskLine
= (unsigned char *) bitmap
;
1045 maskStride
= (width
+ 3) & ~3;
1047 ExamineBitfield (image
->red_mask
, &r_shift
, &r_len
);
1048 ExamineBitfield (image
->green_mask
, &g_shift
, &g_len
);
1049 ExamineBitfield (image
->blue_mask
, &b_shift
, &b_len
);
1051 src_r
= GetField(color
, r_shift
, r_len
);
1052 src_g
= GetField(color
, g_shift
, g_len
);
1053 src_b
= GetField(color
, b_shift
, b_len
);
1055 for(; height
--; y
++)
1058 maskLine
+= maskStride
;
1063 if(y
>= image
->height
) break;
1067 if(tx
>= image
->width
) break;
1070 if(tx
< 0) continue;
1073 XPutPixel (image
, tx
, y
, color
);
1078 pixel
= XGetPixel (image
, tx
, y
);
1080 r
= GetField(pixel
, r_shift
, r_len
);
1081 r
= ((BYTE
)~m
* (WORD
)r
+ (BYTE
)m
* (WORD
)src_r
) >> 8;
1082 g
= GetField(pixel
, g_shift
, g_len
);
1083 g
= ((BYTE
)~m
* (WORD
)g
+ (BYTE
)m
* (WORD
)src_g
) >> 8;
1084 b
= GetField(pixel
, b_shift
, b_len
);
1085 b
= ((BYTE
)~m
* (WORD
)b
+ (BYTE
)m
* (WORD
)src_b
) >> 8;
1087 pixel
= (PutField (r
, r_shift
, r_len
) |
1088 PutField (g
, g_shift
, g_len
) |
1089 PutField (b
, b_shift
, b_len
));
1090 XPutPixel (image
, tx
, y
, pixel
);
1096 /*************************************************************
1099 * Returns an appropriate Picture for tiling the text colour.
1100 * Call and use result within the xrender_cs
1102 static Picture
get_tile_pict(enum drawable_depth_type type
, int text_pixel
)
1112 tile
= &tiles
[type
];
1116 XRenderPictureAttributes pa
;
1119 tile
->xpm
= XCreatePixmap(gdi_display
, root_window
, 1, 1, pict_formats
[type
]->depth
);
1122 tile
->pict
= pXRenderCreatePicture(gdi_display
, tile
->xpm
, pict_formats
[type
], CPRepeat
, &pa
);
1123 wine_tsx11_unlock();
1125 /* init current_color to something different from text_pixel */
1126 tile
->current_color
= ~text_pixel
;
1128 if(type
== mono_drawable
)
1130 /* for a 1bpp bitmap we always need a 1 in the tile */
1131 col
.red
= col
.green
= col
.blue
= 0;
1134 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1135 wine_tsx11_unlock();
1139 if(text_pixel
!= tile
->current_color
&& type
== color_drawable
)
1141 /* Map 0 -- 0xff onto 0 -- 0xffff */
1146 ExamineBitfield (visual
->red_mask
, &r_shift
, &r_len
);
1147 ExamineBitfield (visual
->green_mask
, &g_shift
, &g_len
);
1148 ExamineBitfield (visual
->blue_mask
, &b_shift
, &b_len
);
1150 col
.red
= GetField(text_pixel
, r_shift
, r_len
);
1151 col
.red
|= col
.red
<< 8;
1152 col
.green
= GetField(text_pixel
, g_shift
, g_len
);
1153 col
.green
|= col
.green
<< 8;
1154 col
.blue
= GetField(text_pixel
, b_shift
, b_len
);
1155 col
.blue
|= col
.blue
<< 8;
1159 pXRenderFillRectangle(gdi_display
, PictOpSrc
, tile
->pict
, &col
, 0, 0, 1, 1);
1160 wine_tsx11_unlock();
1161 tile
->current_color
= text_pixel
;
1166 static int XRenderErrorHandler(Display
*dpy
, XErrorEvent
*event
, void *arg
)
1171 /***********************************************************************
1172 * X11DRV_XRender_ExtTextOut
1174 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1175 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1180 gsCacheEntry
*entry
;
1181 gsCacheEntryFormat
*formatEntry
;
1183 HDC hdc
= physDev
->hdc
;
1184 int textPixel
, backgroundPixel
;
1185 HRGN saved_region
= 0;
1186 BOOL disable_antialias
= FALSE
;
1187 AA_Type aa_type
= AA_None
;
1190 double cosEsc
, sinEsc
;
1192 enum drawable_depth_type depth_type
= (physDev
->depth
== 1) ? mono_drawable
: color_drawable
;
1193 Picture tile_pict
= 0;
1195 /* Do we need to disable antialiasing because of palette mode? */
1196 if( !physDev
->bitmap
|| GetObjectW( physDev
->bitmap
->hbitmap
, sizeof(bmp
), &bmp
) != sizeof(bmp
) ) {
1197 TRACE("bitmap is not a DIB\n");
1199 else if (bmp
.dsBmih
.biBitCount
<= 8) {
1200 TRACE("Disabling antialiasing\n");
1201 disable_antialias
= TRUE
;
1204 xgcval
.function
= GXcopy
;
1205 xgcval
.background
= physDev
->backgroundPixel
;
1206 xgcval
.fill_style
= FillSolid
;
1208 XChangeGC( gdi_display
, physDev
->gc
, GCFunction
| GCBackground
| GCFillStyle
, &xgcval
);
1209 wine_tsx11_unlock();
1211 X11DRV_LockDIBSection( physDev
, DIB_Status_GdiMod
);
1213 if(physDev
->depth
== 1) {
1214 if((physDev
->textPixel
& 0xffffff) == 0) {
1216 backgroundPixel
= 1;
1219 backgroundPixel
= 0;
1222 textPixel
= physDev
->textPixel
;
1223 backgroundPixel
= physDev
->backgroundPixel
;
1226 if(flags
& ETO_OPAQUE
)
1229 XSetForeground( gdi_display
, physDev
->gc
, backgroundPixel
);
1230 XFillRectangle( gdi_display
, physDev
->drawable
, physDev
->gc
,
1231 physDev
->dc_rect
.left
+ lprect
->left
, physDev
->dc_rect
.top
+ lprect
->top
,
1232 lprect
->right
- lprect
->left
, lprect
->bottom
- lprect
->top
);
1233 wine_tsx11_unlock();
1243 GetObjectW(GetCurrentObject(physDev
->hdc
, OBJ_FONT
), sizeof(lf
), &lf
);
1244 if(lf
.lfEscapement
!= 0) {
1245 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
1246 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
1252 if (flags
& ETO_CLIPPED
)
1256 clip_region
= CreateRectRgnIndirect( lprect
);
1257 /* make a copy of the current device region */
1258 saved_region
= CreateRectRgn( 0, 0, 0, 0 );
1259 CombineRgn( saved_region
, physDev
->region
, 0, RGN_COPY
);
1260 X11DRV_SetDeviceClipping( physDev
, saved_region
, clip_region
);
1261 DeleteObject( clip_region
);
1264 if(X11DRV_XRender_Installed
) {
1265 if(!physDev
->xrender
->pict
) {
1266 XRenderPictureAttributes pa
;
1267 pa
.subwindow_mode
= IncludeInferiors
;
1270 physDev
->xrender
->pict
= pXRenderCreatePicture(gdi_display
,
1272 pict_formats
[depth_type
],
1273 CPSubwindowMode
, &pa
);
1274 wine_tsx11_unlock();
1276 TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1277 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1279 TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1280 physDev
->xrender
->pict
, hdc
, physDev
->drawable
);
1283 if ((data
= X11DRV_GetRegionData( physDev
->region
, 0 )))
1286 pXRenderSetPictureClipRectangles( gdi_display
, physDev
->xrender
->pict
,
1287 physDev
->dc_rect
.left
, physDev
->dc_rect
.top
,
1288 (XRectangle
*)data
->Buffer
, data
->rdh
.nCount
);
1289 wine_tsx11_unlock();
1290 HeapFree( GetProcessHeap(), 0, data
);
1294 EnterCriticalSection(&xrender_cs
);
1296 entry
= glyphsetCache
+ physDev
->xrender
->cache_index
;
1297 if( disable_antialias
== FALSE
)
1298 aa_type
= entry
->aa_default
;
1299 formatEntry
= entry
->format
[aa_type
];
1301 for(idx
= 0; idx
< count
; idx
++) {
1302 if( !formatEntry
) {
1303 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1304 /* re-evaluate antialias since aa_default may have changed */
1305 if( disable_antialias
== FALSE
)
1306 aa_type
= entry
->aa_default
;
1307 formatEntry
= entry
->format
[aa_type
];
1308 } else if( wstr
[idx
] >= formatEntry
->nrealized
|| formatEntry
->realized
[wstr
[idx
]] == FALSE
) {
1309 UploadGlyph(physDev
, wstr
[idx
], aa_type
);
1314 WARN("could not upload requested glyphs\n");
1315 LeaveCriticalSection(&xrender_cs
);
1319 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr
,count
),
1320 physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1322 if(X11DRV_XRender_Installed
)
1324 XGlyphElt16
*elts
= HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16
) * count
);
1326 POINT desired
, current
;
1327 int render_op
= PictOpOver
;
1329 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1330 So we pass zeros to the function and move to our starting position using the first
1331 element of the elts array. */
1333 desired
.x
= physDev
->dc_rect
.left
+ x
;
1334 desired
.y
= physDev
->dc_rect
.top
+ y
;
1335 current
.x
= current
.y
= 0;
1337 tile_pict
= get_tile_pict(depth_type
, physDev
->textPixel
);
1339 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1341 if((depth_type
== mono_drawable
) && (textPixel
== 0))
1342 render_op
= PictOpOutReverse
; /* This gives us 'black' text */
1344 for(idx
= 0; idx
< count
; idx
++)
1346 elts
[idx
].glyphset
= formatEntry
->glyphset
;
1347 elts
[idx
].chars
= wstr
+ idx
;
1348 elts
[idx
].nchars
= 1;
1349 elts
[idx
].xOff
= desired
.x
- current
.x
;
1350 elts
[idx
].yOff
= desired
.y
- current
.y
;
1352 current
.x
+= (elts
[idx
].xOff
+ formatEntry
->gis
[wstr
[idx
]].xOff
);
1353 current
.y
+= (elts
[idx
].yOff
+ formatEntry
->gis
[wstr
[idx
]].yOff
);
1357 desired
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1358 desired
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1362 offset
+= lpDx
[idx
];
1363 desired
.x
= physDev
->dc_rect
.left
+ x
+ offset
* cosEsc
;
1364 desired
.y
= physDev
->dc_rect
.top
+ y
- offset
* sinEsc
;
1368 pXRenderCompositeText16(gdi_display
, render_op
,
1370 physDev
->xrender
->pict
,
1371 formatEntry
->font_format
,
1372 0, 0, 0, 0, elts
, count
);
1373 wine_tsx11_unlock();
1374 HeapFree(GetProcessHeap(), 0, elts
);
1376 INT offset
= 0, xoff
= 0, yoff
= 0;
1378 XSetForeground( gdi_display
, physDev
->gc
, textPixel
);
1380 if(aa_type
== AA_None
|| physDev
->depth
== 1)
1382 void (* sharp_glyph_fn
)(X11DRV_PDEVICE
*, INT
, INT
, void *, XGlyphInfo
*);
1384 if(aa_type
== AA_None
)
1385 sharp_glyph_fn
= SharpGlyphMono
;
1387 sharp_glyph_fn
= SharpGlyphGray
;
1389 for(idx
= 0; idx
< count
; idx
++) {
1390 sharp_glyph_fn(physDev
, physDev
->dc_rect
.left
+ x
+ xoff
,
1391 physDev
->dc_rect
.top
+ y
+ yoff
,
1392 formatEntry
->bitmaps
[wstr
[idx
]],
1393 &formatEntry
->gis
[wstr
[idx
]]);
1395 offset
+= lpDx
[idx
];
1396 xoff
= offset
* cosEsc
;
1397 yoff
= offset
* -sinEsc
;
1399 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1400 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1405 int image_x
, image_y
, image_off_x
, image_off_y
, image_w
, image_h
;
1406 RECT extents
= {0, 0, 0, 0};
1408 int w
= physDev
->drawable_rect
.right
- physDev
->drawable_rect
.left
;
1409 int h
= physDev
->drawable_rect
.bottom
- physDev
->drawable_rect
.top
;
1411 TRACE("drawable %dx%d\n", w
, h
);
1413 for(idx
= 0; idx
< count
; idx
++) {
1414 if(extents
.left
> cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
)
1415 extents
.left
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
;
1416 if(extents
.top
> cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
)
1417 extents
.top
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
;
1418 if(extents
.right
< cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
)
1419 extents
.right
= cur
.x
- formatEntry
->gis
[wstr
[idx
]].x
+ formatEntry
->gis
[wstr
[idx
]].width
;
1420 if(extents
.bottom
< cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
)
1421 extents
.bottom
= cur
.y
- formatEntry
->gis
[wstr
[idx
]].y
+ formatEntry
->gis
[wstr
[idx
]].height
;
1423 offset
+= lpDx
[idx
];
1424 cur
.x
= offset
* cosEsc
;
1425 cur
.y
= offset
* -sinEsc
;
1427 cur
.x
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1428 cur
.y
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1431 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents
.left
, extents
.top
,
1432 extents
.right
, extents
.bottom
, physDev
->dc_rect
.left
+ x
, physDev
->dc_rect
.top
+ y
);
1434 if(physDev
->dc_rect
.left
+ x
+ extents
.left
>= 0) {
1435 image_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1439 image_off_x
= physDev
->dc_rect
.left
+ x
+ extents
.left
;
1441 if(physDev
->dc_rect
.top
+ y
+ extents
.top
>= 0) {
1442 image_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1446 image_off_y
= physDev
->dc_rect
.top
+ y
+ extents
.top
;
1448 if(physDev
->dc_rect
.left
+ x
+ extents
.right
< w
)
1449 image_w
= physDev
->dc_rect
.left
+ x
+ extents
.right
- image_x
;
1451 image_w
= w
- image_x
;
1452 if(physDev
->dc_rect
.top
+ y
+ extents
.bottom
< h
)
1453 image_h
= physDev
->dc_rect
.top
+ y
+ extents
.bottom
- image_y
;
1455 image_h
= h
- image_y
;
1457 if(image_w
<= 0 || image_h
<= 0) goto no_image
;
1459 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1460 image
= XGetImage(gdi_display
, physDev
->drawable
,
1461 image_x
, image_y
, image_w
, image_h
,
1462 AllPlanes
, ZPixmap
);
1463 X11DRV_check_error();
1465 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1466 gdi_display
, (int)physDev
->drawable
, image_x
, image_y
,
1467 image_w
, image_h
, AllPlanes
, ZPixmap
,
1468 physDev
->depth
, image
);
1470 Pixmap xpm
= XCreatePixmap(gdi_display
, root_window
, image_w
, image_h
,
1475 gcv
.graphics_exposures
= False
;
1476 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1477 XCopyArea(gdi_display
, physDev
->drawable
, xpm
, gc
, image_x
, image_y
,
1478 image_w
, image_h
, 0, 0);
1479 XFreeGC(gdi_display
, gc
);
1480 X11DRV_expect_error(gdi_display
, XRenderErrorHandler
, NULL
);
1481 image
= XGetImage(gdi_display
, xpm
, 0, 0, image_w
, image_h
, AllPlanes
,
1483 X11DRV_check_error();
1484 XFreePixmap(gdi_display
, xpm
);
1486 if(!image
) goto no_image
;
1488 image
->red_mask
= visual
->red_mask
;
1489 image
->green_mask
= visual
->green_mask
;
1490 image
->blue_mask
= visual
->blue_mask
;
1492 offset
= xoff
= yoff
= 0;
1493 for(idx
= 0; idx
< count
; idx
++) {
1494 SmoothGlyphGray(image
, xoff
+ image_off_x
- extents
.left
,
1495 yoff
+ image_off_y
- extents
.top
,
1496 formatEntry
->bitmaps
[wstr
[idx
]],
1497 &formatEntry
->gis
[wstr
[idx
]],
1498 physDev
->textPixel
);
1500 offset
+= lpDx
[idx
];
1501 xoff
= offset
* cosEsc
;
1502 yoff
= offset
* -sinEsc
;
1504 xoff
+= formatEntry
->gis
[wstr
[idx
]].xOff
;
1505 yoff
+= formatEntry
->gis
[wstr
[idx
]].yOff
;
1508 XPutImage(gdi_display
, physDev
->drawable
, physDev
->gc
, image
, 0, 0,
1509 image_x
, image_y
, image_w
, image_h
);
1510 XDestroyImage(image
);
1513 wine_tsx11_unlock();
1515 LeaveCriticalSection(&xrender_cs
);
1517 if (flags
& ETO_CLIPPED
)
1519 /* restore the device region */
1520 X11DRV_SetDeviceClipping( physDev
, saved_region
, 0 );
1521 DeleteObject( saved_region
);
1527 X11DRV_UnlockDIBSection( physDev
, TRUE
);
1531 /******************************************************************************
1532 * AlphaBlend (x11drv.@)
1534 BOOL CDECL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1535 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1536 BLENDFUNCTION blendfn
)
1538 XRenderPictureAttributes pa
;
1539 XRenderPictFormat
*src_format
;
1540 XRenderPictFormat argb32_templ
= {
1542 PictTypeDirect
, /* type */
1545 16, /* direct.red */
1546 0xff, /* direct.redMask */
1547 8, /* direct.green */
1548 0xff, /* direct.greenMask */
1549 0, /* direct.blue */
1550 0xff, /* direct.blueMask */
1551 24, /* direct.alpha */
1552 0xff, /* direct.alphaMask */
1556 unsigned long argb32_templ_mask
=
1562 PictFormatGreenMask
|
1564 PictFormatBlueMask
|
1566 PictFormatAlphaMask
;
1568 Picture dst_pict
, src_pict
;
1574 DWORD
*dstbits
, *data
;
1577 BOOL top_down
= FALSE
;
1579 enum drawable_depth_type dst_depth_type
= (devDst
->depth
== 1) ? mono_drawable
: color_drawable
;
1581 if(!X11DRV_XRender_Installed
) {
1582 FIXME("Unable to AlphaBlend without Xrender\n");
1587 pts
[1].x
= xDst
+ widthDst
;
1588 pts
[1].y
= yDst
+ heightDst
;
1589 LPtoDP(devDst
->hdc
, pts
, 2);
1592 widthDst
= pts
[1].x
- pts
[0].x
;
1593 heightDst
= pts
[1].y
- pts
[0].y
;
1597 pts
[1].x
= xSrc
+ widthSrc
;
1598 pts
[1].y
= ySrc
+ heightSrc
;
1599 LPtoDP(devSrc
->hdc
, pts
, 2);
1602 widthSrc
= pts
[1].x
- pts
[0].x
;
1603 heightSrc
= pts
[1].y
- pts
[0].y
;
1604 if (!widthDst
|| !heightDst
|| !widthSrc
|| !heightSrc
) return TRUE
;
1606 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1607 if(widthDst
!= widthSrc
|| heightDst
!= heightSrc
)
1609 if(!pXRenderSetPictureTransform
)
1612 FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1616 if (!devSrc
->bitmap
|| GetObjectW( devSrc
->bitmap
->hbitmap
, sizeof(dib
), &dib
) != sizeof(dib
))
1618 static BOOL out
= FALSE
;
1621 FIXME("not a dibsection\n");
1627 if (xSrc
< 0 || ySrc
< 0 || widthSrc
< 0 || heightSrc
< 0 || xSrc
+ widthSrc
> dib
.dsBmih
.biWidth
1628 || ySrc
+ heightSrc
> abs(dib
.dsBmih
.biHeight
))
1630 WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc
, ySrc
, widthSrc
, heightSrc
);
1631 SetLastError(ERROR_INVALID_PARAMETER
);
1635 if ((blendfn
.AlphaFormat
& AC_SRC_ALPHA
) && blendfn
.SourceConstantAlpha
!= 0xff)
1636 FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn
.SourceConstantAlpha
);
1638 if(dib
.dsBm
.bmBitsPixel
!= 32) {
1639 FIXME("not a 32 bpp dibsection\n");
1642 dstbits
= data
= HeapAlloc(GetProcessHeap(), 0, heightSrc
* widthSrc
* 4);
1644 if(dib
.dsBmih
.biHeight
< 0) { /* top-down dib */
1646 dstbits
+= widthSrc
* (heightSrc
- 1);
1648 y
= y2
+ heightSrc
- 1;
1652 y
= dib
.dsBmih
.biHeight
- ySrc
- 1;
1653 y2
= y
- heightSrc
+ 1;
1656 if (blendfn
.AlphaFormat
& AC_SRC_ALPHA
)
1660 memcpy(dstbits
, (char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
+ xSrc
* 4,
1662 dstbits
+= (top_down
? -1 : 1) * widthSrc
;
1667 DWORD source_alpha
= (DWORD
)blendfn
.SourceConstantAlpha
<< 24;
1672 DWORD
*srcbits
= (DWORD
*)((char *)dib
.dsBm
.bmBits
+ y
* dib
.dsBm
.bmWidthBytes
) + xSrc
;
1673 for (x
= 0; x
< widthSrc
; x
++)
1675 DWORD argb
= *srcbits
++;
1676 argb
= (argb
& 0xffffff) | source_alpha
;
1679 if (top_down
) /* we traversed the row forward so we should go back by two rows */
1680 dstbits
-= 2 * widthSrc
;
1685 rgndata
= X11DRV_GetRegionData( devDst
->region
, 0 );
1688 image
= XCreateImage(gdi_display
, visual
, 32, ZPixmap
, 0,
1689 (char*) data
, widthSrc
, heightSrc
, 32, widthSrc
* 4);
1692 Avoid using XRenderFindStandardFormat as older libraries don't have it
1693 src_format = pXRenderFindStandardFormat(gdi_display, PictStandardARGB32);
1695 src_format
= pXRenderFindFormat(gdi_display
, argb32_templ_mask
, &argb32_templ
, 0);
1697 TRACE("src_format %p\n", src_format
);
1699 pa
.subwindow_mode
= IncludeInferiors
;
1701 /* FIXME use devDst->xrender->pict ? */
1702 dst_pict
= pXRenderCreatePicture(gdi_display
,
1704 pict_formats
[dst_depth_type
],
1705 CPSubwindowMode
, &pa
);
1706 TRACE("dst_pict %08lx\n", dst_pict
);
1707 TRACE("src_drawable = %08lx\n", devSrc
->drawable
);
1708 xpm
= XCreatePixmap(gdi_display
,
1710 widthSrc
, heightSrc
, 32);
1711 gcv
.graphics_exposures
= False
;
1712 gc
= XCreateGC(gdi_display
, xpm
, GCGraphicsExposures
, &gcv
);
1713 TRACE("xpm = %08lx\n", xpm
);
1714 XPutImage(gdi_display
, xpm
, gc
, image
, 0, 0, 0, 0, widthSrc
, heightSrc
);
1716 src_pict
= pXRenderCreatePicture(gdi_display
,
1718 CPSubwindowMode
, &pa
);
1719 TRACE("src_pict %08lx\n", src_pict
);
1723 pXRenderSetPictureClipRectangles( gdi_display
, dst_pict
,
1724 devDst
->dc_rect
.left
, devDst
->dc_rect
.top
,
1725 (XRectangle
*)rgndata
->Buffer
,
1726 rgndata
->rdh
.nCount
);
1727 HeapFree( GetProcessHeap(), 0, rgndata
);
1730 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1731 if(widthDst
!= widthSrc
|| heightDst
!= heightSrc
) {
1732 double xscale
= widthSrc
/(double)widthDst
;
1733 double yscale
= heightSrc
/(double)heightDst
;
1734 XTransform xform
= {{
1735 { XDoubleToFixed(xscale
), XDoubleToFixed(0), XDoubleToFixed(0) },
1736 { XDoubleToFixed(0), XDoubleToFixed(yscale
), XDoubleToFixed(0) },
1737 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1739 pXRenderSetPictureTransform(gdi_display
, src_pict
, &xform
);
1742 pXRenderComposite(gdi_display
, PictOpOver
, src_pict
, 0, dst_pict
,
1744 xDst
+ devDst
->dc_rect
.left
, yDst
+ devDst
->dc_rect
.top
, widthDst
, heightDst
);
1747 pXRenderFreePicture(gdi_display
, src_pict
);
1748 XFreePixmap(gdi_display
, xpm
);
1749 XFreeGC(gdi_display
, gc
);
1750 pXRenderFreePicture(gdi_display
, dst_pict
);
1752 XDestroyImage(image
);
1754 wine_tsx11_unlock();
1755 HeapFree(GetProcessHeap(), 0, data
);
1759 #else /* SONAME_LIBXRENDER */
1761 void X11DRV_XRender_Init(void)
1763 TRACE("XRender support not compiled in.\n");
1767 void X11DRV_XRender_Finalize(void)
1771 BOOL
X11DRV_XRender_SelectFont(X11DRV_PDEVICE
*physDev
, HFONT hfont
)
1777 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE
*physDev
)
1783 BOOL
X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE
*physDev
, INT x
, INT y
, UINT flags
,
1784 const RECT
*lprect
, LPCWSTR wstr
, UINT count
,
1791 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE
*physDev
)
1797 /******************************************************************************
1798 * AlphaBlend (x11drv.@)
1800 BOOL
X11DRV_AlphaBlend(X11DRV_PDEVICE
*devDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
1801 X11DRV_PDEVICE
*devSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
,
1802 BLENDFUNCTION blendfn
)
1804 FIXME("not supported - XRENDER headers were missing at compile time\n");
1808 #endif /* SONAME_LIBXRENDER */