mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2025-12-22 20:50:11 +01:00
885 lines
20 KiB
C
885 lines
20 KiB
C
/*
|
|
* $XFree86: $
|
|
*
|
|
* Copyright © 2002 Carl D. Worth
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software
|
|
* and its documentation for any purpose is hereby granted without
|
|
* fee, provided that the above copyright notice appear in all copies
|
|
* and that both that copyright notice and this permission notice
|
|
* appear in supporting documentation, and that the name of Carl
|
|
* D. Worth not be used in advertising or publicity pertaining to
|
|
* distribution of the software without specific, written prior
|
|
* permission. Carl D. Worth makes no representations about the
|
|
* suitability of this software for any purpose. It is provided "as
|
|
* is" without express or implied warranty.
|
|
*
|
|
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
|
|
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
|
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
|
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
|
|
#include "xrint.h"
|
|
|
|
static Picture
|
|
_XrGStateGetPicture(XrGState *gstate);
|
|
|
|
static Picture
|
|
_XrGStateGetSrcPicture(XrGState *gstate);
|
|
|
|
XrGState *
|
|
_XrGStateCreate(Display *dpy)
|
|
{
|
|
XrGState *gstate;
|
|
|
|
gstate = malloc(sizeof(XrGState));
|
|
|
|
if (gstate)
|
|
_XrGStateInit(gstate, dpy);
|
|
|
|
return gstate;
|
|
}
|
|
|
|
void
|
|
_XrGStateInit(XrGState *gstate, Display *dpy)
|
|
{
|
|
gstate->dpy = dpy;
|
|
|
|
gstate->operator = XR_GSTATE_OPERATOR_DEFAULT;
|
|
|
|
gstate->tolerance = XR_GSTATE_TOLERANCE_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->dash = NULL;
|
|
gstate->num_dashes = 0;
|
|
gstate->dash_offset = 0.0;
|
|
|
|
gstate->alphaFormat = XcFindStandardFormat(dpy, PictStandardA8);
|
|
|
|
_XrFontInit(&gstate->font);
|
|
|
|
gstate->parent_surface = NULL;
|
|
gstate->surface = _XrSurfaceCreate(dpy);
|
|
gstate->src = _XrSurfaceCreate(dpy);
|
|
gstate->mask = NULL;
|
|
|
|
gstate->alpha = 1.0;
|
|
_XrColorInit(&gstate->color);
|
|
_XrSurfaceSetSolidColor(gstate->src, &gstate->color);
|
|
|
|
_XrTransformInitIdentity(&gstate->ctm);
|
|
_XrTransformInitIdentity(&gstate->ctm_inverse);
|
|
|
|
_XrPathInit(&gstate->path);
|
|
|
|
gstate->has_current_pt = 0;
|
|
|
|
_XrPenInitEmpty(&gstate->pen_regular);
|
|
|
|
gstate->next = NULL;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateInitCopy(XrGState *gstate, XrGState *other)
|
|
{
|
|
XrStatus status;
|
|
|
|
*gstate = *other;
|
|
if (other->dash) {
|
|
gstate->dash = malloc (other->num_dashes * sizeof (double));
|
|
if (gstate->dash == NULL)
|
|
return XrStatusNoMemory;
|
|
memcpy(gstate->dash, other->dash, other->num_dashes * sizeof (double));
|
|
}
|
|
|
|
status = _XrFontInitCopy(&gstate->font, &other->font);
|
|
if (status)
|
|
goto CLEANUP_DASHES;
|
|
|
|
gstate->parent_surface = NULL;
|
|
_XrSurfaceReference(gstate->surface);
|
|
_XrSurfaceReference(gstate->src);
|
|
if (gstate->mask)
|
|
_XrSurfaceReference(gstate->mask);
|
|
|
|
status = _XrPathInitCopy(&gstate->path, &other->path);
|
|
if (status)
|
|
goto CLEANUP_FONT;
|
|
|
|
status = _XrPenInitCopy(&gstate->pen_regular, &other->pen_regular);
|
|
if (status)
|
|
goto CLEANUP_PATH;
|
|
|
|
return status;
|
|
|
|
CLEANUP_PATH:
|
|
_XrPathDeinit(&gstate->path);
|
|
CLEANUP_FONT:
|
|
_XrFontDeinit(&gstate->font);
|
|
CLEANUP_DASHES:
|
|
free (gstate->dash);
|
|
gstate->dash = NULL;
|
|
|
|
return status;
|
|
}
|
|
|
|
void
|
|
_XrGStateDeinit(XrGState *gstate)
|
|
{
|
|
if (gstate->parent_surface)
|
|
_XrGStateEndGroup(gstate);
|
|
|
|
_XrFontDeinit(&gstate->font);
|
|
|
|
_XrSurfaceDereferenceDestroy(gstate->surface);
|
|
_XrSurfaceDereferenceDestroy(gstate->src);
|
|
if (gstate->mask)
|
|
_XrSurfaceDereferenceDestroy(gstate->mask);
|
|
|
|
_XrColorDeinit(&gstate->color);
|
|
|
|
_XrTransformDeinit(&gstate->ctm);
|
|
_XrTransformDeinit(&gstate->ctm_inverse);
|
|
|
|
_XrPathDeinit(&gstate->path);
|
|
|
|
_XrPenDeinit(&gstate->pen_regular);
|
|
|
|
if (gstate->dash) {
|
|
free (gstate->dash);
|
|
gstate->dash = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
_XrGStateDestroy(XrGState *gstate)
|
|
{
|
|
_XrGStateDeinit(gstate);
|
|
free(gstate);
|
|
}
|
|
|
|
XrGState*
|
|
_XrGStateClone(XrGState *gstate)
|
|
{
|
|
XrStatus status;
|
|
XrGState *clone;
|
|
|
|
clone = malloc(sizeof(XrGState));
|
|
if (clone) {
|
|
status = _XrGStateInitCopy(clone, gstate);
|
|
if (status) {
|
|
free(clone);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return clone;
|
|
}
|
|
|
|
/* Push rendering off to an off-screen group. */
|
|
XrStatus
|
|
_XrGStateBeginGroup(XrGState *gstate)
|
|
{
|
|
Pixmap pix;
|
|
XrColor clear;
|
|
unsigned int width, height;
|
|
|
|
gstate->parent_surface = gstate->surface;
|
|
|
|
width = _XrSurfaceGetWidth(gstate->surface);
|
|
height = _XrSurfaceGetHeight(gstate->surface);
|
|
|
|
pix = XCreatePixmap(gstate->dpy,
|
|
_XrSurfaceGetDrawable(gstate->surface),
|
|
width, height,
|
|
_XrSurfaceGetDepth(gstate->surface));
|
|
if (pix == 0)
|
|
return XrStatusNoMemory;
|
|
|
|
gstate->surface = _XrSurfaceCreate(gstate->dpy);
|
|
if (gstate->surface == NULL)
|
|
return XrStatusNoMemory;
|
|
|
|
_XrSurfaceSetDrawableWH(gstate->surface, pix, width, height);
|
|
|
|
_XrColorInit(&clear);
|
|
_XrColorSetAlpha(&clear, 0);
|
|
|
|
XcFillRectangle(gstate->dpy,
|
|
XrOperatorSrc,
|
|
_XrSurfaceGetXcSurface(gstate->surface),
|
|
&clear.xc_color,
|
|
0, 0,
|
|
_XrSurfaceGetWidth(gstate->surface),
|
|
_XrSurfaceGetHeight(gstate->surface));
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
/* Complete the current offscreen group, composing its contents onto the parent surface. */
|
|
XrStatus
|
|
_XrGStateEndGroup(XrGState *gstate)
|
|
{
|
|
Pixmap pix;
|
|
XrColor mask_color;
|
|
XrSurface mask;
|
|
|
|
if (gstate->parent_surface == NULL)
|
|
return XrStatusInvalidPopGroup;
|
|
|
|
_XrSurfaceInit(&mask, gstate->dpy);
|
|
_XrColorInit(&mask_color);
|
|
_XrColorSetAlpha(&mask_color, gstate->alpha);
|
|
|
|
_XrSurfaceSetSolidColor(&mask, &mask_color);
|
|
|
|
/* XXX: This could be made much more efficient by using
|
|
_XrSurfaceGetDamagedWidth/Height if XrSurface actually kept
|
|
track of such informaton. */
|
|
XcComposite(gstate->dpy, gstate->operator,
|
|
_XrSurfaceGetXcSurface(gstate->surface),
|
|
_XrSurfaceGetXcSurface(&mask),
|
|
_XrSurfaceGetXcSurface(gstate->parent_surface),
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
_XrSurfaceGetWidth(gstate->surface),
|
|
_XrSurfaceGetHeight(gstate->surface));
|
|
|
|
_XrSurfaceDeinit(&mask);
|
|
|
|
pix = _XrSurfaceGetDrawable(gstate->surface);
|
|
XFreePixmap(gstate->dpy, pix);
|
|
|
|
_XrSurfaceDestroy(gstate->surface);
|
|
gstate->surface = gstate->parent_surface;
|
|
gstate->parent_surface = NULL;
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetDrawable(XrGState *gstate, Drawable drawable)
|
|
{
|
|
_XrSurfaceSetDrawable(gstate->surface, drawable);
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetVisual(XrGState *gstate, Visual *visual)
|
|
{
|
|
_XrSurfaceSetVisual(gstate->surface, visual);
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetFormat(XrGState *gstate, XrFormat format)
|
|
{
|
|
_XrSurfaceSetFormat(gstate->surface, format);
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetOperator(XrGState *gstate, XrOperator operator)
|
|
{
|
|
gstate->operator = operator;
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetRGBColor(XrGState *gstate, double red, double green, double blue)
|
|
{
|
|
_XrColorSetRGB(&gstate->color, red, green, blue);
|
|
_XrSurfaceSetSolidColor(gstate->src, &gstate->color);
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetTolerance(XrGState *gstate, double tolerance)
|
|
{
|
|
gstate->tolerance = tolerance;
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetAlpha(XrGState *gstate, double alpha)
|
|
{
|
|
gstate->alpha = alpha;
|
|
_XrColorSetAlpha(&gstate->color, alpha);
|
|
_XrSurfaceSetSolidColor(gstate->src, &gstate->color);
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetFillRule(XrGState *gstate, XrFillRule fill_rule)
|
|
{
|
|
gstate->fill_rule = fill_rule;
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetLineWidth(XrGState *gstate, double width)
|
|
{
|
|
gstate->line_width = width;
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetLineCap(XrGState *gstate, XrLineCap line_cap)
|
|
{
|
|
gstate->line_cap = line_cap;
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join)
|
|
{
|
|
gstate->line_join = line_join;
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetDash(XrGState *gstate, double *dash, int num_dashes, double offset)
|
|
{
|
|
if (gstate->dash) {
|
|
free (gstate->dash);
|
|
gstate->dash = NULL;
|
|
}
|
|
|
|
gstate->num_dashes = num_dashes;
|
|
if (gstate->num_dashes) {
|
|
gstate->dash = malloc (gstate->num_dashes * sizeof (double));
|
|
if (gstate->dash == NULL) {
|
|
gstate->num_dashes = 0;
|
|
return XrStatusNoMemory;
|
|
}
|
|
}
|
|
|
|
memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double));
|
|
gstate->dash_offset = offset;
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetMiterLimit(XrGState *gstate, double limit)
|
|
{
|
|
gstate->miter_limit = limit;
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateTranslate(XrGState *gstate, double tx, double ty)
|
|
{
|
|
XrTransform tmp;
|
|
|
|
_XrTransformInitTranslate(&tmp, tx, ty);
|
|
_XrTransformMultiplyIntoRight(&tmp, &gstate->ctm);
|
|
|
|
_XrTransformInitTranslate(&tmp, -tx, -ty);
|
|
_XrTransformMultiplyIntoLeft(&gstate->ctm_inverse, &tmp);
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateScale(XrGState *gstate, double sx, double sy)
|
|
{
|
|
XrTransform tmp;
|
|
|
|
_XrTransformInitScale(&tmp, sx, sy);
|
|
_XrTransformMultiplyIntoRight(&tmp, &gstate->ctm);
|
|
|
|
_XrTransformInitScale(&tmp, 1/sx, 1/sy);
|
|
_XrTransformMultiplyIntoLeft(&gstate->ctm_inverse, &tmp);
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateRotate(XrGState *gstate, double angle)
|
|
{
|
|
XrTransform tmp;
|
|
|
|
_XrTransformInitRotate(&tmp, angle);
|
|
_XrTransformMultiplyIntoRight(&tmp, &gstate->ctm);
|
|
|
|
_XrTransformInitRotate(&tmp, -angle);
|
|
_XrTransformMultiplyIntoLeft(&gstate->ctm_inverse, &tmp);
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateConcatMatrix(XrGState *gstate,
|
|
double a, double b,
|
|
double c, double d,
|
|
double tx, double ty)
|
|
{
|
|
XrTransform tmp;
|
|
|
|
_XrTransformInitMatrix(&tmp, a, b, c, d, tx, ty);
|
|
_XrTransformMultiplyIntoRight(&tmp, &gstate->ctm);
|
|
|
|
_XrTransformComputeInverse(&tmp);
|
|
_XrTransformMultiplyIntoLeft(&gstate->ctm_inverse, &tmp);
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSetMatrix(XrGState *gstate,
|
|
double a, double b,
|
|
double c, double d,
|
|
double tx, double ty)
|
|
{
|
|
XrStatus status;
|
|
|
|
_XrTransformInitMatrix(&gstate->ctm, a, b, c, d, tx, ty);
|
|
|
|
gstate->ctm_inverse = gstate->ctm;
|
|
status = _XrTransformComputeInverse(&gstate->ctm_inverse);
|
|
if (status)
|
|
return status;
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateIdentityMatrix(XrGState *gstate)
|
|
{
|
|
_XrTransformInitIdentity(&gstate->ctm);
|
|
_XrTransformInitIdentity(&gstate->ctm_inverse);
|
|
|
|
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;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateMoveTo(XrGState *gstate, double x, double y)
|
|
{
|
|
XrStatus status;
|
|
|
|
_XrTransformPoint(&gstate->ctm, &x, &y);
|
|
|
|
status = _XrPathMoveTo(&gstate->path, x, y);
|
|
|
|
_XrGStateSetCurrentPt(gstate, x, y);
|
|
|
|
gstate->last_move_pt = gstate->current_pt;
|
|
|
|
return status;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateLineTo(XrGState *gstate, double x, double y)
|
|
{
|
|
XrStatus status;
|
|
|
|
_XrTransformPoint(&gstate->ctm, &x, &y);
|
|
|
|
status = _XrPathLineTo(&gstate->path, x, y);
|
|
|
|
_XrGStateSetCurrentPt(gstate, x, y);
|
|
|
|
return status;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateCurveTo(XrGState *gstate,
|
|
double x1, double y1,
|
|
double x2, double y2,
|
|
double x3, double y3)
|
|
{
|
|
XrStatus status;
|
|
|
|
_XrTransformPoint(&gstate->ctm, &x1, &y1);
|
|
_XrTransformPoint(&gstate->ctm, &x2, &y2);
|
|
_XrTransformPoint(&gstate->ctm, &x3, &y3);
|
|
|
|
status = _XrPathCurveTo(&gstate->path,
|
|
x1, y1,
|
|
x2, y2,
|
|
x3, y3);
|
|
|
|
_XrGStateSetCurrentPt(gstate, x3, y3);
|
|
|
|
return status;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateRelMoveTo(XrGState *gstate, double dx, double dy)
|
|
{
|
|
XrStatus status;
|
|
double x, y;
|
|
|
|
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
|
|
|
x = gstate->current_pt.x + dx;
|
|
y = gstate->current_pt.y + dy;
|
|
|
|
status = _XrPathMoveTo(&gstate->path, x, y);
|
|
|
|
_XrGStateSetCurrentPt(gstate, x, y);
|
|
|
|
gstate->last_move_pt = gstate->current_pt;
|
|
|
|
return status;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateRelLineTo(XrGState *gstate, double dx, double dy)
|
|
{
|
|
XrStatus status;
|
|
double x, y;
|
|
|
|
_XrTransformDistance(&gstate->ctm, &dx, &dy);
|
|
|
|
x = gstate->current_pt.x + dx;
|
|
y = gstate->current_pt.y + dy;
|
|
|
|
status = _XrPathLineTo(&gstate->path, x, y);
|
|
|
|
_XrGStateSetCurrentPt(gstate, x, y);
|
|
|
|
return status;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateRelCurveTo(XrGState *gstate,
|
|
double dx1, double dy1,
|
|
double dx2, double dy2,
|
|
double dx3, double dy3)
|
|
{
|
|
XrStatus status;
|
|
|
|
_XrTransformDistance(&gstate->ctm, &dx1, &dy1);
|
|
_XrTransformDistance(&gstate->ctm, &dx2, &dy2);
|
|
_XrTransformDistance(&gstate->ctm, &dx3, &dy3);
|
|
|
|
status = _XrPathCurveTo(&gstate->path,
|
|
gstate->current_pt.x + dx1, gstate->current_pt.y + dy1,
|
|
gstate->current_pt.x + dx2, gstate->current_pt.y + dy2,
|
|
gstate->current_pt.x + dx3, gstate->current_pt.y + dy3);
|
|
|
|
_XrGStateSetCurrentPt(gstate,
|
|
gstate->current_pt.x + dx3,
|
|
gstate->current_pt.y + dy3);
|
|
|
|
return status;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateClosePath(XrGState *gstate)
|
|
{
|
|
XrStatus status;
|
|
|
|
status = _XrPathClosePath(&gstate->path);
|
|
|
|
_XrGStateSetCurrentPt(gstate,
|
|
gstate->last_move_pt.x,
|
|
gstate->last_move_pt.y);
|
|
|
|
return status;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateStroke(XrGState *gstate)
|
|
{
|
|
XrStatus status;
|
|
|
|
static XrPathCallbacks cb = {
|
|
_XrStrokerAddEdge,
|
|
_XrStrokerAddSpline,
|
|
_XrStrokerDoneSubPath,
|
|
_XrStrokerDonePath
|
|
};
|
|
|
|
static XrPathCallbacks cb_dash = {
|
|
_XrStrokerAddEdgeDashed,
|
|
_XrStrokerAddSpline,
|
|
_XrStrokerDoneSubPath,
|
|
_XrStrokerDonePath
|
|
};
|
|
XrPathCallbacks *cbs = gstate->dash ? &cb_dash : &cb;
|
|
|
|
XrStroker stroker;
|
|
XrTraps traps;
|
|
|
|
_XrPenInit(&gstate->pen_regular, gstate->line_width / 2.0, gstate);
|
|
|
|
_XrTrapsInit(&traps);
|
|
_XrStrokerInit(&stroker, gstate, &traps);
|
|
|
|
status = _XrPathInterpret(&gstate->path, XrPathDirectionForward, cbs, &stroker);
|
|
if (status) {
|
|
_XrStrokerDeinit(&stroker);
|
|
_XrTrapsDeinit(&traps);
|
|
return status;
|
|
}
|
|
|
|
XcCompositeTrapezoids(gstate->dpy, gstate->operator,
|
|
_XrSurfaceGetXcSurface(gstate->src),
|
|
_XrSurfaceGetXcSurface(gstate->surface),
|
|
gstate->alphaFormat,
|
|
0, 0,
|
|
traps.xtraps,
|
|
traps.num_xtraps);
|
|
|
|
_XrStrokerDeinit(&stroker);
|
|
_XrTrapsDeinit(&traps);
|
|
|
|
_XrGStateNewPath(gstate);
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateFill(XrGState *gstate)
|
|
{
|
|
XrStatus status;
|
|
static XrPathCallbacks cb = {
|
|
_XrFillerAddEdge,
|
|
_XrFillerAddSpline,
|
|
_XrFillerDoneSubPath,
|
|
_XrFillerDonePath
|
|
};
|
|
|
|
XrFiller filler;
|
|
XrTraps traps;
|
|
|
|
_XrTrapsInit(&traps);
|
|
_XrFillerInit(&filler, gstate, &traps);
|
|
|
|
status = _XrPathInterpret(&gstate->path, XrPathDirectionForward, &cb, &filler);
|
|
if (status) {
|
|
_XrFillerDeinit(&filler);
|
|
_XrTrapsDeinit(&traps);
|
|
return status;
|
|
}
|
|
|
|
XcCompositeTrapezoids(gstate->dpy, gstate->operator,
|
|
_XrSurfaceGetXcSurface(gstate->src),
|
|
_XrSurfaceGetXcSurface(gstate->surface),
|
|
gstate->alphaFormat,
|
|
0, 0,
|
|
traps.xtraps,
|
|
traps.num_xtraps);
|
|
|
|
_XrFillerDeinit(&filler);
|
|
_XrTrapsDeinit(&traps);
|
|
|
|
_XrGStateNewPath(gstate);
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateSelectFont(XrGState *gstate, const char *key)
|
|
{
|
|
return _XrFontSelect(&gstate->font, key);
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateScaleFont(XrGState *gstate, double scale)
|
|
{
|
|
return _XrFontScale(&gstate->font, scale);
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateTransformFont(XrGState *gstate,
|
|
double a, double b,
|
|
double c, double d)
|
|
{
|
|
return _XrFontTransform(&gstate->font,
|
|
a, b, c, d);
|
|
}
|
|
|
|
XrStatus
|
|
_XrGStateTextExtents(XrGState *gstate,
|
|
const unsigned char *utf8,
|
|
double *x, double *y,
|
|
double *width, double *height,
|
|
double *dx, double *dy)
|
|
{
|
|
XftFont *xft_font;
|
|
XGlyphInfo extents;
|
|
|
|
_XrFontResolveXftFont(&gstate->font, gstate, &xft_font);
|
|
|
|
XftTextExtentsUtf8(gstate->dpy,
|
|
xft_font,
|
|
utf8,
|
|
strlen((char *) utf8),
|
|
&extents);
|
|
|
|
/* XXX: What are the semantics of XftTextExtents? Specifically,
|
|
what does it do with x/y? I think we actually need to use the
|
|
gstate's current point in here somewhere. */
|
|
*x = extents.x;
|
|
*y = extents.y;
|
|
*width = extents.width;
|
|
*height = extents.height;
|
|
*dx = extents.xOff;
|
|
*dy = extents.yOff;
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
XrStatus
|
|
_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,
|
|
gstate->operator,
|
|
_XrGStateGetSrcPicture(gstate),
|
|
xft_font,
|
|
_XrGStateGetPicture(gstate),
|
|
0, 0,
|
|
gstate->current_pt.x,
|
|
gstate->current_pt.y,
|
|
utf8,
|
|
strlen((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,
|
|
width, 0,
|
|
0, height,
|
|
0, 0);
|
|
}
|
|
|
|
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;
|
|
XrColor mask_color;
|
|
XrSurface image_surface, mask;
|
|
XrTransform user_to_image, image_to_user;
|
|
XrTransform image_to_device, device_to_image;
|
|
double dst_x, dst_y;
|
|
double dst_width, dst_height;
|
|
|
|
_XrSurfaceInit(&mask, gstate->dpy);
|
|
_XrColorInit(&mask_color);
|
|
_XrColorSetAlpha(&mask_color, gstate->alpha);
|
|
|
|
_XrSurfaceSetSolidColor(&mask, &mask_color);
|
|
|
|
_XrSurfaceInit(&image_surface, gstate->dpy);
|
|
|
|
_XrSurfaceSetFormat(&image_surface, format);
|
|
|
|
status = _XrSurfaceSetImage(&image_surface, data,width, height, stride);
|
|
if (status)
|
|
return status;
|
|
|
|
_XrTransformInitMatrix(&user_to_image, a, b, c, d, tx, ty);
|
|
_XrTransformMultiply(&gstate->ctm_inverse, &user_to_image, &device_to_image);
|
|
_XrSurfaceSetTransform(&image_surface, &device_to_image);
|
|
|
|
image_to_user = user_to_image;
|
|
_XrTransformComputeInverse(&image_to_user);
|
|
_XrTransformMultiply(&image_to_user, &gstate->ctm, &image_to_device);
|
|
|
|
dst_x = 0;
|
|
dst_y = 0;
|
|
dst_width = width;
|
|
dst_height = height;
|
|
_XrTransformBoundingBox(&image_to_device,
|
|
&dst_x, &dst_y,
|
|
&dst_width, &dst_height);
|
|
|
|
XcComposite(gstate->dpy, gstate->operator,
|
|
_XrSurfaceGetXcSurface(&image_surface),
|
|
_XrSurfaceGetXcSurface(&mask),
|
|
_XrSurfaceGetXcSurface(gstate->surface),
|
|
dst_x, dst_y,
|
|
0, 0,
|
|
dst_x, dst_y,
|
|
dst_width + 2,
|
|
dst_height + 2);
|
|
|
|
_XrSurfaceDeinit(&image_surface);
|
|
_XrSurfaceDeinit(&mask);
|
|
|
|
return XrStatusSuccess;
|
|
}
|
|
|
|
static Picture
|
|
_XrGStateGetPicture(XrGState *gstate)
|
|
{
|
|
return _XrSurfaceGetPicture(gstate->surface);
|
|
}
|
|
|
|
static Picture
|
|
_XrGStateGetSrcPicture(XrGState *gstate)
|
|
{
|
|
return _XrSurfaceGetPicture(gstate->src);
|
|
}
|