~ubuntu-branches/debian/experimental/cups-filters/experimental

« back to all changes in this revision

Viewing changes to pdftoopvp/oprs/OPVPSplashXPath.cxx

Tags: upstream-1.0.20
ImportĀ upstreamĀ versionĀ 1.0.20

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include <config.h>
2
 
#include <stdio.h>
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"
9
 
 
10
 
#if POPPLER_VERSION_MAJOR <= 0 && POPPLER_VERSION_MINOR < 19
11
 
OPVPSplashXPath *OPVPSplashXPath::makeDashedPath(OPVPSplashState *state)
12
 
{
13
 
  OPVPSplashXPath *dPath;
14
 
  GBool lineDashStartOn, lineDashOn;
15
 
  GBool atSegStart, atSegEnd, atDashStart, atDashEnd;
16
 
  int lineDashStartIdx, lineDashIdx, subpathStart;
17
 
  SplashCoord lineDashTotal, lineDashStartPhase, lineDashDist;
18
 
  int segIdx;
19
 
  SplashXPathSeg *seg;
20
 
  SplashCoord sx0, sy0, sx1, sy1, ax0, ay0, ax1, ay1, dist;
21
 
  int i;
22
 
 
23
 
  dPath = new OPVPSplashXPath();
24
 
 
25
 
  lineDashTotal = 0;
26
 
  for (i = 0; i < state->lineDashLength; ++i) {
27
 
    lineDashTotal += state->lineDash[i];
28
 
  }
29
 
  lineDashStartPhase = state->lineDashPhase;
30
 
  i = splashFloor(lineDashStartPhase / lineDashTotal);
31
 
  lineDashStartPhase -= i * lineDashTotal;
32
 
  lineDashStartOn = gTrue;
33
 
  lineDashStartIdx = 0;
34
 
  while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) {
35
 
    lineDashStartOn = !lineDashStartOn;
36
 
    lineDashStartPhase -= state->lineDash[lineDashStartIdx];
37
 
    ++lineDashStartIdx;
38
 
  }
39
 
 
40
 
  segIdx = 0;
41
 
  seg = segs;
42
 
  sx0 = seg->x0;
43
 
  sy0 = seg->y0;
44
 
  sx1 = seg->x1;
45
 
  sy1 = seg->y1;
46
 
  dist = splashDist(sx0, sy0, sx1, sy1);
47
 
  lineDashOn = lineDashStartOn;
48
 
  lineDashIdx = lineDashStartIdx;
49
 
  lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
50
 
  atSegStart = gTrue;
51
 
  atDashStart = gTrue;
52
 
  subpathStart = dPath->length;
53
 
 
54
 
  while (segIdx < length) {
55
 
 
56
 
    ax0 = sx0;
57
 
    ay0 = sy0;
58
 
    if (dist <= lineDashDist) {
59
 
      ax1 = sx1;
60
 
      ay1 = sy1;
61
 
      lineDashDist -= dist;
62
 
      dist = 0;
63
 
      atSegEnd = gTrue;
64
 
      atDashEnd = lineDashDist == 0 || (seg->flags & splashXPathLast);
65
 
    } else {
66
 
      ax1 = sx0 + (lineDashDist / dist) * (sx1 - sx0);
67
 
      ay1 = sy0 + (lineDashDist / dist) * (sy1 - sy0);
68
 
      sx0 = ax1;
69
 
      sy0 = ay1;
70
 
      dist -= lineDashDist;
71
 
      lineDashDist = 0;
72
 
      atSegEnd = gFalse;
73
 
      atDashEnd = gTrue;
74
 
    }
75
 
 
76
 
    if (lineDashOn) {
77
 
      dPath->addSegment(ax0, ay0, ax1, ay1,
78
 
                        atDashStart, atDashEnd,
79
 
                        atDashStart, atDashEnd);
80
 
      // end of closed subpath
81
 
      if (atSegEnd &&
82
 
          (seg->flags & splashXPathLast) &&
83
 
          !(seg->flags & splashXPathEnd1)) {
84
 
        dPath->segs[subpathStart].flags &= ~splashXPathEnd0;
85
 
        dPath->segs[dPath->length - 1].flags &= ~splashXPathEnd1;
86
 
      }
87
 
    }
88
 
 
89
 
    if (atDashEnd) {
90
 
      lineDashOn = !lineDashOn;
91
 
      if (++lineDashIdx == state->lineDashLength) {
92
 
        lineDashIdx = 0;
93
 
      }
94
 
      lineDashDist = state->lineDash[lineDashIdx];
95
 
      atDashStart = gTrue;
96
 
    } else {
97
 
      atDashStart = gFalse;
98
 
    }
99
 
    if (atSegEnd) {
100
 
      if (++segIdx < length) {
101
 
        ++seg;
102
 
        sx0 = seg->x0;
103
 
        sy0 = seg->y0;
104
 
        sx1 = seg->x1;
105
 
        sy1 = seg->y1;
106
 
        dist = splashDist(sx0, sy0, sx1, sy1);
107
 
        if (seg->flags & splashXPathFirst) {
108
 
          lineDashOn = lineDashStartOn;
109
 
          lineDashIdx = lineDashStartIdx;
110
 
          lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
111
 
          atDashStart = gTrue;
112
 
          subpathStart = dPath->length;
113
 
        }
114
 
      }
115
 
      atSegStart = gTrue;
116
 
    } else {
117
 
      atSegStart = gFalse;
118
 
    }
119
 
  }
120
 
 
121
 
  return dPath;
122
 
}
123
 
 
124
 
void OPVPSplashXPath::strokeWide(OPVPSplash *splash, OPVPSplashState *state)
125
 
{
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;
131
 
  int i, j;
132
 
 
133
 
  dx = dy = wdx = wdy = 0; // make gcc happy
134
 
  dxPrev = dyPrev = wdxPrev = wdyPrev = 0; // make gcc happy
135
 
 
136
 
  for (i = 0, seg = segs; i < length; ++i, ++seg) {
137
 
 
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);
146
 
          if (d == 0) {
147
 
            //~ not clear what the behavior should be for joins with d==0
148
 
            dxPrev = 0;
149
 
            dyPrev = 1;
150
 
          } else {
151
 
            d = 1 / d;
152
 
            dxPrev = d * (seg2->x1 - seg2->x0);
153
 
            dyPrev = d * (seg2->y1 - seg2->y0);
154
 
          }
155
 
          wdxPrev = 0.5 * state->lineWidth * dxPrev;
156
 
          wdyPrev = 0.5 * state->lineWidth * dyPrev;
157
 
          break;
158
 
        }
159
 
      }
160
 
    } else {
161
 
      dxPrev = dx;
162
 
      dyPrev = dy;
163
 
      wdxPrev = wdx;
164
 
      wdyPrev = wdy;
165
 
    }
166
 
 
167
 
    // compute deltas for this line segment
168
 
    d = splashDist(seg->x0, seg->y0, seg->x1, seg->y1);
169
 
    if (d == 0) {
170
 
      // we need to draw end caps on zero-length lines
171
 
      //~ not clear what the behavior should be for splashLineCapButt with d==0
172
 
      dx = 0;
173
 
      dy = 1;
174
 
    } else {
175
 
      d = 1 / d;
176
 
      dx = d * (seg->x1 - seg->x0);
177
 
      dy = d * (seg->y1 - seg->y0);
178
 
    }
179
 
    wdx = 0.5 * state->lineWidth * dx;
180
 
    wdy = 0.5 * state->lineWidth * dy;
181
 
 
182
 
    // initialize the path (which will be filled)
183
 
    widePath = new OPVPSplashPath();
184
 
    widePath->moveTo(seg->x0 - wdy, seg->y0 + wdx);
185
 
 
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);
191
 
        break;
192
 
      case splashLineCapRound:
193
 
        x0 = seg->x0 - wdy;
194
 
        y0 = seg->y0 + wdx;
195
 
        x3 = seg->x0 - wdx;
196
 
        y3 = seg->y0 - wdy;
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);
200
 
        x0 = x3;
201
 
        y0 = y3;
202
 
        x3 = seg->x0 + wdy;
203
 
        y3 = seg->y0 - wdx;
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);
207
 
        break;
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);
212
 
        break;
213
 
      }
214
 
    } else {
215
 
      widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
216
 
    }
217
 
 
218
 
    // draw the left side of the segment
219
 
    widePath->lineTo(seg->x1 + wdy, seg->y1 - wdx);
220
 
 
221
 
    // draw the end cap
222
 
    if (seg->flags & splashXPathEnd1) {
223
 
      switch (state->lineCap) {
224
 
      case splashLineCapButt:
225
 
        widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
226
 
        break;
227
 
      case splashLineCapRound:
228
 
        x0 = seg->x1 + wdy;
229
 
        y0 = seg->y1 - wdx;
230
 
        x3 = seg->x1 + wdx;
231
 
        y3 = seg->y1 + wdy;
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);
235
 
        x0 = x3;
236
 
        y0 = y3;
237
 
        x3 = seg->x1 - wdy;
238
 
        y3 = seg->y1 + wdx;
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);
242
 
        break;
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);
247
 
        break;
248
 
      }
249
 
    } else {
250
 
      widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx);
251
 
    }
252
 
 
253
 
    // draw the right side of the segment
254
 
    widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
255
 
 
256
 
    // fill the segment
257
 
    splash->fill(widePath, gTrue);
258
 
    delete widePath;
259
 
 
260
 
    // draw the line join
261
 
    if (!(seg->flags & splashXPathEnd0)) {
262
 
      widePath = NULL;
263
 
      switch (state->lineJoin) {
264
 
      case splashLineJoinMiter:
265
 
        dotprod = -(dx * dxPrev + dy * dyPrev);
266
 
        if (dotprod != 1) {
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);
277
 
            } else {
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);
282
 
            }
283
 
          } else {
284
 
            if (dy * dxPrev > dx * dyPrev) {
285
 
              widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev);
286
 
              widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx);
287
 
            } else {
288
 
              widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
289
 
              widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
290
 
            }
291
 
          }
292
 
        }
293
 
        break;
294
 
      case splashLineJoinRound:
295
 
        widePath = new OPVPSplashPath();
296
 
        /* draw circle */
297
 
        widePath->moveTo(seg->x0 + wdy, seg->y0 - wdx);
298
 
        x0 = seg->x0 + wdy;
299
 
        y0 = seg->y0 - wdx;
300
 
        x3 = seg->x0 - wdx;
301
 
        y3 = seg->y0 - wdy;
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);
305
 
        x0 = x3;
306
 
        y0 = y3;
307
 
        x3 = seg->x0 - wdy;
308
 
        y3 = seg->y0 + wdx;
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);
312
 
        x0 = x3;
313
 
        y0 = y3;
314
 
        x3 = seg->x0 + wdx;
315
 
        y3 = seg->y0 + wdy;
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);
319
 
        x0 = x3;
320
 
        y0 = y3;
321
 
        x3 = seg->x0 + wdy;
322
 
        y3 = seg->y0 - wdx;
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);
326
 
        break;
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);
333
 
        } else {
334
 
          widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev);
335
 
          widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx);
336
 
        }
337
 
        break;
338
 
      }
339
 
      if (widePath) {
340
 
        splash->fill(widePath, gTrue);
341
 
        delete widePath;
342
 
      }
343
 
    }
344
 
  }
345
 
}
346
 
#endif
347
 
 
348
 
void OPVPSplashXPath::strokeNarrow(OPVPSplash *splash, OPVPSplashState *state)
349
 
{
350
 
  SplashXPathSeg *seg;
351
 
  int x0, x1, x2, x3, y0, y1, x, y, t;
352
 
  SplashCoord dx, dy, dxdy;
353
 
  SplashClipResult clipRes;
354
 
  int i;
355
 
 
356
 
  for (i = 0, seg = segs; i < length; ++i, ++seg) {
357
 
 
358
 
    x0 = splashFloor(seg->x0);
359
 
    x1 = splashFloor(seg->x1);
360
 
    y0 = splashFloor(seg->y0);
361
 
    y1 = splashFloor(seg->y1);
362
 
 
363
 
    // horizontal segment
364
 
    if (y0 == y1) {
365
 
      if (x0 > x1) {
366
 
        t = x0; x0 = x1; x1 = t;
367
 
      }
368
 
      if ((clipRes = state->clip->testSpan(x0, x1, y0))
369
 
          != splashClipAllOutside) {
370
 
        splash->drawSpan(x0, x1, y0, clipRes == splashClipAllInside);
371
 
      }
372
 
 
373
 
    // segment with |dx| > |dy|
374
 
    } else if (splashAbs(seg->dxdy) > 1) {
375
 
      dx = seg->x1 - seg->x0;
376
 
      dy = seg->y1 - seg->y0;
377
 
      dxdy = seg->dxdy;
378
 
      if (y0 > y1) {
379
 
        t = y0; y0 = y1; y1 = t;
380
 
        t = x0; x0 = x1; x1 = t;
381
 
        dx = -dx;
382
 
        dy = -dy;
383
 
      }
384
 
      if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
385
 
                                           x0 <= x1 ? x1 : x0, y1))
386
 
          != splashClipAllOutside) {
387
 
        if (dx > 0) {
388
 
          x2 = x0;
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);
392
 
            x2 = x3;
393
 
          }
394
 
          splash->drawSpan(x2, x1, y, clipRes == splashClipAllInside);
395
 
        } else {
396
 
          x2 = x0;
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);
400
 
            x2 = x3;
401
 
          }
402
 
          splash->drawSpan(x1, x2, y, clipRes == splashClipAllInside);
403
 
        }
404
 
      }
405
 
 
406
 
    // segment with |dy| > |dx|
407
 
    } else {
408
 
      dxdy = seg->dxdy;
409
 
      if (y0 > y1) {
410
 
        t = y0; y0 = y1; y1 = t;
411
 
      }
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);
418
 
        }
419
 
      }
420
 
    }
421
 
  }
422
 
}
423