mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-05 18:08:03 +02:00
Fixed pen to transform user-space radius to device space, (vertices_needed computation still broken). Pen now behaves well when an extra point is coincident with an original vertex point.
This commit is contained in:
parent
cf6f2e67d9
commit
13216da122
10 changed files with 124 additions and 64 deletions
4
Xr.h
4
Xr.h
|
|
@ -145,8 +145,6 @@ XrScale(XrState *xrs, double sx, double sy);
|
|||
void
|
||||
XrRotate(XrState *xrs, double angle);
|
||||
|
||||
/* XXX: NYI: XrSetDash, ... */
|
||||
|
||||
/* Path creation */
|
||||
void
|
||||
XrNewPath(XrState *xrs);
|
||||
|
|
@ -178,8 +176,6 @@ XrRelCurveTo(XrState *xrs,
|
|||
void
|
||||
XrClosePath(XrState *xrs);
|
||||
|
||||
/* XXX: NYI: XrArcTo, XrCurveTo, XrRelCurveTo, ... */
|
||||
|
||||
/* Render current path */
|
||||
void
|
||||
XrStroke(XrState *xrs);
|
||||
|
|
|
|||
4
src/Xr.h
4
src/Xr.h
|
|
@ -145,8 +145,6 @@ XrScale(XrState *xrs, double sx, double sy);
|
|||
void
|
||||
XrRotate(XrState *xrs, double angle);
|
||||
|
||||
/* XXX: NYI: XrSetDash, ... */
|
||||
|
||||
/* Path creation */
|
||||
void
|
||||
XrNewPath(XrState *xrs);
|
||||
|
|
@ -178,8 +176,6 @@ XrRelCurveTo(XrState *xrs,
|
|||
void
|
||||
XrClosePath(XrState *xrs);
|
||||
|
||||
/* XXX: NYI: XrArcTo, XrCurveTo, XrRelCurveTo, ... */
|
||||
|
||||
/* Render current path */
|
||||
void
|
||||
XrStroke(XrState *xrs);
|
||||
|
|
|
|||
|
|
@ -114,6 +114,9 @@ XrGStateDeinit(XrGState *gstate)
|
|||
XrTransformDeinit(&gstate->ctm_inverse);
|
||||
|
||||
XrPathDeinit(&gstate->path);
|
||||
|
||||
XrPenDeinit(&gstate->pen_regular);
|
||||
|
||||
if (gstate->dashes)
|
||||
free (gstate->dashes);
|
||||
}
|
||||
|
|
@ -354,7 +357,7 @@ XrGStateStroke(XrGState *gstate)
|
|||
XrStroker stroker;
|
||||
XrTraps traps;
|
||||
|
||||
XrPenInit(&gstate->pen_regular, gstate->line_width / 2.0, gstate->tolerance);
|
||||
XrPenInit(&gstate->pen_regular, gstate->line_width / 2.0, gstate);
|
||||
|
||||
XrTrapsInit(&traps);
|
||||
XrStrokerInit(&stroker, gstate, &traps);
|
||||
|
|
|
|||
|
|
@ -434,7 +434,7 @@ XrSurfaceSetFormat(XrSurface *surface, XrFormat format);
|
|||
|
||||
/* xrpen.c */
|
||||
XrError
|
||||
XrPenInit(XrPen *pen, double radius, double tolerance);
|
||||
XrPenInit(XrPen *pen, double radius, XrGState *gstate);
|
||||
|
||||
XrError
|
||||
XrPenInitEmpty(XrPen *pen);
|
||||
|
|
|
|||
36
src/xrpen.c
36
src/xrpen.c
|
|
@ -58,21 +58,26 @@ XrPenInitEmpty(XrPen *pen)
|
|||
}
|
||||
|
||||
XrError
|
||||
XrPenInit(XrPen *pen, double radius, double tolerance)
|
||||
XrPenInit(XrPen *pen, double radius, XrGState *gstate)
|
||||
{
|
||||
int i;
|
||||
XrPenVertex *v;
|
||||
XPointDouble pt;
|
||||
|
||||
if (pen->num_vertices) {
|
||||
/* XXX: It would be nice to notice that the pen is already properly constructed.
|
||||
However, this test would also have to account for possible changes in the transformation
|
||||
matrix.
|
||||
if (pen->radius == radius && pen->tolerance == tolerance)
|
||||
return XrErrorSuccess;
|
||||
*/
|
||||
XrPenDeinit(pen);
|
||||
}
|
||||
|
||||
pen->radius = radius;
|
||||
pen->tolerance = tolerance;
|
||||
pen->tolerance = gstate->tolerance;
|
||||
|
||||
pen->num_vertices = _XrPenVerticesNeeded(radius, tolerance);
|
||||
pen->num_vertices = _XrPenVerticesNeeded(radius, gstate->tolerance);
|
||||
|
||||
pen->vertex = malloc(pen->num_vertices * sizeof(XrPenVertex));
|
||||
if (pen->vertex == NULL) {
|
||||
|
|
@ -82,8 +87,11 @@ XrPenInit(XrPen *pen, double radius, double tolerance)
|
|||
for (i=0; i < pen->num_vertices; i++) {
|
||||
v = &pen->vertex[i];
|
||||
v->theta = 2 * M_PI * i / (double) pen->num_vertices;
|
||||
v->pt.x = XDoubleToFixed(radius * cos(v->theta));
|
||||
v->pt.y = XDoubleToFixed(radius * sin(v->theta));
|
||||
pt.x = radius * cos(v->theta);
|
||||
pt.y = radius * sin(v->theta);
|
||||
XrTransformPointWithoutTranslate(&gstate->ctm, &pt);
|
||||
v->pt.x = XDoubleToFixed(pt.x);
|
||||
v->pt.y = XDoubleToFixed(pt.y);
|
||||
v->tag = XrPenVertexTagNone;
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +134,7 @@ _XrPenVertexCompareByTheta(const void *a, const void *b)
|
|||
XrError
|
||||
XrPenAddPoints(XrPen *pen, XrPenTaggedPoint *pt, int num_pts)
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
XrPenVertex *v, *new_vertex;
|
||||
XrPenVertex *vi, *pi;
|
||||
|
||||
|
|
@ -159,11 +167,21 @@ XrPenAddPoints(XrPen *pen, XrPenTaggedPoint *pt, int num_pts)
|
|||
/* merge new vertices into original */
|
||||
pi = pen->vertex + pen->num_vertices - num_pts - 1;
|
||||
vi = v + num_pts - 1;
|
||||
for (i = pen->num_vertices - 1; i >= 0; i--) {
|
||||
if (vi >= v && vi->theta > pi->theta)
|
||||
for (i = pen->num_vertices - 1; vi >= v; i--) {
|
||||
if (pi >= pen->vertex
|
||||
&& vi->pt.x == pi->pt.x && vi->pt.y == pi->pt.y) {
|
||||
/* Eliminate the duplicate vertex */
|
||||
for (j=i; j < pen->num_vertices - 1; j++)
|
||||
pen->vertex[j] = pen->vertex[j+1];
|
||||
pen->vertex[--i] = *vi;
|
||||
pen->num_vertices--;
|
||||
pi--;
|
||||
vi--;
|
||||
} else if (pi < pen->vertex || vi->theta >= pi->theta) {
|
||||
pen->vertex[i] = *vi--;
|
||||
else
|
||||
} else {
|
||||
pen->vertex[i] = *pi--;
|
||||
}
|
||||
}
|
||||
|
||||
free(v);
|
||||
|
|
|
|||
|
|
@ -338,6 +338,14 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
|
|||
XrError err;
|
||||
XrStroker *stroker = closure;
|
||||
XrStrokeFace start, end;
|
||||
|
||||
if (p1->x == p2->x && p1->y == p2->y) {
|
||||
/* XXX: Need to rethink how this case should be handled, (both
|
||||
here and in XrStrokerAddSubEdge and in _ComputeFace). The
|
||||
key behavior is that degenerate paths should draw as much
|
||||
as possible. */
|
||||
return XrErrorSuccess;
|
||||
}
|
||||
|
||||
err = XrStrokerAddSubEdge (stroker, p1, p2, &start, &end);
|
||||
if (err)
|
||||
|
|
@ -478,7 +486,7 @@ XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *
|
|||
XrSpline spline;
|
||||
XrPolygon polygon;
|
||||
XrPen pen;
|
||||
XrStrokeFace face1, face2;
|
||||
XrStrokeFace start, end;
|
||||
XrPenTaggedPoint extra_points[4];
|
||||
|
||||
XrSplineInit(&spline, a, b, c, d);
|
||||
|
|
@ -492,30 +500,35 @@ XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *
|
|||
if (err)
|
||||
goto CLEANUP_POLYGON;
|
||||
|
||||
_ComputeInitialFace(a, b, gstate, &face1);
|
||||
_ComputeFinalFace(c, d, gstate, &face2);
|
||||
_ComputeInitialFace(a, b, gstate, &start);
|
||||
_ComputeFinalFace(c, d, gstate, &end);
|
||||
|
||||
if (stroker->have_prev) {
|
||||
err = _XrStrokerJoin(stroker, &stroker->prev, &face1);
|
||||
err = _XrStrokerJoin (stroker, &stroker->prev, &start);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
stroker->have_prev = 1;
|
||||
stroker->first = face1;
|
||||
if (stroker->is_first) {
|
||||
stroker->have_first = 1;
|
||||
stroker->first = start;
|
||||
}
|
||||
}
|
||||
stroker->prev = end;
|
||||
stroker->is_first = 0;
|
||||
|
||||
extra_points[0].pt = face1.cw;
|
||||
extra_points[0].pt.x -= face1.pt.x;
|
||||
extra_points[0].pt.y -= face1.pt.y;
|
||||
extra_points[1].pt = face1.ccw; extra_points[1].tag = XrPenVertexTagNone;
|
||||
extra_points[1].pt.x -= face1.pt.x;
|
||||
extra_points[1].pt.y -= face1.pt.y;
|
||||
extra_points[2].pt = face2.cw; extra_points[2].tag = XrPenVertexTagNone;
|
||||
extra_points[2].pt.x -= face2.pt.x;
|
||||
extra_points[2].pt.y -= face2.pt.y;
|
||||
extra_points[3].pt = face2.ccw; extra_points[3].tag = XrPenVertexTagReverse;
|
||||
extra_points[3].pt.x -= face2.pt.x;
|
||||
extra_points[3].pt.y -= face2.pt.y;
|
||||
extra_points[0].pt = start.cw; extra_points[0].tag = XrPenVertexTagForward;
|
||||
extra_points[0].pt.x -= start.pt.x;
|
||||
extra_points[0].pt.y -= start.pt.y;
|
||||
extra_points[1].pt = start.ccw; extra_points[1].tag = XrPenVertexTagNone;
|
||||
extra_points[1].pt.x -= start.pt.x;
|
||||
extra_points[1].pt.y -= start.pt.y;
|
||||
extra_points[2].pt = end.cw; extra_points[2].tag = XrPenVertexTagNone;
|
||||
extra_points[2].pt.x -= end.pt.x;
|
||||
extra_points[2].pt.y -= end.pt.y;
|
||||
extra_points[3].pt = end.ccw; extra_points[3].tag = XrPenVertexTagReverse;
|
||||
extra_points[3].pt.x -= end.pt.x;
|
||||
extra_points[3].pt.y -= end.pt.y;
|
||||
|
||||
err = XrPenAddPoints(&pen, extra_points, 4);
|
||||
if (err)
|
||||
|
|
|
|||
|
|
@ -114,6 +114,9 @@ XrGStateDeinit(XrGState *gstate)
|
|||
XrTransformDeinit(&gstate->ctm_inverse);
|
||||
|
||||
XrPathDeinit(&gstate->path);
|
||||
|
||||
XrPenDeinit(&gstate->pen_regular);
|
||||
|
||||
if (gstate->dashes)
|
||||
free (gstate->dashes);
|
||||
}
|
||||
|
|
@ -354,7 +357,7 @@ XrGStateStroke(XrGState *gstate)
|
|||
XrStroker stroker;
|
||||
XrTraps traps;
|
||||
|
||||
XrPenInit(&gstate->pen_regular, gstate->line_width / 2.0, gstate->tolerance);
|
||||
XrPenInit(&gstate->pen_regular, gstate->line_width / 2.0, gstate);
|
||||
|
||||
XrTrapsInit(&traps);
|
||||
XrStrokerInit(&stroker, gstate, &traps);
|
||||
|
|
|
|||
2
xrint.h
2
xrint.h
|
|
@ -434,7 +434,7 @@ XrSurfaceSetFormat(XrSurface *surface, XrFormat format);
|
|||
|
||||
/* xrpen.c */
|
||||
XrError
|
||||
XrPenInit(XrPen *pen, double radius, double tolerance);
|
||||
XrPenInit(XrPen *pen, double radius, XrGState *gstate);
|
||||
|
||||
XrError
|
||||
XrPenInitEmpty(XrPen *pen);
|
||||
|
|
|
|||
36
xrpen.c
36
xrpen.c
|
|
@ -58,21 +58,26 @@ XrPenInitEmpty(XrPen *pen)
|
|||
}
|
||||
|
||||
XrError
|
||||
XrPenInit(XrPen *pen, double radius, double tolerance)
|
||||
XrPenInit(XrPen *pen, double radius, XrGState *gstate)
|
||||
{
|
||||
int i;
|
||||
XrPenVertex *v;
|
||||
XPointDouble pt;
|
||||
|
||||
if (pen->num_vertices) {
|
||||
/* XXX: It would be nice to notice that the pen is already properly constructed.
|
||||
However, this test would also have to account for possible changes in the transformation
|
||||
matrix.
|
||||
if (pen->radius == radius && pen->tolerance == tolerance)
|
||||
return XrErrorSuccess;
|
||||
*/
|
||||
XrPenDeinit(pen);
|
||||
}
|
||||
|
||||
pen->radius = radius;
|
||||
pen->tolerance = tolerance;
|
||||
pen->tolerance = gstate->tolerance;
|
||||
|
||||
pen->num_vertices = _XrPenVerticesNeeded(radius, tolerance);
|
||||
pen->num_vertices = _XrPenVerticesNeeded(radius, gstate->tolerance);
|
||||
|
||||
pen->vertex = malloc(pen->num_vertices * sizeof(XrPenVertex));
|
||||
if (pen->vertex == NULL) {
|
||||
|
|
@ -82,8 +87,11 @@ XrPenInit(XrPen *pen, double radius, double tolerance)
|
|||
for (i=0; i < pen->num_vertices; i++) {
|
||||
v = &pen->vertex[i];
|
||||
v->theta = 2 * M_PI * i / (double) pen->num_vertices;
|
||||
v->pt.x = XDoubleToFixed(radius * cos(v->theta));
|
||||
v->pt.y = XDoubleToFixed(radius * sin(v->theta));
|
||||
pt.x = radius * cos(v->theta);
|
||||
pt.y = radius * sin(v->theta);
|
||||
XrTransformPointWithoutTranslate(&gstate->ctm, &pt);
|
||||
v->pt.x = XDoubleToFixed(pt.x);
|
||||
v->pt.y = XDoubleToFixed(pt.y);
|
||||
v->tag = XrPenVertexTagNone;
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +134,7 @@ _XrPenVertexCompareByTheta(const void *a, const void *b)
|
|||
XrError
|
||||
XrPenAddPoints(XrPen *pen, XrPenTaggedPoint *pt, int num_pts)
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
XrPenVertex *v, *new_vertex;
|
||||
XrPenVertex *vi, *pi;
|
||||
|
||||
|
|
@ -159,11 +167,21 @@ XrPenAddPoints(XrPen *pen, XrPenTaggedPoint *pt, int num_pts)
|
|||
/* merge new vertices into original */
|
||||
pi = pen->vertex + pen->num_vertices - num_pts - 1;
|
||||
vi = v + num_pts - 1;
|
||||
for (i = pen->num_vertices - 1; i >= 0; i--) {
|
||||
if (vi >= v && vi->theta > pi->theta)
|
||||
for (i = pen->num_vertices - 1; vi >= v; i--) {
|
||||
if (pi >= pen->vertex
|
||||
&& vi->pt.x == pi->pt.x && vi->pt.y == pi->pt.y) {
|
||||
/* Eliminate the duplicate vertex */
|
||||
for (j=i; j < pen->num_vertices - 1; j++)
|
||||
pen->vertex[j] = pen->vertex[j+1];
|
||||
pen->vertex[--i] = *vi;
|
||||
pen->num_vertices--;
|
||||
pi--;
|
||||
vi--;
|
||||
} else if (pi < pen->vertex || vi->theta >= pi->theta) {
|
||||
pen->vertex[i] = *vi--;
|
||||
else
|
||||
} else {
|
||||
pen->vertex[i] = *pi--;
|
||||
}
|
||||
}
|
||||
|
||||
free(v);
|
||||
|
|
|
|||
47
xrstroker.c
47
xrstroker.c
|
|
@ -338,6 +338,14 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
|
|||
XrError err;
|
||||
XrStroker *stroker = closure;
|
||||
XrStrokeFace start, end;
|
||||
|
||||
if (p1->x == p2->x && p1->y == p2->y) {
|
||||
/* XXX: Need to rethink how this case should be handled, (both
|
||||
here and in XrStrokerAddSubEdge and in _ComputeFace). The
|
||||
key behavior is that degenerate paths should draw as much
|
||||
as possible. */
|
||||
return XrErrorSuccess;
|
||||
}
|
||||
|
||||
err = XrStrokerAddSubEdge (stroker, p1, p2, &start, &end);
|
||||
if (err)
|
||||
|
|
@ -478,7 +486,7 @@ XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *
|
|||
XrSpline spline;
|
||||
XrPolygon polygon;
|
||||
XrPen pen;
|
||||
XrStrokeFace face1, face2;
|
||||
XrStrokeFace start, end;
|
||||
XrPenTaggedPoint extra_points[4];
|
||||
|
||||
XrSplineInit(&spline, a, b, c, d);
|
||||
|
|
@ -492,30 +500,35 @@ XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *
|
|||
if (err)
|
||||
goto CLEANUP_POLYGON;
|
||||
|
||||
_ComputeInitialFace(a, b, gstate, &face1);
|
||||
_ComputeFinalFace(c, d, gstate, &face2);
|
||||
_ComputeInitialFace(a, b, gstate, &start);
|
||||
_ComputeFinalFace(c, d, gstate, &end);
|
||||
|
||||
if (stroker->have_prev) {
|
||||
err = _XrStrokerJoin(stroker, &stroker->prev, &face1);
|
||||
err = _XrStrokerJoin (stroker, &stroker->prev, &start);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
stroker->have_prev = 1;
|
||||
stroker->first = face1;
|
||||
if (stroker->is_first) {
|
||||
stroker->have_first = 1;
|
||||
stroker->first = start;
|
||||
}
|
||||
}
|
||||
stroker->prev = end;
|
||||
stroker->is_first = 0;
|
||||
|
||||
extra_points[0].pt = face1.cw;
|
||||
extra_points[0].pt.x -= face1.pt.x;
|
||||
extra_points[0].pt.y -= face1.pt.y;
|
||||
extra_points[1].pt = face1.ccw; extra_points[1].tag = XrPenVertexTagNone;
|
||||
extra_points[1].pt.x -= face1.pt.x;
|
||||
extra_points[1].pt.y -= face1.pt.y;
|
||||
extra_points[2].pt = face2.cw; extra_points[2].tag = XrPenVertexTagNone;
|
||||
extra_points[2].pt.x -= face2.pt.x;
|
||||
extra_points[2].pt.y -= face2.pt.y;
|
||||
extra_points[3].pt = face2.ccw; extra_points[3].tag = XrPenVertexTagReverse;
|
||||
extra_points[3].pt.x -= face2.pt.x;
|
||||
extra_points[3].pt.y -= face2.pt.y;
|
||||
extra_points[0].pt = start.cw; extra_points[0].tag = XrPenVertexTagForward;
|
||||
extra_points[0].pt.x -= start.pt.x;
|
||||
extra_points[0].pt.y -= start.pt.y;
|
||||
extra_points[1].pt = start.ccw; extra_points[1].tag = XrPenVertexTagNone;
|
||||
extra_points[1].pt.x -= start.pt.x;
|
||||
extra_points[1].pt.y -= start.pt.y;
|
||||
extra_points[2].pt = end.cw; extra_points[2].tag = XrPenVertexTagNone;
|
||||
extra_points[2].pt.x -= end.pt.x;
|
||||
extra_points[2].pt.y -= end.pt.y;
|
||||
extra_points[3].pt = end.ccw; extra_points[3].tag = XrPenVertexTagReverse;
|
||||
extra_points[3].pt.x -= end.pt.x;
|
||||
extra_points[3].pt.y -= end.pt.y;
|
||||
|
||||
err = XrPenAddPoints(&pen, extra_points, 4);
|
||||
if (err)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue