/src/ghostpdl/psi/zpath1.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2021 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, |
13 | | CA 94945, U.S.A., +1(415)492-9861, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* PostScript Level 1 additional path operators */ |
18 | | #include "memory_.h" |
19 | | #include "ghost.h" |
20 | | #include "oper.h" |
21 | | #include "oparc.h" /* for prototypes */ |
22 | | #include "estack.h" /* for pathforall */ |
23 | | #include "ialloc.h" |
24 | | #include "igstate.h" |
25 | | #include "gsstruct.h" |
26 | | #include "gspath.h" |
27 | | #include "store.h" |
28 | | |
29 | | /* Forward references */ |
30 | | static int common_arc(i_ctx_t *, |
31 | | int (*)(gs_gstate *, double, double, double, double, double)); |
32 | | static int common_arct(i_ctx_t *, float *); |
33 | | |
34 | | /* <x> <y> <r> <ang1> <ang2> arc - */ |
35 | | int |
36 | | zarc(i_ctx_t *i_ctx_p) |
37 | 28.2k | { |
38 | 28.2k | return common_arc(i_ctx_p, gs_arc); |
39 | 28.2k | } |
40 | | |
41 | | /* <x> <y> <r> <ang1> <ang2> arcn - */ |
42 | | int |
43 | | zarcn(i_ctx_t *i_ctx_p) |
44 | 55 | { |
45 | 55 | return common_arc(i_ctx_p, gs_arcn); |
46 | 55 | } |
47 | | |
48 | | /* Common code for arc[n] */ |
49 | | static int |
50 | | common_arc(i_ctx_t *i_ctx_p, |
51 | | int (*aproc)(gs_gstate *, double, double, double, double, double)) |
52 | 28.3k | { |
53 | 28.3k | os_ptr op = osp; |
54 | 28.3k | double xyra[5]; /* x, y, r, ang1, ang2 */ |
55 | 28.3k | int code = num_params(op, 5, xyra); |
56 | | |
57 | 28.3k | if (code < 0) |
58 | 35 | return code; |
59 | 28.3k | code = (*aproc)(igs, xyra[0], xyra[1], xyra[2], xyra[3], xyra[4]); |
60 | 28.3k | if (code >= 0) |
61 | 28.2k | pop(5); |
62 | 28.3k | return code; |
63 | 28.3k | } |
64 | | |
65 | | /* <x1> <y1> <x2> <y2> <r> arct - */ |
66 | | int |
67 | | zarct(i_ctx_t *i_ctx_p) |
68 | 19 | { |
69 | 19 | int code = common_arct(i_ctx_p, (float *)0); |
70 | | |
71 | 19 | if (code < 0) |
72 | 19 | return code; |
73 | 0 | pop(5); |
74 | 0 | return 0; |
75 | 19 | } |
76 | | |
77 | | /* <x1> <y1> <x2> <y2> <r> arcto <xt1> <yt1> <xt2> <yt2> */ |
78 | | static int |
79 | | zarcto(i_ctx_t *i_ctx_p) |
80 | 27 | { |
81 | 27 | os_ptr op = osp; |
82 | 27 | float tanxy[4]; /* xt1, yt1, xt2, yt2 */ |
83 | 27 | int code = common_arct(i_ctx_p, tanxy); |
84 | | |
85 | 27 | if (code < 0) |
86 | 27 | return code; |
87 | 0 | make_real(op - 4, tanxy[0]); |
88 | 0 | make_real(op - 3, tanxy[1]); |
89 | 0 | make_real(op - 2, tanxy[2]); |
90 | 0 | make_real(op - 1, tanxy[3]); |
91 | 0 | pop(1); |
92 | 0 | return 0; |
93 | 27 | } |
94 | | |
95 | | /* Common code for arct[o] */ |
96 | | static int |
97 | | common_arct(i_ctx_t *i_ctx_p, float *tanxy) |
98 | 46 | { |
99 | 46 | os_ptr op = osp; |
100 | 46 | double args[5]; /* x1, y1, x2, y2, r */ |
101 | 46 | int code = num_params(op, 5, args); |
102 | | |
103 | 46 | if (code < 0) |
104 | 34 | return code; |
105 | 12 | return gs_arcto(igs, args[0], args[1], args[2], args[3], args[4], tanxy); |
106 | 46 | } |
107 | | |
108 | | /* - .dashpath - */ |
109 | | static int |
110 | | zdashpath(i_ctx_t *i_ctx_p) |
111 | 0 | { |
112 | 0 | return gs_dashpath(igs); |
113 | 0 | } |
114 | | |
115 | | /* - flattenpath - */ |
116 | | static int |
117 | | zflattenpath(i_ctx_t *i_ctx_p) |
118 | 1.29k | { |
119 | 1.29k | return gs_flattenpath(igs); |
120 | 1.29k | } |
121 | | |
122 | | /* - reversepath - */ |
123 | | static int |
124 | | zreversepath(i_ctx_t *i_ctx_p) |
125 | 43 | { |
126 | 43 | return gs_reversepath(igs); |
127 | 43 | } |
128 | | |
129 | | /* - strokepath - */ |
130 | | static int |
131 | | zstrokepath(i_ctx_t *i_ctx_p) |
132 | 121 | { |
133 | 121 | return gs_strokepath(igs); |
134 | 121 | } |
135 | | |
136 | | /* - clippath - */ |
137 | | static int |
138 | | zclippath(i_ctx_t *i_ctx_p) |
139 | 4.45k | { |
140 | 4.45k | return gs_clippath(igs); |
141 | 4.45k | } |
142 | | |
143 | | /* <bool> .pathbbox <llx> <lly> <urx> <ury> */ |
144 | | static int |
145 | | z1pathbbox(i_ctx_t *i_ctx_p) |
146 | 5.58k | { |
147 | 5.58k | os_ptr op = osp; |
148 | 5.58k | gs_rect box; |
149 | 5.58k | int code; |
150 | | |
151 | 5.58k | check_type(*op, t_boolean); |
152 | 5.58k | code = gs_upathbbox(igs, &box, op->value.boolval); |
153 | 5.58k | if (code < 0) |
154 | 14 | return code; |
155 | 5.58k | push(3); |
156 | 5.56k | make_real(op - 3, box.p.x); |
157 | 5.56k | make_real(op - 2, box.p.y); |
158 | 5.56k | make_real(op - 1, box.q.x); |
159 | 5.56k | make_real(op, box.q.y); |
160 | 5.56k | return 0; |
161 | 5.56k | } |
162 | | |
163 | | /* |
164 | | * In order to match Adobe output on a Genoa test, pathbbox must be an |
165 | | * operator, not an operator procedure, even though it has a trivial |
166 | | * definition as a procedure. |
167 | | */ |
168 | | static int |
169 | | zpathbbox(i_ctx_t *i_ctx_p) |
170 | 5.58k | { |
171 | 5.58k | os_ptr op = osp; |
172 | 5.58k | int code; |
173 | | |
174 | 5.58k | push(1); |
175 | 5.58k | make_false(op); |
176 | 5.58k | code = z1pathbbox(i_ctx_p); |
177 | 5.58k | if (code < 0) { |
178 | 14 | pop(1); /* remove the Boolean */ |
179 | 14 | } |
180 | 5.58k | return code; |
181 | 5.58k | } |
182 | | |
183 | | /* <moveproc> <lineproc> <curveproc> <closeproc> pathforall - */ |
184 | | static int path_continue(i_ctx_t *); |
185 | | static int path_cleanup(i_ctx_t *); |
186 | | static int |
187 | | zpathforall(i_ctx_t *i_ctx_p) |
188 | 12 | { |
189 | 12 | os_ptr op = osp; |
190 | 12 | gs_path_enum *penum; |
191 | 12 | int code; |
192 | | |
193 | 12 | check_proc(op[-3]); |
194 | 12 | check_proc(op[-2]); |
195 | 0 | check_proc(op[-1]); |
196 | 0 | check_proc(*op); |
197 | 0 | check_estack(8); |
198 | |
|
199 | 0 | if ((penum = gs_path_enum_alloc(imemory, "pathforall")) == 0) |
200 | 0 | return_error(gs_error_VMerror); |
201 | 0 | code = gs_path_enum_init(imemory, penum, igs); |
202 | 0 | if (code < 0) { |
203 | 0 | ifree_object(penum, "path_cleanup"); |
204 | 0 | return code; |
205 | 0 | } |
206 | | /* Push a mark, the four procedures, and the path enumerator. */ |
207 | 0 | push_mark_estack(es_for, path_cleanup); /* iterator */ |
208 | 0 | memcpy(esp + 1, op - 3, 4 * sizeof(ref)); /* 4 procs */ |
209 | 0 | esp += 5; |
210 | 0 | make_istruct(esp, 0, penum); |
211 | 0 | push_op_estack(path_continue); |
212 | 0 | pop(4); |
213 | 0 | op -= 4; |
214 | 0 | return o_push_estack; |
215 | 0 | } |
216 | | /* Continuation procedure for pathforall */ |
217 | | static void pf_push(i_ctx_t *, gs_point *, int); |
218 | | static int |
219 | | path_continue(i_ctx_t *i_ctx_p) |
220 | 0 | { |
221 | 0 | gs_path_enum *penum = r_ptr(esp, gs_path_enum); |
222 | 0 | gs_point ppts[3]; |
223 | 0 | int code; |
224 | | |
225 | | /* Make sure we have room on the o-stack for the worst case */ |
226 | | /* before we enumerate the next path element. */ |
227 | 0 | check_ostack(6); /* 3 points for curveto */ |
228 | 0 | code = gs_path_enum_next(penum, ppts); |
229 | 0 | switch (code) { |
230 | 0 | case 0: /* all done */ |
231 | 0 | esp -= 6; |
232 | 0 | path_cleanup(i_ctx_p); |
233 | 0 | return o_pop_estack; |
234 | 0 | default: /* error */ |
235 | 0 | esp -= 6; |
236 | 0 | path_cleanup(i_ctx_p); |
237 | 0 | return code; |
238 | 0 | case gs_pe_moveto: |
239 | 0 | esp[2] = esp[-4]; /* moveto proc */ |
240 | 0 | pf_push(i_ctx_p, ppts, 1); |
241 | 0 | break; |
242 | 0 | case gs_pe_lineto: |
243 | 0 | esp[2] = esp[-3]; /* lineto proc */ |
244 | 0 | pf_push(i_ctx_p, ppts, 1); |
245 | 0 | break; |
246 | 0 | case gs_pe_curveto: |
247 | 0 | esp[2] = esp[-2]; /* curveto proc */ |
248 | 0 | pf_push(i_ctx_p, ppts, 3); |
249 | 0 | break; |
250 | 0 | case gs_pe_closepath: |
251 | 0 | esp[2] = esp[-1]; /* closepath proc */ |
252 | 0 | break; |
253 | 0 | } |
254 | 0 | push_op_estack(path_continue); |
255 | 0 | ++esp; /* include pushed procedure */ |
256 | 0 | return o_push_estack; |
257 | 0 | } |
258 | | /* Internal procedure to push one or more points */ |
259 | | static void |
260 | | pf_push(i_ctx_t *i_ctx_p, gs_point * ppts, int n) |
261 | 0 | { |
262 | 0 | os_ptr op = osp; |
263 | |
|
264 | 0 | while (n--) { |
265 | 0 | op += 2; |
266 | 0 | make_real(op - 1, ppts->x); |
267 | 0 | make_real(op, ppts->y); |
268 | 0 | ppts++; |
269 | 0 | } |
270 | 0 | osp = op; |
271 | 0 | } |
272 | | /* Clean up after a pathforall */ |
273 | | static int |
274 | | path_cleanup(i_ctx_t *i_ctx_p) |
275 | 0 | { |
276 | 0 | gs_path_enum *penum = r_ptr(esp + 6, gs_path_enum); |
277 | |
|
278 | 0 | gs_path_enum_cleanup(penum); |
279 | 0 | ifree_object(penum, "path_cleanup"); |
280 | 0 | return 0; |
281 | 0 | } |
282 | | |
283 | | /* ------ Initialization procedure ------ */ |
284 | | |
285 | | const op_def zpath1_op_defs[] = |
286 | | { |
287 | | {"5arc", zarc}, |
288 | | {"5arcn", zarcn}, |
289 | | {"5arct", zarct}, |
290 | | {"5arcto", zarcto}, |
291 | | {"0clippath", zclippath}, |
292 | | {"0.dashpath", zdashpath}, |
293 | | {"0flattenpath", zflattenpath}, |
294 | | {"4pathforall", zpathforall}, |
295 | | {"0reversepath", zreversepath}, |
296 | | {"0strokepath", zstrokepath}, |
297 | | {"1.pathbbox", z1pathbbox}, |
298 | | {"0pathbbox", zpathbbox}, |
299 | | /* Internal operators */ |
300 | | {"0%path_continue", path_continue}, |
301 | | op_def_end(0) |
302 | | }; |