20
20
//------------------------------------------------------------------------
22
#define maxCurveSplits (1 << 10)
22
struct SplashXPathPoint {
26
struct SplashXPathAdjust {
27
int firstPt, lastPt; // range of points
28
GBool vert; // vertical or horizontal hint
29
SplashCoord x0a, x0b, // hint boundaries
32
SplashCoord x0, x1, xm; // adjusted coordinates
35
//------------------------------------------------------------------------
37
// Transform a point from user space to device space.
38
inline void SplashXPath::transform(SplashCoord *matrix,
39
SplashCoord xi, SplashCoord yi,
40
SplashCoord *xo, SplashCoord *yo) {
42
// [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ]
44
*xo = xi * matrix[0] + yi * matrix[2] + matrix[4];
45
*yo = xi * matrix[1] + yi * matrix[3] + matrix[5];
24
48
//------------------------------------------------------------------------
33
SplashXPath::SplashXPath(SplashPath *path, SplashCoord flatness,
34
GBool closeSubpaths) {
35
SplashCoord xc, yc, dx, dy, r, x0, y0, x1, y1;
36
int quad0, quad1, quad;
37
int curSubpath, n, i, j;
57
SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
58
SplashCoord flatness, GBool closeSubpaths) {
60
SplashXPathPoint *pts;
61
SplashXPathAdjust *adjusts, *adjust;
62
SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp;
63
SplashCoord adj0, adj1, w;
65
int curSubpath, curSubpathX, i, j;
67
// transform the points
68
pts = (SplashXPathPoint *)gmallocn(path->length, sizeof(SplashXPathPoint));
69
for (i = 0; i < path->length; ++i) {
70
transform(matrix, path->pts[i].x, path->pts[i].y, &pts[i].x, &pts[i].y);
73
// set up the stroke adjustment hints
75
adjusts = (SplashXPathAdjust *)gmallocn(path->hintsLength,
76
sizeof(SplashXPathAdjust));
77
for (i = 0; i < path->hintsLength; ++i) {
78
hint = &path->hints[i];
79
x0 = pts[hint->ctrl0 ].x; y0 = pts[hint->ctrl0 ].y;
80
x1 = pts[hint->ctrl0 + 1].x; y1 = pts[hint->ctrl0 + 1].y;
81
x2 = pts[hint->ctrl1 ].x; y2 = pts[hint->ctrl1 ].y;
82
x3 = pts[hint->ctrl1 + 1].x; y3 = pts[hint->ctrl1 + 1].y;
83
if (x0 == x1 && x2 == x3) {
84
adjusts[i].vert = gTrue;
87
} else if (y0 == y1 && y2 == y3) {
88
adjusts[i].vert = gFalse;
106
adjusts[i].x0a = adj0 - 0.01;
107
adjusts[i].x0b = adj0 + 0.01;
108
adjusts[i].xma = (SplashCoord)0.5 * (adj0 + adj1) - 0.01;
109
adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + 0.01;
110
adjusts[i].x1a = adj1 - 0.01;
111
adjusts[i].x1b = adj1 + 0.01;
112
adjusts[i].x0 = (SplashCoord)splashRound(adj0);
113
adjusts[i].x1 = adjusts[i].x0 + ww - 0.01;
114
adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1);
115
adjusts[i].firstPt = hint->firstPt;
116
adjusts[i].lastPt = hint->lastPt;
123
// perform stroke adjustment
125
for (i = 0, adjust = adjusts; i < path->hintsLength; ++i, ++adjust) {
126
for (j = adjust->firstPt; j <= adjust->lastPt; ++j) {
127
strokeAdjust(adjust, &pts[j].x, &pts[j].y);
40
134
length = size = 0;
136
x0 = y0 = xsp = ysp = 0; // make gcc happy
137
adj0 = adj1 = 0; // make gcc happy
44
141
while (i < path->length) {
46
143
// first point in subpath - skip it
47
144
if (path->flags[i] & splashPathFirst) {
150
curSubpathX = length;
54
156
if (path->flags[i] & splashPathCurve) {
55
addCurve(path->pts[i-1].x, path->pts[i-1].y,
56
path->pts[i ].x, path->pts[i ].y,
57
path->pts[i+1].x, path->pts[i+1].y,
58
path->pts[i+2].x, path->pts[i+2].y,
163
addCurve(x0, y0, x1, y1, x2, y2, x3, y3,
60
165
(path->flags[i-1] & splashPathFirst),
61
166
(path->flags[i+2] & splashPathLast),
66
171
(path->flags[i+2] & splashPathLast) &&
67
172
!(path->flags[i+2] & splashPathClosed));
70
// clockwise circular arc
71
} else if (path->flags[i] & splashPathArcCW) {
74
dx = path->pts[i+1].x - xc;
75
dy = path->pts[i+1].y - yc;
76
r = splashSqrt(dx * dx + dy * dy);
77
if (path->pts[i-1].x < xc && path->pts[i-1].y <= yc) {
79
} else if (path->pts[i-1].x >= xc && path->pts[i-1].y < yc) {
81
} else if (path->pts[i-1].x > xc && path->pts[i-1].y >= yc) {
86
if (path->pts[i+1].x <= xc && path->pts[i+1].y < yc) {
88
} else if (path->pts[i+1].x > xc && path->pts[i+1].y <= yc) {
90
} else if (path->pts[i+1].x >= xc && path->pts[i+1].y > yc) {
95
n = 0; // make gcc happy
99
case 1: n = path->pts[i-1].x < path->pts[i+1].x ? 0 : 4; break;
101
case 3: n = path->pts[i-1].x > path->pts[i+1].x ? 0 : 4; break;
104
n = (quad1 - quad0) & 3;
106
x0 = path->pts[i-1].x;
107
y0 = path->pts[i-1].y;
108
x1 = y1 = 0; // make gcc happy
110
for (j = 0; j < n; ++j) {
112
case 0: x1 = xc; y1 = yc - r; break;
113
case 1: x1 = xc + r; y1 = yc; break;
114
case 2: x1 = xc; y1 = yc + r; break;
115
case 3: x1 = xc - r; y1 = yc; break;
117
addArc(x0, y0, x1, y1,
118
xc, yc, r, quad, flatness,
119
quad == quad0 && (path->flags[i-1] & splashPathFirst),
121
quad == quad0 && !closeSubpaths &&
122
(path->flags[i-1] & splashPathFirst) &&
123
!(path->flags[i-1] & splashPathClosed),
127
quad = (quad + 1) & 3;
129
addArc(x0, y0, path->pts[i+1].x, path->pts[i+1].y,
130
xc, yc, r, quad, flatness,
131
quad == quad0 && (path->flags[i-1] & splashPathFirst),
132
(path->flags[i+1] & splashPathLast),
133
quad == quad0 && !closeSubpaths &&
134
(path->flags[i-1] & splashPathFirst) &&
135
!(path->flags[i-1] & splashPathClosed),
137
(path->flags[i+1] & splashPathLast) &&
138
!(path->flags[i+1] & splashPathClosed));
143
addSegment(path->pts[i-1].x, path->pts[i-1].y,
144
path->pts[i].x, path->pts[i].y,
181
addSegment(x0, y0, x1, y1,
145
182
path->flags[i-1] & splashPathFirst,
146
183
path->flags[i] & splashPathLast,
147
184
!closeSubpaths &&
150
187
!closeSubpaths &&
151
188
(path->flags[i] & splashPathLast) &&
152
189
!(path->flags[i] & splashPathClosed));
156
195
// close a subpath
157
196
if (closeSubpaths &&
158
197
(path->flags[i-1] & splashPathLast) &&
159
(path->pts[i-1].x != path->pts[curSubpath].x ||
160
path->pts[i-1].y != path->pts[curSubpath]. y)) {
161
addSegment(path->pts[i-1].x, path->pts[i-1].y,
162
path->pts[curSubpath].x, path->pts[curSubpath].y,
198
(pts[i-1].x != pts[curSubpath].x ||
199
pts[i-1].y != pts[curSubpath].y)) {
200
addSegment(x0, y0, xsp, ysp,
163
201
gFalse, gTrue, gFalse, gFalse);
209
// Apply the stroke adjust hints to point <pt>: (*<xp>, *<yp>).
210
void SplashXPath::strokeAdjust(SplashXPathAdjust *adjust,
211
SplashCoord *xp, SplashCoord *yp) {
216
if (x > adjust->x0a && x < adjust->x0b) {
218
} else if (x > adjust->xma && x < adjust->xmb) {
220
} else if (x > adjust->x1a && x < adjust->x1b) {
225
if (y > adjust->x0a && y < adjust->x0b) {
227
} else if (y > adjust->xma && y < adjust->xmb) {
229
} else if (y > adjust->x1a && y < adjust->x1b) {
169
235
SplashXPath::SplashXPath(SplashXPath *xPath) {
196
262
SplashCoord x3, SplashCoord y3,
197
263
SplashCoord flatness,
198
264
GBool first, GBool last, GBool end0, GBool end1) {
199
SplashCoord cx[maxCurveSplits + 1][3];
200
SplashCoord cy[maxCurveSplits + 1][3];
201
int cNext[maxCurveSplits + 1];
265
SplashCoord cx[splashMaxCurveSplits + 1][3];
266
SplashCoord cy[splashMaxCurveSplits + 1][3];
267
int cNext[splashMaxCurveSplits + 1];
202
268
SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
203
269
SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
204
270
SplashCoord dx, dy, mx, my, d1, d2, flatness2;
277
void SplashXPath::addArc(SplashCoord x0, SplashCoord y0,
278
SplashCoord x1, SplashCoord y1,
279
SplashCoord xc, SplashCoord yc,
280
SplashCoord r, int quad,
281
SplashCoord flatness,
282
GBool first, GBool last, GBool end0, GBool end1) {
283
SplashCoord px[maxCurveSplits + 1];
284
SplashCoord py[maxCurveSplits + 1];
285
int pNext[maxCurveSplits + 1];
286
SplashCoord r2, flatness2;
287
SplashCoord xx0, yy0, xx1, yy1, xm, ym, t, dx, dy;
291
flatness2 = flatness * flatness;
296
px[p1] = x0; py[p1] = y0;
297
px[p2] = x1; py[p2] = y1;
300
while (p1 < maxCurveSplits) {
302
// get the next segment
303
xx0 = px[p1]; yy0 = py[p1];
305
xx1 = px[p2]; yy1 = py[p2];
307
// compute the arc midpoint
308
t = (xx0 - xc) * (xx1 - xc) - (yy0 - yc) * (yy1 - yc);
309
xm = splashSqrt((SplashCoord)0.5 * (r2 + t));
310
ym = splashSqrt((SplashCoord)0.5 * (r2 - t));
312
case 0: xm = xc - xm; ym = yc - ym; break;
313
case 1: xm = xc + xm; ym = yc - ym; break;
314
case 2: xm = xc + xm; ym = yc + ym; break;
315
case 3: xm = xc - xm; ym = yc + ym; break;
318
// compute distance from midpoint of straight segment to midpoint
320
dx = (SplashCoord)0.5 * (xx0 + xx1) - xm;
321
dy = (SplashCoord)0.5 * (yy0 + yy1) - ym;
323
// if the arc is flat enough, or no more subdivisions are allowed,
324
// add the straight line segment
325
if (p2 - p1 == 1 || dx * dx + dy * dy <= flatness2) {
326
addSegment(xx0, yy0, xx1, yy1,
328
p2 == maxCurveSplits && last,
330
p2 == maxCurveSplits && end1);
333
// otherwise, subdivide the arc
344
343
void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0,
345
344
SplashCoord x1, SplashCoord y1,
346
345
GBool first, GBool last, GBool end0, GBool end1) {
372
371
segs[length].dxdy = segs[length].dydx = 0;
373
372
segs[length].flags |= splashXPathVert;
375
if (FixedPoint::divCheck(x1 - x0, y1 - y0, &segs[length].dxdy)) {
376
segs[length].dydx = (SplashCoord)1 / segs[length].dxdy;
378
segs[length].dxdy = segs[length].dydx = 0;
379
if (splashAbs(x1 - x0) > splashAbs(y1 - y0)) {
380
segs[length].flags |= splashXPathHoriz;
382
segs[length].flags |= splashXPathVert;
375
386
segs[length].dxdy = (x1 - x0) / (y1 - y0);
376
387
segs[length].dydx = (SplashCoord)1 / segs[length].dxdy;
379
391
segs[length].flags |= splashXPathFlip;