#include "windef.h"
#include "winbase.h"
-#include "wownt32.h"
#include "x11drv.h"
#include "winternl.h"
#include "wine/library.h"
WINE_DEFAULT_DEBUG_CHANNEL(xrender);
-#ifdef HAVE_X11_EXTENSIONS_XRENDER_H
+#ifdef SONAME_LIBXRENDER
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
-static XRenderPictFormat *screen_format; /* format of screen */
-static XRenderPictFormat *mono_format; /* format of mono bitmap */
+
+enum drawable_depth_type {mono_drawable, color_drawable};
+static XRenderPictFormat *pict_formats[2];
typedef struct
{
{
int cache_index;
Picture pict;
- Picture tile_pict;
- Pixmap tile_xpm;
- COLORREF lastTextColor;
};
static int antialias = 1;
-/* some default values just in case */
-#ifndef SONAME_LIBX11
-#define SONAME_LIBX11 "libX11.so"
-#endif
-#ifndef SONAME_LIBXEXT
-#define SONAME_LIBXEXT "libXext.so"
-#endif
-#ifndef SONAME_LIBXRENDER
-#define SONAME_LIBXRENDER "libXrender.so"
-#endif
-
static void *xrender_handle;
#define MAKE_FUNCPTR(f) static typeof(f) * p##f;
MAKE_FUNCPTR(XRenderCompositeString8)
MAKE_FUNCPTR(XRenderCompositeString16)
MAKE_FUNCPTR(XRenderCompositeString32)
+MAKE_FUNCPTR(XRenderCompositeText16)
MAKE_FUNCPTR(XRenderCreateGlyphSet)
MAKE_FUNCPTR(XRenderCreatePicture)
MAKE_FUNCPTR(XRenderFillRectangle)
LOAD_FUNCPTR(XRenderCompositeString8)
LOAD_FUNCPTR(XRenderCompositeString16)
LOAD_FUNCPTR(XRenderCompositeString32)
+LOAD_FUNCPTR(XRenderCompositeText16)
LOAD_FUNCPTR(XRenderCreateGlyphSet)
LOAD_FUNCPTR(XRenderCreatePicture)
LOAD_FUNCPTR(XRenderFillRectangle)
if(pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) {
X11DRV_XRender_Installed = TRUE;
TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
- screen_format = pXRenderFindVisualFormat(gdi_display, visual);
- if(!screen_format)
+ pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, visual);
+ if(!pict_formats[color_drawable])
{
/* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
if (visual->class == DirectColor)
if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
screen_depth, TrueColor, &info ))
{
- screen_format = pXRenderFindVisualFormat(gdi_display, info.visual);
- if (screen_format) visual = info.visual;
+ pict_formats[color_drawable] = pXRenderFindVisualFormat(gdi_display, info.visual);
+ if (pict_formats[color_drawable]) visual = info.visual;
}
}
}
- if(!screen_format) /* This fails in buggy versions of libXrender.so */
+ if(!pict_formats[color_drawable]) /* This fails in buggy versions of libXrender.so */
{
wine_tsx11_unlock();
WINE_MESSAGE(
pf.depth = 1;
pf.direct.alpha = 0;
pf.direct.alphaMask = 1;
- mono_format = pXRenderFindFormat(gdi_display, PictFormatType |
- PictFormatDepth | PictFormatAlpha |
- PictFormatAlphaMask, &pf, 0);
- if(!mono_format) {
+ pict_formats[mono_drawable] = pXRenderFindFormat(gdi_display, PictFormatType |
+ PictFormatDepth | PictFormatAlpha |
+ PictFormatAlphaMask, &pf, 0);
+ if(!pict_formats[mono_drawable]) {
ERR("mono_format == NULL?\n");
X11DRV_XRender_Installed = FALSE;
}
HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
formatEntry->bitmaps = NULL;
- HeapFree(GetProcessHeap(), 0, formatEntry->gis);
- formatEntry->gis = NULL;
}
+ HeapFree(GetProcessHeap(), 0, formatEntry->gis);
+ formatEntry->gis = NULL;
formatEntry->nrealized = 0;
}
*/
void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
{
- wine_tsx11_lock();
- if(physDev->xrender->tile_pict)
- pXRenderFreePicture(gdi_display, physDev->xrender->tile_pict);
-
- if(physDev->xrender->tile_xpm)
- XFreePixmap(gdi_display, physDev->xrender->tile_xpm);
-
- if(physDev->xrender->pict) {
- TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
- pXRenderFreePicture(gdi_display, physDev->xrender->pict);
- }
- wine_tsx11_unlock();
+ X11DRV_XRender_UpdateDrawable(physDev);
EnterCriticalSection(&xrender_cs);
if(physDev->xrender->cache_index != -1)
* X11DRV_XRender_UpdateDrawable
*
* This gets called from X11DRV_SetDrawable and X11DRV_SelectBitmap.
- * It deletes the pict when the drawable changes.
+ * It deletes the pict and tile when the drawable changes.
*/
void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
{
- if(physDev->xrender->pict) {
- TRACE("freeing pict %08lx from dc %p drawable %08lx\n", physDev->xrender->pict,
- physDev->hdc, physDev->drawable);
- wine_tsx11_lock();
+ wine_tsx11_lock();
+
+ if(physDev->xrender->pict)
+ {
+ TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
XFlush(gdi_display);
pXRenderFreePicture(gdi_display, physDev->xrender->pict);
- wine_tsx11_unlock();
+ physDev->xrender->pict = 0;
}
- physDev->xrender->pict = 0;
+ wine_tsx11_unlock();
+
return;
}
gsCacheEntryFormat *formatEntry;
UINT ggo_format = GGO_GLYPH_INDEX;
XRenderPictFormat pf;
+ static const char zero[4];
switch(format) {
case AA_Grey:
formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
-
- if (formatEntry->gis)
+ }
+ if (formatEntry->gis)
formatEntry->gis = HeapReAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
formatEntry->gis,
formatEntry->nrealized * sizeof(formatEntry->gis[0]));
- else
+ else
formatEntry->gis = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
- formatEntry->nrealized * sizeof(formatEntry->gis[0]));
- }
+ formatEntry->nrealized * sizeof(formatEntry->gis[0]));
}
}
}
+
if(formatEntry->glyphset) {
if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
unsigned char *byte = (unsigned char*) buf, c;
}
}
gid = glyph;
+
+ /*
+ XRenderCompositeText seems to ignore 0x0 glyphs when
+ AA_None, which means we lose the advance width of glyphs
+ like the space. We'll pretend that such glyphs are 1x1
+ bitmaps.
+ */
+
+ if(buflen == 0)
+ gi.width = gi.height = 1;
+
wine_tsx11_lock();
pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
- buf, buflen);
+ buflen ? buf : zero, buflen ? buflen : sizeof(zero));
wine_tsx11_unlock();
HeapFree(GetProcessHeap(), 0, buf);
} else {
formatEntry->bitmaps[glyph] = buf;
- memcpy(&formatEntry->gis[glyph], &gi, sizeof(gi));
}
+
+ memcpy(&formatEntry->gis[glyph], &gi, sizeof(gi));
+
return TRUE;
}
}
}
+/*************************************************************
+ * get_tile_pict
+ *
+ * Returns an appropiate Picture for tiling the text colour.
+ * Call and use result within the xrender_cs
+ */
+static Picture get_tile_pict(enum drawable_depth_type type, int text_pixel)
+{
+ static struct
+ {
+ Pixmap xpm;
+ Picture pict;
+ int current_color;
+ } tiles[2], *tile;
+ XRenderColor col;
+
+ tile = &tiles[type];
+
+ if(!tile->xpm)
+ {
+ XRenderPictureAttributes pa;
+
+ wine_tsx11_lock();
+ tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_formats[type]->depth);
+
+ pa.repeat = True;
+ tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_formats[type], CPRepeat, &pa);
+ wine_tsx11_unlock();
+
+ /* init current_color to something different from text_pixel */
+ tile->current_color = ~text_pixel;
+
+ if(type == mono_drawable)
+ {
+ /* for a 1bpp bitmap we always need a 1 in the tile */
+ col.red = col.green = col.blue = 0;
+ col.alpha = 0xffff;
+ wine_tsx11_lock();
+ pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
+ wine_tsx11_unlock();
+ }
+ }
+
+ if(text_pixel != tile->current_color && type == color_drawable)
+ {
+ /* Map 0 -- 0xff onto 0 -- 0xffff */
+ int r_shift, r_len;
+ int g_shift, g_len;
+ int b_shift, b_len;
+
+ ExamineBitfield (visual->red_mask, &r_shift, &r_len );
+ ExamineBitfield (visual->green_mask, &g_shift, &g_len);
+ ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
+
+ col.red = GetField(text_pixel, r_shift, r_len);
+ col.red |= col.red << 8;
+ col.green = GetField(text_pixel, g_shift, g_len);
+ col.green |= col.green << 8;
+ col.blue = GetField(text_pixel, b_shift, b_len);
+ col.blue |= col.blue << 8;
+ col.alpha = 0x0;
+
+ wine_tsx11_lock();
+ pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
+ wine_tsx11_unlock();
+ tile->current_color = text_pixel;
+ }
+ return tile->pict;
+}
+
static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
{
return 1;
const RECT *lprect, LPCWSTR wstr, UINT count,
const INT *lpDx )
{
- XRenderColor col;
RGNDATA *data;
XGCValues xgcval;
int render_op = PictOpOver;
int textPixel, backgroundPixel;
HRGN saved_region = 0;
BOOL disable_antialias = FALSE;
- AA_Type antialias = AA_None;
+ AA_Type aa_type = AA_None;
DIBSECTION bmp;
unsigned int idx;
double cosEsc, sinEsc;
LOGFONTW lf;
+ enum drawable_depth_type depth_type = (physDev->depth == 1) ? mono_drawable : color_drawable;
+ Picture tile_pict = 0;
/* Do we need to disable antialiasing because of palette mode? */
if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
DeleteObject( clip_region );
}
+ EnterCriticalSection(&xrender_cs);
+
if(X11DRV_XRender_Installed) {
if(!physDev->xrender->pict) {
XRenderPictureAttributes pa;
wine_tsx11_lock();
physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
physDev->drawable,
- (physDev->depth == 1) ?
- mono_format : screen_format,
+ pict_formats[depth_type],
CPSubwindowMode, &pa);
wine_tsx11_unlock();
wine_tsx11_unlock();
HeapFree( GetProcessHeap(), 0, data );
}
- }
-
- if(X11DRV_XRender_Installed) {
- /* Create a 1x1 pixmap to tile over the font mask */
- if(!physDev->xrender->tile_xpm) {
- XRenderPictureAttributes pa;
-
- XRenderPictFormat *format = (physDev->depth == 1) ? mono_format : screen_format;
- wine_tsx11_lock();
- physDev->xrender->tile_xpm = XCreatePixmap(gdi_display,
- physDev->drawable,
- 1, 1,
- format->depth);
- pa.repeat = True;
- physDev->xrender->tile_pict = pXRenderCreatePicture(gdi_display,
- physDev->xrender->tile_xpm,
- format,
- CPRepeat, &pa);
- wine_tsx11_unlock();
- TRACE("Created pixmap of depth %d\n", format->depth);
- /* init lastTextColor to something different from textPixel */
- physDev->xrender->lastTextColor = ~physDev->textPixel;
-
- }
- if(physDev->textPixel != physDev->xrender->lastTextColor) {
- if(physDev->depth != 1) {
- /* Map 0 -- 0xff onto 0 -- 0xffff */
- int r_shift, r_len;
- int g_shift, g_len;
- int b_shift, b_len;
-
- ExamineBitfield (visual->red_mask, &r_shift, &r_len );
- ExamineBitfield (visual->green_mask, &g_shift, &g_len);
- ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
-
- col.red = GetField(physDev->textPixel, r_shift, r_len);
- col.red |= col.red << 8;
- col.green = GetField(physDev->textPixel, g_shift, g_len);
- col.green |= col.green << 8;
- col.blue = GetField(physDev->textPixel, b_shift, b_len);
- 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;
- }
- wine_tsx11_lock();
- pXRenderFillRectangle(gdi_display, PictOpSrc,
- physDev->xrender->tile_pict,
- &col, 0, 0, 1, 1);
- wine_tsx11_unlock();
- physDev->xrender->lastTextColor = physDev->textPixel;
- }
+ tile_pict = get_tile_pict(depth_type, physDev->textPixel);
/* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
*/
- if((physDev->depth == 1) && (textPixel == 0))
+ if((depth_type == mono_drawable) && (textPixel == 0))
render_op = PictOpOutReverse; /* This gives us 'black' text */
}
- EnterCriticalSection(&xrender_cs);
entry = glyphsetCache + physDev->xrender->cache_index;
if( disable_antialias == FALSE )
- antialias = entry->aa_default;
- formatEntry = entry->format[antialias];
+ aa_type = entry->aa_default;
+ formatEntry = entry->format[aa_type];
for(idx = 0; idx < count; idx++) {
if( !formatEntry ) {
- UploadGlyph(physDev, wstr[idx], antialias);
+ UploadGlyph(physDev, wstr[idx], aa_type);
/* re-evaluate antialias since aa_default may have changed */
if( disable_antialias == FALSE )
- antialias = entry->aa_default;
- formatEntry = entry->format[antialias];
+ aa_type = entry->aa_default;
+ formatEntry = entry->format[aa_type];
} else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
- UploadGlyph(physDev, wstr[idx], antialias);
+ UploadGlyph(physDev, wstr[idx], aa_type);
}
}
if (!formatEntry)
TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
physDev->dc_rect.left + x, physDev->dc_rect.top + y);
- if(X11DRV_XRender_Installed) {
- wine_tsx11_lock();
- if(!lpDx)
- pXRenderCompositeString16(gdi_display, render_op,
- physDev->xrender->tile_pict,
- physDev->xrender->pict,
- formatEntry->font_format, formatEntry->glyphset,
- 0, 0, physDev->dc_rect.left + x, physDev->dc_rect.top + y,
- wstr, count);
- else {
- INT offset = 0, xoff = 0, yoff = 0;
- for(idx = 0; idx < count; idx++) {
- pXRenderCompositeString16(gdi_display, render_op,
- physDev->xrender->tile_pict,
- physDev->xrender->pict,
- formatEntry->font_format, formatEntry->glyphset,
- 0, 0, physDev->dc_rect.left + x + xoff,
- physDev->dc_rect.top + y + yoff,
- wstr + idx, 1);
- offset += lpDx[idx];
- xoff = offset * cosEsc;
- yoff = offset * -sinEsc;
- }
- }
- wine_tsx11_unlock();
+ if(X11DRV_XRender_Installed)
+ {
+ XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
+ INT offset = 0;
+ POINT desired, current;
+
+ /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
+ So we pass zeros to the function and move to our starting position using the first
+ element of the elts array. */
+
+ desired.x = physDev->dc_rect.left + x;
+ desired.y = physDev->dc_rect.top + y;
+ current.x = current.y = 0;
+
+ for(idx = 0; idx < count; idx++)
+ {
+ elts[idx].glyphset = formatEntry->glyphset;
+ elts[idx].chars = wstr + idx;
+ elts[idx].nchars = 1;
+ elts[idx].xOff = desired.x - current.x;
+ elts[idx].yOff = desired.y - current.y;
+
+ current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
+ current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
+ if(!lpDx)
+ {
+ desired.x += formatEntry->gis[wstr[idx]].xOff;
+ desired.y += formatEntry->gis[wstr[idx]].yOff;
+ }
+ else
+ {
+ offset += lpDx[idx];
+ desired.x = physDev->dc_rect.left + x + offset * cosEsc;
+ desired.y = physDev->dc_rect.top + y - offset * sinEsc;
+ }
+ }
+ wine_tsx11_lock();
+ pXRenderCompositeText16(gdi_display, render_op,
+ tile_pict,
+ physDev->xrender->pict,
+ formatEntry->font_format,
+ 0, 0, 0, 0, elts, count);
+ wine_tsx11_unlock();
+ HeapFree(GetProcessHeap(), 0, elts);
} else {
INT offset = 0, xoff = 0, yoff = 0;
wine_tsx11_lock();
XSetForeground( gdi_display, physDev->gc, textPixel );
- if(antialias == AA_None) {
- for(idx = 0; idx < count; idx++) {
- SharpGlyphMono(physDev, physDev->dc_rect.left + x + xoff,
- physDev->dc_rect.top + y + yoff,
- formatEntry->bitmaps[wstr[idx]],
- &formatEntry->gis[wstr[idx]]);
- if(lpDx) {
- offset += lpDx[idx];
- xoff = offset * cosEsc;
- yoff = offset * -sinEsc;
- } else {
- xoff += formatEntry->gis[wstr[idx]].xOff;
- yoff += formatEntry->gis[wstr[idx]].yOff;
- }
- }
- } else if(physDev->depth == 1) {
+ if(aa_type == AA_None || physDev->depth == 1)
+ {
+ void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
+
+ if(aa_type == AA_None)
+ sharp_glyph_fn = SharpGlyphMono;
+ else
+ sharp_glyph_fn = SharpGlyphGray;
+
for(idx = 0; idx < count; idx++) {
- SharpGlyphGray(physDev, physDev->dc_rect.left + x + xoff,
+ sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
physDev->dc_rect.top + y + yoff,
formatEntry->bitmaps[wstr[idx]],
&formatEntry->gis[wstr[idx]]);
xoff += formatEntry->gis[wstr[idx]].xOff;
yoff += formatEntry->gis[wstr[idx]].yOff;
}
-
}
} else {
XImage *image;
image_w, image_h, AllPlanes, ZPixmap,
physDev->depth, image);
if(!image) {
- Pixmap xpm = XCreatePixmap(gdi_display, physDev->drawable, image_w, image_h,
+ Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
physDev->depth);
GC gc;
XGCValues gcv;
POINT pts[2];
BOOL top_down = FALSE;
RGNDATA *rgndata;
+ enum drawable_depth_type dst_depth_type = (devDst->depth == 1) ? mono_drawable : color_drawable;
if(!X11DRV_XRender_Installed) {
FIXME("Unable to AlphaBlend without Xrender\n");
/* FIXME use devDst->xrender->pict ? */
dst_pict = pXRenderCreatePicture(gdi_display,
devDst->drawable,
- (devDst->depth == 1) ?
- mono_format : screen_format,
+ pict_formats[dst_depth_type],
CPSubwindowMode, &pa);
TRACE("dst_pict %08lx\n", dst_pict);
TRACE("src_drawable = %08lx\n", devSrc->drawable);
xpm = XCreatePixmap(gdi_display,
- devSrc->drawable,
+ root_window,
widthSrc, heightSrc, 32);
gcv.graphics_exposures = False;
gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
return TRUE;
}
-#else /* HAVE_X11_EXTENSIONS_XRENDER_H */
+#else /* SONAME_LIBXRENDER */
void X11DRV_XRender_Init(void)
{
return FALSE;
}
-#endif /* HAVE_X11_EXTENSIONS_XRENDER_H */
+#endif /* SONAME_LIBXRENDER */