Second part of font stuff from CodeWeaver's Patch
Huw D M Davies
h.davies1 at physics.ox.ac.uk
Sat Jan 26 09:36:04 CST 2002
This requires the first part of the font stuff.
Huw D M Davies <hdavies at codeweavers.com>
Uses Xrender extension to allow client side font rendering.
Adds nice things like anti-aliased text.
-------------- next part --------------
? dlls/x11drv/xrender.c
Index: dlls/x11drv/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/Makefile.in,v
retrieving revision 1.15
diff -u -r1.15 Makefile.in
--- dlls/x11drv/Makefile.in 2001/10/18 21:38:59 1.15
+++ dlls/x11drv/Makefile.in 2002/01/26 13:36:58
@@ -15,6 +15,7 @@
winpos.c \
x11ddraw.c \
x11drv_main.c \
+ xrender.c \
xvidmode.c
PROGRAMS = \
Index: dlls/x11drv/x11drv.spec
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/x11drv.spec,v
retrieving revision 1.28
diff -u -r1.28 x11drv.spec
--- dlls/x11drv/x11drv.spec 2002/01/04 18:27:44 1.28
+++ dlls/x11drv/x11drv.spec 2002/01/26 13:36:58
@@ -9,7 +9,7 @@
import ntdll.dll
debug_channels (bitblt bitmap clipboard cursor dinput event font gdi graphics
- key keyboard opengl palette text win x11drv)
+ key keyboard opengl palette text win x11drv xrender)
# GDI driver
Index: graphics/x11drv/clipping.c
===================================================================
RCS file: /home/wine/wine/graphics/x11drv/clipping.c,v
retrieving revision 1.17
diff -u -r1.17 clipping.c
--- graphics/x11drv/clipping.c 2001/07/25 00:43:35 1.17
+++ graphics/x11drv/clipping.c 2002/01/26 13:36:58
@@ -99,6 +99,8 @@
dc->DCOrgY = org_y;
physDev->drawable = drawable;
TSXSetSubwindowMode( gdi_display, physDev->gc, mode );
+ if(physDev->xrender)
+ X11DRV_XRender_UpdateDrawable(dc);
GDI_ReleaseObj( hdc );
}
}
Index: graphics/x11drv/init.c
===================================================================
RCS file: /home/wine/wine/graphics/x11drv/init.c,v
retrieving revision 1.42
diff -u -r1.42 init.c
--- graphics/x11drv/init.c 2002/01/04 18:27:44 1.42
+++ graphics/x11drv/init.c 2002/01/26 13:36:59
@@ -66,6 +66,9 @@
if (!X11DRV_BITMAP_Init()) return FALSE;
+ /* Initialize XRender */
+ X11DRV_XRender_Init();
+
/* Initialize fonts and text caps */
log_pixels_x = MulDiv( WidthOfScreen(screen), 254, WidthMMOfScreen(screen) * 10 );
@@ -157,6 +160,9 @@
BOOL X11DRV_DeleteDC( DC *dc )
{
X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
+
+ if(physDev->xrender)
+ X11DRV_XRender_DeleteDC(dc);
wine_tsx11_lock();
XFreeGC( gdi_display, physDev->gc );
while (physDev->used_visuals-- > 0)
Index: graphics/x11drv/text.c
===================================================================
RCS file: /home/wine/wine/graphics/x11drv/text.c,v
retrieving revision 1.27
diff -u -r1.27 text.c
--- graphics/x11drv/text.c 2001/07/25 00:43:35 1.27
+++ graphics/x11drv/text.c 2002/01/26 13:36:59
@@ -46,11 +46,17 @@
BOOL dibUpdateFlag = FALSE;
BOOL result = TRUE;
+
+ if(dc->gdiFont)
+ return X11DRV_XRender_ExtTextOut(dc, x, y, flags, lprect, wstr, count,
+ lpDx);
+
+
if (!X11DRV_SetupGCForText( dc )) return TRUE;
pfo = XFONT_GetFontObject( physDev->font );
font = pfo->fs;
-
+
if (pfo->lf.lfEscapement && pfo->lpX11Trans)
rotated = TRUE;
dfBreakChar = (char)pfo->fi->df.dfBreakChar;
Index: graphics/x11drv/xfont.c
===================================================================
RCS file: /home/wine/wine/graphics/x11drv/xfont.c,v
retrieving revision 1.89
diff -u -r1.89 xfont.c
--- graphics/x11drv/xfont.c 2001/11/06 00:46:36 1.89
+++ graphics/x11drv/xfont.c 2002/01/26 13:36:59
@@ -206,6 +206,10 @@
{ "1", DEFAULT_CHARSET, 0, X11DRV_CPTABLE_UNICODE },
{ NULL, DEFAULT_CHARSET, 0, X11DRV_CPTABLE_UNICODE }};
+static const SuffixCharset sufch_dec[] = {
+ { "dectech", SYMBOL_CHARSET, CP_SYMBOL, X11DRV_CPTABLE_SBCS },
+ { NULL, 0, 0, X11DRV_CPTABLE_SBCS }};
+
/* Each of these must be matched explicitly */
static const SuffixCharset sufch_any[] = {
{ "fontspecific", SYMBOL_CHARSET, CP_SYMBOL, X11DRV_CPTABLE_SBCS },
@@ -244,6 +248,7 @@
{ "unicode", sufch_unicode, &__fETTable[19]},
{ "iso10646", sufch_iso10646, &__fETTable[20]},
{ "cp", sufch_windows, &__fETTable[21]},
+ { "dec", sufch_dec, &__fETTable[22]},
/* NULL prefix matches anything so put it last */
{ NULL, sufch_any, NULL },
};
@@ -2919,6 +2924,10 @@
RAW_ASCENT = TSXInternAtom(gdi_display, "RAW_ASCENT", TRUE);
RAW_DESCENT = TSXInternAtom(gdi_display, "RAW_DESCENT", TRUE);
+
+ if(X11DRV_XRender_Installed)
+ XTextCaps |= TC_VA_ABLE;
+
return XTextCaps;
}
@@ -3166,10 +3175,16 @@
LOGFONT16 lf;
X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
+ TRACE("dc=%p, hfont=%04x\n", dc, hfont);
+
if (!GetObjectW( hfont, sizeof(logfont), &logfont )) return GDI_ERROR;
+
+ TRACE("dc->gdiFont = %p\n", dc->gdiFont);
- /* If we want to use a gdi font, we should check for XRender extension
- and return FALSE here */
+ if(dc->gdiFont && X11DRV_XRender_Installed) {
+ X11DRV_XRender_SelectFont(dc, hfont);
+ return FALSE;
+ }
EnterCriticalSection( &crtsc_fonts_X11 );
--- /dev/null Sat Mar 24 04:37:44 2001
+++ dlls/x11drv/xrender.c Sat Jan 26 15:22:37 2002
@@ -0,0 +1,826 @@
+/*
+ * Functions to use the XRender extension
+ *
+ * Copyright 2001 Huw D M Davies for CodeWeavers
+ */
+#include "config.h"
+
+#include "winnt.h"
+#include "x11drv.h"
+#include "bitmap.h"
+#include "debugtools.h"
+#include "region.h"
+#include <string.h>
+#include <stdlib.h>
+#include "wine/unicode.h"
+#include <assert.h>
+
+BOOL X11DRV_XRender_Installed = FALSE;
+DEFAULT_DEBUG_CHANNEL(xrender);
+
+#ifdef HAVE_LIBXRENDER
+
+#include "ts_xlib.h"
+#include "ts_xrender.h"
+
+static XRenderPictFormat *screen_format; /* format of screen */
+static XRenderPictFormat *mono_format; /* format of mono bitmap */
+
+typedef struct
+{
+ LOGFONTW lf;
+ XFORM xform; /* this is dum as we don't care about offsets */
+ DWORD hash;
+} LFANDSIZE;
+
+#define INITIAL_REALIZED_BUF_SIZE 128
+
+
+typedef struct
+{
+ LFANDSIZE lfsz;
+ GlyphSet glyphset;
+ XRenderPictFormat *font_format;
+ int nrealized;
+ BOOL *realized;
+ UINT count;
+ INT next;
+} gsCacheEntry;
+
+struct tagXRENDERINFO
+{
+ gsCacheEntry *cacheEntry;
+ Picture pict;
+ Picture tile_pict;
+ Pixmap tile_xpm;
+ COLORREF lastTextColor;
+};
+
+
+static gsCacheEntry *glyphsetCache = NULL;
+static DWORD glyphsetCacheSize = 0;
+static INT lastfree = -1;
+static INT mru = -1;
+
+#define INIT_CACHE_SIZE 10
+
+static int antialias = 1;
+
+/***********************************************************************
+ * X11DRV_XRender_Init
+ *
+ * Let's see if our XServer has the extension available
+ *
+ */
+void X11DRV_XRender_Init(void)
+{
+ int error_base, event_base, i;
+ XRenderPictFormat pf;
+
+ if(TSXRenderQueryExtension(gdi_display, &event_base, &error_base)) {
+ X11DRV_XRender_Installed = TRUE;
+ TRACE("Xrender is up and running error_base = %d\n", error_base);
+ screen_format = TSXRenderFindVisualFormat(gdi_display, visual);
+ pf.type = PictTypeDirect;
+ pf.depth = 1;
+ pf.direct.alpha = 0;
+ pf.direct.alphaMask = 1;
+ mono_format = TSXRenderFindFormat(gdi_display, PictFormatType |
+ PictFormatDepth | PictFormatAlpha |
+ PictFormatAlphaMask, &pf, 0);
+
+ glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
+
+ glyphsetCacheSize = INIT_CACHE_SIZE;
+ lastfree = 0;
+ for(i = 0; i < INIT_CACHE_SIZE; i++) {
+ glyphsetCache[i].next = i + 1;
+ glyphsetCache[i].count = -1;
+ }
+ glyphsetCache[i-1].next = -1;
+ } else {
+ TRACE("Xrender is not available on this server\n");
+ }
+ return;
+}
+
+static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
+{
+ if(p1->hash != p2->hash) return TRUE;
+ if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
+ if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
+ return strcmpW(p1->lf.lfFaceName, p2->lf.lfFaceName);
+}
+
+static void walk_cache(void)
+{
+ int i;
+
+ for(i=mru; i >= 0; i = glyphsetCache[i].next)
+ TRACE("item %d\n", i);
+}
+
+static gsCacheEntry *LookupEntry(LFANDSIZE *plfsz)
+{
+ int i, prev_i = -1;
+
+ for(i = mru; i >= 0; i = glyphsetCache[i].next) {
+ TRACE("%d\n", i);
+ if(glyphsetCache[i].count == -1) { /* reached free list so stop */
+ i = -1;
+ break;
+ }
+
+ if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
+ glyphsetCache[i].count++;
+ if(prev_i >= 0) {
+ glyphsetCache[prev_i].next = glyphsetCache[i].next;
+ glyphsetCache[i].next = mru;
+ mru = i;
+ }
+ TRACE("found font in cache %d\n", i);
+ return glyphsetCache + i;
+ }
+ prev_i = i;
+ }
+ TRACE("font not in cache\n");
+ return NULL;
+}
+
+static gsCacheEntry *AllocEntry(void)
+{
+ int best = -1, prev_best = -1, i, prev_i = -1;
+
+ if(lastfree >= 0) {
+ assert(glyphsetCache[lastfree].count == -1);
+ glyphsetCache[lastfree].count = 1;
+ best = lastfree;
+ lastfree = glyphsetCache[lastfree].next;
+ assert(best != mru);
+ glyphsetCache[best].next = mru;
+ mru = best;
+
+ TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
+ return glyphsetCache + mru;
+ }
+
+ for(i = mru; i >= 0; i = glyphsetCache[i].next) {
+ if(glyphsetCache[i].count == 0) {
+ best = i;
+ prev_best = prev_i;
+ }
+ prev_i = i;
+ }
+
+ if(best >= 0) {
+ TRACE("freeing unused glyphset at cache %d\n", best);
+ TSXRenderFreeGlyphSet(gdi_display, glyphsetCache[best].glyphset);
+ glyphsetCache[best].glyphset = 0;
+ if(glyphsetCache[best].nrealized) { /* do we really want to do this? */
+ HeapFree(GetProcessHeap(), 0, glyphsetCache[best].realized);
+ glyphsetCache[best].realized = NULL;
+ glyphsetCache[best].nrealized = 0;
+ }
+ glyphsetCache[best].count = 1;
+ if(prev_best >= 0) {
+ glyphsetCache[prev_best].next = glyphsetCache[best].next;
+ glyphsetCache[best].next = mru;
+ mru = best;
+ } else {
+ assert(mru == best);
+ }
+ return glyphsetCache + mru;
+ }
+
+ TRACE("Growing cache\n");
+ glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ glyphsetCache,
+ (glyphsetCacheSize + INIT_CACHE_SIZE)
+ * sizeof(*glyphsetCache));
+ for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
+ i++) {
+ glyphsetCache[i].next = i + 1;
+ glyphsetCache[i].count = -1;
+ }
+ glyphsetCache[i-1].next = -1;
+ glyphsetCacheSize += INIT_CACHE_SIZE;
+
+ lastfree = glyphsetCache[best].next;
+ glyphsetCache[best].count = 1;
+ glyphsetCache[best].next = mru;
+ mru = best;
+ TRACE("new free cache slot at %d\n", mru);
+ return glyphsetCache + mru;
+}
+
+static gsCacheEntry *GetCacheEntry(LFANDSIZE *plfsz)
+{
+ XRenderPictFormat pf;
+ gsCacheEntry *ret;
+
+ if((ret = LookupEntry(plfsz)) != NULL) return ret;
+
+ ret = AllocEntry();
+ ret->lfsz = *plfsz;
+ assert(ret->nrealized == 0);
+
+
+ if(antialias && abs(plfsz->lf.lfHeight) > 16) {
+ pf.depth = 8;
+ pf.direct.alphaMask = 0xff;
+ } else {
+ pf.depth = 1;
+ pf.direct.alphaMask = 1;
+ }
+ pf.type = PictTypeDirect;
+ pf.direct.alpha = 0;
+
+ ret->font_format = TSXRenderFindFormat(gdi_display,
+ PictFormatType |
+ PictFormatDepth |
+ PictFormatAlpha |
+ PictFormatAlphaMask,
+ &pf, 0);
+
+ ret->glyphset = TSXRenderCreateGlyphSet(gdi_display, ret->font_format);
+ return ret;
+}
+
+static void dec_ref_cache(gsCacheEntry *entry)
+{
+ TRACE("dec'ing entry %d to %d\n", entry - glyphsetCache, entry->count - 1);
+ assert(entry->count > 0);
+ entry->count--;
+}
+
+static void lfsz_calc_hash(LFANDSIZE *plfsz)
+{
+ DWORD hash = 0, *ptr;
+ int i;
+
+ for(ptr = (DWORD*)&plfsz->xform; ptr < (DWORD*)(&plfsz->xform + 1); ptr++)
+ hash ^= *ptr;
+ for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
+ hash ^= *ptr;
+ for(i = 0, ptr = (DWORD*)&plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
+ WCHAR *pwc = (WCHAR *)ptr;
+ if(!*pwc) break;
+ hash ^= *ptr;
+ pwc++;
+ if(!*pwc) break;
+ }
+ plfsz->hash = hash;
+ return;
+}
+
+/***********************************************************************
+ * X11DRV_XRender_Finalize
+ */
+void X11DRV_XRender_Finalize(void)
+{
+ FIXME("Free cached glyphsets\n");
+ return;
+}
+
+
+/***********************************************************************
+ * X11DRV_XRender_SelectFont
+ */
+BOOL X11DRV_XRender_SelectFont(DC *dc, HFONT hfont)
+{
+ X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
+ LFANDSIZE lfsz;
+
+ GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
+ TRACE("h=%ld w=%ld weight=%ld it=%d charset=%d name=%s\n",
+ lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
+ lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
+ lfsz.xform = dc->xformWorld2Vport;
+ lfsz_calc_hash(&lfsz);
+
+ if(!physDev->xrender)
+ physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof(*physDev->xrender));
+
+ else if(physDev->xrender->cacheEntry)
+ dec_ref_cache(physDev->xrender->cacheEntry);
+ physDev->xrender->cacheEntry = GetCacheEntry(&lfsz);
+ return 0;
+}
+
+/***********************************************************************
+ * X11DRV_XRender_DeleteDC
+ */
+void X11DRV_XRender_DeleteDC(DC *dc)
+{
+ X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
+
+ if(physDev->xrender->tile_pict)
+ TSXRenderFreePicture(gdi_display, physDev->xrender->tile_pict);
+
+ if(physDev->xrender->tile_xpm)
+ TSXFreePixmap(gdi_display, physDev->xrender->tile_xpm);
+
+ if(physDev->xrender->pict) {
+ TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, dc);
+ TSXRenderFreePicture(gdi_display, physDev->xrender->pict);
+ }
+
+ if(physDev->xrender->cacheEntry)
+ dec_ref_cache(physDev->xrender->cacheEntry);
+
+ HeapFree(GetProcessHeap(), 0, physDev->xrender);
+ physDev->xrender = NULL;
+ return;
+}
+
+/***********************************************************************
+ * X11DRV_XRender_UpdateDrawable
+ *
+ * This gets called from X11DRV_SetDrawable and deletes the pict when the
+ * drawable changes. However at the moment we delete the pict at the end of
+ * every ExtTextOut so this is basically a NOP.
+ */
+void X11DRV_XRender_UpdateDrawable(DC *dc)
+{
+ X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
+
+ if(physDev->xrender->pict) {
+ TRACE("freeing pict %08lx from dc %p\n", physDev->xrender->pict, dc);
+ TSXRenderFreePicture(gdi_display, physDev->xrender->pict);
+ }
+ physDev->xrender->pict = 0;
+ return;
+}
+
+static BOOL UploadGlyph(DC *dc, WCHAR glyph)
+{
+ X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
+ int buflen;
+ char *buf;
+ Glyph gid;
+ GLYPHMETRICS gm;
+ XGlyphInfo gi;
+ gsCacheEntry *entry = physDev->xrender->cacheEntry;
+ UINT ggo_format;
+ BOOL aa;
+
+ if(entry->nrealized <= glyph) {
+ entry->nrealized = (glyph / 128 + 1) * 128;
+ entry->realized = HeapReAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ entry->realized,
+ entry->nrealized * sizeof(BOOL));
+ }
+ entry->realized[glyph] = TRUE;
+
+ if(entry->font_format->depth == 8) {
+ aa = TRUE;
+ ggo_format = WINE_GGO_GRAY16_BITMAP;
+ } else {
+ aa = FALSE;
+ ggo_format = GGO_BITMAP;
+ }
+
+ buflen = GetGlyphOutlineW(dc->hSelf, glyph, ggo_format, &gm, 0, NULL,
+ NULL);
+ if(buflen == GDI_ERROR)
+ return FALSE;
+
+ buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
+ GetGlyphOutlineW(dc->hSelf, glyph, ggo_format, &gm, buflen, buf, NULL);
+
+ TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%ld,%ld\n",
+ buflen,
+ gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
+ gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
+
+ gi.width = gm.gmBlackBoxX;
+ gi.height = gm.gmBlackBoxY;
+ gi.x = -gm.gmptGlyphOrigin.x;
+ gi.y = gm.gmptGlyphOrigin.y;
+ gi.xOff = gm.gmCellIncX;
+ gi.yOff = gm.gmCellIncY;
+
+ if(TRACE_ON(xrender)) {
+ int pitch, i, j;
+ char output[300];
+ unsigned char *line;
+
+ if(!aa) {
+ pitch = ((gi.width + 31) / 32) * 4;
+ for(i = 0; i < gi.height; i++) {
+ line = buf + i * pitch;
+ output[0] = '\0';
+ for(j = 0; j < pitch * 8; j++) {
+ strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
+ }
+ strcat(output, "\n");
+ TRACE(output);
+ }
+ } else {
+ char blks[] = " .:;!o*#";
+ char str[2];
+
+ str[1] = '\0';
+ pitch = ((gi.width + 3) / 4) * 4;
+ for(i = 0; i < gi.height; i++) {
+ line = buf + i * pitch;
+ output[0] = '\0';
+ for(j = 0; j < pitch; j++) {
+ str[0] = blks[line[j] >> 5];
+ strcat(output, str);
+ }
+ strcat(output, "\n");
+ TRACE(output);
+ }
+ }
+ }
+
+ if(!aa && BitmapBitOrder(gdi_display) != MSBFirst) {
+ unsigned char *byte = buf, c;
+ int i = buflen;
+
+ while(i--) {
+ c = *byte;
+
+ /* magic to flip bit order */
+ c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
+ c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
+ c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
+
+ *byte++ = c;
+ }
+ }
+ gid = glyph;
+ TSXRenderAddGlyphs(gdi_display, entry->glyphset, &gid, &gi, 1,
+ buf, buflen);
+ HeapFree(GetProcessHeap(), 0, buf);
+ return TRUE;
+}
+
+/***********************************************************************
+ * X11DRV_XRender_ExtTextOut
+ */
+BOOL X11DRV_XRender_ExtTextOut( DC *dc, INT x, INT y, UINT flags,
+ const RECT *lprect, LPCWSTR wstr, UINT count,
+ const INT *lpDx )
+{
+ XRenderColor col;
+ int idx;
+ TEXTMETRICW tm;
+ X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
+ RGNOBJ *obj;
+ XRectangle *pXrect;
+ SIZE sz;
+ RECT rc;
+ BOOL done_extents = FALSE;
+ INT width, xwidth, ywidth;
+ double cosEsc, sinEsc;
+ XGCValues xgcval;
+ LOGFONTW lf;
+ int render_op = PictOpOver;
+
+ TRACE("%04x, %d, %d, %08x, %p, %s, %d, %p)\n", dc->hSelf, x, y, flags,
+ lprect, debugstr_wn(wstr, count), count, lpDx);
+ if(lprect)
+ TRACE("rect: %d,%d - %d,%d\n", lprect->left, lprect->top, lprect->right,
+ lprect->bottom);
+ TRACE("align = %x bkmode = %x mapmode = %x\n", dc->textAlign,
+ dc->backgroundMode,
+ dc->MapMode);
+
+ if(dc->textAlign & TA_UPDATECP) {
+ x = dc->CursPosX;
+ y = dc->CursPosY;
+ }
+
+ GetObjectW(GetCurrentObject(dc->hSelf, OBJ_FONT), sizeof(lf), &lf);
+ if(lf.lfEscapement != 0) {
+ cosEsc = cos(lf.lfEscapement * M_PI / 1800);
+ sinEsc = sin(lf.lfEscapement * M_PI / 1800);
+ } else {
+ cosEsc = 1;
+ sinEsc = 0;
+ }
+
+ if(flags & (ETO_CLIPPED | ETO_OPAQUE)) {
+ if(!lprect) {
+ if(flags & ETO_CLIPPED) return FALSE;
+ GetTextExtentPointW(dc->hSelf, wstr, count, &sz);
+ done_extents = TRUE;
+ rc.left = x;
+ rc.top = y;
+ rc.right = x + sz.cx;
+ rc.bottom = y + sz.cy;
+ } else {
+ rc = *lprect;
+ }
+
+ rc.left = INTERNAL_XWPTODP(dc, rc.left, rc.top);
+ rc.top = INTERNAL_YWPTODP(dc, rc.left, rc.top);
+ rc.right = INTERNAL_XWPTODP(dc, rc.right, rc.bottom);
+ rc.bottom = INTERNAL_YWPTODP(dc, rc.right, rc.bottom);
+
+ if(rc.left > rc.right) {INT tmp = rc.left; rc.left = rc.right; rc.right = tmp;}
+ if(rc.top > rc.bottom) {INT tmp = rc.top; rc.top = rc.bottom; rc.bottom = tmp;}
+ }
+
+ xgcval.function = GXcopy;
+ xgcval.background = physDev->backgroundPixel;
+ xgcval.fill_style = FillSolid;
+ TSXChangeGC( gdi_display, physDev->gc,
+ GCFunction | GCBackground | GCFillStyle, &xgcval );
+
+ X11DRV_LockDIBSection( dc, DIB_Status_GdiMod, FALSE );
+
+ if(flags & ETO_OPAQUE) {
+ TSXSetForeground( gdi_display, physDev->gc, physDev->backgroundPixel );
+ TSXFillRectangle( gdi_display, physDev->drawable, physDev->gc,
+ dc->DCOrgX + rc.left, dc->DCOrgY + rc.top,
+ rc.right - rc.left, rc.bottom - rc.top );
+ }
+
+ if(count == 0) {
+ X11DRV_UnlockDIBSection( dc, TRUE );
+ return TRUE;
+ }
+
+ x = INTERNAL_XWPTODP( dc, x, y );
+ y = INTERNAL_YWPTODP( dc, x, y );
+
+ TRACE("real x,y %d,%d\n", x, y);
+
+ if(lpDx) {
+ width = 0;
+ for(idx = 0; idx < count; idx++)
+ width += lpDx[idx];
+ } else {
+ if(!done_extents) {
+ GetTextExtentPointW(dc->hSelf, wstr, count, &sz);
+ done_extents = TRUE;
+ }
+ width = sz.cx;
+ }
+ width = INTERNAL_XWSTODS(dc, width);
+ xwidth = width * cosEsc;
+ ywidth = width * sinEsc;
+
+ GetTextMetricsW(dc->hSelf, &tm);
+
+ switch( dc->textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER) ) {
+ case TA_LEFT:
+ if (dc->textAlign & TA_UPDATECP) {
+ dc->CursPosX = INTERNAL_XDPTOWP( dc, x + xwidth, y - ywidth );
+ dc->CursPosY = INTERNAL_YDPTOWP( dc, x + xwidth, y - ywidth );
+ }
+ break;
+
+ case TA_CENTER:
+ x -= xwidth / 2;
+ y += ywidth / 2;
+ break;
+
+ case TA_RIGHT:
+ x -= xwidth;
+ y += ywidth;
+ if (dc->textAlign & TA_UPDATECP) {
+ dc->CursPosX = INTERNAL_XDPTOWP( dc, x + xwidth, y - ywidth );
+ dc->CursPosY = INTERNAL_YDPTOWP( dc, x + xwidth, y - ywidth );
+ }
+ break;
+ }
+
+ switch( dc->textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE) ) {
+ case TA_TOP:
+ y += tm.tmAscent * cosEsc;
+ x += tm.tmAscent * sinEsc;
+ break;
+
+ case TA_BOTTOM:
+ y -= tm.tmDescent * cosEsc;
+ x -= tm.tmDescent * sinEsc;
+ break;
+
+ case TA_BASELINE:
+ break;
+ }
+
+ if (flags & ETO_CLIPPED)
+ {
+ SaveVisRgn16( dc->hSelf );
+ CLIPPING_IntersectVisRect( dc, rc.left, rc.top, rc.right,
+ rc.bottom, FALSE );
+ }
+
+
+
+ if(!physDev->xrender->pict) {
+ XRenderPictureAttributes pa;
+ pa.subwindow_mode = IncludeInferiors;
+
+ physDev->xrender->pict =
+ TSXRenderCreatePicture(gdi_display,
+ physDev->drawable,
+ (dc->bitsPerPixel == 1) ?
+ mono_format : screen_format,
+ CPSubwindowMode, &pa);
+
+ TRACE("allocing pict = %lx dc = %p drawable = %08lx\n", physDev->xrender->pict, dc, physDev->drawable);
+ } else {
+ TRACE("using existing pict = %lx dc = %p\n", physDev->xrender->pict, dc);
+ }
+
+ obj = (RGNOBJ *) GDI_GetObjPtr(dc->hGCClipRgn, REGION_MAGIC);
+ if (!obj)
+ {
+ ERR("Rgn is 0. Please report this.\n");
+ return FALSE;
+ }
+
+ if (obj->rgn->numRects > 0)
+ {
+ XRectangle *pXr;
+ RECT *pRect = obj->rgn->rects;
+ RECT *pEndRect = obj->rgn->rects + obj->rgn->numRects;
+
+ pXrect = HeapAlloc( GetProcessHeap(), 0,
+ sizeof(*pXrect) * obj->rgn->numRects );
+ if(!pXrect)
+ {
+ WARN("Can't alloc buffer\n");
+ GDI_ReleaseObj( dc->hGCClipRgn );
+ return FALSE;
+ }
+
+ for(pXr = pXrect; pRect < pEndRect; pRect++, pXr++)
+ {
+ pXr->x = pRect->left;
+ pXr->y = pRect->top;
+ pXr->width = pRect->right - pRect->left;
+ pXr->height = pRect->bottom - pRect->top;
+ TRACE("Adding clip rect %d,%d - %d,%d\n", pRect->left, pRect->top,
+ pRect->right, pRect->bottom);
+ }
+ }
+ else {
+ TRACE("no clip rgn\n");
+ pXrect = NULL;
+ }
+
+ TSXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
+ 0, 0, pXrect, obj->rgn->numRects );
+
+ if(pXrect)
+ HeapFree( GetProcessHeap(), 0, pXrect );
+
+ GDI_ReleaseObj( dc->hGCClipRgn );
+
+ if(dc->backgroundMode != TRANSPARENT) {
+ if(!((flags & ETO_CLIPPED) && (flags & ETO_OPAQUE))) {
+ if(!(flags & ETO_OPAQUE) || x < rc.left || x + width >= rc.right ||
+ y - tm.tmAscent < rc.top || y + tm.tmDescent >= rc.bottom) {
+ TSXSetForeground( gdi_display, physDev->gc, physDev->backgroundPixel );
+ TSXFillRectangle( gdi_display, physDev->drawable, physDev->gc,
+ dc->DCOrgX + x, dc->DCOrgY + y - tm.tmAscent,
+ width, tm.tmAscent + tm.tmDescent );
+ }
+ }
+ }
+
+ /* Create a 1x1 pixmap to tile over the font mask */
+ if(!physDev->xrender->tile_xpm) {
+ XRenderPictureAttributes pa;
+
+ XRenderPictFormat *format = (dc->bitsPerPixel == 1) ? mono_format : screen_format;
+ physDev->xrender->tile_xpm = TSXCreatePixmap(gdi_display,
+ physDev->drawable,
+ 1, 1,
+ format->depth);
+ pa.repeat = True;
+ physDev->xrender->tile_pict = TSXRenderCreatePicture(gdi_display,
+ physDev->xrender->tile_xpm,
+ format,
+ CPRepeat, &pa);
+ TRACE("Created pixmap of depth %d\n", format->depth);
+ /* init lastTextColor to something different from dc->textColor */
+ physDev->xrender->lastTextColor = ~dc->textColor;
+
+ }
+
+ if(dc->textColor != physDev->xrender->lastTextColor) {
+ if(dc->bitsPerPixel != 1) {
+ /* Map 0 -- 0xff onto 0 -- 0xffff */
+ col.red = GetRValue(dc->textColor);
+ col.red |= col.red << 8;
+ col.green = GetGValue(dc->textColor);
+ col.green |= col.green << 8;
+ col.blue = GetBValue(dc->textColor);
+ col.blue |= col.blue << 8;
+ col.alpha = 0x0;
+ } else { /* for a 1bpp bitmap we always need a 1 in the tile */
+ col.red = col.green = col.blue = 0;
+ col.alpha = 0xffff;
+ }
+ TSXRenderFillRectangle(gdi_display, PictOpSrc,
+ physDev->xrender->tile_pict,
+ &col, 0, 0, 1, 1);
+ physDev->xrender->lastTextColor = dc->textColor;
+ }
+
+ /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
+ */
+ if((dc->bitsPerPixel == 1) && ((dc->textColor & 0xffffff) == 0))
+ render_op = PictOpOutReverse; /* This gives us 'black' text */
+
+ for(idx = 0; idx < count; idx++) {
+ if(wstr[idx] >= physDev->xrender->cacheEntry->nrealized ||
+ physDev->xrender->cacheEntry->realized[wstr[idx]] == FALSE) {
+ UploadGlyph(dc, wstr[idx]);
+ }
+ }
+
+
+ TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count), dc->DCOrgX + x,
+ dc->DCOrgY + y);
+ if(!lpDx)
+ TSXRenderCompositeString16(gdi_display, render_op,
+ physDev->xrender->tile_pict,
+ physDev->xrender->pict,
+ physDev->xrender->cacheEntry->font_format,
+ physDev->xrender->cacheEntry->glyphset,
+ 0, 0, dc->DCOrgX + x, dc->DCOrgY + y, wstr,
+ count);
+
+ else {
+ INT offset = 0, xoff = 0, yoff = 0;
+ for(idx = 0; idx < count; idx++) {
+ TSXRenderCompositeString16(gdi_display, render_op,
+ physDev->xrender->tile_pict,
+ physDev->xrender->pict,
+ physDev->xrender->cacheEntry->font_format,
+ physDev->xrender->cacheEntry->glyphset,
+ 0, 0, dc->DCOrgX + x + xoff,
+ dc->DCOrgY + y + yoff,
+ wstr + idx, 1);
+ offset += INTERNAL_XWSTODS(dc, lpDx[idx]);
+ xoff = offset * cosEsc;
+ yoff = offset * sinEsc;
+ }
+ }
+
+ if(physDev->xrender->pict) {
+ TSXRenderFreePicture(gdi_display, physDev->xrender->pict);
+ }
+ physDev->xrender->pict = 0;
+
+
+ if (flags & ETO_CLIPPED)
+ RestoreVisRgn16( dc->hSelf );
+
+ X11DRV_UnlockDIBSection( dc, TRUE );
+ return TRUE;
+}
+
+#else /* #ifdef HAVE_LIBXRENDER */
+
+void X11DRV_XRender_Init(void)
+{
+ TRACE("XRender support not compiled in.\n");
+ return;
+}
+
+void X11DRV_XRender_Finalize(void)
+{
+ assert(0);
+ return;
+}
+
+BOOL X11DRV_XRender_SelectFont(DC *dc, HFONT hfont)
+{
+ assert(0);
+ return FALSE;
+}
+
+void X11DRV_XRender_DeleteDC(DC *dc)
+{
+ assert(0);
+ return;
+}
+
+BOOL X11DRV_XRender_ExtTextOut( DC *dc, INT x, INT y, UINT flags,
+ const RECT *lprect, LPCWSTR wstr, UINT count,
+ const INT *lpDx )
+{
+ assert(0);
+ return FALSE;
+}
+
+void X11DRV_XRender_UpdateDrawable(DC *dc)
+{
+ assert(0);
+ return;
+}
+
+#endif
More information about the wine-patches
mailing list