diff --git a/ChangeLog b/ChangeLog index e9c6716e3..9a410cd7d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2002-11-01 Carl Worth + + * xrsurface.c (_XrSurfaceSetImage): Prelimary image + support. Really only works with ARGB32. I still need to think + about what formats will be supported. + (_XrSurfaceSetTransform): Partial support for transformed + surfaces. + (_XrSurfaceGetXcSurface): Moved all creation/destruction of the + XcSurface into this function so that it is only lazily created + when needed. + + * xrgstate.c (_XrGStateSetCurrentPt): gstate now can throw errors + when an operation needs current point, but it doesn't exist yet. + (_XrGStateShowImage, _XrGStateShowImageTransform): Preliminary + image support, (currently it only scales according to the CTM. The + matrix passed with the image doesn't do anything yet.) + + * xrfont.c (_XrFontInitCopy): Removed bogus out of memory errors. + + * xr.c (XrShowImage, XrShowImageTransform): Added very preliminary + image support. Things don't work completely yet and all the + interfaces are likely to change. + (XrGetStatusString): Added function to map status values to strings. + 2002-10-31 Carl Worth * xrfont.c (_XrFontInit): diff --git a/Xr.h b/Xr.h index 713aeec3c..160eeb8b4 100644 --- a/Xr.h +++ b/Xr.h @@ -214,16 +214,41 @@ XrTextExtents(XrState *xrs, void XrShowText(XrState *xrs, const unsigned char *utf8); +/* Image functions */ + +void +XrShowImage(XrState *xrs, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride); + +void +XrShowImageTransform(XrState *xrs, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride, + double a, double b, + double c, double d, + double tx, double ty); + /* Error status queries */ typedef enum _XrStatus { XrStatusSuccess = 0, XrStatusNoMemory, - XrStatusInvalidRestore + XrStatusInvalidRestore, + XrStatusNoCurrentPoint } XrStatus; XrStatus XrGetStatus(XrState *xrs); +const char * +XrGetStatusString(XrState *xrs); + #endif diff --git a/src/Xr.h b/src/Xr.h index 713aeec3c..160eeb8b4 100644 --- a/src/Xr.h +++ b/src/Xr.h @@ -214,16 +214,41 @@ XrTextExtents(XrState *xrs, void XrShowText(XrState *xrs, const unsigned char *utf8); +/* Image functions */ + +void +XrShowImage(XrState *xrs, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride); + +void +XrShowImageTransform(XrState *xrs, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride, + double a, double b, + double c, double d, + double tx, double ty); + /* Error status queries */ typedef enum _XrStatus { XrStatusSuccess = 0, XrStatusNoMemory, - XrStatusInvalidRestore + XrStatusInvalidRestore, + XrStatusNoCurrentPoint } XrStatus; XrStatus XrGetStatus(XrState *xrs); +const char * +XrGetStatusString(XrState *xrs); + #endif diff --git a/src/xr.c b/src/xr.c index 5f65ba4d9..6869689ae 100644 --- a/src/xr.c +++ b/src/xr.c @@ -381,12 +381,68 @@ XrShowText(XrState *xrs, const unsigned char *utf8) xrs->status = _XrGStateShowText(_XR_CURRENT_GSTATE(xrs), utf8); } +void +XrShowImage(XrState *xrs, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride) +{ + if (xrs->status) + return; + + xrs->status = _XrGStateShowImage(_XR_CURRENT_GSTATE(xrs), + data, format, + width, height, stride); +} + +void +XrShowImageTransform(XrState *xrs, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride, + double a, double b, + double c, double d, + double tx, double ty) +{ + if (xrs->status) + return; + + xrs->status = _XrGStateShowImageTransform(_XR_CURRENT_GSTATE(xrs), + data, format, + width, height, stride, + a, b, + c, d, + tx, ty); +} + + XrStatus XrGetStatus(XrState *xrs) { return xrs->status; } +const char * +XrGetStatusString(XrState *xrs) +{ + switch (xrs->status) { + case XrStatusSuccess: + return "success"; + case XrStatusNoMemory: + return "out of memory"; + case XrStatusInvalidRestore: + return "XrRestore without matchin XrSave"; + case XrStatusNoCurrentPoint: + return "no current point defined"; + } + + return ""; +} + static void _XrClipValue(double *value, double min, double max) { diff --git a/src/xrfont.c b/src/xrfont.c index 7efc144d3..c0f70e1de 100644 --- a/src/xrfont.c +++ b/src/xrfont.c @@ -52,7 +52,7 @@ _XrFontInitCopy(XrFont *font, XrFont *other) if (other->xft_font) { font->xft_font = XftFontCopy(other->dpy, other->xft_font); - if (font->xft_font) + if (font->xft_font == NULL) return XrStatusNoMemory; } diff --git a/src/xrgstate.c b/src/xrgstate.c index 977d6567e..5397690ed 100644 --- a/src/xrgstate.c +++ b/src/xrgstate.c @@ -57,32 +57,35 @@ _XrGStateInit(XrGState *gstate, Display *dpy) gstate->tolerance = XR_GSTATE_TOLERANCE_DEFAULT; - gstate->fill_rule = XR_GSTATE_FILL_RULE_DEFAULT; - gstate->line_width = XR_GSTATE_LINE_WIDTH_DEFAULT; gstate->line_cap = XR_GSTATE_LINE_CAP_DEFAULT; gstate->line_join = XR_GSTATE_LINE_JOIN_DEFAULT; gstate->miter_limit = XR_GSTATE_MITER_LIMIT_DEFAULT; + + gstate->fill_rule = XR_GSTATE_FILL_RULE_DEFAULT; + gstate->dashes = 0; gstate->ndashes = 0; gstate->dash_offset = 0.0; - gstate->solidFormat = XcFindStandardFormat(dpy, PictStandardARGB32); gstate->alphaFormat = XcFindStandardFormat(dpy, PictStandardA8); _XrFontInit(&gstate->font, gstate); _XrSurfaceInit(&gstate->surface, dpy); _XrSurfaceInit(&gstate->src, dpy); + gstate->mask = NULL; _XrColorInit(&gstate->color); - _XrSurfaceSetSolidColor(&gstate->src, &gstate->color, gstate->solidFormat); + _XrSurfaceSetSolidColor(&gstate->src, &gstate->color); _XrTransformInit(&gstate->ctm); _XrTransformInit(&gstate->ctm_inverse); _XrPathInit(&gstate->path); + gstate->has_current_pt = 0; + _XrPenInitEmpty(&gstate->pen_regular); gstate->next = NULL; @@ -107,6 +110,8 @@ _XrGStateInitCopy(XrGState *gstate, XrGState *other) _XrSurfaceReference(&gstate->surface); _XrSurfaceReference(&gstate->src); + if (gstate->mask) + _XrSurfaceReference(gstate->mask); status = _XrPathInitCopy(&gstate->path, &other->path); if (status) @@ -136,6 +141,8 @@ _XrGStateDeinit(XrGState *gstate) _XrSurfaceDereference(&gstate->src); _XrSurfaceDereference(&gstate->surface); + if (gstate->mask) + _XrSurfaceDereferenceDestroy(gstate->mask); _XrColorDeinit(&gstate->color); @@ -213,7 +220,7 @@ XrStatus _XrGStateSetRGBColor(XrGState *gstate, double red, double green, double blue) { _XrColorSetRGB(&gstate->color, red, green, blue); - _XrSurfaceSetSolidColor(&gstate->src, &gstate->color, gstate->solidFormat); + _XrSurfaceSetSolidColor(&gstate->src, &gstate->color); return XrStatusSuccess; } @@ -230,7 +237,7 @@ XrStatus _XrGStateSetAlpha(XrGState *gstate, double alpha) { _XrColorSetAlpha(&gstate->color, alpha); - _XrSurfaceSetSolidColor(&gstate->src, &gstate->color, gstate->solidFormat); + _XrSurfaceSetSolidColor(&gstate->src, &gstate->color); return XrStatusSuccess; } @@ -353,10 +360,20 @@ _XrGStateConcatMatrix(XrGState *gstate, return XrStatusSuccess; } +static void +_XrGStateSetCurrentPt(XrGState *gstate, double x, double y) +{ + gstate->current_pt.x = x; + gstate->current_pt.y = y; + + gstate->has_current_pt = 1; +} + XrStatus _XrGStateNewPath(XrGState *gstate) { _XrPathDeinit(&gstate->path); + gstate->has_current_pt = 0; return XrStatusSuccess; } @@ -370,8 +387,7 @@ _XrGStateMoveTo(XrGState *gstate, double x, double y) status = _XrPathMoveTo(&gstate->path, x, y); - gstate->current_pt.x = x; - gstate->current_pt.y = y; + _XrGStateSetCurrentPt(gstate, x, y); gstate->last_move_pt = gstate->current_pt; @@ -387,8 +403,7 @@ _XrGStateLineTo(XrGState *gstate, double x, double y) status = _XrPathLineTo(&gstate->path, x, y); - gstate->current_pt.x = x; - gstate->current_pt.y = y; + _XrGStateSetCurrentPt(gstate, x, y); return status; } @@ -410,9 +425,7 @@ _XrGStateCurveTo(XrGState *gstate, x2, y2, x3, y3); - - gstate->current_pt.x = x3; - gstate->current_pt.y = y3; + _XrGStateSetCurrentPt(gstate, x3, y3); return status; } @@ -421,15 +434,16 @@ XrStatus _XrGStateRelMoveTo(XrGState *gstate, double dx, double dy) { XrStatus status; + double x, y; _XrTransformDistance(&gstate->ctm, &dx, &dy); - status = _XrPathMoveTo(&gstate->path, - gstate->current_pt.x + dx, - gstate->current_pt.y + dy); + x = gstate->current_pt.x + dx; + y = gstate->current_pt.y + dy; - gstate->current_pt.x += dx; - gstate->current_pt.y += dy; + status = _XrPathMoveTo(&gstate->path, x, y); + + _XrGStateSetCurrentPt(gstate, x, y); gstate->last_move_pt = gstate->current_pt; @@ -440,16 +454,16 @@ XrStatus _XrGStateRelLineTo(XrGState *gstate, double dx, double dy) { XrStatus status; + double x, y; _XrTransformDistance(&gstate->ctm, &dx, &dy); - status = _XrPathLineTo(&gstate->path, - gstate->current_pt.x + dx, - gstate->current_pt.y + dy); + x = gstate->current_pt.x + dx; + y = gstate->current_pt.y + dy; + status = _XrPathLineTo(&gstate->path, x, y); - gstate->current_pt.x += dx; - gstate->current_pt.y += dy; + _XrGStateSetCurrentPt(gstate, x, y); return status; } @@ -471,8 +485,9 @@ _XrGStateRelCurveTo(XrGState *gstate, gstate->current_pt.x + dx2, gstate->current_pt.y + dy2, gstate->current_pt.x + dx3, gstate->current_pt.y + dy3); - gstate->current_pt.x += dx3; - gstate->current_pt.y += dy3; + _XrGStateSetCurrentPt(gstate, + gstate->current_pt.x + dx3, + gstate->current_pt.y + dy3); return status; } @@ -484,7 +499,9 @@ _XrGStateClosePath(XrGState *gstate) status = _XrPathClosePath(&gstate->path); - gstate->current_pt = gstate->last_move_pt; + _XrGStateSetCurrentPt(gstate, + gstate->last_move_pt.x, + gstate->last_move_pt.y); return status; } @@ -525,8 +542,8 @@ _XrGStateStroke(XrGState *gstate) } XcCompositeTrapezoids(gstate->dpy, gstate->operator, - gstate->src.xc_surface, - gstate->surface.xc_surface, + _XrSurfaceGetXcSurface(&gstate->src), + _XrSurfaceGetXcSurface(&gstate->surface), gstate->alphaFormat, 0, 0, traps.xtraps, @@ -565,8 +582,8 @@ _XrGStateFill(XrGState *gstate) } XcCompositeTrapezoids(gstate->dpy, gstate->operator, - gstate->src.xc_surface, - gstate->surface.xc_surface, + _XrSurfaceGetXcSurface(&gstate->src), + _XrSurfaceGetXcSurface(&gstate->surface), gstate->alphaFormat, 0, 0, traps.xtraps, @@ -637,6 +654,9 @@ _XrGStateShowText(XrGState *gstate, const unsigned char *utf8) { XftFont *xft_font; + if (gstate->has_current_pt == 0) + return XrStatusNoCurrentPoint; + _XrFontResolveXftFont(&gstate->font, gstate, &xft_font); XftTextRenderUtf8(gstate->dpy, @@ -653,6 +673,67 @@ _XrGStateShowText(XrGState *gstate, const unsigned char *utf8) return XrStatusSuccess; } +XrStatus +_XrGStateShowImage(XrGState *gstate, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride) +{ + return _XrGStateShowImageTransform(gstate, + data, format, width, height, stride, + 1, 0, + 0, 1, + - gstate->current_pt.x, + - gstate->current_pt.y); +} + +XrStatus +_XrGStateShowImageTransform(XrGState *gstate, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride, + double a, double b, + double c, double d, + double tx, double ty) +{ + XrStatus status; + XrSurface image_surface; + double dst_width, dst_height; + + _XrSurfaceInit(&image_surface, gstate->dpy); + + _XrSurfaceSetFormat(&image_surface, format); + + status = _XrSurfaceSetImage(&image_surface, data, width, height, stride); + if (status) + return status; + + _XrSurfaceSetTransform(&image_surface, &gstate->ctm_inverse); + + dst_width = width; + dst_height = height; + _XrTransformDistance(&gstate->ctm, &dst_width, &dst_height); + + XcComposite(gstate->dpy, gstate->operator, + _XrSurfaceGetXcSurface(&image_surface), + 0, + _XrSurfaceGetXcSurface(&gstate->surface), + 0, 0, + 0, 0, + gstate->current_pt.x, + gstate->current_pt.y, + dst_width, + dst_height); + + _XrSurfaceDeinit(&image_surface); + + return XrStatusSuccess; +} + static Picture _XrGStateGetPicture(XrGState *gstate) { diff --git a/src/xrint.h b/src/xrint.h index b2bf53d85..35ed6b1d0 100644 --- a/src/xrint.h +++ b/src/xrint.h @@ -169,6 +169,7 @@ typedef struct _XrSurface { Display *dpy; Drawable drawable; + GC gc; unsigned int depth; @@ -177,6 +178,7 @@ typedef struct _XrSurface { XcFormat *xc_format; XcSurface *xc_surface; + int needs_new_xc_surface; unsigned int ref_count; } XrSurface; @@ -226,29 +228,31 @@ typedef struct _XrFont { typedef struct _XrGState { Display *dpy; + XrOperator operator; + double tolerance; /* stroke style */ double line_width; XrLineCap line_cap; XrLineJoin line_join; - double *dashes; - int ndashes; - double dash_offset; double miter_limit; XrFillRule fill_rule; - XrOperator operator; - - XcFormat *solidFormat; + double *dashes; + int ndashes; + double dash_offset; + XcFormat *alphaFormat; XrFont font; - XrColor color; XrSurface src; XrSurface surface; + XrSurface *mask; + + XrColor color; XrTransform ctm; XrTransform ctm_inverse; @@ -257,6 +261,7 @@ typedef struct _XrGState { XPointDouble last_move_pt; XPointDouble current_pt; + int has_current_pt; XrPen pen_regular; @@ -447,6 +452,25 @@ _XrGStateTextExtents(XrGState *gstate, XrStatus _XrGStateShowText(XrGState *gstate, const unsigned char *utf8); +XrStatus +_XrGStateShowImage(XrGState *gstate, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride); + +XrStatus +_XrGStateShowImageTransform(XrGState *gstate, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride, + double a, double b, + double c, double d, + double tx, double ty); + /* xrcolor.c */ void _XrColorInit(XrColor *color); @@ -523,11 +547,24 @@ _XrSurfaceReference(XrSurface *surface); void _XrSurfaceDereference(XrSurface *surface); +void +_XrSurfaceDereferenceDestroy(XrSurface *surface); + void _XrSurfaceDeinit(XrSurface *surface); void -_XrSurfaceSetSolidColor(XrSurface *surface, XrColor *color, XcFormat *xc_format); +_XrSurfaceSetSolidColor(XrSurface *surface, XrColor *color); + +XrStatus +_XrSurfaceSetImage(XrSurface *surface, + char *data, + unsigned int width, + unsigned int height, + unsigned int stride); + +XrStatus +_XrSurfaceSetTransform(XrSurface *surface, XrTransform *transform); void _XrSurfaceSetDrawable(XrSurface *surface, Drawable drawable); @@ -538,6 +575,9 @@ _XrSurfaceSetVisual(XrSurface *surface, Visual *visual); void _XrSurfaceSetFormat(XrSurface *surface, XrFormat format); +XcSurface * +_XrSurfaceGetXcSurface(XrSurface *surface); + Picture _XrSurfaceGetPicture(XrSurface *surface); diff --git a/src/xrsurface.c b/src/xrsurface.c index 975f651a9..6e8a8a05d 100644 --- a/src/xrsurface.c +++ b/src/xrsurface.c @@ -25,26 +25,22 @@ #include "xrint.h" -static void -_XrSurfaceCreateXcSurface(XrSurface *surface); - -static void -_XrSurfaceDestroyXcSurface(XrSurface *surface); - - void _XrSurfaceInit(XrSurface *surface, Display *dpy) { surface->dpy = dpy; surface->drawable = 0; + surface->gc = 0; surface->depth = 0; surface->xc_sa_mask = 0; - surface->xc_format = 0; + surface->xc_format = XcFindStandardFormat(dpy, PictStandardARGB32); + surface->xc_surface = 0; + surface->needs_new_xc_surface = 1; surface->ref_count = 0; } @@ -64,6 +60,15 @@ _XrSurfaceDereference(XrSurface *surface) surface->ref_count--; } +void +_XrSurfaceDereferenceDestroy(XrSurface *surface) +{ + _XrSurfaceDereference(surface); + + if (surface->ref_count == 0) + free(surface); +} + void _XrSurfaceDeinit(XrSurface *surface) { @@ -72,17 +77,18 @@ _XrSurfaceDeinit(XrSurface *surface) } void -_XrSurfaceSetSolidColor(XrSurface *surface, XrColor *color, XcFormat *format) +_XrSurfaceSetSolidColor(XrSurface *surface, XrColor *color) { /* XXX: QUESTION: Special handling for depth==1 ala xftdraw.c? */ - if (surface->xc_surface == 0) { - Pixmap pix; - XcSurfaceAttributes sa; - - pix = XCreatePixmap(surface->dpy, DefaultRootWindow(surface->dpy), 1, 1, format->depth); - sa.repeat = True; - surface->xc_surface = XcCreateDrawableSurface(surface->dpy, pix, format, CPRepeat, &sa); + Pixmap pix = XCreatePixmap(surface->dpy, + DefaultRootWindow(surface->dpy), + 1, 1, + surface->xc_format->depth); + _XrSurfaceSetDrawable(surface, pix); + surface->xc_sa_mask |= CPRepeat; + surface->xc_sa.repeat = True; + _XrSurfaceGetXcSurface(surface); XFreePixmap(surface->dpy, pix); } @@ -91,62 +97,134 @@ _XrSurfaceSetSolidColor(XrSurface *surface, XrColor *color, XcFormat *format) 0, 0, 1, 1); } -static void -_XrSurfaceCreateXcSurface(XrSurface *surface) +XrStatus +_XrSurfaceSetImage(XrSurface *surface, + char *data, + unsigned int width, + unsigned int height, + unsigned int stride) { - if (surface->drawable && surface->xc_format) { - surface->xc_surface = XcCreateDrawableSurface(surface->dpy, - surface->drawable, - surface->xc_format, - surface->xc_sa_mask, - &surface->xc_sa); - } + XImage *image; + unsigned int depth, bitmap_pad; + Pixmap pix; + + depth = surface->xc_format->depth; + + if (depth > 16) + bitmap_pad = 32; + else if (depth > 8) + bitmap_pad = 16; + else + bitmap_pad = 8; + + pix = XCreatePixmap(surface->dpy, + DefaultRootWindow(surface->dpy), + width, height, + depth); + _XrSurfaceSetDrawable(surface, pix); + + image = XCreateImage(surface->dpy, + DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)), + depth, ZPixmap, 0, + data, width, height, + bitmap_pad, + stride); + if (image == NULL) + return XrStatusNoMemory; + + XPutImage(surface->dpy, surface->drawable, surface->gc, + image, 0, 0, 0, 0, width, height); + + /* Foolish XDestroyImage thinks it can free my data, but I won't + stand for it. */ + image->data = NULL; + XDestroyImage(image); + + return XrStatusSuccess; } -static void -_XrSurfaceDestroyXcSurface(XrSurface *surface) +/* XXX: We may want to move to projective matrices at some point. If + nothing else, that would eliminate the two different transform data + structures we have here. */ +XrStatus +_XrSurfaceSetTransform(XrSurface *surface, XrTransform *transform) { - if (surface->xc_surface) { - XcFreeSurface(surface->dpy, surface->xc_surface); - surface->xc_surface = 0; - } + XTransform xtransform; + + xtransform.matrix[0][0] = XDoubleToFixed(transform->m[0][0]); + xtransform.matrix[0][1] = 0; + xtransform.matrix[0][2] = 0; + + xtransform.matrix[1][0] = 0; + xtransform.matrix[1][1] = XDoubleToFixed(transform->m[1][1]); + xtransform.matrix[1][2] = 0; + + xtransform.matrix[2][0] = 0; + xtransform.matrix[2][1] = 0; + xtransform.matrix[2][2] = XDoubleToFixed(1); + + XcSetSurfaceTransform(surface->dpy, + _XrSurfaceGetXcSurface(surface), + &xtransform); + + return XrStatusSuccess; } -/* XXX: These should probably be made to use lazy evaluation. - A new API will be needed, something like _XrSurfacePrepare -*/ void _XrSurfaceSetDrawable(XrSurface *surface, Drawable drawable) { - _XrSurfaceDestroyXcSurface(surface); + if (surface->gc) + XFreeGC(surface->dpy, surface->gc); surface->drawable = drawable; + surface->gc = XCreateGC(surface->dpy, surface->drawable, 0, 0); - _XrSurfaceCreateXcSurface(surface); + surface->needs_new_xc_surface = 1; } void _XrSurfaceSetVisual(XrSurface *surface, Visual *visual) { - _XrSurfaceDestroyXcSurface(surface); - surface->xc_format = XcFindVisualFormat(surface->dpy, visual); - - _XrSurfaceCreateXcSurface(surface); + surface->needs_new_xc_surface = 1; } void _XrSurfaceSetFormat(XrSurface *surface, XrFormat format) { - _XrSurfaceDestroyXcSurface(surface); - surface->xc_format = XcFindStandardFormat(surface->dpy, format); + surface->needs_new_xc_surface = 1; +} - _XrSurfaceCreateXcSurface(surface); +XcSurface * +_XrSurfaceGetXcSurface(XrSurface *surface) +{ + if (surface == NULL) + return NULL; + + if (! surface->needs_new_xc_surface) + return surface->xc_surface; + + if (surface->xc_surface) + XcFreeSurface(surface->dpy, surface->xc_surface); + + if (surface->drawable) + surface->xc_surface = XcCreateDrawableSurface(surface->dpy, + surface->drawable, + surface->xc_format, + surface->xc_sa_mask, + &surface->xc_sa); + else + /* XXX: Is this what we wnat to do here? */ + surface->xc_surface = 0; + + surface->needs_new_xc_surface = 0; + + return surface->xc_surface; } Picture _XrSurfaceGetPicture(XrSurface *surface) { - return XcSurfaceGetPicture(surface->xc_surface); + return XcSurfaceGetPicture(_XrSurfaceGetXcSurface(surface)); } diff --git a/xr.c b/xr.c index 5f65ba4d9..6869689ae 100644 --- a/xr.c +++ b/xr.c @@ -381,12 +381,68 @@ XrShowText(XrState *xrs, const unsigned char *utf8) xrs->status = _XrGStateShowText(_XR_CURRENT_GSTATE(xrs), utf8); } +void +XrShowImage(XrState *xrs, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride) +{ + if (xrs->status) + return; + + xrs->status = _XrGStateShowImage(_XR_CURRENT_GSTATE(xrs), + data, format, + width, height, stride); +} + +void +XrShowImageTransform(XrState *xrs, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride, + double a, double b, + double c, double d, + double tx, double ty) +{ + if (xrs->status) + return; + + xrs->status = _XrGStateShowImageTransform(_XR_CURRENT_GSTATE(xrs), + data, format, + width, height, stride, + a, b, + c, d, + tx, ty); +} + + XrStatus XrGetStatus(XrState *xrs) { return xrs->status; } +const char * +XrGetStatusString(XrState *xrs) +{ + switch (xrs->status) { + case XrStatusSuccess: + return "success"; + case XrStatusNoMemory: + return "out of memory"; + case XrStatusInvalidRestore: + return "XrRestore without matchin XrSave"; + case XrStatusNoCurrentPoint: + return "no current point defined"; + } + + return ""; +} + static void _XrClipValue(double *value, double min, double max) { diff --git a/xrfont.c b/xrfont.c index 7efc144d3..c0f70e1de 100644 --- a/xrfont.c +++ b/xrfont.c @@ -52,7 +52,7 @@ _XrFontInitCopy(XrFont *font, XrFont *other) if (other->xft_font) { font->xft_font = XftFontCopy(other->dpy, other->xft_font); - if (font->xft_font) + if (font->xft_font == NULL) return XrStatusNoMemory; } diff --git a/xrgstate.c b/xrgstate.c index 977d6567e..5397690ed 100644 --- a/xrgstate.c +++ b/xrgstate.c @@ -57,32 +57,35 @@ _XrGStateInit(XrGState *gstate, Display *dpy) gstate->tolerance = XR_GSTATE_TOLERANCE_DEFAULT; - gstate->fill_rule = XR_GSTATE_FILL_RULE_DEFAULT; - gstate->line_width = XR_GSTATE_LINE_WIDTH_DEFAULT; gstate->line_cap = XR_GSTATE_LINE_CAP_DEFAULT; gstate->line_join = XR_GSTATE_LINE_JOIN_DEFAULT; gstate->miter_limit = XR_GSTATE_MITER_LIMIT_DEFAULT; + + gstate->fill_rule = XR_GSTATE_FILL_RULE_DEFAULT; + gstate->dashes = 0; gstate->ndashes = 0; gstate->dash_offset = 0.0; - gstate->solidFormat = XcFindStandardFormat(dpy, PictStandardARGB32); gstate->alphaFormat = XcFindStandardFormat(dpy, PictStandardA8); _XrFontInit(&gstate->font, gstate); _XrSurfaceInit(&gstate->surface, dpy); _XrSurfaceInit(&gstate->src, dpy); + gstate->mask = NULL; _XrColorInit(&gstate->color); - _XrSurfaceSetSolidColor(&gstate->src, &gstate->color, gstate->solidFormat); + _XrSurfaceSetSolidColor(&gstate->src, &gstate->color); _XrTransformInit(&gstate->ctm); _XrTransformInit(&gstate->ctm_inverse); _XrPathInit(&gstate->path); + gstate->has_current_pt = 0; + _XrPenInitEmpty(&gstate->pen_regular); gstate->next = NULL; @@ -107,6 +110,8 @@ _XrGStateInitCopy(XrGState *gstate, XrGState *other) _XrSurfaceReference(&gstate->surface); _XrSurfaceReference(&gstate->src); + if (gstate->mask) + _XrSurfaceReference(gstate->mask); status = _XrPathInitCopy(&gstate->path, &other->path); if (status) @@ -136,6 +141,8 @@ _XrGStateDeinit(XrGState *gstate) _XrSurfaceDereference(&gstate->src); _XrSurfaceDereference(&gstate->surface); + if (gstate->mask) + _XrSurfaceDereferenceDestroy(gstate->mask); _XrColorDeinit(&gstate->color); @@ -213,7 +220,7 @@ XrStatus _XrGStateSetRGBColor(XrGState *gstate, double red, double green, double blue) { _XrColorSetRGB(&gstate->color, red, green, blue); - _XrSurfaceSetSolidColor(&gstate->src, &gstate->color, gstate->solidFormat); + _XrSurfaceSetSolidColor(&gstate->src, &gstate->color); return XrStatusSuccess; } @@ -230,7 +237,7 @@ XrStatus _XrGStateSetAlpha(XrGState *gstate, double alpha) { _XrColorSetAlpha(&gstate->color, alpha); - _XrSurfaceSetSolidColor(&gstate->src, &gstate->color, gstate->solidFormat); + _XrSurfaceSetSolidColor(&gstate->src, &gstate->color); return XrStatusSuccess; } @@ -353,10 +360,20 @@ _XrGStateConcatMatrix(XrGState *gstate, return XrStatusSuccess; } +static void +_XrGStateSetCurrentPt(XrGState *gstate, double x, double y) +{ + gstate->current_pt.x = x; + gstate->current_pt.y = y; + + gstate->has_current_pt = 1; +} + XrStatus _XrGStateNewPath(XrGState *gstate) { _XrPathDeinit(&gstate->path); + gstate->has_current_pt = 0; return XrStatusSuccess; } @@ -370,8 +387,7 @@ _XrGStateMoveTo(XrGState *gstate, double x, double y) status = _XrPathMoveTo(&gstate->path, x, y); - gstate->current_pt.x = x; - gstate->current_pt.y = y; + _XrGStateSetCurrentPt(gstate, x, y); gstate->last_move_pt = gstate->current_pt; @@ -387,8 +403,7 @@ _XrGStateLineTo(XrGState *gstate, double x, double y) status = _XrPathLineTo(&gstate->path, x, y); - gstate->current_pt.x = x; - gstate->current_pt.y = y; + _XrGStateSetCurrentPt(gstate, x, y); return status; } @@ -410,9 +425,7 @@ _XrGStateCurveTo(XrGState *gstate, x2, y2, x3, y3); - - gstate->current_pt.x = x3; - gstate->current_pt.y = y3; + _XrGStateSetCurrentPt(gstate, x3, y3); return status; } @@ -421,15 +434,16 @@ XrStatus _XrGStateRelMoveTo(XrGState *gstate, double dx, double dy) { XrStatus status; + double x, y; _XrTransformDistance(&gstate->ctm, &dx, &dy); - status = _XrPathMoveTo(&gstate->path, - gstate->current_pt.x + dx, - gstate->current_pt.y + dy); + x = gstate->current_pt.x + dx; + y = gstate->current_pt.y + dy; - gstate->current_pt.x += dx; - gstate->current_pt.y += dy; + status = _XrPathMoveTo(&gstate->path, x, y); + + _XrGStateSetCurrentPt(gstate, x, y); gstate->last_move_pt = gstate->current_pt; @@ -440,16 +454,16 @@ XrStatus _XrGStateRelLineTo(XrGState *gstate, double dx, double dy) { XrStatus status; + double x, y; _XrTransformDistance(&gstate->ctm, &dx, &dy); - status = _XrPathLineTo(&gstate->path, - gstate->current_pt.x + dx, - gstate->current_pt.y + dy); + x = gstate->current_pt.x + dx; + y = gstate->current_pt.y + dy; + status = _XrPathLineTo(&gstate->path, x, y); - gstate->current_pt.x += dx; - gstate->current_pt.y += dy; + _XrGStateSetCurrentPt(gstate, x, y); return status; } @@ -471,8 +485,9 @@ _XrGStateRelCurveTo(XrGState *gstate, gstate->current_pt.x + dx2, gstate->current_pt.y + dy2, gstate->current_pt.x + dx3, gstate->current_pt.y + dy3); - gstate->current_pt.x += dx3; - gstate->current_pt.y += dy3; + _XrGStateSetCurrentPt(gstate, + gstate->current_pt.x + dx3, + gstate->current_pt.y + dy3); return status; } @@ -484,7 +499,9 @@ _XrGStateClosePath(XrGState *gstate) status = _XrPathClosePath(&gstate->path); - gstate->current_pt = gstate->last_move_pt; + _XrGStateSetCurrentPt(gstate, + gstate->last_move_pt.x, + gstate->last_move_pt.y); return status; } @@ -525,8 +542,8 @@ _XrGStateStroke(XrGState *gstate) } XcCompositeTrapezoids(gstate->dpy, gstate->operator, - gstate->src.xc_surface, - gstate->surface.xc_surface, + _XrSurfaceGetXcSurface(&gstate->src), + _XrSurfaceGetXcSurface(&gstate->surface), gstate->alphaFormat, 0, 0, traps.xtraps, @@ -565,8 +582,8 @@ _XrGStateFill(XrGState *gstate) } XcCompositeTrapezoids(gstate->dpy, gstate->operator, - gstate->src.xc_surface, - gstate->surface.xc_surface, + _XrSurfaceGetXcSurface(&gstate->src), + _XrSurfaceGetXcSurface(&gstate->surface), gstate->alphaFormat, 0, 0, traps.xtraps, @@ -637,6 +654,9 @@ _XrGStateShowText(XrGState *gstate, const unsigned char *utf8) { XftFont *xft_font; + if (gstate->has_current_pt == 0) + return XrStatusNoCurrentPoint; + _XrFontResolveXftFont(&gstate->font, gstate, &xft_font); XftTextRenderUtf8(gstate->dpy, @@ -653,6 +673,67 @@ _XrGStateShowText(XrGState *gstate, const unsigned char *utf8) return XrStatusSuccess; } +XrStatus +_XrGStateShowImage(XrGState *gstate, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride) +{ + return _XrGStateShowImageTransform(gstate, + data, format, width, height, stride, + 1, 0, + 0, 1, + - gstate->current_pt.x, + - gstate->current_pt.y); +} + +XrStatus +_XrGStateShowImageTransform(XrGState *gstate, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride, + double a, double b, + double c, double d, + double tx, double ty) +{ + XrStatus status; + XrSurface image_surface; + double dst_width, dst_height; + + _XrSurfaceInit(&image_surface, gstate->dpy); + + _XrSurfaceSetFormat(&image_surface, format); + + status = _XrSurfaceSetImage(&image_surface, data, width, height, stride); + if (status) + return status; + + _XrSurfaceSetTransform(&image_surface, &gstate->ctm_inverse); + + dst_width = width; + dst_height = height; + _XrTransformDistance(&gstate->ctm, &dst_width, &dst_height); + + XcComposite(gstate->dpy, gstate->operator, + _XrSurfaceGetXcSurface(&image_surface), + 0, + _XrSurfaceGetXcSurface(&gstate->surface), + 0, 0, + 0, 0, + gstate->current_pt.x, + gstate->current_pt.y, + dst_width, + dst_height); + + _XrSurfaceDeinit(&image_surface); + + return XrStatusSuccess; +} + static Picture _XrGStateGetPicture(XrGState *gstate) { diff --git a/xrint.h b/xrint.h index b2bf53d85..35ed6b1d0 100644 --- a/xrint.h +++ b/xrint.h @@ -169,6 +169,7 @@ typedef struct _XrSurface { Display *dpy; Drawable drawable; + GC gc; unsigned int depth; @@ -177,6 +178,7 @@ typedef struct _XrSurface { XcFormat *xc_format; XcSurface *xc_surface; + int needs_new_xc_surface; unsigned int ref_count; } XrSurface; @@ -226,29 +228,31 @@ typedef struct _XrFont { typedef struct _XrGState { Display *dpy; + XrOperator operator; + double tolerance; /* stroke style */ double line_width; XrLineCap line_cap; XrLineJoin line_join; - double *dashes; - int ndashes; - double dash_offset; double miter_limit; XrFillRule fill_rule; - XrOperator operator; - - XcFormat *solidFormat; + double *dashes; + int ndashes; + double dash_offset; + XcFormat *alphaFormat; XrFont font; - XrColor color; XrSurface src; XrSurface surface; + XrSurface *mask; + + XrColor color; XrTransform ctm; XrTransform ctm_inverse; @@ -257,6 +261,7 @@ typedef struct _XrGState { XPointDouble last_move_pt; XPointDouble current_pt; + int has_current_pt; XrPen pen_regular; @@ -447,6 +452,25 @@ _XrGStateTextExtents(XrGState *gstate, XrStatus _XrGStateShowText(XrGState *gstate, const unsigned char *utf8); +XrStatus +_XrGStateShowImage(XrGState *gstate, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride); + +XrStatus +_XrGStateShowImageTransform(XrGState *gstate, + char *data, + XrFormat format, + unsigned int width, + unsigned int height, + unsigned int stride, + double a, double b, + double c, double d, + double tx, double ty); + /* xrcolor.c */ void _XrColorInit(XrColor *color); @@ -523,11 +547,24 @@ _XrSurfaceReference(XrSurface *surface); void _XrSurfaceDereference(XrSurface *surface); +void +_XrSurfaceDereferenceDestroy(XrSurface *surface); + void _XrSurfaceDeinit(XrSurface *surface); void -_XrSurfaceSetSolidColor(XrSurface *surface, XrColor *color, XcFormat *xc_format); +_XrSurfaceSetSolidColor(XrSurface *surface, XrColor *color); + +XrStatus +_XrSurfaceSetImage(XrSurface *surface, + char *data, + unsigned int width, + unsigned int height, + unsigned int stride); + +XrStatus +_XrSurfaceSetTransform(XrSurface *surface, XrTransform *transform); void _XrSurfaceSetDrawable(XrSurface *surface, Drawable drawable); @@ -538,6 +575,9 @@ _XrSurfaceSetVisual(XrSurface *surface, Visual *visual); void _XrSurfaceSetFormat(XrSurface *surface, XrFormat format); +XcSurface * +_XrSurfaceGetXcSurface(XrSurface *surface); + Picture _XrSurfaceGetPicture(XrSurface *surface); diff --git a/xrsurface.c b/xrsurface.c index 975f651a9..6e8a8a05d 100644 --- a/xrsurface.c +++ b/xrsurface.c @@ -25,26 +25,22 @@ #include "xrint.h" -static void -_XrSurfaceCreateXcSurface(XrSurface *surface); - -static void -_XrSurfaceDestroyXcSurface(XrSurface *surface); - - void _XrSurfaceInit(XrSurface *surface, Display *dpy) { surface->dpy = dpy; surface->drawable = 0; + surface->gc = 0; surface->depth = 0; surface->xc_sa_mask = 0; - surface->xc_format = 0; + surface->xc_format = XcFindStandardFormat(dpy, PictStandardARGB32); + surface->xc_surface = 0; + surface->needs_new_xc_surface = 1; surface->ref_count = 0; } @@ -64,6 +60,15 @@ _XrSurfaceDereference(XrSurface *surface) surface->ref_count--; } +void +_XrSurfaceDereferenceDestroy(XrSurface *surface) +{ + _XrSurfaceDereference(surface); + + if (surface->ref_count == 0) + free(surface); +} + void _XrSurfaceDeinit(XrSurface *surface) { @@ -72,17 +77,18 @@ _XrSurfaceDeinit(XrSurface *surface) } void -_XrSurfaceSetSolidColor(XrSurface *surface, XrColor *color, XcFormat *format) +_XrSurfaceSetSolidColor(XrSurface *surface, XrColor *color) { /* XXX: QUESTION: Special handling for depth==1 ala xftdraw.c? */ - if (surface->xc_surface == 0) { - Pixmap pix; - XcSurfaceAttributes sa; - - pix = XCreatePixmap(surface->dpy, DefaultRootWindow(surface->dpy), 1, 1, format->depth); - sa.repeat = True; - surface->xc_surface = XcCreateDrawableSurface(surface->dpy, pix, format, CPRepeat, &sa); + Pixmap pix = XCreatePixmap(surface->dpy, + DefaultRootWindow(surface->dpy), + 1, 1, + surface->xc_format->depth); + _XrSurfaceSetDrawable(surface, pix); + surface->xc_sa_mask |= CPRepeat; + surface->xc_sa.repeat = True; + _XrSurfaceGetXcSurface(surface); XFreePixmap(surface->dpy, pix); } @@ -91,62 +97,134 @@ _XrSurfaceSetSolidColor(XrSurface *surface, XrColor *color, XcFormat *format) 0, 0, 1, 1); } -static void -_XrSurfaceCreateXcSurface(XrSurface *surface) +XrStatus +_XrSurfaceSetImage(XrSurface *surface, + char *data, + unsigned int width, + unsigned int height, + unsigned int stride) { - if (surface->drawable && surface->xc_format) { - surface->xc_surface = XcCreateDrawableSurface(surface->dpy, - surface->drawable, - surface->xc_format, - surface->xc_sa_mask, - &surface->xc_sa); - } + XImage *image; + unsigned int depth, bitmap_pad; + Pixmap pix; + + depth = surface->xc_format->depth; + + if (depth > 16) + bitmap_pad = 32; + else if (depth > 8) + bitmap_pad = 16; + else + bitmap_pad = 8; + + pix = XCreatePixmap(surface->dpy, + DefaultRootWindow(surface->dpy), + width, height, + depth); + _XrSurfaceSetDrawable(surface, pix); + + image = XCreateImage(surface->dpy, + DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)), + depth, ZPixmap, 0, + data, width, height, + bitmap_pad, + stride); + if (image == NULL) + return XrStatusNoMemory; + + XPutImage(surface->dpy, surface->drawable, surface->gc, + image, 0, 0, 0, 0, width, height); + + /* Foolish XDestroyImage thinks it can free my data, but I won't + stand for it. */ + image->data = NULL; + XDestroyImage(image); + + return XrStatusSuccess; } -static void -_XrSurfaceDestroyXcSurface(XrSurface *surface) +/* XXX: We may want to move to projective matrices at some point. If + nothing else, that would eliminate the two different transform data + structures we have here. */ +XrStatus +_XrSurfaceSetTransform(XrSurface *surface, XrTransform *transform) { - if (surface->xc_surface) { - XcFreeSurface(surface->dpy, surface->xc_surface); - surface->xc_surface = 0; - } + XTransform xtransform; + + xtransform.matrix[0][0] = XDoubleToFixed(transform->m[0][0]); + xtransform.matrix[0][1] = 0; + xtransform.matrix[0][2] = 0; + + xtransform.matrix[1][0] = 0; + xtransform.matrix[1][1] = XDoubleToFixed(transform->m[1][1]); + xtransform.matrix[1][2] = 0; + + xtransform.matrix[2][0] = 0; + xtransform.matrix[2][1] = 0; + xtransform.matrix[2][2] = XDoubleToFixed(1); + + XcSetSurfaceTransform(surface->dpy, + _XrSurfaceGetXcSurface(surface), + &xtransform); + + return XrStatusSuccess; } -/* XXX: These should probably be made to use lazy evaluation. - A new API will be needed, something like _XrSurfacePrepare -*/ void _XrSurfaceSetDrawable(XrSurface *surface, Drawable drawable) { - _XrSurfaceDestroyXcSurface(surface); + if (surface->gc) + XFreeGC(surface->dpy, surface->gc); surface->drawable = drawable; + surface->gc = XCreateGC(surface->dpy, surface->drawable, 0, 0); - _XrSurfaceCreateXcSurface(surface); + surface->needs_new_xc_surface = 1; } void _XrSurfaceSetVisual(XrSurface *surface, Visual *visual) { - _XrSurfaceDestroyXcSurface(surface); - surface->xc_format = XcFindVisualFormat(surface->dpy, visual); - - _XrSurfaceCreateXcSurface(surface); + surface->needs_new_xc_surface = 1; } void _XrSurfaceSetFormat(XrSurface *surface, XrFormat format) { - _XrSurfaceDestroyXcSurface(surface); - surface->xc_format = XcFindStandardFormat(surface->dpy, format); + surface->needs_new_xc_surface = 1; +} - _XrSurfaceCreateXcSurface(surface); +XcSurface * +_XrSurfaceGetXcSurface(XrSurface *surface) +{ + if (surface == NULL) + return NULL; + + if (! surface->needs_new_xc_surface) + return surface->xc_surface; + + if (surface->xc_surface) + XcFreeSurface(surface->dpy, surface->xc_surface); + + if (surface->drawable) + surface->xc_surface = XcCreateDrawableSurface(surface->dpy, + surface->drawable, + surface->xc_format, + surface->xc_sa_mask, + &surface->xc_sa); + else + /* XXX: Is this what we wnat to do here? */ + surface->xc_surface = 0; + + surface->needs_new_xc_surface = 0; + + return surface->xc_surface; } Picture _XrSurfaceGetPicture(XrSurface *surface) { - return XcSurfaceGetPicture(surface->xc_surface); + return XcSurfaceGetPicture(_XrSurfaceGetXcSurface(surface)); }