3
#include "splash/Splash.h"
4
#include "splash/SplashMath.h"
5
#include "OPVPSplashClip.h"
6
#include "OPVPSplashXPath.h"
7
#include "OPVPWrapper.h"
8
#include "OPVPSplash.h"
10
#if POPPLER_VERSION_MAJOR <= 0 && POPPLER_VERSION_MINOR < 19
11
OPVPSplashXPath *OPVPSplashXPath::makeDashedPath(OPVPSplashState *state)
13
OPVPSplashXPath *dPath;
14
GBool lineDashStartOn, lineDashOn;
15
GBool atSegStart, atSegEnd, atDashStart, atDashEnd;
16
int lineDashStartIdx, lineDashIdx, subpathStart;
17
SplashCoord lineDashTotal, lineDashStartPhase, lineDashDist;
20
SplashCoord sx0, sy0, sx1, sy1, ax0, ay0, ax1, ay1, dist;
23
dPath = new OPVPSplashXPath();
26
for (i = 0; i < state->lineDashLength; ++i) {
27
lineDashTotal += state->lineDash[i];
29
lineDashStartPhase = state->lineDashPhase;
30
i = splashFloor(lineDashStartPhase / lineDashTotal);
31
lineDashStartPhase -= i * lineDashTotal;
32
lineDashStartOn = gTrue;
34
while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) {
35
lineDashStartOn = !lineDashStartOn;
36
lineDashStartPhase -= state->lineDash[lineDashStartIdx];
46
dist = splashDist(sx0, sy0, sx1, sy1);
47
lineDashOn = lineDashStartOn;
48
lineDashIdx = lineDashStartIdx;
49
lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
52
subpathStart = dPath->length;
54
while (segIdx < length) {
58
if (dist <= lineDashDist) {
64
atDashEnd = lineDashDist == 0 || (seg->flags & splashXPathLast);
66
ax1 = sx0 + (lineDashDist / dist) * (sx1 - sx0);
67
ay1 = sy0 + (lineDashDist / dist) * (sy1 - sy0);
77
dPath->addSegment(ax0, ay0, ax1, ay1,
78
atDashStart, atDashEnd,
79
atDashStart, atDashEnd);
80
// end of closed subpath
82
(seg->flags & splashXPathLast) &&
83
!(seg->flags & splashXPathEnd1)) {
84
dPath->segs[subpathStart].flags &= ~splashXPathEnd0;
85
dPath->segs[dPath->length - 1].flags &= ~splashXPathEnd1;
90
lineDashOn = !lineDashOn;
91
if (++lineDashIdx == state->lineDashLength) {
94
lineDashDist = state->lineDash[lineDashIdx];
100
if (++segIdx < length) {
106
dist = splashDist(sx0, sy0, sx1, sy1);
107
if (seg->flags & splashXPathFirst) {
108
lineDashOn = lineDashStartOn;
109
lineDashIdx = lineDashStartIdx;
110
lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
112
subpathStart = dPath->length;
124
void OPVPSplashXPath::strokeWide(OPVPSplash *splash, OPVPSplashState *state)
126
SplashXPathSeg *seg, *seg2;
127
OPVPSplashPath *widePath;
128
SplashCoord d, dx, dy, wdx, wdy, dxPrev, dyPrev, wdxPrev, wdyPrev;
129
SplashCoord dotprod, miter;
130
SplashCoord x0,y0,x1,y1,x2,y2,x3,y3;
133
dx = dy = wdx = wdy = 0; // make gcc happy
134
dxPrev = dyPrev = wdxPrev = wdyPrev = 0; // make gcc happy
136
for (i = 0, seg = segs; i < length; ++i, ++seg) {
138
// save the deltas for the previous segment; if this is the first
139
// segment on a subpath, compute the deltas for the last segment
140
// on the subpath (which may be used to draw a line join)
141
if (seg->flags & splashXPathFirst) {
142
for (j = i + 1, seg2 = &segs[j];
143
j < length; ++j, ++seg2) {
144
if (seg2->flags & splashXPathLast) {
145
d = splashDist(seg2->x0, seg2->y0, seg2->x1, seg2->y1);
147
//~ not clear what the behavior should be for joins with d==0
152
dxPrev = d * (seg2->x1 - seg2->x0);
153
dyPrev = d * (seg2->y1 - seg2->y0);
155
wdxPrev = 0.5 * state->lineWidth * dxPrev;
156
wdyPrev = 0.5 * state->lineWidth * dyPrev;
167
// compute deltas for this line segment
168
d = splashDist(seg->x0, seg->y0, seg->x1, seg->y1);
170
// we need to draw end caps on zero-length lines
171
//~ not clear what the behavior should be for splashLineCapButt with d==0
176
dx = d * (seg->x1 - seg->x0);
177
dy = d * (seg->y1 - seg->y0);
179
wdx = 0.5 * state->lineWidth * dx;
180
wdy = 0.5 * state->lineWidth * dy;
182
// initialize the path (which will be filled)
183
widePath = new OPVPSplashPath();
184
widePath->moveTo(seg->x0 - wdy, seg->y0 + wdx);
186
// draw the start cap
187
if (seg->flags & splashXPathEnd0) {
188
switch (state->lineCap) {
189
case splashLineCapButt:
190
widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
192
case splashLineCapRound:
197
splash->arcToCurve(x0, y0, x3, y3,
198
seg->x0, seg->y0, &x1,&y1,&x2,&y2);
199
widePath->curveTo(x2,y2,x1,y1,x3,y3);
204
splash->arcToCurve(x0,y0,x3,y3,
205
seg->x0, seg->y0, &x1,&y1,&x2,&y2);
206
widePath->curveTo(x2,y2,x1,y1,x3,y3);
208
case splashLineCapProjecting:
209
widePath->lineTo(seg->x0 - wdx - wdy, seg->y0 + wdx - wdy);
210
widePath->lineTo(seg->x0 - wdx + wdy, seg->y0 - wdx - wdy);
211
widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
215
widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
218
// draw the left side of the segment
219
widePath->lineTo(seg->x1 + wdy, seg->y1 - wdx);
222
if (seg->flags & splashXPathEnd1) {
223
switch (state->lineCap) {
224
case splashLineCapButt:
225
widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
227
case splashLineCapRound:
232
splash->arcToCurve(x0, y0, x3, y3,
233
seg->x1, seg->y1, &x1,&y1,&x2,&y2);
234
widePath->curveTo(x2,y2,x1,y1,x3,y3);
239
splash->arcToCurve(x0,y0,x3,y3,
240
seg->x1, seg->y1, &x1,&y1,&x2,&y2);
241
widePath->curveTo(x2,y2,x1,y1,x3,y3);
243
case splashLineCapProjecting:
244
widePath->lineTo(seg->x1 + wdx + wdy, seg->y1 - wdx + wdy);
245
widePath->lineTo(seg->x1 + wdx - wdy, seg->y1 + wdx + wdy);
246
widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
250
widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
253
// draw the right side of the segment
254
widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
257
splash->fill(widePath, gTrue);
260
// draw the line join
261
if (!(seg->flags & splashXPathEnd0)) {
263
switch (state->lineJoin) {
264
case splashLineJoinMiter:
265
dotprod = -(dx * dxPrev + dy * dyPrev);
267
widePath = new OPVPSplashPath();
268
widePath->moveTo(seg->x0, seg->y0);
269
miter = 2 / (1 - dotprod);
270
if (splashSqrt(miter) <= state->miterLimit) {
271
miter = splashSqrt(miter - 1);
272
if (dy * dxPrev > dx * dyPrev) {
273
widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev);
274
widePath->lineTo(seg->x0 + wdy - miter * wdx,
275
seg->y0 - wdx - miter * wdy);
276
widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
278
widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
279
widePath->lineTo(seg->x0 - wdy - miter * wdx,
280
seg->y0 + wdx - miter * wdy);
281
widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
284
if (dy * dxPrev > dx * dyPrev) {
285
widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev);
286
widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
288
widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
289
widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
294
case splashLineJoinRound:
295
widePath = new OPVPSplashPath();
297
widePath->moveTo(seg->x0 + wdy, seg->y0 - wdx);
302
splash->arcToCurve(x0, y0, x3, y3,
303
seg->x0, seg->y0, &x1,&y1,&x2,&y2);
304
widePath->curveTo(x1,y1,x2,y2,x3,y3);
309
splash->arcToCurve(x0, y0, x3, y3,
310
seg->x0, seg->y0, &x1,&y1,&x2,&y2);
311
widePath->curveTo(x1,y1,x2,y2,x3,y3);
316
splash->arcToCurve(x0, y0, x3, y3,
317
seg->x0, seg->y0, &x1,&y1,&x2,&y2);
318
widePath->curveTo(x1,y1,x2,y2,x3,y3);
323
splash->arcToCurve(x0, y0, x3, y3,
324
seg->x0, seg->y0, &x1,&y1,&x2,&y2);
325
widePath->curveTo(x1,y1,x2,y2,x3,y3);
327
case splashLineJoinBevel:
328
widePath = new OPVPSplashPath();
329
widePath->moveTo(seg->x0, seg->y0);
330
if (dy * dxPrev > dx * dyPrev) {
331
widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev);
332
widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
334
widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
335
widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
340
splash->fill(widePath, gTrue);
348
void OPVPSplashXPath::strokeNarrow(OPVPSplash *splash, OPVPSplashState *state)
351
int x0, x1, x2, x3, y0, y1, x, y, t;
352
SplashCoord dx, dy, dxdy;
353
SplashClipResult clipRes;
356
for (i = 0, seg = segs; i < length; ++i, ++seg) {
358
x0 = splashFloor(seg->x0);
359
x1 = splashFloor(seg->x1);
360
y0 = splashFloor(seg->y0);
361
y1 = splashFloor(seg->y1);
363
// horizontal segment
366
t = x0; x0 = x1; x1 = t;
368
if ((clipRes = state->clip->testSpan(x0, x1, y0))
369
!= splashClipAllOutside) {
370
splash->drawSpan(x0, x1, y0, clipRes == splashClipAllInside);
373
// segment with |dx| > |dy|
374
} else if (splashAbs(seg->dxdy) > 1) {
375
dx = seg->x1 - seg->x0;
376
dy = seg->y1 - seg->y0;
379
t = y0; y0 = y1; y1 = t;
380
t = x0; x0 = x1; x1 = t;
384
if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
385
x0 <= x1 ? x1 : x0, y1))
386
!= splashClipAllOutside) {
389
for (y = y0; y < y1; ++y) {
390
x3 = splashFloor(seg->x0 + (y + 1 - seg->y0) * dxdy);
391
splash->drawSpan(x2, x3 - 1, y, clipRes == splashClipAllInside);
394
splash->drawSpan(x2, x1, y, clipRes == splashClipAllInside);
397
for (y = y0; y < y1; ++y) {
398
x3 = splashFloor(seg->x0 + (y + 1 - seg->y0) * dxdy);
399
splash->drawSpan(x3 + 1, x2, y, clipRes == splashClipAllInside);
402
splash->drawSpan(x1, x2, y, clipRes == splashClipAllInside);
406
// segment with |dy| > |dx|
410
t = y0; y0 = y1; y1 = t;
412
if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
413
x0 <= x1 ? x1 : x0, y1))
414
!= splashClipAllOutside) {
415
for (y = y0; y <= y1; ++y) {
416
x = splashFloor(seg->x0 + (y - seg->y0) * dxdy);
417
splash->drawPixel(x, y, clipRes == splashClipAllInside);