cairo/xrgstate.c

510 lines
11 KiB
C
Raw Normal View History

2002-06-11 04:02:23 +00:00
/*
* $XFree86: $
*
* Copyright <EFBFBD> 2002 University of Southern California
*
* 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 University
* of Southern California not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. University of Southern California makes
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl Worth, USC, Information Sciences Institute */
#include <stdlib.h>
#include <math.h>
#include "xrint.h"
/* Private functions */
static XrGState *
_XrGStateAlloc(void);
static void
_TranslatePoint(XPointDouble *pt, const XPointDouble *offset);
static void
2002-07-23 07:22:23 +00:00
_XrGStateStrokePath(XrGState *gstate, XrPath *path, XrTraps *traps);
2002-06-11 04:02:23 +00:00
static void
2002-07-23 07:22:23 +00:00
_XrGStateStrokeSubPath(XrGState *gstate, XrSubPath *subpath, XrTraps *traps);
2002-06-11 04:02:23 +00:00
static void
2002-07-23 07:22:23 +00:00
_XrGStateStrokeCap(XrGState *gstate,
const XPointDouble *p0, const XPointDouble *p1,
XrTraps *traps);
static void
_XrGStateStrokeJoin(XrGState *gstate,
const XPointDouble *p0, const XPointDouble *p1, const XPointDouble *p2,
XrTraps *traps);
static void
_XrGStateStrokeSegment(XrGState *gstate,
const XPointDouble *p0, const XPointDouble *p1,
XrTraps *traps);
2002-06-11 04:02:23 +00:00
static void
_XrGStateFillPath(XrGState *gstate, XrPath *path);
static XrGState *
_XrGStateAlloc(void)
{
return malloc(sizeof(XrGState));
}
XrGState *
XrGStateCreate(Display *dpy)
{
XrGState *gstate;
gstate = _XrGStateAlloc();
XrGStateInit(gstate, dpy);
return gstate;
}
void
XrGStateInit(XrGState *gstate, Display *dpy)
{
gstate->dpy = dpy;
2002-07-23 07:22:23 +00:00
gstate->operator = XR_GSTATE_OPERATOR_DEFAULT;
2002-06-11 04:02:23 +00:00
gstate->winding = XR_GSTATE_WINDING_DEFAULT;
gstate->line_width = XR_GSTATE_LINE_WIDTH_DEFAULT;
2002-07-23 07:22:23 +00:00
gstate->line_cap = XR_GSTATE_LINE_CAP_DEFAULT;
gstate->line_join = XR_GSTATE_LINE_JOIN_DEFAULT;
gstate->miter_limit = XR_GSTATE_MITER_LIMIT_DEFAULT;
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
gstate->solidFormat = XcFindStandardFormat(dpy, PictStandardARGB32);
gstate->alphaFormat = XcFindStandardFormat(dpy, PictStandardA8);
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
XrSurfaceInit(&gstate->surface, dpy);
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
XrSurfaceInit(&gstate->src, dpy);
2002-06-11 04:02:23 +00:00
XrColorInit(&gstate->color);
2002-07-23 07:22:23 +00:00
XrSurfaceSetSolidColor(&gstate->src, &gstate->color, gstate->solidFormat);
2002-06-11 04:02:23 +00:00
XrTransformInit(&gstate->ctm);
XrTransformInit(&gstate->ctm_inverse);
2002-06-11 04:02:23 +00:00
XrPathInit(&gstate->path);
}
void
XrGStateInitCopy(XrGState *gstate, XrGState *other)
{
*gstate = *other;
2002-07-23 07:22:23 +00:00
XrSurfaceInit(&gstate->src, gstate->dpy);
XrSurfaceSetSolidColor(&gstate->src, &gstate->color, gstate->solidFormat);
2002-06-11 04:02:23 +00:00
XrPathInitCopy(&gstate->path, &other->path);
}
void
XrGStateDeinit(XrGState *gstate)
{
XrColorDeinit(&gstate->color);
2002-07-23 07:22:23 +00:00
XrSurfaceDeinit(&gstate->src);
XrSurfaceDeinit(&gstate->surface);
XrTransformDeinit(&gstate->ctm);
XrTransformDeinit(&gstate->ctm_inverse);
2002-06-11 04:02:23 +00:00
XrPathDeinit(&gstate->path);
}
void
XrGStateDestroy(XrGState *gstate)
{
XrGStateDeinit(gstate);
free(gstate);
}
XrGState *
XrGStateClone(XrGState *gstate)
{
XrGState *clone;
clone = _XrGStateAlloc();
XrGStateInitCopy(clone, gstate);
return clone;
}
void
XrGStateGetCurrentPoint(XrGState *gstate, XPointDouble *pt)
{
XrPathGetCurrentPoint(&gstate->path, pt);
}
void
XrGStateSetDrawable(XrGState *gstate, Drawable drawable)
2002-06-11 04:02:23 +00:00
{
2002-07-23 07:22:23 +00:00
XrSurfaceSetDrawable(&gstate->surface, drawable);
}
void
XrGStateSetVisual(XrGState *gstate, Visual *visual)
{
2002-07-23 07:22:23 +00:00
XrSurfaceSetVisual(&gstate->surface, visual);
}
void
XrGStateSetFormat(XrGState *gstate, XrFormat format)
{
2002-07-23 07:22:23 +00:00
XrSurfaceSetFormat(&gstate->surface, format);
}
void
XrGStateSetOperator(XrGState *gstate, XrOperator operator)
{
gstate->operator = operator;
2002-06-11 04:02:23 +00:00
}
void
2002-07-23 07:22:23 +00:00
XrGStateSetRGBColor(XrGState *gstate, double red, double green, double blue)
2002-06-11 04:02:23 +00:00
{
XrColorSetRGB(&gstate->color, red, green, blue);
2002-07-23 07:22:23 +00:00
XrSurfaceSetSolidColor(&gstate->src, &gstate->color, gstate->solidFormat);
2002-06-11 04:02:23 +00:00
}
void
XrGStateSetAlpha(XrGState *gstate, double alpha)
{
XrColorSetAlpha(&gstate->color, alpha);
2002-07-23 07:22:23 +00:00
XrSurfaceSetSolidColor(&gstate->src, &gstate->color, gstate->solidFormat);
2002-06-11 04:02:23 +00:00
}
void
XrGStateSetLineWidth(XrGState *gstate, double width)
{
gstate->line_width = width;
}
2002-07-23 07:22:23 +00:00
void
XrGStateSetLineCap(XrGState *gstate, XrLineCap line_cap)
{
gstate->line_cap = line_cap;
}
void
XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join)
{
gstate->line_join = line_join;
}
void
XrGStateSetMiterLimit(XrGState *gstate, double limit)
{
gstate->miter_limit = limit;
}
2002-06-11 04:02:23 +00:00
void
XrGStateTranslate(XrGState *gstate, double tx, double ty)
{
XrTransform tmp;
XrTransformInitTranslate(&tmp, tx, ty);
XrTransformMultiplyIntoRight(&tmp, &gstate->ctm);
2002-06-11 04:02:23 +00:00
XrTransformInitTranslate(&tmp, -tx, -ty);
XrTransformMultiplyIntoLeft(&gstate->ctm_inverse, &tmp);
2002-06-11 04:02:23 +00:00
}
void
XrGStateScale(XrGState *gstate, double sx, double sy)
{
XrTransform tmp;
2002-06-11 04:02:23 +00:00
XrTransformInitScale(&tmp, sx, sy);
XrTransformMultiplyIntoRight(&tmp, &gstate->ctm);
XrTransformInitScale(&tmp, -sx, -sy);
XrTransformMultiplyIntoLeft(&gstate->ctm_inverse, &tmp);
2002-06-11 04:02:23 +00:00
}
void
XrGStateRotate(XrGState *gstate, double angle)
{
XrTransform tmp;
XrTransformInitRotate(&tmp, angle);
XrTransformMultiplyIntoRight(&tmp, &gstate->ctm);
2002-06-11 04:02:23 +00:00
XrTransformInitRotate(&tmp, -angle);
XrTransformMultiplyIntoLeft(&gstate->ctm_inverse, &tmp);
2002-06-11 04:02:23 +00:00
}
void
XrGStateNewPath(XrGState *gstate)
{
XrPathDeinit(&gstate->path);
}
void
XrGStateMoveTo(XrGState *gstate, double x, double y)
{
XPointDouble pt;
pt.x = x;
pt.y = y;
XrTransformPoint(&gstate->ctm, &pt);
2002-06-11 04:02:23 +00:00
XrPathMoveTo(&gstate->path, &pt);
}
void
XrGStateLineTo(XrGState *gstate, double x, double y)
{
XPointDouble pt;
pt.x = x;
pt.y = y;
XrTransformPoint(&gstate->ctm, &pt);
2002-06-11 04:02:23 +00:00
XrPathLineTo(&gstate->path, &pt);
}
static void
_TranslatePoint(XPointDouble *pt, const XPointDouble *offset)
{
pt->x += offset->x;
pt->y += offset->y;
}
void
XrGStateRelMoveTo(XrGState *gstate, double x, double y)
{
XPointDouble pt, current;
pt.x = x;
pt.y = y;
XrTransformPointWithoutTranslate(&gstate->ctm, &pt);
2002-06-11 04:02:23 +00:00
XrGStateGetCurrentPoint(gstate, &current);
_TranslatePoint(&pt, &current);
XrPathMoveTo(&gstate->path, &pt);
}
void
XrGStateRelLineTo(XrGState *gstate, double x, double y)
{
XPointDouble pt, current;
pt.x = x;
pt.y = y;
XrTransformPointWithoutTranslate(&gstate->ctm, &pt);
2002-06-11 04:02:23 +00:00
XrGStateGetCurrentPoint(gstate, &current);
_TranslatePoint(&pt, &current);
XrPathLineTo(&gstate->path, &pt);
}
void
XrGStateClosePath(XrGState *gstate)
{
XrPathClose(&gstate->path);
}
void
XrGStateStroke(XrGState *gstate)
{
2002-07-23 07:22:23 +00:00
XrTraps traps;
XrTrapsInit(&traps);
_XrGStateStrokePath(gstate, &gstate->path, &traps);
XcCompositeTrapezoids(gstate->dpy, gstate->operator,
gstate->src.xcsurface, gstate->surface.xcsurface,
gstate->alphaFormat,
0, 0,
traps.xtraps,
traps.num_xtraps);
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
XrTrapsDeinit(&traps);
XrGStateNewPath(gstate);
2002-06-11 04:02:23 +00:00
}
void
XrGStateFill(XrGState *gstate)
{
_XrGStateFillPath(gstate, &gstate->path);
2002-07-23 07:22:23 +00:00
XrGStateNewPath(gstate);
2002-06-11 04:02:23 +00:00
}
static void
2002-07-23 07:22:23 +00:00
_XrGStateStrokePath(XrGState *gstate, XrPath *path, XrTraps *traps)
2002-06-11 04:02:23 +00:00
{
2002-07-23 07:22:23 +00:00
XrSubPath *subpath;
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
for (subpath = path->head; subpath; subpath = subpath->next) {
if (subpath->num_pts) {
_XrGStateStrokeSubPath(gstate, subpath, traps);
2002-06-11 04:02:23 +00:00
}
}
}
static void
2002-07-23 07:22:23 +00:00
_XrGStateStrokeSubPath(XrGState *gstate, XrSubPath *subpath, XrTraps *traps)
2002-06-11 04:02:23 +00:00
{
int i;
2002-07-23 07:22:23 +00:00
XPointDouble *pt_prev, *pt, *pt_next;
/* XXX: BUG: Need to consider degenrate paths here, (all paths
less then 3 points may need special consideration) */
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
/* Stroke initial cap or join */
pt_prev = subpath->pts + subpath->num_pts - 1;
pt = subpath->pts;
pt_next = pt + 1;
if (subpath->closed) {
_XrGStateStrokeJoin(gstate, pt_prev, pt, pt_next, traps);
} else {
_XrGStateStrokeCap(gstate, pt_next, pt, traps);
}
_XrGStateStrokeSegment(gstate, pt, pt_next, traps);
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
/* Stroke path segments */
for (i = 1; i < subpath->num_pts - 1; i++) {
pt_prev = pt;
pt = pt_next;
pt_next++;
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
_XrGStateStrokeJoin(gstate, pt_prev, pt, pt_next, traps);
_XrGStateStrokeSegment(gstate, pt, pt_next, traps);
2002-06-11 04:02:23 +00:00
}
2002-07-23 07:22:23 +00:00
/* Close path or add final cap as necessary */
pt_prev = pt;
pt = pt_next;
pt_next = subpath->pts;
2002-06-11 04:02:23 +00:00
if (subpath->closed) {
2002-07-23 07:22:23 +00:00
_XrGStateStrokeJoin(gstate, pt_prev, pt, pt_next, traps);
_XrGStateStrokeSegment(gstate, pt, pt_next, traps);
2002-06-11 04:02:23 +00:00
} else {
2002-07-23 07:22:23 +00:00
_XrGStateStrokeCap(gstate, pt_prev, pt, traps);
2002-06-11 04:02:23 +00:00
}
2002-07-23 07:22:23 +00:00
}
static void
_XrGStateStrokeCap(XrGState *gstate,
const XPointDouble *p0, const XPointDouble *p1,
XrTraps *traps)
{
switch (gstate->line_cap) {
case XrLineCapRound:
/* XXX: NYI */
break;
case XrLineCapSquare:
/* XXX: NYI */
break;
case XrLineCapButt:
default:
/* XXX: NYI */
break;
2002-06-11 04:02:23 +00:00
}
2002-07-23 07:22:23 +00:00
}
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
static void
_XrGStateStrokeJoin(XrGState *gstate,
const XPointDouble *p0, const XPointDouble *p1, const XPointDouble *p2,
XrTraps *traps)
{
switch (gstate->line_join) {
case XrLineJoinMiter:
/* XXX: NYI */
break;
case XrLineJoinRound:
/* XXX: NYI */
break;
case XrLineJoinBevel:
default:
/* XXX: NYI */
break;
2002-06-11 04:02:23 +00:00
}
}
static void
2002-07-23 07:22:23 +00:00
_XrGStateStrokeSegment(XrGState *gstate,
const XPointDouble *p0, const XPointDouble *p1,
XrTraps *traps)
2002-06-11 04:02:23 +00:00
{
double mag, tmp;
2002-06-11 04:02:23 +00:00
XPointDouble offset;
2002-07-23 07:22:23 +00:00
XPointDouble quad[4];
2002-06-11 04:02:23 +00:00
offset.x = p1->x - p0->x;
offset.y = p1->y - p0->y;
mag = sqrt(offset.x * offset.x + offset.y * offset.y);
if (mag == 0) {
return;
}
offset.x /= mag;
offset.y /= mag;
2002-06-11 04:02:23 +00:00
XrTransformPointWithoutTranslate(&gstate->ctm_inverse, &offset);
2002-06-11 04:02:23 +00:00
tmp = offset.x;
2002-07-23 07:22:23 +00:00
offset.x = offset.y * (gstate->line_width / 2.0);
offset.y = - tmp * (gstate->line_width / 2.0);
XrTransformPointWithoutTranslate(&gstate->ctm, &offset);
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
quad[0] = *p0;
_TranslatePoint(&quad[0], &offset);
quad[1] = *p1;
_TranslatePoint(&quad[1], &offset);
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
offset.x = - offset.x;
offset.y = - offset.y;
quad[2] = *p1;
_TranslatePoint(&quad[2], &offset);
quad[3] = *p0;
_TranslatePoint(&quad[3], &offset);
XrTrapsTessellateConvexQuad(traps, quad);
2002-06-11 04:02:23 +00:00
}
static void
_XrGStateFillPath(XrGState *gstate, XrPath *path)
{
2002-07-23 07:22:23 +00:00
XrTraps traps;
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
XrTrapsInit(&traps);
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
XrTrapsTessellatePath(&traps, path, gstate->winding);
XcCompositeTrapezoids(gstate->dpy, gstate->operator,
gstate->src.xcsurface, gstate->surface.xcsurface,
gstate->alphaFormat,
0, 0,
traps.xtraps,
traps.num_xtraps);
2002-06-11 04:02:23 +00:00
2002-07-23 07:22:23 +00:00
XrTrapsDeinit(&traps);
2002-06-11 04:02:23 +00:00
}
2002-07-23 07:22:23 +00:00