/src/ghostpdl/psi/zmatrix.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 | | /* Matrix operators */ |
18 | | #include "ghost.h" |
19 | | #include "oper.h" |
20 | | #include "igstate.h" |
21 | | #include "gsmatrix.h" |
22 | | #include "gscoord.h" |
23 | | #include "store.h" |
24 | | |
25 | | /* Forward references */ |
26 | | static int common_transform(i_ctx_t *, |
27 | | int (*)(gs_gstate *, double, double, gs_point *), |
28 | | int (*)(double, double, const gs_matrix *, gs_point *)); |
29 | | |
30 | | /* - initmatrix - */ |
31 | | static int |
32 | | zinitmatrix(i_ctx_t *i_ctx_p) |
33 | 107k | { |
34 | 107k | return gs_initmatrix(igs); |
35 | 107k | } |
36 | | |
37 | | /* <matrix> defaultmatrix <matrix> */ |
38 | | static int |
39 | | zdefaultmatrix(i_ctx_t *i_ctx_p) |
40 | 115k | { |
41 | 115k | os_ptr op = osp; |
42 | 115k | gs_matrix mat; |
43 | | |
44 | 115k | check_op(1); |
45 | 115k | gs_defaultmatrix(igs, &mat); |
46 | 115k | return write_matrix(op, &mat); |
47 | 115k | } |
48 | | |
49 | | /* - .currentmatrix <xx> <xy> <yx> <yy> <tx> <ty> */ |
50 | | static int |
51 | | zcurrentmatrix(i_ctx_t *i_ctx_p) |
52 | 107k | { |
53 | 107k | os_ptr op = osp; |
54 | 107k | gs_matrix mat; |
55 | 107k | int code = gs_currentmatrix(igs, &mat); |
56 | | |
57 | 107k | if (code < 0) |
58 | 0 | return code; |
59 | 107k | push(6); |
60 | 107k | code = make_floats(op - 5, &mat.xx, 6); |
61 | 107k | if (code < 0) |
62 | 0 | pop(6); |
63 | 107k | return code; |
64 | 107k | } |
65 | | |
66 | | /* <xx> <xy> <yx> <yy> <tx> <ty> .setmatrix - */ |
67 | | static int |
68 | | zsetmatrix(i_ctx_t *i_ctx_p) |
69 | 0 | { |
70 | 0 | os_ptr op = osp; |
71 | 0 | gs_matrix mat; |
72 | 0 | int code; |
73 | |
|
74 | 0 | check_op(6); |
75 | 0 | code = float_params(op, 6, &mat.xx); |
76 | |
|
77 | 0 | if (code < 0) |
78 | 0 | return code; |
79 | 0 | if ((code = gs_setmatrix(igs, &mat)) < 0) |
80 | 0 | return code; |
81 | 0 | pop(6); |
82 | 0 | return 0; |
83 | 0 | } |
84 | | |
85 | | /* <matrix|null> .setdefaultmatrix - */ |
86 | | static int |
87 | | zsetdefaultmatrix(i_ctx_t *i_ctx_p) |
88 | 107k | { |
89 | 107k | os_ptr op = osp; |
90 | 107k | int code; |
91 | | |
92 | 107k | check_op(1); |
93 | 107k | if (r_has_type(op, t_null)) |
94 | 0 | code = gs_setdefaultmatrix(igs, NULL); |
95 | 107k | else { |
96 | 107k | gs_matrix mat; |
97 | | |
98 | 107k | code = read_matrix(imemory, op, &mat); |
99 | 107k | if (code < 0) |
100 | 0 | return code; |
101 | 107k | code = gs_setdefaultmatrix(igs, &mat); |
102 | 107k | } |
103 | 107k | if (code < 0) |
104 | 0 | return code; |
105 | 107k | pop(1); |
106 | 107k | return 0; |
107 | 107k | } |
108 | | |
109 | | /* <tx> <ty> translate - */ |
110 | | /* <tx> <ty> <matrix> translate <matrix> */ |
111 | | static int |
112 | | ztranslate(i_ctx_t *i_ctx_p) |
113 | 109k | { |
114 | 109k | os_ptr op = osp; |
115 | 109k | int code; |
116 | 109k | double trans[2]; |
117 | | |
118 | 109k | if ((code = num_params(op, 2, trans)) >= 0) { |
119 | 109k | code = gs_translate(igs, trans[0], trans[1]); |
120 | 109k | if (code < 0) |
121 | 0 | return code; |
122 | 109k | } else { /* matrix operand */ |
123 | 4 | gs_matrix mat; |
124 | | |
125 | | /* The num_params failure might be a stack underflow. */ |
126 | 4 | check_op(2); |
127 | 3 | if ((code = num_params(op - 1, 2, trans)) < 0 || |
128 | 3 | (code = gs_make_translation(trans[0], trans[1], &mat)) < 0 || |
129 | 3 | (code = write_matrix(op, &mat)) < 0 |
130 | 3 | ) { /* Might be a stack underflow. */ |
131 | 3 | check_op(3); |
132 | 2 | return code; |
133 | 3 | } |
134 | 0 | op[-2] = *op; |
135 | 0 | } |
136 | 109k | pop(2); |
137 | 109k | return code; |
138 | 109k | } |
139 | | |
140 | | /* <sx> <sy> scale - */ |
141 | | /* <sx> <sy> <matrix> scale <matrix> */ |
142 | | static int |
143 | | zscale(i_ctx_t *i_ctx_p) |
144 | 11 | { |
145 | 11 | os_ptr op = osp; |
146 | 11 | int code; |
147 | 11 | double scale[2]; |
148 | | |
149 | 11 | if ((code = num_params(op, 2, scale)) >= 0) { |
150 | 5 | code = gs_scale(igs, scale[0], scale[1]); |
151 | 5 | if (code < 0) |
152 | 0 | return code; |
153 | 6 | } else { /* matrix operand */ |
154 | 6 | gs_matrix mat; |
155 | | |
156 | | /* The num_params failure might be a stack underflow. */ |
157 | 6 | check_op(2); |
158 | 4 | if ((code = num_params(op - 1, 2, scale)) < 0 || |
159 | 4 | (code = gs_make_scaling(scale[0], scale[1], &mat)) < 0 || |
160 | 4 | (code = write_matrix(op, &mat)) < 0 |
161 | 4 | ) { /* Might be a stack underflow. */ |
162 | 4 | check_op(3); |
163 | 3 | return code; |
164 | 4 | } |
165 | 0 | op[-2] = *op; |
166 | 0 | } |
167 | 5 | pop(2); |
168 | 5 | return code; |
169 | 11 | } |
170 | | |
171 | | /* <angle> rotate - */ |
172 | | /* <angle> <matrix> rotate <matrix> */ |
173 | | static int |
174 | | zrotate(i_ctx_t *i_ctx_p) |
175 | 20 | { |
176 | 20 | os_ptr op = osp; |
177 | 20 | int code; |
178 | 20 | double ang; |
179 | | |
180 | 20 | if ((code = real_param(op, &ang)) >= 0) { |
181 | 9 | code = gs_rotate(igs, ang); |
182 | 9 | if (code < 0) |
183 | 0 | return code; |
184 | 11 | } else { /* matrix operand */ |
185 | 11 | gs_matrix mat; |
186 | | |
187 | | /* The num_params failure might be a stack underflow. */ |
188 | 11 | check_op(1); |
189 | 9 | if ((code = num_params(op - 1, 1, &ang)) < 0 || |
190 | 9 | (code = gs_make_rotation(ang, &mat)) < 0 || |
191 | 9 | (code = write_matrix(op, &mat)) < 0 |
192 | 9 | ) { /* Might be a stack underflow. */ |
193 | 9 | check_op(2); |
194 | 8 | return code; |
195 | 9 | } |
196 | 0 | op[-1] = *op; |
197 | 0 | } |
198 | 9 | pop(1); |
199 | 9 | return code; |
200 | 20 | } |
201 | | |
202 | | /* <matrix> concat - */ |
203 | | static int |
204 | | zconcat(i_ctx_t *i_ctx_p) |
205 | 107k | { |
206 | 107k | os_ptr op = osp; |
207 | 107k | gs_matrix mat; |
208 | 107k | int code; |
209 | | |
210 | 107k | check_op(1); |
211 | 107k | code = read_matrix(imemory, op, &mat); |
212 | | |
213 | 107k | if (code < 0) |
214 | 1 | return code; |
215 | 107k | code = gs_concat(igs, &mat); |
216 | 107k | if (code < 0) |
217 | 0 | return code; |
218 | 107k | pop(1); |
219 | 107k | return 0; |
220 | 107k | } |
221 | | |
222 | | /* <matrix1> <matrix2> <matrix> concatmatrix <matrix> */ |
223 | | static int |
224 | | zconcatmatrix(i_ctx_t *i_ctx_p) |
225 | 2 | { |
226 | 2 | os_ptr op = osp; |
227 | 2 | gs_matrix m1, m2, mp; |
228 | 2 | int code; |
229 | | |
230 | 2 | check_op(3); |
231 | 1 | if ((code = read_matrix(imemory, op - 2, &m1)) < 0 || |
232 | 1 | (code = read_matrix(imemory, op - 1, &m2)) < 0 || |
233 | 1 | (code = gs_matrix_multiply(&m1, &m2, &mp)) < 0 || |
234 | 1 | (code = write_matrix(op, &mp)) < 0 |
235 | 1 | ) |
236 | 1 | return code; |
237 | 0 | op[-2] = *op; |
238 | 0 | pop(2); |
239 | 0 | return code; |
240 | 1 | } |
241 | | |
242 | | /* <x> <y> transform <xt> <yt> */ |
243 | | /* <x> <y> <matrix> transform <xt> <yt> */ |
244 | | static int |
245 | | ztransform(i_ctx_t *i_ctx_p) |
246 | 9 | { |
247 | 9 | return common_transform(i_ctx_p, gs_transform, gs_point_transform); |
248 | 9 | } |
249 | | |
250 | | /* <dx> <dy> dtransform <dxt> <dyt> */ |
251 | | /* <dx> <dy> <matrix> dtransform <dxt> <dyt> */ |
252 | | static int |
253 | | zdtransform(i_ctx_t *i_ctx_p) |
254 | 124k | { |
255 | 124k | return common_transform(i_ctx_p, gs_dtransform, gs_distance_transform); |
256 | 124k | } |
257 | | |
258 | | /* <xt> <yt> itransform <x> <y> */ |
259 | | /* <xt> <yt> <matrix> itransform <x> <y> */ |
260 | | static int |
261 | | zitransform(i_ctx_t *i_ctx_p) |
262 | 8 | { |
263 | 8 | return common_transform(i_ctx_p, gs_itransform, gs_point_transform_inverse); |
264 | 8 | } |
265 | | |
266 | | /* <dxt> <dyt> idtransform <dx> <dy> */ |
267 | | /* <dxt> <dyt> <matrix> idtransform <dx> <dy> */ |
268 | | static int |
269 | | zidtransform(i_ctx_t *i_ctx_p) |
270 | 107k | { |
271 | 107k | return common_transform(i_ctx_p, gs_idtransform, gs_distance_transform_inverse); |
272 | 107k | } |
273 | | |
274 | | /* Common logic for [i][d]transform */ |
275 | | static int |
276 | | common_transform(i_ctx_t *i_ctx_p, |
277 | | int (*ptproc)(gs_gstate *, double, double, gs_point *), |
278 | | int (*matproc)(double, double, const gs_matrix *, gs_point *)) |
279 | 231k | { |
280 | 231k | os_ptr op = osp; |
281 | 231k | double opxy[2]; |
282 | 231k | gs_point pt; |
283 | 231k | int code; |
284 | | |
285 | | /* Optimize for the non-matrix case */ |
286 | 231k | switch (r_type(op)) { |
287 | 107k | case t_real: |
288 | 107k | opxy[1] = op->value.realval; |
289 | 107k | break; |
290 | 8.72k | case t_integer: |
291 | 8.72k | opxy[1] = (double)op->value.intval; |
292 | 8.72k | break; |
293 | 115k | case t_array: /* might be a matrix */ |
294 | 115k | case t_shortarray: |
295 | 115k | case t_mixedarray: { |
296 | 115k | gs_matrix mat; |
297 | 115k | gs_matrix *pmat = &mat; |
298 | | |
299 | 115k | if ((code = read_matrix(imemory, op, pmat)) < 0 || |
300 | 115k | (code = num_params(op - 1, 2, opxy)) < 0 || |
301 | 115k | (code = (*matproc) (opxy[0], opxy[1], pmat, &pt)) < 0 |
302 | 115k | ) { /* Might be a stack underflow. */ |
303 | 2 | check_op(3); |
304 | 1 | return code; |
305 | 2 | } |
306 | 115k | op--; |
307 | 115k | pop(1); |
308 | 115k | goto out; |
309 | 115k | } |
310 | 8 | default: |
311 | 8 | return_op_typecheck(op); |
312 | 231k | } |
313 | 115k | switch (r_type(op - 1)) { |
314 | 107k | case t_real: |
315 | 107k | opxy[0] = (op - 1)->value.realval; |
316 | 107k | break; |
317 | 8.71k | case t_integer: |
318 | 8.71k | opxy[0] = (double)(op - 1)->value.intval; |
319 | 8.71k | break; |
320 | 8 | default: |
321 | 8 | return_op_typecheck(op - 1); |
322 | 115k | } |
323 | 115k | if ((code = (*ptproc) (igs, opxy[0], opxy[1], &pt)) < 0) |
324 | 0 | return code; |
325 | 231k | out: |
326 | 231k | make_real(op - 1, pt.x); |
327 | 231k | make_real(op, pt.y); |
328 | 231k | return 0; |
329 | 115k | } |
330 | | |
331 | | /* <matrix> <inv_matrix> invertmatrix <inv_matrix> */ |
332 | | static int |
333 | | zinvertmatrix(i_ctx_t *i_ctx_p) |
334 | 3 | { |
335 | 3 | os_ptr op = osp; |
336 | 3 | gs_matrix m; |
337 | 3 | int code; |
338 | | |
339 | 3 | check_op(2); |
340 | 2 | if ((code = read_matrix(imemory, op - 1, &m)) < 0 || |
341 | 2 | (code = gs_matrix_invert(&m, &m)) < 0 || |
342 | 2 | (code = write_matrix(op, &m)) < 0 |
343 | 2 | ) |
344 | 2 | return code; |
345 | 0 | op[-1] = *op; |
346 | 0 | pop(1); |
347 | 0 | return code; |
348 | 2 | } |
349 | | |
350 | | static int |
351 | | zupdatematrices(i_ctx_t *i_ctx_p) |
352 | 237k | { |
353 | 237k | return gs_updatematrices(igs); |
354 | 237k | } |
355 | | |
356 | | /* ------ Initialization procedure ------ */ |
357 | | |
358 | | const op_def zmatrix_op_defs[] = |
359 | | { |
360 | | {"1concat", zconcat}, |
361 | | {"2dtransform", zdtransform}, |
362 | | {"3concatmatrix", zconcatmatrix}, |
363 | | {"0.currentmatrix", zcurrentmatrix}, |
364 | | {"1defaultmatrix", zdefaultmatrix}, |
365 | | {"2idtransform", zidtransform}, |
366 | | {"0initmatrix", zinitmatrix}, |
367 | | {"2invertmatrix", zinvertmatrix}, |
368 | | {"2itransform", zitransform}, |
369 | | {"1rotate", zrotate}, |
370 | | {"2scale", zscale}, |
371 | | {"6.setmatrix", zsetmatrix}, |
372 | | {"1.setdefaultmatrix", zsetdefaultmatrix}, |
373 | | {"2transform", ztransform}, |
374 | | {"2translate", ztranslate}, |
375 | | op_def_end(0) |
376 | | }; |
377 | | |
378 | | const op_def zmatrix2_op_defs[] = |
379 | | { |
380 | | {"1.updatematrices", zupdatematrices}, |
381 | | op_def_end(0) |
382 | | }; |