/src/ghostpdl/psi/zpath1.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 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., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, 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 | 80.0k | { |
38 | 80.0k | return common_arc(i_ctx_p, gs_arc); |
39 | 80.0k | } |
40 | | |
41 | | /* <x> <y> <r> <ang1> <ang2> arcn - */ |
42 | | int |
43 | | zarcn(i_ctx_t *i_ctx_p) |
44 | 129 | { |
45 | 129 | return common_arc(i_ctx_p, gs_arcn); |
46 | 129 | } |
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 | 80.1k | { |
53 | 80.1k | os_ptr op = osp; |
54 | 80.1k | double xyra[5]; /* x, y, r, ang1, ang2 */ |
55 | 80.1k | int code; |
56 | | |
57 | 80.1k | check_op(5); |
58 | 80.1k | code = num_params(op, 5, xyra); |
59 | 80.1k | if (code < 0) |
60 | 14 | return code; |
61 | 80.0k | code = (*aproc)(igs, xyra[0], xyra[1], xyra[2], xyra[3], xyra[4]); |
62 | 80.0k | if (code >= 0) |
63 | 80.0k | pop(5); |
64 | 80.0k | return code; |
65 | 80.1k | } |
66 | | |
67 | | /* <x1> <y1> <x2> <y2> <r> arct - */ |
68 | | int |
69 | | zarct(i_ctx_t *i_ctx_p) |
70 | 23 | { |
71 | 23 | int code = common_arct(i_ctx_p, (float *)0); |
72 | | |
73 | 23 | if (code < 0) |
74 | 23 | return code; |
75 | 0 | pop(5); |
76 | 0 | return 0; |
77 | 23 | } |
78 | | |
79 | | /* <x1> <y1> <x2> <y2> <r> arcto <xt1> <yt1> <xt2> <yt2> */ |
80 | | static int |
81 | | zarcto(i_ctx_t *i_ctx_p) |
82 | 29 | { |
83 | 29 | os_ptr op = osp; |
84 | 29 | float tanxy[4]; /* xt1, yt1, xt2, yt2 */ |
85 | 29 | int code = common_arct(i_ctx_p, tanxy); |
86 | | |
87 | 29 | if (code < 0) |
88 | 29 | return code; |
89 | 0 | make_real(op - 4, tanxy[0]); |
90 | 0 | make_real(op - 3, tanxy[1]); |
91 | 0 | make_real(op - 2, tanxy[2]); |
92 | 0 | make_real(op - 1, tanxy[3]); |
93 | 0 | pop(1); |
94 | 0 | return 0; |
95 | 29 | } |
96 | | |
97 | | /* Common code for arct[o] */ |
98 | | static int |
99 | | common_arct(i_ctx_t *i_ctx_p, float *tanxy) |
100 | 52 | { |
101 | 52 | os_ptr op = osp; |
102 | 52 | double args[5]; /* x1, y1, x2, y2, r */ |
103 | 52 | int code; |
104 | | |
105 | 52 | check_op(5); |
106 | 20 | code = num_params(op, 5, args); |
107 | 20 | if (code < 0) |
108 | 6 | return code; |
109 | 14 | return gs_arcto(igs, args[0], args[1], args[2], args[3], args[4], tanxy); |
110 | 20 | } |
111 | | |
112 | | /* - .dashpath - */ |
113 | | static int |
114 | | zdashpath(i_ctx_t *i_ctx_p) |
115 | 0 | { |
116 | 0 | return gs_dashpath(igs); |
117 | 0 | } |
118 | | |
119 | | /* - flattenpath - */ |
120 | | static int |
121 | | zflattenpath(i_ctx_t *i_ctx_p) |
122 | 1.56k | { |
123 | 1.56k | return gs_flattenpath(igs); |
124 | 1.56k | } |
125 | | |
126 | | /* - reversepath - */ |
127 | | static int |
128 | | zreversepath(i_ctx_t *i_ctx_p) |
129 | 50 | { |
130 | 50 | return gs_reversepath(igs); |
131 | 50 | } |
132 | | |
133 | | /* - strokepath - */ |
134 | | static int |
135 | | zstrokepath(i_ctx_t *i_ctx_p) |
136 | 147 | { |
137 | 147 | return gs_strokepath(igs); |
138 | 147 | } |
139 | | |
140 | | /* - clippath - */ |
141 | | static int |
142 | | zclippath(i_ctx_t *i_ctx_p) |
143 | 4.65k | { |
144 | 4.65k | return gs_clippath(igs); |
145 | 4.65k | } |
146 | | |
147 | | /* <bool> .pathbbox <llx> <lly> <urx> <ury> */ |
148 | | static int |
149 | | z1pathbbox(i_ctx_t *i_ctx_p) |
150 | 6.05k | { |
151 | 6.05k | os_ptr op = osp; |
152 | 6.05k | gs_rect box; |
153 | 6.05k | int code; |
154 | | |
155 | 6.05k | check_op(1); |
156 | 6.05k | check_type(*op, t_boolean); |
157 | 6.05k | code = gs_upathbbox(igs, &box, op->value.boolval); |
158 | 6.05k | if (code < 0) |
159 | 18 | return code; |
160 | 6.05k | push(3); |
161 | 6.03k | make_real(op - 3, box.p.x); |
162 | 6.03k | make_real(op - 2, box.p.y); |
163 | 6.03k | make_real(op - 1, box.q.x); |
164 | 6.03k | make_real(op, box.q.y); |
165 | 6.03k | return 0; |
166 | 6.03k | } |
167 | | |
168 | | /* |
169 | | * In order to match Adobe output on a Genoa test, pathbbox must be an |
170 | | * operator, not an operator procedure, even though it has a trivial |
171 | | * definition as a procedure. |
172 | | */ |
173 | | static int |
174 | | zpathbbox(i_ctx_t *i_ctx_p) |
175 | 6.05k | { |
176 | 6.05k | os_ptr op = osp; |
177 | 6.05k | int code; |
178 | | |
179 | 6.05k | push(1); |
180 | 6.05k | make_false(op); |
181 | 6.05k | code = z1pathbbox(i_ctx_p); |
182 | 6.05k | if (code < 0) { |
183 | 18 | pop(1); /* remove the Boolean */ |
184 | 18 | } |
185 | 6.05k | return code; |
186 | 6.05k | } |
187 | | |
188 | | /* <moveproc> <lineproc> <curveproc> <closeproc> pathforall - */ |
189 | | static int path_continue(i_ctx_t *); |
190 | | static int path_cleanup(i_ctx_t *); |
191 | | static int |
192 | | zpathforall(i_ctx_t *i_ctx_p) |
193 | 18 | { |
194 | 18 | os_ptr op = osp; |
195 | 18 | gs_path_enum *penum; |
196 | 18 | int code; |
197 | | |
198 | 18 | check_op(4); |
199 | 18 | check_proc(op[-3]); |
200 | 3 | check_proc(op[-2]); |
201 | 0 | check_proc(op[-1]); |
202 | 0 | check_proc(*op); |
203 | 0 | check_estack(8); |
204 | |
|
205 | 0 | if ((penum = gs_path_enum_alloc(imemory, "pathforall")) == 0) |
206 | 0 | return_error(gs_error_VMerror); |
207 | 0 | code = gs_path_enum_init(imemory, penum, igs); |
208 | 0 | if (code < 0) { |
209 | 0 | ifree_object(penum, "path_cleanup"); |
210 | 0 | return code; |
211 | 0 | } |
212 | | /* Push a mark, the four procedures, and the path enumerator. */ |
213 | 0 | push_mark_estack(es_for, path_cleanup); /* iterator */ |
214 | 0 | memcpy(esp + 1, op - 3, 4 * sizeof(ref)); /* 4 procs */ |
215 | 0 | esp += 5; |
216 | 0 | make_istruct(esp, 0, penum); |
217 | 0 | push_op_estack(path_continue); |
218 | 0 | pop(4); |
219 | 0 | op -= 4; |
220 | 0 | return o_push_estack; |
221 | 0 | } |
222 | | /* Continuation procedure for pathforall */ |
223 | | static void pf_push(i_ctx_t *, gs_point *, int); |
224 | | static int |
225 | | path_continue(i_ctx_t *i_ctx_p) |
226 | 0 | { |
227 | 0 | gs_path_enum *penum = r_ptr(esp, gs_path_enum); |
228 | 0 | gs_point ppts[3]; |
229 | 0 | int code; |
230 | | |
231 | | /* Make sure we have room on the o-stack for the worst case */ |
232 | | /* before we enumerate the next path element. */ |
233 | 0 | check_ostack(6); /* 3 points for curveto */ |
234 | 0 | code = gs_path_enum_next(penum, ppts); |
235 | 0 | switch (code) { |
236 | 0 | case 0: /* all done */ |
237 | 0 | esp -= 6; |
238 | 0 | path_cleanup(i_ctx_p); |
239 | 0 | return o_pop_estack; |
240 | 0 | default: /* error */ |
241 | 0 | esp -= 6; |
242 | 0 | path_cleanup(i_ctx_p); |
243 | 0 | return code; |
244 | 0 | case gs_pe_moveto: |
245 | 0 | esp[2] = esp[-4]; /* moveto proc */ |
246 | 0 | pf_push(i_ctx_p, ppts, 1); |
247 | 0 | break; |
248 | 0 | case gs_pe_lineto: |
249 | 0 | esp[2] = esp[-3]; /* lineto proc */ |
250 | 0 | pf_push(i_ctx_p, ppts, 1); |
251 | 0 | break; |
252 | 0 | case gs_pe_curveto: |
253 | 0 | esp[2] = esp[-2]; /* curveto proc */ |
254 | 0 | pf_push(i_ctx_p, ppts, 3); |
255 | 0 | break; |
256 | 0 | case gs_pe_closepath: |
257 | 0 | esp[2] = esp[-1]; /* closepath proc */ |
258 | 0 | break; |
259 | 0 | } |
260 | 0 | push_op_estack(path_continue); |
261 | 0 | ++esp; /* include pushed procedure */ |
262 | 0 | return o_push_estack; |
263 | 0 | } |
264 | | /* Internal procedure to push one or more points */ |
265 | | static void |
266 | | pf_push(i_ctx_t *i_ctx_p, gs_point * ppts, int n) |
267 | 0 | { |
268 | 0 | os_ptr op = osp; |
269 | |
|
270 | 0 | while (n--) { |
271 | 0 | op += 2; |
272 | 0 | make_real(op - 1, ppts->x); |
273 | 0 | make_real(op, ppts->y); |
274 | 0 | ppts++; |
275 | 0 | } |
276 | 0 | osp = op; |
277 | 0 | } |
278 | | /* Clean up after a pathforall */ |
279 | | static int |
280 | | path_cleanup(i_ctx_t *i_ctx_p) |
281 | 0 | { |
282 | 0 | gs_path_enum *penum = r_ptr(esp + 6, gs_path_enum); |
283 | |
|
284 | 0 | gs_path_enum_cleanup(penum); |
285 | 0 | ifree_object(penum, "path_cleanup"); |
286 | | /* We need to 'null' the ref on the exec stack because a later GC could |
287 | | * run off the top of the stack and try to reloc the pointer, even |
288 | | * though we've freed it. See the fix for bug 707007. |
289 | | */ |
290 | 0 | make_null(esp + 6); |
291 | 0 | return 0; |
292 | 0 | } |
293 | | |
294 | | /* ------ Initialization procedure ------ */ |
295 | | |
296 | | const op_def zpath1_op_defs[] = |
297 | | { |
298 | | {"5arc", zarc}, |
299 | | {"5arcn", zarcn}, |
300 | | {"5arct", zarct}, |
301 | | {"5arcto", zarcto}, |
302 | | {"0clippath", zclippath}, |
303 | | {"0.dashpath", zdashpath}, |
304 | | {"0flattenpath", zflattenpath}, |
305 | | {"4pathforall", zpathforall}, |
306 | | {"0reversepath", zreversepath}, |
307 | | {"0strokepath", zstrokepath}, |
308 | | {"1.pathbbox", z1pathbbox}, |
309 | | {"0pathbbox", zpathbbox}, |
310 | | /* Internal operators */ |
311 | | {"0%path_continue", path_continue}, |
312 | | op_def_end(0) |
313 | | }; |