1
//========================================================================
5
//========================================================================
7
//========================================================================
9
// Modified under the Poppler project - http://poppler.freedesktop.org
11
// All changes made under the Poppler project to this file are licensed
12
// under GPL version 2 or later
14
// Copyright (C) 2010 PaweÅ Wiejacha <pawel.wiejacha@gmail.com>
15
// Copyright (C) 2010 Albert Astals Cid <aacid@kde.org>
17
// To see a description of the changes please see the Changelog file that
18
// came with your tarball or type make ChangeLog if you are building from git
20
//========================================================================
24
#ifdef USE_GCC_PRAGMAS
25
#pragma implementation
32
#include "SplashMath.h"
33
#include "SplashPath.h"
34
#include "SplashXPath.h"
36
//------------------------------------------------------------------------
38
struct SplashXPathPoint {
42
struct SplashXPathAdjust {
43
int firstPt, lastPt; // range of points
44
GBool vert; // vertical or horizontal hint
45
SplashCoord x0a, x0b, // hint boundaries
48
SplashCoord x0, x1, xm; // adjusted coordinates
51
//------------------------------------------------------------------------
53
// Transform a point from user space to device space.
54
inline void SplashXPath::transform(SplashCoord *matrix,
55
SplashCoord xi, SplashCoord yi,
56
SplashCoord *xo, SplashCoord *yo) {
58
// [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ]
60
*xo = xi * matrix[0] + yi * matrix[2] + matrix[4];
61
*yo = xi * matrix[1] + yi * matrix[3] + matrix[5];
64
//------------------------------------------------------------------------
66
//------------------------------------------------------------------------
68
SplashXPath::SplashXPath() {
73
SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
74
SplashCoord flatness, GBool closeSubpaths) {
76
SplashXPathPoint *pts;
77
SplashXPathAdjust *adjusts, *adjust;
78
SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp;
79
SplashCoord adj0, adj1, w;
81
int curSubpath, curSubpathX, i, j;
83
// transform the points
84
pts = (SplashXPathPoint *)gmallocn(path->length, sizeof(SplashXPathPoint));
85
for (i = 0; i < path->length; ++i) {
86
transform(matrix, path->pts[i].x, path->pts[i].y, &pts[i].x, &pts[i].y);
89
// set up the stroke adjustment hints
91
adjusts = (SplashXPathAdjust *)gmallocn(path->hintsLength,
92
sizeof(SplashXPathAdjust));
93
for (i = 0; i < path->hintsLength; ++i) {
94
hint = &path->hints[i];
95
if (hint->ctrl0 + 1 >= path->length || hint->ctrl1 + 1 >= path->length) {
100
x0 = pts[hint->ctrl0 ].x; y0 = pts[hint->ctrl0 ].y;
101
x1 = pts[hint->ctrl0 + 1].x; y1 = pts[hint->ctrl0 + 1].y;
102
x2 = pts[hint->ctrl1 ].x; y2 = pts[hint->ctrl1 ].y;
103
x3 = pts[hint->ctrl1 + 1].x; y3 = pts[hint->ctrl1 + 1].y;
104
if (x0 == x1 && x2 == x3) {
105
adjusts[i].vert = gTrue;
108
} else if (y0 == y1 && y2 == y3) {
109
adjusts[i].vert = gFalse;
127
adjusts[i].x0a = adj0 - 0.01;
128
adjusts[i].x0b = adj0 + 0.01;
129
adjusts[i].xma = (SplashCoord)0.5 * (adj0 + adj1) - 0.01;
130
adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + 0.01;
131
adjusts[i].x1a = adj1 - 0.01;
132
adjusts[i].x1b = adj1 + 0.01;
133
adjusts[i].x0 = (SplashCoord)splashRound(adj0);
134
adjusts[i].x1 = adjusts[i].x0 + ww - 0.01;
135
adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1);
136
adjusts[i].firstPt = hint->firstPt;
137
adjusts[i].lastPt = hint->lastPt;
144
// perform stroke adjustment
146
for (i = 0, adjust = adjusts; i < path->hintsLength; ++i, ++adjust) {
147
for (j = adjust->firstPt; j <= adjust->lastPt; ++j) {
148
strokeAdjust(adjust, &pts[j].x, &pts[j].y);
157
x0 = y0 = xsp = ysp = 0; // make gcc happy
158
adj0 = adj1 = 0; // make gcc happy
162
while (i < path->length) {
164
// first point in subpath - skip it
165
if (path->flags[i] & splashPathFirst) {
171
curSubpathX = length;
177
if (path->flags[i] & splashPathCurve) {
184
addCurve(x0, y0, x1, y1, x2, y2, x3, y3,
186
(path->flags[i-1] & splashPathFirst),
187
(path->flags[i+2] & splashPathLast),
189
(path->flags[i-1] & splashPathFirst) &&
190
!(path->flags[i-1] & splashPathClosed),
192
(path->flags[i+2] & splashPathLast) &&
193
!(path->flags[i+2] & splashPathClosed));
202
addSegment(x0, y0, x1, y1,
203
path->flags[i-1] & splashPathFirst,
204
path->flags[i] & splashPathLast,
206
(path->flags[i-1] & splashPathFirst) &&
207
!(path->flags[i-1] & splashPathClosed),
209
(path->flags[i] & splashPathLast) &&
210
!(path->flags[i] & splashPathClosed));
218
(path->flags[i-1] & splashPathLast) &&
219
(pts[i-1].x != pts[curSubpath].x ||
220
pts[i-1].y != pts[curSubpath].y)) {
221
addSegment(x0, y0, xsp, ysp,
222
gFalse, gTrue, gFalse, gFalse);
230
// Apply the stroke adjust hints to point <pt>: (*<xp>, *<yp>).
231
void SplashXPath::strokeAdjust(SplashXPathAdjust *adjust,
232
SplashCoord *xp, SplashCoord *yp) {
237
if (x > adjust->x0a && x < adjust->x0b) {
239
} else if (x > adjust->xma && x < adjust->xmb) {
241
} else if (x > adjust->x1a && x < adjust->x1b) {
246
if (y > adjust->x0a && y < adjust->x0b) {
248
} else if (y > adjust->xma && y < adjust->xmb) {
250
} else if (y > adjust->x1a && y < adjust->x1b) {
256
SplashXPath::SplashXPath(SplashXPath *xPath) {
257
length = xPath->length;
259
segs = (SplashXPathSeg *)gmallocn(size, sizeof(SplashXPathSeg));
260
memcpy(segs, xPath->segs, length * sizeof(SplashXPathSeg));
263
SplashXPath::~SplashXPath() {
267
// Add space for <nSegs> more segments
268
void SplashXPath::grow(int nSegs) {
269
if (length + nSegs > size) {
273
while (size < length + nSegs) {
276
segs = (SplashXPathSeg *)greallocn(segs, size, sizeof(SplashXPathSeg));
280
void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0,
281
SplashCoord x1, SplashCoord y1,
282
SplashCoord x2, SplashCoord y2,
283
SplashCoord x3, SplashCoord y3,
284
SplashCoord flatness,
285
GBool first, GBool last, GBool end0, GBool end1) {
286
SplashCoord cx[splashMaxCurveSplits + 1][3];
287
SplashCoord cy[splashMaxCurveSplits + 1][3];
288
int cNext[splashMaxCurveSplits + 1];
289
SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
290
SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
291
SplashCoord dx, dy, mx, my, d1, d2, flatness2;
294
flatness2 = flatness * flatness;
298
p2 = splashMaxCurveSplits;
299
cx[p1][0] = x0; cy[p1][0] = y0;
300
cx[p1][1] = x1; cy[p1][1] = y1;
301
cx[p1][2] = x2; cy[p1][2] = y2;
302
cx[p2][0] = x3; cy[p2][0] = y3;
305
while (p1 < splashMaxCurveSplits) {
307
// get the next segment
308
xl0 = cx[p1][0]; yl0 = cy[p1][0];
309
xx1 = cx[p1][1]; yy1 = cy[p1][1];
310
xx2 = cx[p1][2]; yy2 = cy[p1][2];
312
xr3 = cx[p2][0]; yr3 = cy[p2][0];
314
// compute the distances from the control points to the
315
// midpoint of the straight line (this is a bit of a hack, but
316
// it's much faster than computing the actual distances to the
318
mx = (xl0 + xr3) * 0.5;
319
my = (yl0 + yr3) * 0.5;
327
// if the curve is flat enough, or no more subdivisions are
328
// allowed, add the straight line segment
329
if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) {
330
addSegment(xl0, yl0, xr3, yr3,
332
p2 == splashMaxCurveSplits && last,
334
p2 == splashMaxCurveSplits && end1);
337
// otherwise, subdivide the curve
339
xl1 = (xl0 + xx1) * 0.5;
340
yl1 = (yl0 + yy1) * 0.5;
341
xh = (xx1 + xx2) * 0.5;
342
yh = (yy1 + yy2) * 0.5;
343
xl2 = (xl1 + xh) * 0.5;
344
yl2 = (yl1 + yh) * 0.5;
345
xr2 = (xx2 + xr3) * 0.5;
346
yr2 = (yy2 + yr3) * 0.5;
347
xr1 = (xh + xr2) * 0.5;
348
yr1 = (yh + yr2) * 0.5;
349
xr0 = (xl2 + xr1) * 0.5;
350
yr0 = (yl2 + yr1) * 0.5;
351
// add the new subdivision points
353
cx[p1][1] = xl1; cy[p1][1] = yl1;
354
cx[p1][2] = xl2; cy[p1][2] = yl2;
356
cx[p3][0] = xr0; cy[p3][0] = yr0;
357
cx[p3][1] = xr1; cy[p3][1] = yr1;
358
cx[p3][2] = xr2; cy[p3][2] = yr2;
364
void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0,
365
SplashCoord x1, SplashCoord y1,
366
GBool first, GBool last, GBool end0, GBool end1) {
368
segs[length].x0 = x0;
369
segs[length].y0 = y0;
370
segs[length].x1 = x1;
371
segs[length].y1 = y1;
372
segs[length].flags = 0;
374
segs[length].flags |= splashXPathFirst;
377
segs[length].flags |= splashXPathLast;
380
segs[length].flags |= splashXPathEnd0;
383
segs[length].flags |= splashXPathEnd1;
386
segs[length].dxdy = segs[length].dydx = 0;
387
segs[length].flags |= splashXPathHoriz;
389
segs[length].flags |= splashXPathVert;
391
} else if (x1 == x0) {
392
segs[length].dxdy = segs[length].dydx = 0;
393
segs[length].flags |= splashXPathVert;
396
if (FixedPoint::divCheck(x1 - x0, y1 - y0, &segs[length].dxdy)) {
397
segs[length].dydx = (SplashCoord)1 / segs[length].dxdy;
399
segs[length].dxdy = segs[length].dydx = 0;
400
if (splashAbs(x1 - x0) > splashAbs(y1 - y0)) {
401
segs[length].flags |= splashXPathHoriz;
403
segs[length].flags |= splashXPathVert;
407
segs[length].dxdy = (x1 - x0) / (y1 - y0);
408
segs[length].dydx = (SplashCoord)1 / segs[length].dxdy;
412
segs[length].flags |= splashXPathFlip;
417
static bool cmpXPathSegs(const SplashXPathSeg &seg0, const SplashXPathSeg &seg1) {
418
SplashCoord x0, y0, x1, y1;
420
if (seg0.flags & splashXPathFlip) {
427
if (seg1.flags & splashXPathFlip) {
435
return (y0 < y1) ? true : false;
438
return (x0 < x1) ? true : false;
443
void SplashXPath::aaScale() {
447
for (i = 0, seg = segs; i < length; ++i, ++seg) {
448
seg->x0 *= splashAASize;
449
seg->y0 *= splashAASize;
450
seg->x1 *= splashAASize;
451
seg->y1 *= splashAASize;
455
void SplashXPath::sort() {
456
std::sort(segs, segs + length, &cmpXPathSegs);