1 /* Copyright (C) 1989, 1995, 1996, 1997, 1999 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: gsline.c,v 1.2.6.1.2.1 2003/01/17 00:49:02 giles Exp $ */
20 /* Line parameter operators for Ghostscript library */
21 #include "math_.h"
22 #include "memory_.h"
23 #include "gx.h"
24 #include "gserrors.h"
25 #include "gxfixed.h"		/* ditto */
26 #include "gxmatrix.h"		/* for gzstate */
27 #include "gzstate.h"
28 #include "gscoord.h"		/* for currentmatrix, setmatrix */
29 #include "gsline.h"		/* for prototypes */
30 #include "gzline.h"
31 
32 /* ------ Device-independent parameters ------ */
33 
34 #define pgs_lp gs_currentlineparams_inline(pgs)
35 
36 /* setlinewidth */
37 int
gs_setlinewidth(gs_state * pgs,floatp width)38 gs_setlinewidth(gs_state * pgs, floatp width)
39 {
40     gx_set_line_width(pgs_lp, width);
41     return 0;
42 }
43 
44 /* currentlinewidth */
45 float
gs_currentlinewidth(const gs_state * pgs)46 gs_currentlinewidth(const gs_state * pgs)
47 {
48     return gx_current_line_width(pgs_lp);
49 }
50 
51 /* setlinecap */
52 int
gs_setlinecap(gs_state * pgs,gs_line_cap cap)53 gs_setlinecap(gs_state * pgs, gs_line_cap cap)
54 {
55     if ((uint) cap > gs_line_cap_max)
56 	return_error(gs_error_rangecheck);
57     pgs_lp->cap = cap;
58     return 0;
59 }
60 
61 /* currentlinecap */
62 gs_line_cap
gs_currentlinecap(const gs_state * pgs)63 gs_currentlinecap(const gs_state * pgs)
64 {
65     return pgs_lp->cap;
66 }
67 
68 /* setlinejoin */
69 int
gs_setlinejoin(gs_state * pgs,gs_line_join join)70 gs_setlinejoin(gs_state * pgs, gs_line_join join)
71 {
72     if ((uint) join > gs_line_join_max)
73 	return_error(gs_error_rangecheck);
74     pgs_lp->join = join;
75     return 0;
76 }
77 
78 /* currentlinejoin */
79 gs_line_join
gs_currentlinejoin(const gs_state * pgs)80 gs_currentlinejoin(const gs_state * pgs)
81 {
82     return pgs_lp->join;
83 }
84 
85 /* setmiterlimit */
86 int
gx_set_miter_limit(gx_line_params * plp,floatp limit)87 gx_set_miter_limit(gx_line_params * plp, floatp limit)
88 {
89     if (limit < 1.0)
90 	return_error(gs_error_rangecheck);
91     plp->miter_limit = limit;
92     /*
93      * Compute the miter check value.  The supplied miter limit is an
94      * upper bound on 1/sin(phi/2); we convert this to a lower bound on
95      * tan(phi).  Note that if phi > pi/2, this is negative.  We use the
96      * half-angle and angle-sum formulas here to avoid the trig functions.
97      * We also need a special check for phi/2 close to pi/4.
98      * Some C compilers can't handle this as a conditional expression....
99      */
100     {
101 	double limit_squared = limit * limit;
102 
103 	if (limit_squared < 2.0001 && limit_squared > 1.9999)
104 	    plp->miter_check = 1.0e6;
105 	else
106 	    plp->miter_check =
107 		sqrt(limit_squared - 1) * 2 / (limit_squared - 2);
108     }
109     return 0;
110 }
111 int
gs_setmiterlimit(gs_state * pgs,floatp limit)112 gs_setmiterlimit(gs_state * pgs, floatp limit)
113 {
114     return gx_set_miter_limit(pgs_lp, limit);
115 }
116 
117 /* currentmiterlimit */
118 float
gs_currentmiterlimit(const gs_state * pgs)119 gs_currentmiterlimit(const gs_state * pgs)
120 {
121     return pgs_lp->miter_limit;
122 }
123 
124 /* setdash */
125 int
gx_set_dash(gx_dash_params * dash,const float * pattern,uint length,floatp offset,gs_memory_t * mem)126 gx_set_dash(gx_dash_params * dash, const float *pattern, uint length,
127 	    floatp offset, gs_memory_t * mem)
128 {
129     uint n = length;
130     const float *dfrom = pattern;
131     bool ink = true;
132     int index = 0;
133     float pattern_length = 0.0;
134     float dist_left;
135     float *ppat = dash->pattern;
136 
137     /* Check the dash pattern. */
138     while (n--) {
139 	float elt = *dfrom++;
140 
141 	if (elt < 0)
142 	    return_error(gs_error_rangecheck);
143 	pattern_length += elt;
144     }
145     if (length == 0) {		/* empty pattern */
146 	dist_left = 0.0;
147 	if (mem && ppat) {
148 	    gs_free_object(mem, ppat, "gx_set_dash(old pattern)");
149 	    ppat = 0;
150 	}
151     } else {
152 	uint size = length * sizeof(float);
153 
154 	if (pattern_length == 0)
155 	    return_error(gs_error_rangecheck);
156 	/* Compute the initial index, ink_on, and distance left */
157 	/* in the pattern, according to the offset. */
158 #define f_mod(a, b) ((a) - floor((a) / (b)) * (b))
159 	if (length & 1) {	/* Odd and even repetitions of the pattern */
160 	    /* have opposite ink values! */
161 	    float length2 = pattern_length * 2;
162 
163 	    dist_left = f_mod(offset, length2);
164 	    if (dist_left >= pattern_length)
165 		dist_left -= pattern_length, ink = !ink;
166 	} else
167 	    dist_left = f_mod(offset, pattern_length);
168 	while ((dist_left -= pattern[index]) >= 0 &&
169 	       (dist_left > 0 || pattern[index] != 0)
170 	    )
171 	    ink = !ink, index++;
172 	if (mem) {
173 	    if (ppat == 0)
174 		ppat = (float *)gs_alloc_bytes(mem, size,
175 					       "gx_set_dash(pattern)");
176 	    else if (length != dash->pattern_size)
177 		ppat = gs_resize_object(mem, ppat, size,
178 					"gx_set_dash(pattern)");
179 	    if (ppat == 0)
180 		return_error(gs_error_VMerror);
181 	}
182 	memcpy(ppat, pattern, length * sizeof(float));
183     }
184     dash->pattern = ppat;
185     dash->pattern_size = length;
186     dash->offset = offset;
187     dash->pattern_length = pattern_length;
188     dash->init_ink_on = ink;
189     dash->init_index = index;
190     dash->init_dist_left = -dist_left;
191     return 0;
192 }
193 int
gs_setdash(gs_state * pgs,const float * pattern,uint length,floatp offset)194 gs_setdash(gs_state * pgs, const float *pattern, uint length, floatp offset)
195 {
196     return gx_set_dash(&pgs_lp->dash, pattern, length, offset,
197 		       pgs->memory);
198 }
199 
200 /* currentdash */
201 uint
gs_currentdash_length(const gs_state * pgs)202 gs_currentdash_length(const gs_state * pgs)
203 {
204     return pgs_lp->dash.pattern_size;
205 }
206 const float *
gs_currentdash_pattern(const gs_state * pgs)207 gs_currentdash_pattern(const gs_state * pgs)
208 {
209     return pgs_lp->dash.pattern;
210 }
211 float
gs_currentdash_offset(const gs_state * pgs)212 gs_currentdash_offset(const gs_state * pgs)
213 {
214     return pgs_lp->dash.offset;
215 }
216 
217 /* Internal accessor for line parameters */
218 const gx_line_params *
gs_currentlineparams(const gs_imager_state * pis)219 gs_currentlineparams(const gs_imager_state * pis)
220 {
221     return gs_currentlineparams_inline(pis);
222 }
223 
224 /* ------ Device-dependent parameters ------ */
225 
226 /* setflat */
227 int
gs_imager_setflat(gs_imager_state * pis,floatp flat)228 gs_imager_setflat(gs_imager_state * pis, floatp flat)
229 {
230     if (flat <= 0.2)
231 	flat = 0.2;
232     else if (flat > 100)
233 	flat = 100;
234     pis->flatness = flat;
235     return 0;
236 }
237 int
gs_setflat(gs_state * pgs,floatp flat)238 gs_setflat(gs_state * pgs, floatp flat)
239 {
240     return gs_imager_setflat((gs_imager_state *) pgs, flat);
241 }
242 
243 /* currentflat */
244 float
gs_currentflat(const gs_state * pgs)245 gs_currentflat(const gs_state * pgs)
246 {
247     return pgs->flatness;
248 }
249 
250 /* setstrokeadjust */
251 int
gs_setstrokeadjust(gs_state * pgs,bool stroke_adjust)252 gs_setstrokeadjust(gs_state * pgs, bool stroke_adjust)
253 {
254     pgs->stroke_adjust = stroke_adjust;
255     return 0;
256 }
257 
258 /* currentstrokeadjust */
259 bool
gs_currentstrokeadjust(const gs_state * pgs)260 gs_currentstrokeadjust(const gs_state * pgs)
261 {
262     return pgs->stroke_adjust;
263 }
264 
265 /* ------ Extensions ------ */
266 
267 /* Device-independent */
268 
269 /* setdashadapt */
270 void
gs_setdashadapt(gs_state * pgs,bool adapt)271 gs_setdashadapt(gs_state * pgs, bool adapt)
272 {
273     pgs_lp->dash.adapt = adapt;
274 }
275 
276 /* currentdashadapt */
277 bool
gs_imager_currentdashadapt(const gs_imager_state * pis)278 gs_imager_currentdashadapt(const gs_imager_state * pis)
279 {
280     return gs_currentlineparams_inline(pis)->dash.adapt;
281 }
282 bool
gs_currentdashadapt(const gs_state * pgs)283 gs_currentdashadapt(const gs_state * pgs)
284 {
285     return gs_imager_currentdashadapt((const gs_imager_state *)pgs);
286 }
287 
288 /* setcurvejoin */
289 int
gs_setcurvejoin(gs_state * pgs,int join)290 gs_setcurvejoin(gs_state * pgs, int join)
291 {
292     if (join < -1 || join > gs_line_join_max)
293 	return_error(gs_error_rangecheck);
294     pgs_lp->curve_join = join;
295     return 0;
296 }
297 
298 /* currentcurvejoin */
299 int
gs_currentcurvejoin(const gs_state * pgs)300 gs_currentcurvejoin(const gs_state * pgs)
301 {
302     return pgs_lp->curve_join;
303 }
304 
305 /* Device-dependent */
306 
307 /* setaccuratecurves */
308 void
gs_setaccuratecurves(gs_state * pgs,bool accurate)309 gs_setaccuratecurves(gs_state * pgs, bool accurate)
310 {
311     pgs->accurate_curves = accurate;
312 }
313 
314 /* currentaccuratecurves */
315 bool
gs_imager_currentaccuratecurves(const gs_imager_state * pis)316 gs_imager_currentaccuratecurves(const gs_imager_state * pis)
317 {
318     return pis->accurate_curves;
319 }
320 bool
gs_currentaccuratecurves(const gs_state * pgs)321 gs_currentaccuratecurves(const gs_state * pgs)
322 {
323     return gs_imager_currentaccuratecurves((const gs_imager_state *)pgs);
324 }
325 
326 /* setdotlength */
327 int
gx_set_dot_length(gx_line_params * plp,floatp length,bool absolute)328 gx_set_dot_length(gx_line_params * plp, floatp length, bool absolute)
329 {
330     if (length < 0)
331 	return_error(gs_error_rangecheck);
332     plp->dot_length = length;
333     plp->dot_length_absolute = absolute;
334     return 0;
335 }
336 int
gs_setdotlength(gs_state * pgs,floatp length,bool absolute)337 gs_setdotlength(gs_state * pgs, floatp length, bool absolute)
338 {
339     return gx_set_dot_length(pgs_lp, length, absolute);
340 }
341 
342 /* currentdotlength */
343 float
gs_currentdotlength(const gs_state * pgs)344 gs_currentdotlength(const gs_state * pgs)
345 {
346     return pgs_lp->dot_length;
347 }
348 bool
gs_currentdotlength_absolute(const gs_state * pgs)349 gs_currentdotlength_absolute(const gs_state * pgs)
350 {
351     return pgs_lp->dot_length_absolute;
352 }
353 
354 /* setdotorientation */
355 int
gs_setdotorientation(gs_state * pgs)356 gs_setdotorientation(gs_state *pgs)
357 {
358     if (is_xxyy(&pgs->ctm) || is_xyyx(&pgs->ctm))
359 	return gs_currentmatrix(pgs, &pgs_lp->dot_orientation);
360     return_error(gs_error_rangecheck);
361 }
362 
363 /* dotorientation */
364 int
gs_dotorientation(gs_state * pgs)365 gs_dotorientation(gs_state *pgs)
366 {
367     return gs_setmatrix(pgs, &pgs_lp->dot_orientation);
368 }
369