1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gxstroke.c,v 1.18 2005/08/17 14:40:11 igor Exp $ */
18 /* Path stroking procedures for Ghostscript library */
19 #include "math_.h"
20 #include "gx.h"
21 #include "gpcheck.h"
22 #include "gserrors.h"
23 #include "gsdcolor.h"
24 #include "gxfixed.h"
25 #include "gxfarith.h"
26 #include "gxmatrix.h"
27 #include "gscoord.h"
28 #include "gsdevice.h"
29 #include "gxdevice.h"
30 #include "gxhttile.h"
31 #include "gxistate.h"
32 #include "gzline.h"
33 #include "gzpath.h"
34 #include "gzcpath.h"
35 #include "gxpaint.h"
36 #include "vdtrace.h"
37
38 /*
39 * We don't really know whether it's a good idea to take fill adjustment
40 * into account for stroking. Disregarding it means that strokes
41 * come out thinner than fills; observing it produces heavy-looking
42 * strokes at low resolutions. But in any case, we must disregard it
43 * when stroking zero-width lines.
44 */
45 #define USE_FILL_ADJUSTMENT
46
47 #ifdef USE_FILL_ADJUSTMENT
48 # define STROKE_ADJUSTMENT(thin, pis, xy)\
49 (thin ? fixed_0 : (pis)->fill_adjust.xy)
50 #else
51 # define STROKE_ADJUSTMENT(thin, pis, xy) fixed_0
52 #endif
53
54 /*
55 * For some reason, we commented out the optimization for portrait,
56 * landscape, and uniform (non-scaled) transformations. We have no record
57 * of why we did this, and we don't know what bugs re-enabling it may
58 * introduce.
59 */
60 #define OPTIMIZE_ORIENTATION
61
62 /*
63 * Compute the amount by which to expand a stroked bounding box to account
64 * for line width, caps and joins. Return 0 if the result is exact, 1 if
65 * it may be conservative, or gs_error_limitcheck if the result is too
66 * large to fit in a gs_fixed_point.
67 *
68 * Because of square caps and miter and triangular joins, the maximum
69 * expansion on each side (in user space) is
70 * K * line_width/2
71 * where K is determined as follows:
72 * If the path is only a single line segment, K = 1;
73 * if triangular joins, K = 2;
74 * if miter joins, K = miter_limit;
75 * otherwise, K = 1.
76 *
77 * If the following conditions apply, K = 1 yields an exact result:
78 * - The CTM is of the form [X 0 0 Y] or [0 X Y 0].
79 * - Square or round caps are used, or all subpaths are closed.
80 * - All segments (including the implicit segment created by
81 * closepath) are vertical or horizontal lines.
82 *
83 * Note that these conditions are sufficient, but not necessary, to get an
84 * exact result. We choose this set of conditions because it is easy to
85 * check and covers many common cases. Clients that care always have the
86 * option of using strokepath to get an exact result.
87 */
88 private float join_expansion_factor(const gs_imager_state *, gs_line_join);
89 int
gx_stroke_path_expansion(const gs_imager_state * pis,const gx_path * ppath,gs_fixed_point * ppt)90 gx_stroke_path_expansion(const gs_imager_state * pis, const gx_path * ppath,
91 gs_fixed_point * ppt)
92 {
93 const subpath *psub = ppath->first_subpath;
94 const segment *pseg;
95 double cx = fabs(pis->ctm.xx) + fabs(pis->ctm.yx);
96 double cy = fabs(pis->ctm.xy) + fabs(pis->ctm.yy);
97 double expand = pis->line_params.half_width;
98 int result = 1;
99
100 /* Check for whether an exact result can be computed easily. */
101 if (is_fzero2(pis->ctm.xy, pis->ctm.yx) ||
102 is_fzero2(pis->ctm.xx, pis->ctm.yy)
103 ) {
104 bool must_be_closed =
105 !(pis->line_params.cap == gs_cap_square ||
106 pis->line_params.cap == gs_cap_round);
107 gs_fixed_point prev;
108
109 for (pseg = (const segment *)psub; pseg;
110 prev = pseg->pt, pseg = pseg->next
111 )
112 switch (pseg->type) {
113 case s_start:
114 if (((const subpath *)pseg)->curve_count ||
115 (must_be_closed && !((const subpath *)pseg)->is_closed)
116 )
117 goto not_exact;
118 break;
119 case s_line:
120 case s_line_close:
121 if (!(pseg->pt.x == prev.x || pseg->pt.y == prev.y))
122 goto not_exact;
123 break;
124 default: /* other/unknown segment type */
125 goto not_exact;
126 }
127 result = 0; /* exact result */
128 }
129 not_exact:
130 if (result) {
131 if (!gx_path_has_curves(ppath) && gx_path_subpath_count(ppath) <= 1 &&
132 (psub == 0 || (pseg = psub->next) == 0 ||
133 (pseg = pseg->next) == 0 || pseg->type == s_line_close))
134 DO_NOTHING;
135 else {
136 float factor = join_expansion_factor(pis, pis->line_params.join);
137
138 if (pis->line_params.curve_join >= 0)
139 factor = max(factor, join_expansion_factor(pis,
140 (gs_line_join)pis->line_params.curve_join));
141 expand *= factor;
142 }
143 }
144
145 /* Short-cut gs_bbox_transform. */
146 {
147 float exx = expand * cx;
148 float exy = expand * cy;
149 int code = set_float2fixed_vars(ppt->x, exx);
150
151 if (code < 0)
152 return code;
153 code = set_float2fixed_vars(ppt->y, exy);
154 if (code < 0)
155 return code;
156 }
157
158 return result;
159 }
160 private float
join_expansion_factor(const gs_imager_state * pis,gs_line_join join)161 join_expansion_factor(const gs_imager_state *pis, gs_line_join join)
162 {
163 switch (join) {
164 case gs_join_miter: return pis->line_params.miter_limit;
165 case gs_join_triangle: return 2.0;
166 default: return 1.0;
167 }
168 }
169
170 /*
171 * Structure for a partial line (passed to the drawing routine).
172 * Two of these are required to do joins right.
173 * Each endpoint includes the two ends of the cap as well,
174 * and the deltas for square, round, and triangular cap computation.
175 *
176 * The two base values for computing the caps of a partial line are the
177 * width and the end cap delta. The width value is one-half the line
178 * width (suitably transformed) at 90 degrees counter-clockwise
179 * (in device space, but with "90 degrees" interpreted in *user*
180 * coordinates) at the end (as opposed to the origin) of the line.
181 * The cdelta value is one-half the transformed line width in the same
182 * direction as the line. From these, we compute two other values at each
183 * end of the line: co and ce, which are the ends of the cap.
184 * Note that the cdelta values at o are the negatives of the values at e,
185 * as are the offsets from p to co and ce.
186 *
187 * Initially, only o.p, e.p, e.cdelta, width, and thin are set.
188 * compute_caps fills in the rest.
189 */
190 typedef gs_fixed_point *p_ptr;
191 typedef struct endpoint_s {
192 gs_fixed_point p; /* the end of the line */
193 gs_fixed_point co, ce; /* ends of the cap, p +/- width */
194 gs_fixed_point cdelta; /* +/- cap length */
195 } endpoint;
196 typedef endpoint *ep_ptr;
197 typedef const endpoint *const_ep_ptr;
198 typedef struct partial_line_s {
199 endpoint o; /* starting coordinate */
200 endpoint e; /* ending coordinate */
201 gs_fixed_point width; /* one-half line width, see above */
202 bool thin; /* true if minimum-width line */
203 } partial_line;
204 typedef partial_line *pl_ptr;
205
206 /* Assign a point. Some compilers would do this with very slow code */
207 /* if we simply implemented it as an assignment. */
208 #define ASSIGN_POINT(pp, p)\
209 ((pp)->x = (p).x, (pp)->y = (p).y)
210
211 /* Other forward declarations */
212 private bool width_is_thin(pl_ptr);
213 private void adjust_stroke(pl_ptr, const gs_imager_state *, bool);
214 private int line_join_points(const gx_line_params * pgs_lp,
215 pl_ptr plp, pl_ptr nplp,
216 gs_fixed_point * join_points,
217 const gs_matrix * pmat, gs_line_join join,
218 bool reflected);
219 private void compute_caps(pl_ptr);
220 private int add_points(gx_path *, const gs_fixed_point *,
221 int, bool);
222 private int add_round_cap(gx_path *, const_ep_ptr);
223 private int cap_points(gs_line_cap, const_ep_ptr,
224 gs_fixed_point * /*[3] */ );
225
226 /* Define the default implementation of the device stroke_path procedure. */
227 int
gx_default_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)228 gx_default_stroke_path(gx_device * dev, const gs_imager_state * pis,
229 gx_path * ppath, const gx_stroke_params * params,
230 const gx_drawing_color * pdcolor,
231 const gx_clip_path * pcpath)
232 {
233 return gx_stroke_path_only(ppath, (gx_path *) 0, dev, pis, params,
234 pdcolor, pcpath);
235 }
236
237 /* Fill a partial stroked path. Free variables: */
238 /* to_path, stroke_path_body, fill_params, always_thin, pis, dev, pdevc, */
239 /* code, ppath, exit(label). */
240 #define FILL_STROKE_PATH(thin)\
241 if(to_path==&stroke_path_body && !gx_path_is_void(&stroke_path_body)) {\
242 fill_params.adjust.x = STROKE_ADJUSTMENT(thin, pis, x);\
243 fill_params.adjust.y = STROKE_ADJUSTMENT(thin, pis, y);\
244 code = gx_fill_path_only(to_path, dev, pis, &fill_params, pdevc, pcpath);\
245 gx_path_free(&stroke_path_body, "fill_stroke_path");\
246 if ( code < 0 ) goto exit;\
247 gx_path_init_local(&stroke_path_body, ppath->memory);\
248 }
249
250 /*
251 * Define the internal procedures that stroke a partial_line
252 * (the first pl_ptr argument). If both partial_lines are non-null,
253 * the procedure creates an appropriate join; otherwise, the procedure
254 * creates an end cap. If the first int is 0, the procedure also starts
255 * with an appropriate cap.
256 */
257 #define stroke_line_proc(proc)\
258 int proc(gx_path *, int, pl_ptr, pl_ptr, const gx_device_color *,\
259 gx_device *, const gs_imager_state *,\
260 const gx_stroke_params *, const gs_fixed_rect *, int,\
261 gs_line_join, bool)
262 typedef stroke_line_proc((*stroke_line_proc_t));
263
264 private stroke_line_proc(stroke_add);
265 private stroke_line_proc(stroke_fill);
266
267 /* Define the orientations we handle specially. */
268 typedef enum {
269 orient_other = 0,
270 orient_portrait, /* [xx 0 0 yy tx ty] */
271 orient_landscape /* [0 xy yx 0 tx ty] */
272 } orientation;
273
274 /*
275 * Stroke a path. If to_path != 0, append the stroke outline to it;
276 * if to_path == 0, draw the strokes on dev.
277 *
278 * Note that gx_stroke_path_only with to_path != NULL may clip the path to
279 * the clipping path, as for to_path == NULL. This is almost never
280 * what is wanted.
281 */
282 private int
gx_stroke_path_only_aux(gx_path * ppath,gx_path * to_path,gx_device * pdev,const gs_imager_state * pis,const gx_stroke_params * params,const gx_device_color * pdevc,const gx_clip_path * pcpath)283 gx_stroke_path_only_aux(gx_path * ppath, gx_path * to_path, gx_device * pdev,
284 const gs_imager_state * pis, const gx_stroke_params * params,
285 const gx_device_color * pdevc, const gx_clip_path * pcpath)
286 {
287 stroke_line_proc_t line_proc =
288 (to_path == 0 ? stroke_fill : stroke_add);
289 gs_fixed_rect ibox, cbox;
290 gx_device_clip cdev;
291 gx_device *dev = pdev;
292 int code = 0;
293 gx_fill_params fill_params;
294 const gx_line_params *pgs_lp = gs_currentlineparams_inline(pis);
295 int dash_count = pgs_lp->dash.pattern_size;
296 gx_path fpath, dpath;
297 gx_path stroke_path_body;
298 const gx_path *spath;
299 float xx = pis->ctm.xx, xy = pis->ctm.xy;
300 float yx = pis->ctm.yx, yy = pis->ctm.yy;
301 /*
302 * We are dealing with a reflected coordinate system
303 * if transform(1,0) is counter-clockwise from transform(0,1).
304 * See the note in stroke_add for the algorithm.
305 */
306 int uniform;
307 bool reflected;
308 orientation orient =
309 (
310 #ifdef OPTIMIZE_ORIENTATION
311 is_fzero2(xy, yx) ?
312 (uniform = (xx == yy ? 1 : xx == -yy ? -1 : 0),
313 reflected = (uniform ? uniform < 0 : (xx < 0) != (yy < 0)),
314 orient_portrait) :
315 is_fzero2(xx, yy) ?
316 (uniform = (xy == yx ? -1 : xy == -yx ? 1 : 0),
317 reflected = (uniform ? uniform < 0 : (xy < 0) == (yx < 0)),
318 orient_landscape) :
319 /* We should optimize uniform rotated coordinate systems */
320 /* here as well, but we don't. */
321 #endif
322 (uniform = 0,
323 reflected = xy * yx > xx * yy,
324 orient_other));
325 /*
326 * Formerly, there was a hack here that only treated the joins of
327 * flattened curves specially if the dot length was non-zero.
328 * This was a surrogate to detect use of the library by PCL
329 * interpreters. We have replaced this hack with an explicit
330 * curve join parameter in the graphics state.
331 */
332 #if 0
333 segment_notes not_first =
334 (!is_fzero(pis->line_params.dot_length) ? sn_not_first : sn_none);
335 #else
336 const segment_notes not_first = sn_not_first;
337 #endif
338 gs_line_join curve_join =
339 (pgs_lp->curve_join >= 0 ? (gs_line_join)pgs_lp->curve_join :
340 pgs_lp->join == gs_join_none || pgs_lp->join == gs_join_round ?
341 gs_join_bevel : pgs_lp->join);
342 float line_width = pgs_lp->half_width; /* (*half* the line width) */
343 bool always_thin;
344 double line_width_and_scale;
345 double device_line_width_scale = 0; /* Quiet compiler. */
346 double device_dot_length = pgs_lp->dot_length * fixed_1;
347 const subpath *psub;
348 gs_matrix initial_matrix;
349 bool initial_matrix_reflected;
350
351 (*dev_proc(pdev, get_initial_matrix)) (pdev, &initial_matrix);
352 initial_matrix_reflected = initial_matrix.xy * initial_matrix.yx >
353 initial_matrix.xx * initial_matrix.yy;
354
355 #ifdef DEBUG
356 if (gs_debug_c('o')) {
357 int count = pgs_lp->dash.pattern_size;
358 int i;
359
360 dlprintf3("[o]half_width=%f, cap=%d, join=%d,\n",
361 pgs_lp->half_width, (int)pgs_lp->cap, (int)pgs_lp->join);
362 dlprintf2(" miter_limit=%f, miter_check=%f,\n",
363 pgs_lp->miter_limit, pgs_lp->miter_check);
364 dlprintf1(" dash pattern=%d", count);
365 for (i = 0; i < count; i++)
366 dprintf1(",%f", pgs_lp->dash.pattern[i]);
367 dputs(",\n");
368 dlprintf4("\toffset=%f, init(ink_on=%d, index=%d, dist_left=%f)\n",
369 pgs_lp->dash.offset, pgs_lp->dash.init_ink_on,
370 pgs_lp->dash.init_index, pgs_lp->dash.init_dist_left);
371 }
372 #endif
373
374 gx_path_bbox(ppath, &ibox);
375 /* Expand the path bounding box by the scaled line width. */
376 {
377 gs_fixed_point expansion;
378
379 if (gx_stroke_path_expansion(pis, ppath, &expansion) < 0) {
380 /* The expansion is so large it caused a limitcheck. */
381 ibox.p.x = ibox.p.y = min_fixed;
382 ibox.q.x = ibox.q.y = max_fixed;
383 } else {
384 expansion.x += pis->fill_adjust.x;
385 expansion.y += pis->fill_adjust.y;
386 /*
387 * It's theoretically possible for the following computations to
388 * overflow, so we need to check for this.
389 */
390 ibox.p.x = (ibox.p.x < min_fixed + expansion.x ? min_fixed :
391 ibox.p.x - expansion.x);
392 ibox.p.y = (ibox.p.y < min_fixed + expansion.y ? min_fixed :
393 ibox.p.y - expansion.y);
394 ibox.q.x = (ibox.q.x > max_fixed - expansion.x ? max_fixed :
395 ibox.q.x + expansion.x);
396 ibox.q.y = (ibox.q.y > max_fixed - expansion.y ? max_fixed :
397 ibox.q.y + expansion.y);
398 }
399 }
400 /* Check the expanded bounding box against the clipping regions. */
401 if (pcpath)
402 gx_cpath_inner_box(pcpath, &cbox);
403 else if (pdevc)
404 (*dev_proc(dev, get_clipping_box)) (dev, &cbox);
405 else {
406 /* This is strokepath, not stroke. Don't clip. */
407 cbox = ibox;
408 }
409 if (!rect_within(ibox, cbox)) {
410 /* Intersect the path box and the clip bounding box. */
411 /* If the intersection is empty, this call is a no-op. */
412 gs_fixed_rect bbox;
413
414 if (pcpath) {
415 gx_cpath_outer_box(pcpath, &bbox);
416 if_debug4('f', " outer_box=(%g,%g),(%g,%g)\n",
417 fixed2float(bbox.p.x), fixed2float(bbox.p.y),
418 fixed2float(bbox.q.x), fixed2float(bbox.q.y));
419 rect_intersect(ibox, bbox);
420 } else
421 rect_intersect(ibox, cbox);
422 if (ibox.p.x >= ibox.q.x || ibox.p.y >= ibox.q.y) {
423 /* Intersection of boxes is empty! */
424 return 0;
425 }
426 /*
427 * The path is neither entirely inside the inner clip box
428 * nor entirely outside the outer clip box.
429 * If we had to flatten the path, this is where we would
430 * recompute its bbox and make the tests again,
431 * but we don't bother right now.
432 *
433 * If there is a clipping path, set up a clipping device.
434 */
435 if (pcpath) {
436 gx_make_clip_device(&cdev, gx_cpath_list(pcpath));
437 cdev.target = dev;
438 cdev.max_fill_band = dev->max_fill_band;
439 dev = (gx_device *) & cdev;
440 (*dev_proc(dev, open_device)) (dev);
441 }
442 }
443 fill_params.rule = gx_rule_winding_number;
444 fill_params.flatness = pis->flatness;
445 #ifdef USE_FILL_ADJUSTMENT
446 fill_params.fill_zero_width =
447 (pis->fill_adjust.x | pis->fill_adjust.y) != 0;
448 #else
449 fill_params.fill_zero_width = false;
450 #endif
451 if (line_width < 0)
452 line_width = -line_width;
453 line_width_and_scale = line_width * (double)int2fixed(1);
454 if (is_fzero(line_width))
455 always_thin = true;
456 else {
457 float xa, ya;
458
459 switch (orient) {
460 case orient_portrait:
461 xa = xx, ya = yy;
462 goto sat;
463 case orient_landscape:
464 xa = xy, ya = yx;
465 sat:
466 if (xa < 0)
467 xa = -xa;
468 if (ya < 0)
469 ya = -ya;
470 always_thin = (max(xa, ya) * line_width < 0.5);
471 if (!always_thin && uniform) { /* Precompute a value we'll need later. */
472 device_line_width_scale = line_width_and_scale * xa;
473 }
474 break;
475 default:
476 {
477 /* The check is more complicated, but it's worth it. */
478 double xsq = xx * xx + xy * xy;
479 double ysq = yx * yx + yy * yy;
480 double cross = xx * yx + xy * yy;
481
482 if (cross < 0)
483 cross = 0;
484 always_thin =
485 ((max(xsq, ysq) + cross) * line_width * line_width
486 < 0.25);
487 }
488 }
489 }
490 if_debug7('o', "[o]ctm=(%g,%g,%g,%g,%g,%g) thin=%d\n",
491 xx, xy, yx, yy, pis->ctm.tx, pis->ctm.ty, always_thin);
492 if (device_dot_length != 0) {
493 /*
494 * Compute the dot length in device space. We can't do this
495 * quite right for non-uniform coordinate systems; too bad.
496 */
497 gs_matrix mat;
498 const gs_matrix *pmat;
499
500 if (pgs_lp->dot_length_absolute) {
501 gs_deviceinitialmatrix(pdev, &mat);
502 pmat = &mat;
503 } else
504 pmat = (const gs_matrix *)&pis->ctm;
505 device_dot_length *= fabs(pmat->xy) + fabs(pmat->yy);
506 }
507 /* Start by flattening the path. We should do this on-the-fly.... */
508 if (!gx_path_has_curves(ppath)) { /* don't need to flatten */
509 if (!ppath->first_subpath)
510 return 0;
511 spath = ppath;
512 } else {
513 gx_path_init_local(&fpath, ppath->memory);
514 if ((code = gx_path_add_flattened_for_stroke(ppath, &fpath,
515 params->flatness, pis)) < 0
516 )
517 return code;
518 spath = &fpath;
519 }
520 if (dash_count) {
521 gx_path_init_local(&dpath, ppath->memory);
522 code = gx_path_add_dash_expansion(spath, &dpath, pis);
523 if (code < 0)
524 goto exf;
525 spath = &dpath;
526 }
527 if (to_path == 0) {
528 /* We might try to defer this if it's expensive.... */
529 to_path = &stroke_path_body;
530 gx_path_init_local(&stroke_path_body, ppath->memory);
531 }
532 for (psub = spath->first_subpath; psub != 0;) {
533 int index = 0;
534 const segment *pseg = (const segment *)psub;
535 fixed x = pseg->pt.x;
536 fixed y = pseg->pt.y;
537 bool is_closed = ((const subpath *)pseg)->is_closed;
538 partial_line pl, pl_prev, pl_first;
539
540 while ((pseg = pseg->next) != 0 &&
541 pseg->type != s_start
542 ) {
543 /* Compute the width parameters in device space. */
544 /* We work with unscaled values, for speed. */
545 fixed sx = pseg->pt.x, udx = sx - x;
546 fixed sy = pseg->pt.y, udy = sy - y;
547
548 pl.o.p.x = x, pl.o.p.y = y;
549 d:pl.e.p.x = sx, pl.e.p.y = sy;
550 if (!(udx | udy)) { /* degenerate */
551 /*
552 * If this is the first segment of the subpath,
553 * check the entire subpath for degeneracy.
554 * Otherwise, ignore the degenerate segment.
555 */
556 if (index != 0)
557 continue;
558 /* Check for a degenerate subpath. */
559 while ((pseg = pseg->next) != 0 &&
560 pseg->type != s_start
561 ) {
562 sx = pseg->pt.x, udx = sx - x;
563 sy = pseg->pt.y, udy = sy - y;
564 if (udx | udy)
565 goto d;
566 }
567 /*
568 * The entire subpath is degenerate, but it includes
569 * more than one point. If the dot length is non-zero,
570 * draw the caps, otherwise do nothing.
571 */
572 if (pgs_lp->dot_length != 0)
573 break;
574 if (pgs_lp->cap != gs_cap_round) {
575 /* From PLRM, stroke operator :
576 If a subpath is degenerate (consists of a single-point closed path
577 or of two or more points at the same coordinates),
578 stroke paints it only if round line caps have been specified */
579 break;
580 }
581 /*
582 * Orient the dot according to the previous segment if
583 * any, or else the next segment if any, or else
584 * according to the specified dot orientation.
585 */
586 {
587 const segment *end = psub->prev;
588
589 if (end != 0 && (end->pt.x != x || end->pt.y != y))
590 sx = end->pt.x, sy = end->pt.y;
591 else if (pseg != 0 &&
592 (pseg->pt.x != x || pseg->pt.y != y)
593 )
594 sx = pseg->pt.x, sy = pseg->pt.y;
595 }
596 /*
597 * Compute the properly oriented dot length, and then
598 * draw the dot like a very short line.
599 */
600 udx = sx - x, udy = sy - y;
601 if ((udx | udy) == 0) {
602 if (is_fzero(pgs_lp->dot_orientation.xy)) {
603 /* Portrait orientation, dot length = X */
604 udx = fixed_1;
605 } else {
606 /* Landscape orientation, dot length = Y */
607 udy = fixed_1;
608 }
609 }
610 {
611 double scale = device_dot_length /
612 hypot((double)udx, (double)udy);
613
614 /*
615 * If we're using butt caps, make sure the "line" is
616 * long enough to show up.
617 */
618 if (pgs_lp->cap == gs_cap_butt) {
619 fixed dmax = max(any_abs(udx), any_abs(udy));
620
621 if (dmax * scale < fixed_1)
622 scale = (float)fixed_1 / dmax;
623 }
624 udx = (fixed) (udx * scale);
625 udy = (fixed) (udy * scale);
626 if ((udx | udy) == 0)
627 udy = fixed_epsilon;
628 sx = x + udx;
629 sy = y + udy;
630 }
631 /*
632 * Back up 1 segment to keep the bookkeeping straight.
633 */
634 pseg = (pseg != 0 ? pseg->prev : psub->last);
635 goto d;
636 }
637 if (always_thin) {
638 pl.e.cdelta.x = pl.e.cdelta.y = 0;
639 pl.width.x = pl.width.y = 0;
640 pl.thin = true;
641 } else {
642 if (uniform != 0) {
643 /* We can save a lot of work in this case. */
644 /* We know orient != orient_other. */
645 double dpx = udx, dpy = udy;
646 double wl = device_line_width_scale /
647 hypot(dpx, dpy);
648
649 pl.e.cdelta.x = (fixed) (dpx * wl);
650 pl.e.cdelta.y = (fixed) (dpy * wl);
651 /* The width is the cap delta rotated by */
652 /* 90 degrees. */
653 if (initial_matrix_reflected)
654 pl.width.x = pl.e.cdelta.y, pl.width.y = -pl.e.cdelta.x;
655 else
656 pl.width.x = -pl.e.cdelta.y, pl.width.y = pl.e.cdelta.x;
657 pl.thin = false; /* if not always_thin, */
658 /* then never thin. */
659
660 } else {
661 gs_point dpt; /* unscaled */
662 float wl;
663
664 gs_imager_idtransform(pis,
665 (float)udx, (float)udy, &dpt);
666 wl = line_width_and_scale /
667 hypot(dpt.x, dpt.y);
668 /* Construct the width vector in */
669 /* user space, still unscaled. */
670 dpt.x *= wl;
671 dpt.y *= wl;
672 /*
673 * We now compute both perpendicular
674 * and (optionally) parallel half-widths,
675 * as deltas in device space. We use
676 * a fixed-point, unscaled version of
677 * gs_dtransform. The second computation
678 * folds in a 90-degree rotation (in user
679 * space, before transforming) in the
680 * direction that corresponds to counter-
681 * clockwise in device space.
682 */
683 pl.e.cdelta.x = (fixed) (dpt.x * xx);
684 pl.e.cdelta.y = (fixed) (dpt.y * yy);
685 if (orient != orient_portrait)
686 pl.e.cdelta.x += (fixed) (dpt.y * yx),
687 pl.e.cdelta.y += (fixed) (dpt.x * xy);
688 if (!reflected ^ initial_matrix_reflected)
689 dpt.x = -dpt.x, dpt.y = -dpt.y;
690 pl.width.x = (fixed) (dpt.y * xx),
691 pl.width.y = -(fixed) (dpt.x * yy);
692 if (orient != orient_portrait)
693 pl.width.x -= (fixed) (dpt.x * yx),
694 pl.width.y += (fixed) (dpt.y * xy);
695 pl.thin = width_is_thin(&pl);
696 }
697 if (!pl.thin) {
698 adjust_stroke(&pl, pis, false);
699 compute_caps(&pl);
700 }
701 }
702 if (index++) {
703 gs_line_join join =
704 (pseg->notes & not_first ? curve_join : pgs_lp->join);
705 int first;
706 pl_ptr lptr;
707
708 if (join == gs_join_none) {
709 /* Fake the end of a subpath so we get */
710 /* caps instead of joins. */
711 first = 0;
712 lptr = 0;
713 index = 1;
714 } else {
715 first = (is_closed ? 1 : index - 2);
716 lptr = &pl;
717 }
718 code = (*line_proc) (to_path, first, &pl_prev, lptr,
719 pdevc, dev, pis, params, &cbox,
720 uniform, join, initial_matrix_reflected);
721 if (code < 0)
722 goto exit;
723 FILL_STROKE_PATH(always_thin);
724 } else
725 pl_first = pl;
726 pl_prev = pl;
727 x = sx, y = sy;
728 }
729 if (index) {
730 /* If closed, join back to start, else cap. */
731 gs_line_join join =
732 ((pseg == 0 ? (const segment *)spath->first_subpath :
733 pseg)->notes & not_first ? curve_join : pgs_lp->join);
734 /* For some reason, the Borland compiler requires the cast */
735 /* in the following statement. */
736 pl_ptr lptr =
737 (!is_closed || join == gs_join_none ?
738 (pl_ptr) 0 : (pl_ptr) & pl_first);
739
740 code = (*line_proc) (to_path, index - 1, &pl_prev, lptr, pdevc,
741 dev, pis, params, &cbox, uniform, join,
742 initial_matrix_reflected);
743 if (code < 0)
744 goto exit;
745 FILL_STROKE_PATH(always_thin);
746 }
747 psub = (const subpath *)pseg;
748 }
749 exit:
750 if (to_path == &stroke_path_body)
751 gx_path_free(&stroke_path_body, "gx_stroke_path_only error"); /* (only needed if error) */
752 if (dash_count)
753 gx_path_free(&dpath, "gx_stroke_path exit(dash path)");
754 exf:
755 if (ppath->curve_count)
756 gx_path_free(&fpath, "gx_stroke_path exit(flattened path)");
757 return code;
758 }
759
760 int
gx_stroke_path_only(gx_path * ppath,gx_path * to_path,gx_device * pdev,const gs_imager_state * pis,const gx_stroke_params * params,const gx_device_color * pdevc,const gx_clip_path * pcpath)761 gx_stroke_path_only(gx_path * ppath, gx_path * to_path, gx_device * pdev,
762 const gs_imager_state * pis, const gx_stroke_params * params,
763 const gx_device_color * pdevc, const gx_clip_path * pcpath)
764 {
765 int code;
766
767 if (vd_allowed('S')) {
768 vd_get_dc('S');
769 if (vd_enabled) {
770 vd_set_shift(0, 100);
771 vd_set_scale(0.03);
772 vd_set_origin(0, 0);
773 vd_erase(RGB(192, 192, 192));
774 }
775 }
776 code = gx_stroke_path_only_aux(ppath, to_path, pdev, pis, params, pdevc, pcpath);
777 if (vd_allowed('S'))
778 vd_release_dc;
779 return code;
780 }
781
782 /* ------ Internal routines ------ */
783
784 /*
785 * Test whether a line is thin, i.e., whether the half-width, measured
786 * perpendicular to the line in device space, is less than 0.5 pixel.
787 * Unfortunately, the width values we computed are perpendicular to the
788 * line in *user* space, so we may have to do some extra work.
789 */
790 private bool
width_is_thin(pl_ptr plp)791 width_is_thin(pl_ptr plp)
792 {
793 fixed dx, dy, wx = plp->width.x, wy = plp->width.y;
794
795 /* If the line is horizontal or vertical, things are easy. */
796 if ((dy = plp->e.p.y - plp->o.p.y) == 0)
797 return any_abs(wy) < fixed_half;
798 if ((dx = plp->e.p.x - plp->o.p.x) == 0)
799 return any_abs(wx) < fixed_half;
800
801 /*
802 * If both horizontal and vertical widths are less than
803 * 0.5, the line is thin.
804 */
805 if (any_abs(wx) < fixed_half && any_abs(wy) < fixed_half)
806 return true;
807
808 /*
809 * We have to do this the hard way, by actually computing the
810 * perpendicular distance. The distance from the point (U,V)
811 * from a line from (0,0) to (C,D) is
812 * abs(C*V - D*U) / sqrt(C^2 + D^2)
813 * In this case, (U,V) is plp->width, and (C,D) is (dx,dy).
814 */
815 {
816 double C = dx, D = dy;
817 double num = C * wy - D * wx;
818 double denom = hypot(C, D);
819
820 /* both num and denom are scaled by fixed_scale^2, */
821 /* so we don't need to do any de-scaling for the test. */
822 return fabs(num) < denom * 0.5;
823 }
824 }
825
826 /* Adjust the endpoints and width of a stroke segment */
827 /* to achieve more uniform rendering. */
828 /* Only o.p, e.p, e.cdelta, and width have been set. */
829 private void
adjust_stroke(pl_ptr plp,const gs_imager_state * pis,bool thin)830 adjust_stroke(pl_ptr plp, const gs_imager_state * pis, bool thin)
831 {
832 fixed *pw;
833 fixed *pov;
834 fixed *pev;
835 fixed w, w2;
836 fixed adj2;
837
838 if (!pis->stroke_adjust && plp->width.x != 0 && plp->width.y != 0)
839 return; /* don't adjust */
840 if (any_abs(plp->width.x) < any_abs(plp->width.y)) {
841 /* More horizontal stroke */
842 pw = &plp->width.y, pov = &plp->o.p.y, pev = &plp->e.p.y;
843 adj2 = STROKE_ADJUSTMENT(thin, pis, y) << 1;
844 } else {
845 /* More vertical stroke */
846 pw = &plp->width.x, pov = &plp->o.p.x, pev = &plp->e.p.x;
847 adj2 = STROKE_ADJUSTMENT(thin, pis, x) << 1;
848 }
849 /* Round the larger component of the width up or down, */
850 /* whichever way produces a result closer to the correct width. */
851 /* Note that just rounding the larger component */
852 /* may not produce the correct result. */
853 w = *pw;
854 if (w > 0)
855 w2 = fixed_rounded(w << 1); /* full line width */
856 else
857 w2 = -fixed_rounded(-w << 1); /* full line width */
858 if (w2 == 0 && *pw != 0) {
859 /* Make sure thin lines don't disappear. */
860 w2 = (*pw < 0 ? -fixed_1 + adj2 : fixed_1 - adj2);
861 *pw = arith_rshift_1(w2);
862 }
863 /* Only adjust the endpoints if the line is horizontal or vertical. */
864 if (*pov == *pev) {
865 /* We're going to round the endpoint coordinates, so */
866 /* take the fill adjustment into account now. */
867 if (w >= 0)
868 w2 += adj2;
869 else
870 w2 = adj2 - w2;
871 if (w2 & fixed_1) /* odd width, move to half-pixel */
872 *pov = *pev = fixed_floor(*pov) + fixed_half;
873 else /* even width, move to pixel */
874 *pov = *pev = fixed_rounded(*pov);
875
876 }
877 }
878
879 /* Compute the intersection of two lines. This is a messy algorithm */
880 /* that somehow ought to be useful in more places than just here.... */
881 /* If the lines are (nearly) parallel, return -1 without setting *pi; */
882 /* otherwise, return 0 if the intersection is beyond *pp1 and *pp2 in */
883 /* the direction determined by *pd1 and *pd2, and 1 otherwise. */
884 private int
line_intersect(p_ptr pp1,p_ptr pd1,p_ptr pp2,p_ptr pd2,p_ptr pi)885 line_intersect(
886 p_ptr pp1, /* point on 1st line */
887 p_ptr pd1, /* slope of 1st line (dx,dy) */
888 p_ptr pp2, /* point on 2nd line */
889 p_ptr pd2, /* slope of 2nd line */
890 p_ptr pi)
891 { /* return intersection here */
892 /* We don't have to do any scaling, the factors all work out right. */
893 double u1 = pd1->x, v1 = pd1->y;
894 double u2 = pd2->x, v2 = pd2->y;
895 double denom = u1 * v2 - u2 * v1;
896 double xdiff = pp2->x - pp1->x;
897 double ydiff = pp2->y - pp1->y;
898 double f1;
899 double max_result = any_abs(denom) * (double)max_fixed;
900
901 #ifdef DEBUG
902 if (gs_debug_c('O')) {
903 dlprintf4("[o]Intersect %f,%f(%f/%f)",
904 fixed2float(pp1->x), fixed2float(pp1->y),
905 fixed2float(pd1->x), fixed2float(pd1->y));
906 dlprintf4(" & %f,%f(%f/%f),\n",
907 fixed2float(pp2->x), fixed2float(pp2->y),
908 fixed2float(pd2->x), fixed2float(pd2->y));
909 dlprintf3("\txdiff=%f ydiff=%f denom=%f ->\n",
910 xdiff, ydiff, denom);
911 }
912 #endif
913 /* Check for degenerate result. */
914 if (any_abs(xdiff) >= max_result || any_abs(ydiff) >= max_result) {
915 /* The lines are nearly parallel, */
916 /* or one of them has zero length. Punt. */
917 if_debug0('O', "\tdegenerate!\n");
918 return -1;
919 }
920 f1 = (v2 * xdiff - u2 * ydiff) / denom;
921 pi->x = pp1->x + (fixed) (f1 * u1);
922 pi->y = pp1->y + (fixed) (f1 * v1);
923 if_debug2('O', "\t%f,%f\n",
924 fixed2float(pi->x), fixed2float(pi->y));
925 return (f1 >= 0 && (v1 * xdiff >= u1 * ydiff ? denom >= 0 : denom < 0) ? 0 : 1);
926 }
927
928 /* Set up the width and delta parameters for a thin line. */
929 /* We only approximate the width and height. */
930 private void
set_thin_widths(register pl_ptr plp)931 set_thin_widths(register pl_ptr plp)
932 {
933 fixed dx = plp->e.p.x - plp->o.p.x, dy = plp->e.p.y - plp->o.p.y;
934
935 #define TRSIGN(v, c) ((v) >= 0 ? (c) : -(c))
936 if (any_abs(dx) > any_abs(dy)) {
937 plp->width.x = plp->e.cdelta.y = 0;
938 plp->width.y = plp->e.cdelta.x = TRSIGN(dx, fixed_half);
939 } else {
940 plp->width.y = plp->e.cdelta.x = 0;
941 plp->width.x = -(plp->e.cdelta.y = TRSIGN(dy, fixed_half));
942 }
943 #undef TRSIGN
944 }
945
946 /* Draw a line on the device. */
947 /* Treat no join the same as a bevel join. */
948 private int
stroke_fill(gx_path * ppath,int first,register pl_ptr plp,pl_ptr nplp,const gx_device_color * pdevc,gx_device * dev,const gs_imager_state * pis,const gx_stroke_params * params,const gs_fixed_rect * pbbox,int uniform,gs_line_join join,bool reflected)949 stroke_fill(gx_path * ppath, int first, register pl_ptr plp, pl_ptr nplp,
950 const gx_device_color * pdevc, gx_device * dev,
951 const gs_imager_state * pis, const gx_stroke_params * params,
952 const gs_fixed_rect * pbbox, int uniform, gs_line_join join,
953 bool reflected)
954 {
955 const fixed lix = plp->o.p.x;
956 const fixed liy = plp->o.p.y;
957 const fixed litox = plp->e.p.x;
958 const fixed litoy = plp->e.p.y;
959
960 if (plp->thin) {
961 /* Minimum-width line, don't have to be careful with caps/joins. */
962 return (*dev_proc(dev, draw_thin_line))(dev, lix, liy, litox, litoy,
963 pdevc, pis->log_op);
964 }
965 /* Check for being able to fill directly. */
966 {
967 const gx_line_params *pgs_lp = gs_currentlineparams_inline(pis);
968 gs_line_cap cap = pgs_lp->cap;
969
970 if (!plp->thin && (nplp == 0 || !nplp->thin)
971 && ((first != 0 && nplp != 0) || cap == gs_cap_butt
972 || cap == gs_cap_square)
973 && (join == gs_join_bevel || join == gs_join_miter ||
974 join == gs_join_none)
975 && (pis->fill_adjust.x | pis->fill_adjust.y) == 0
976 && lop_is_idempotent(pis->log_op)
977 ) {
978 gs_fixed_point points[6];
979 int npoints, code;
980 fixed ax, ay, bx, by;
981
982 npoints = cap_points((first == 0 ? cap : gs_cap_butt),
983 &plp->o, points);
984 if (nplp == 0)
985 code = cap_points(cap, &plp->e, points + npoints);
986 else
987 code = line_join_points(pgs_lp, plp, nplp, points + npoints,
988 (uniform ? (gs_matrix *) 0 :
989 &ctm_only(pis)), join, reflected);
990 if (code < 0)
991 goto general;
992 /* Make sure the parallelogram fill won't overflow. */
993 #define SUB_OVERFLOWS(r, u, v)\
994 (((r = u - v) ^ u) < 0 && (u ^ v) < 0)
995 if (SUB_OVERFLOWS(ax, points[0].x, points[1].x) ||
996 SUB_OVERFLOWS(ay, points[0].y, points[1].y) ||
997 SUB_OVERFLOWS(bx, points[2].x, points[1].x) ||
998 SUB_OVERFLOWS(by, points[2].y, points[1].y)
999 )
1000 goto general;
1001 #undef SUB_OVERFLOWS
1002 if (nplp != 0) {
1003 if (join == gs_join_miter) {
1004 /* Make sure we have a bevel and not a miter. */
1005 if (!(points[2].x == plp->e.co.x &&
1006 points[2].y == plp->e.co.y &&
1007 points[5].x == plp->e.ce.x &&
1008 points[5].y == plp->e.ce.y)
1009 )
1010 goto fill;
1011 } {
1012 const gs_fixed_point *bevel = points + 2;
1013
1014 /* Identify which 3 points define the bevel triangle. */
1015 if (points[3].x == nplp->o.p.x &&
1016 points[3].y == nplp->o.p.y
1017 )
1018 ++bevel;
1019 /* Fill the bevel. */
1020 code = (*dev_proc(dev, fill_triangle)) (dev,
1021 bevel->x, bevel->y,
1022 bevel[1].x - bevel->x, bevel[1].y - bevel->y,
1023 bevel[2].x - bevel->x, bevel[2].y - bevel->y,
1024 pdevc, pis->log_op);
1025 if (code < 0)
1026 return code;
1027 }
1028 }
1029 /* Fill the body of the stroke. */
1030 return (*dev_proc(dev, fill_parallelogram)) (dev,
1031 points[1].x, points[1].y,
1032 ax, ay, bx, by,
1033 pdevc, pis->log_op);
1034 fill:
1035 code = add_points(ppath, points, npoints + code, true);
1036 if (code < 0)
1037 return code;
1038 return gx_path_close_subpath(ppath);
1039 }
1040 }
1041 /* General case: construct a path for the fill algorithm. */
1042 general:
1043 return stroke_add(ppath, first, plp, nplp, pdevc, dev, pis, params,
1044 pbbox, uniform, join, reflected);
1045 }
1046
1047 /* Add a segment to the path. This handles all the complex cases. */
1048 private int
stroke_add(gx_path * ppath,int first,pl_ptr plp,pl_ptr nplp,const gx_device_color * pdevc,gx_device * dev,const gs_imager_state * pis,const gx_stroke_params * params,const gs_fixed_rect * ignore_pbbox,int uniform,gs_line_join join,bool reflected)1049 stroke_add(gx_path * ppath, int first, pl_ptr plp, pl_ptr nplp,
1050 const gx_device_color * pdevc, gx_device * dev,
1051 const gs_imager_state * pis, const gx_stroke_params * params,
1052 const gs_fixed_rect * ignore_pbbox, int uniform, gs_line_join join,
1053 bool reflected)
1054 {
1055 const gx_line_params *pgs_lp = gs_currentlineparams_inline(pis);
1056 gs_fixed_point points[8];
1057 int npoints;
1058 int code;
1059 bool moveto_first = true;
1060
1061 if (plp->thin) {
1062 /* We didn't set up the endpoint parameters before, */
1063 /* because the line was thin. Do it now. */
1064 set_thin_widths(plp);
1065 adjust_stroke(plp, pis, true);
1066 compute_caps(plp);
1067 }
1068 /* Create an initial cap if desired. */
1069 if (first == 0 && pgs_lp->cap == gs_cap_round) {
1070 vd_moveto(plp->o.co.x, plp->o.co.y);
1071 if ((code = gx_path_add_point(ppath, plp->o.co.x, plp->o.co.y)) < 0 ||
1072 (code = add_round_cap(ppath, &plp->o)) < 0
1073 )
1074 return code;
1075 npoints = 0;
1076 moveto_first = false;
1077 } else {
1078 if ((npoints = cap_points((first == 0 ? pgs_lp->cap : gs_cap_butt), &plp->o, points)) < 0)
1079 return npoints;
1080 }
1081 if (nplp == 0) {
1082 /* Add a final cap. */
1083 if (pgs_lp->cap == gs_cap_round) {
1084 ASSIGN_POINT(&points[npoints], plp->e.co);
1085 vd_lineto(points[npoints].x, points[npoints].y);
1086 ++npoints;
1087 if ((code = add_points(ppath, points, npoints, moveto_first)) < 0)
1088 return code;
1089 code = add_round_cap(ppath, &plp->e);
1090 goto done;
1091 }
1092 code = cap_points(pgs_lp->cap, &plp->e, points + npoints);
1093 } else if (join == gs_join_round) {
1094 ASSIGN_POINT(&points[npoints], plp->e.co);
1095 vd_lineto(points[npoints].x, points[npoints].y);
1096 ++npoints;
1097 if ((code = add_points(ppath, points, npoints, moveto_first)) < 0)
1098 return code;
1099 code = add_round_cap(ppath, &plp->e);
1100 goto done;
1101 } else if (nplp->thin) /* no join */
1102 code = cap_points(gs_cap_butt, &plp->e, points + npoints);
1103 else /* non-round join */
1104 code = line_join_points(pgs_lp, plp, nplp, points + npoints,
1105 (uniform ? (gs_matrix *) 0 : &ctm_only(pis)),
1106 join, reflected);
1107 if (code < 0)
1108 return code;
1109 code = add_points(ppath, points, npoints + code, moveto_first);
1110 done:
1111 if (code < 0)
1112 return code;
1113 vd_closepath;
1114 return gx_path_close_subpath(ppath);
1115 }
1116
1117 /* Add lines with a possible initial moveto. */
1118 private int
add_points(gx_path * ppath,const gs_fixed_point * points,int npoints,bool moveto_first)1119 add_points(gx_path * ppath, const gs_fixed_point * points, int npoints,
1120 bool moveto_first)
1121 {
1122 int code;
1123
1124 vd_setcolor(0);
1125 vd_setlinewidth(0);
1126 if (moveto_first) {
1127 code = gx_path_add_point(ppath, points[0].x, points[0].y);
1128 vd_moveto(points[0].x, points[0].y);
1129 if (code < 0)
1130 return code;
1131 vd_lineto_multi(points + 1, npoints - 1);
1132 return gx_path_add_lines(ppath, points + 1, npoints - 1);
1133 } else {
1134 vd_lineto_multi(points, npoints);
1135 return gx_path_add_lines(ppath, points, npoints);
1136 }
1137 }
1138
1139 /* ---------------- Join computation ---------------- */
1140
1141 /* Compute the points for a bevel, miter, or triangle join. */
1142 /* Treat no join the same as a bevel join. */
1143 /* If pmat != 0, we must inverse-transform the distances for */
1144 /* the miter check. */
1145 private int
line_join_points(const gx_line_params * pgs_lp,pl_ptr plp,pl_ptr nplp,gs_fixed_point * join_points,const gs_matrix * pmat,gs_line_join join,bool reflected)1146 line_join_points(const gx_line_params * pgs_lp, pl_ptr plp, pl_ptr nplp,
1147 gs_fixed_point * join_points, const gs_matrix * pmat,
1148 gs_line_join join, bool reflected)
1149 {
1150 #define jp1 join_points[0]
1151 #define np1 join_points[1]
1152 #define np2 join_points[2]
1153 #define jp2 join_points[3]
1154 #define jpx join_points[4]
1155 /*
1156 * Set np to whichever of nplp->o.co or .ce is outside
1157 * the current line. We observe that the point (x2,y2)
1158 * is counter-clockwise from (x1,y1), relative to the origin,
1159 * iff
1160 * (arctan(y2/x2) - arctan(y1/x1)) mod 2*pi < pi,
1161 * taking the signs of xi and yi into account to determine
1162 * the quadrants of the results. It turns out that
1163 * even though arctan is monotonic only in the 4th/1st
1164 * quadrants and the 2nd/3rd quadrants, case analysis on
1165 * the signs of xi and yi demonstrates that this test
1166 * is equivalent to the much less expensive test
1167 * x1 * y2 > x2 * y1
1168 * in all cases.
1169 *
1170 * In the present instance, x1,y1 are plp->width,
1171 * x2,y2 are nplp->width, and the origin is
1172 * their common point (plp->e.p, nplp->o.p).
1173 * ccw will be true iff nplp.o.co (nplp.o.p + width) is
1174 * counter-clockwise from plp.e.ce (plp.e.p + width),
1175 * in which case we want tan(a-b) rather than tan(b-a).
1176 *
1177 * We make the test using double arithmetic only because
1178 * the !@#&^*% C language doesn't give us access to
1179 * the double-width-result multiplication operation
1180 * that almost all CPUs provide!
1181 */
1182 bool ccw =
1183 (double)(plp->width.x) /* x1 */ * (nplp->width.y) /* y2 */ >
1184 (double)(nplp->width.x) /* x2 */ * (plp->width.y) /* y1 */;
1185 bool ccw0 = ccw;
1186 p_ptr outp, np;
1187
1188 ccw ^= reflected;
1189
1190 /* Initialize for a bevel join. */
1191 ASSIGN_POINT(&jp1, plp->e.co);
1192 ASSIGN_POINT(&jp2, plp->e.ce);
1193
1194 /*
1195 * Because of stroke adjustment, it is possible that
1196 * plp->e.p != nplp->o.p. For that reason, we must use
1197 * nplp->o.p as np1 or np2.
1198 */
1199 if (!ccw) {
1200 outp = &jp2;
1201 ASSIGN_POINT(&np2, nplp->o.co);
1202 ASSIGN_POINT(&np1, nplp->o.p);
1203 np = &np2;
1204 } else {
1205 outp = &jp1;
1206 ASSIGN_POINT(&np1, nplp->o.ce);
1207 ASSIGN_POINT(&np2, nplp->o.p);
1208 np = &np1;
1209 }
1210 if_debug1('O', "[o]use %s\n", (ccw ? "co (ccw)" : "ce (cw)"));
1211
1212 /* Handle triangular joins now. */
1213 if (join == gs_join_triangle) {
1214 fixed tpx = outp->x - nplp->o.p.x + np->x;
1215 fixed tpy = outp->y - nplp->o.p.y + np->y;
1216
1217 ASSIGN_POINT(&jpx, jp2);
1218 if (!ccw) {
1219 /* Insert tp between np2 and jp2. */
1220 jp2.x = tpx, jp2.y = tpy;
1221 } else {
1222 /* Insert tp between jp1 and np1. */
1223 ASSIGN_POINT(&jp2, np2);
1224 ASSIGN_POINT(&np2, np1);
1225 np1.x = tpx, np1.y = tpy;
1226 }
1227 return 5;
1228 }
1229 /*
1230 * Don't bother with the miter check if the two
1231 * points to be joined are very close together,
1232 * namely, in the same square half-pixel.
1233 */
1234 if (join == gs_join_miter &&
1235 !(fixed2long(outp->x << 1) == fixed2long(np->x << 1) &&
1236 fixed2long(outp->y << 1) == fixed2long(np->y << 1))
1237 ) {
1238 /*
1239 * Check whether a miter join is appropriate.
1240 * Let a, b be the angles of the two lines.
1241 * We check tan(a-b) against the miter_check
1242 * by using the following formula:
1243 * If tan(a)=u1/v1 and tan(b)=u2/v2, then
1244 * tan(a-b) = (u1*v2 - u2*v1) / (u1*u2 + v1*v2).
1245 *
1246 * We can do all the computations unscaled,
1247 * because we're only concerned with ratios.
1248 * However, if we have a non-uniform coordinate
1249 * system (indicated by pmat != 0), we must do the
1250 * computations in user space.
1251 */
1252 float check = pgs_lp->miter_check;
1253 double u1 = plp->e.cdelta.y, v1 = plp->e.cdelta.x;
1254 double u2 = nplp->o.cdelta.y, v2 = nplp->o.cdelta.x;
1255 double num, denom;
1256 int code;
1257
1258 if (pmat) {
1259 gs_point pt;
1260
1261 code = gs_distance_transform_inverse(v1, u1, pmat, &pt);
1262 if (code < 0)
1263 return code;
1264 v1 = pt.x, u1 = pt.y;
1265 code = gs_distance_transform_inverse(v2, u2, pmat, &pt);
1266 if (code < 0)
1267 return code;
1268 v2 = pt.x, u2 = pt.y;
1269 /*
1270 * We need to recompute ccw according to the
1271 * relative positions of the lines in user space.
1272 * We repeat the computation described above,
1273 * using the cdelta values instead of the widths.
1274 * Because the definition of ccw above is inverted
1275 * from the intuitive one (for historical reasons),
1276 * we actually have to do the test backwards.
1277 */
1278 ccw0 = v1 * u2 < v2 * u1;
1279 #ifdef DEBUG
1280 {
1281 double a1 = atan2(u1, v1), a2 = atan2(u2, v2), dif = a1 - a2;
1282
1283 if (dif < 0)
1284 dif += 2 * M_PI;
1285 else if (dif >= 2 * M_PI)
1286 dif -= 2 * M_PI;
1287 if (dif != 0 && (dif < M_PI) != ccw0)
1288 lprintf8("ccw wrong: tan(a1=%g)=%g/%g, tan(a2=%g)=%g,%g, dif=%g, ccw=%d\n",
1289 a1, u1, v1, a2, u2, v2, dif, ccw);
1290 }
1291 #endif
1292 }
1293 num = u1 * v2 - u2 * v1;
1294 denom = u1 * u2 + v1 * v2;
1295 /*
1296 * We will want either tan(a-b) or tan(b-a)
1297 * depending on the orientations of the lines.
1298 * Fortunately we know the relative orientations already.
1299 */
1300 if (!ccw0) /* have plp - nplp, want vice versa */
1301 num = -num;
1302 #ifdef DEBUG
1303 if (gs_debug_c('O')) {
1304 dlprintf4("[o]Miter check: u1/v1=%f/%f, u2/v2=%f/%f,\n",
1305 u1, v1, u2, v2);
1306 dlprintf3(" num=%f, denom=%f, check=%f\n",
1307 num, denom, check);
1308 }
1309 #endif
1310 /*
1311 * If we define T = num / denom, then we want to use
1312 * a miter join iff arctan(T) >= arctan(check).
1313 * We know that both of these angles are in the 1st
1314 * or 2nd quadrant, and since arctan is monotonic
1315 * within each quadrant, we can do the comparisons
1316 * on T and check directly, taking signs into account
1317 * as follows:
1318 * sign(T) sign(check) atan(T) >= atan(check)
1319 * ------- ----------- ----------------------
1320 * + + T >= check
1321 * - + true
1322 * + - false
1323 * - - T >= check
1324 */
1325 if (denom < 0)
1326 num = -num, denom = -denom;
1327 /* Now denom >= 0, so sign(num) = sign(T). */
1328 if (check > 0 ?
1329 (num < 0 || num >= denom * check) :
1330 (num < 0 && num >= denom * check)
1331 ) {
1332 /* OK to use a miter join. */
1333 gs_fixed_point mpt;
1334
1335 if_debug0('O', " ... passes.\n");
1336 /* Compute the intersection of */
1337 /* the extended edge lines. */
1338 if (line_intersect(outp, &plp->e.cdelta, np,
1339 &nplp->o.cdelta, &mpt) == 0
1340 )
1341 ASSIGN_POINT(outp, mpt);
1342 }
1343 }
1344 return 4;
1345 }
1346 /* ---------------- Cap computations ---------------- */
1347
1348 /* Compute the endpoints of the two caps of a segment. */
1349 /* Only o.p, e.p, width, and cdelta have been set. */
1350 private void
compute_caps(pl_ptr plp)1351 compute_caps(pl_ptr plp)
1352 {
1353 fixed wx2 = plp->width.x;
1354 fixed wy2 = plp->width.y;
1355
1356 plp->o.co.x = plp->o.p.x + wx2, plp->o.co.y = plp->o.p.y + wy2;
1357 plp->o.cdelta.x = -plp->e.cdelta.x,
1358 plp->o.cdelta.y = -plp->e.cdelta.y;
1359 plp->o.ce.x = plp->o.p.x - wx2, plp->o.ce.y = plp->o.p.y - wy2;
1360 plp->e.co.x = plp->e.p.x - wx2, plp->e.co.y = plp->e.p.y - wy2;
1361 plp->e.ce.x = plp->e.p.x + wx2, plp->e.ce.y = plp->e.p.y + wy2;
1362 #ifdef DEBUG
1363 if (gs_debug_c('O')) {
1364 dlprintf4("[o]Stroke o=(%f,%f) e=(%f,%f)\n",
1365 fixed2float(plp->o.p.x), fixed2float(plp->o.p.y),
1366 fixed2float(plp->e.p.x), fixed2float(plp->e.p.y));
1367 dlprintf4("\twxy=(%f,%f) lxy=(%f,%f)\n",
1368 fixed2float(wx2), fixed2float(wy2),
1369 fixed2float(plp->e.cdelta.x),
1370 fixed2float(plp->e.cdelta.y));
1371 }
1372 #endif
1373 }
1374
1375 #define px endp->p.x
1376 #define py endp->p.y
1377 #define xo endp->co.x
1378 #define yo endp->co.y
1379 #define xe endp->ce.x
1380 #define ye endp->ce.y
1381 #define cdx endp->cdelta.x
1382 #define cdy endp->cdelta.y
1383
1384 /* Add a round cap to a path. */
1385 /* Assume the current point is the cap origin (endp->co). */
1386 private int
add_round_cap(gx_path * ppath,const_ep_ptr endp)1387 add_round_cap(gx_path * ppath, const_ep_ptr endp)
1388 {
1389 int code;
1390
1391 /*
1392 * Per the Red Book, we draw a full circle, even though a semicircle
1393 * is sufficient for the join.
1394 */
1395 if ((code = gx_path_add_partial_arc(ppath, px + cdx, py + cdy,
1396 xo + cdx, yo + cdy,
1397 quarter_arc_fraction)) < 0 ||
1398 (code = gx_path_add_partial_arc(ppath, xe, ye, xe + cdx, ye + cdy,
1399 quarter_arc_fraction)) < 0 ||
1400 (code = gx_path_add_partial_arc(ppath, px - cdx, py - cdy,
1401 xe - cdx, ye - cdy,
1402 quarter_arc_fraction)) < 0 ||
1403 (code = gx_path_add_partial_arc(ppath, xo, yo, xo - cdx, yo - cdy,
1404 quarter_arc_fraction)) < 0 ||
1405 /* The final point must be (xe,ye). */
1406 (code = gx_path_add_line(ppath, xe, ye)) < 0
1407 )
1408 return code;
1409 vd_lineto(xe, ye);
1410 return 0;
1411 }
1412
1413 /* Compute the points for a non-round cap. */
1414 /* Return the number of points. */
1415 private int
cap_points(gs_line_cap type,const_ep_ptr endp,gs_fixed_point * pts)1416 cap_points(gs_line_cap type, const_ep_ptr endp, gs_fixed_point *pts /*[3]*/)
1417 {
1418 #define PUT_POINT(i, px, py)\
1419 pts[i].x = (px), pts[i].y = (py)
1420 switch (type) {
1421 case gs_cap_butt:
1422 PUT_POINT(0, xo, yo);
1423 PUT_POINT(1, xe, ye);
1424 return 2;
1425 case gs_cap_square:
1426 PUT_POINT(0, xo + cdx, yo + cdy);
1427 PUT_POINT(1, xe + cdx, ye + cdy);
1428 return 2;
1429 case gs_cap_triangle: /* (not supported by PostScript) */
1430 PUT_POINT(0, xo, yo);
1431 PUT_POINT(1, px + cdx, py + cdy);
1432 PUT_POINT(2, xe, ye);
1433 return 3;
1434 default: /* can't happen */
1435 return_error(gs_error_unregistered);
1436 }
1437 #undef PUT_POINT
1438 }
1439