xref: /plan9/sys/src/cmd/gs/src/gxstroke.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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