Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1995, 1996, 1997, 1998 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: gxpdash.c,v 1.6 2004/10/18 15:23:20 igor Exp $ */
18
/* Dash expansion for paths */
19
#include "math_.h"
20
#include "gx.h"
21
#include "gsmatrix.h"		/* for gscoord.h */
22
#include "gscoord.h"
23
#include "gxfixed.h"
24
#include "gsline.h"
25
#include "gzline.h"
26
#include "gzpath.h"
27
 
28
/* Expand a dashed path into explicit segments. */
29
/* The path contains no curves. */
30
private int subpath_expand_dashes(const subpath *, gx_path *,
31
				  const gs_imager_state *,
32
				  const gx_dash_params *);
33
int
34
gx_path_add_dash_expansion(const gx_path * ppath_old, gx_path * ppath,
35
			   const gs_imager_state * pis)
36
{
37
    const subpath *psub;
38
    const gx_dash_params *dash = &gs_currentlineparams(pis)->dash;
39
    int code = 0;
40
 
41
    if (dash->pattern_size == 0)
42
	return gx_path_copy(ppath_old, ppath);
43
    for (psub = ppath_old->first_subpath; psub != 0 && code >= 0;
44
	 psub = (const subpath *)psub->last->next
45
	)
46
	code = subpath_expand_dashes(psub, ppath, pis, dash);
47
    return code;
48
}
49
 
50
private int
51
subpath_expand_dashes(const subpath * psub, gx_path * ppath,
52
		   const gs_imager_state * pis, const gx_dash_params * dash)
53
{
54
    const float *pattern = dash->pattern;
55
    int count, index;
56
    bool ink_on;
57
    double elt_length;
58
    fixed x0 = psub->pt.x, y0 = psub->pt.y;
59
    fixed x, y;
60
    const segment *pseg;
61
    int wrap = (dash->init_ink_on && psub->is_closed ? -1 : 0);
62
    int drawing = wrap;
63
    segment_notes notes = ~sn_not_first;
64
    int code;
65
 
66
    if ((code = gx_path_add_point(ppath, x0, y0)) < 0)
67
	return code;
68
    /*
69
     * To do the right thing at the beginning of a closed path, we have
70
     * to skip any initial line, and then redo it at the end of the
71
     * path.  Drawing = -1 while skipping, 0 while drawing normally, and
72
     * 1 on the second round.  Note that drawing != 0 implies ink_on.
73
     */
74
  top:count = dash->pattern_size;
75
    ink_on = dash->init_ink_on;
76
    index = dash->init_index;
77
    elt_length = dash->init_dist_left;
78
    x = x0, y = y0;
79
    pseg = (const segment *)psub;
80
    while ((pseg = pseg->next) != 0 && pseg->type != s_start) {
81
	fixed sx = pseg->pt.x, sy = pseg->pt.y;
82
	fixed udx = sx - x, udy = sy - y;
83
	double length, dx, dy;
84
	double scale = 1;
85
	double left;
86
 
87
	if (!(udx | udy)) {	/* degenerate */
88
	    if (gs_currentlinecap((const gs_state *)pis) != gs_cap_round) {
89
		/* From PLRM, stroke operator :
90
		   If a subpath is degenerate (consists of a single-point closed path 
91
		   or of two or more points at the same coordinates), 
92
		   stroke paints it only if round line caps have been specified */
93
		continue;
94
	    }
95
	    dx = 0, dy = 0, length = 0;
96
	} else {
97
  	    gs_point d;
98
 
99
	    dx = udx, dy = udy;	/* scaled as fixed */
100
	    gs_imager_idtransform(pis, dx, dy, &d);
101
	    length = hypot(d.x, d.y) * (1.0 / fixed_1);
102
	    if (gs_imager_currentdashadapt(pis)) {
103
		double reps = length / dash->pattern_length;
104
 
105
		scale = reps / ceil(reps);
106
		/* Ensure we're starting at the start of a */
107
		/* repetition.  (This shouldn't be necessary, */
108
		/* but it is.) */
109
		count = dash->pattern_size;
110
		ink_on = dash->init_ink_on;
111
		index = dash->init_index;
112
		elt_length = dash->init_dist_left * scale;
113
	    }
114
	}
115
	left = length;
116
	while (left > elt_length) {	/* We are using up the line segment. */
117
	    double fraction = elt_length / length;
118
	    fixed nx = x + (fixed) (dx * fraction);
119
	    fixed ny = y + (fixed) (dy * fraction);
120
 
121
	    if (ink_on) {
122
		if (drawing >= 0)
123
		    code = gx_path_add_line_notes(ppath, nx, ny,
124
						  notes & pseg->notes);
125
		notes |= sn_not_first;
126
	    } else {
127
		if (drawing > 0)	/* done */
128
		    return 0;
129
		code = gx_path_add_point(ppath, nx, ny);
130
		notes &= ~sn_not_first;
131
		drawing = 0;
132
	    }
133
	    if (code < 0)
134
		return code;
135
	    left -= elt_length;
136
	    ink_on = !ink_on;
137
	    if (++index == count)
138
		index = 0;
139
	    elt_length = pattern[index] * scale;
140
	    x = nx, y = ny;
141
	}
142
	elt_length -= left;
143
	/* Handle the last dash of a segment. */
144
      on:if (ink_on) {
145
	    if (drawing >= 0) {
146
		code =
147
		    (pseg->type == s_line_close && drawing > 0 ?
148
		     gx_path_close_subpath_notes(ppath,
149
						 notes & pseg->notes) :
150
		     gx_path_add_line_notes(ppath, sx, sy,
151
					    notes & pseg->notes));
152
		notes |= sn_not_first;
153
	    }
154
	} else {
155
	    code = gx_path_add_point(ppath, sx, sy);
156
	    notes &= ~sn_not_first;
157
	    if (elt_length < fixed2float(fixed_epsilon) &&
158
		(pseg->next == 0 || pseg->next->type == s_start)
159
		) {		/*
160
				 * Ink is off, but we're within epsilon of the end
161
				 * of the dash element, and at the end of the
162
				 * subpath.  "Stretch" a little so we get a dot.
163
				 */
164
		if (code < 0)
165
		    return code;
166
		elt_length = 0;
167
		ink_on = true;
168
		if (++index == count)
169
		    index = 0;
170
		elt_length = pattern[index] * scale;
171
		goto on;
172
	    }
173
	    if (drawing > 0)	/* done */
174
		return code;
175
	    drawing = 0;
176
	}
177
	if (code < 0)
178
	    return code;
179
	x = sx, y = sy;
180
    }
181
    /* Check for wraparound. */
182
    if (wrap && drawing <= 0) {	/* We skipped some initial lines. */
183
	/* Go back and do them now. */
184
	drawing = 1;
185
	goto top;
186
    }
187
    return 0;
188
}