/src/ghostpdl/psi/zmatrix.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 | | /* 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 | 375k | { |
34 | 375k | return gs_initmatrix(igs); |
35 | 375k | } |
36 | | |
37 | | /* <matrix> defaultmatrix <matrix> */ |
38 | | static int |
39 | | zdefaultmatrix(i_ctx_t *i_ctx_p) |
40 | 364k | { |
41 | 364k | os_ptr op = osp; |
42 | 364k | gs_matrix mat; |
43 | | |
44 | 364k | gs_defaultmatrix(igs, &mat); |
45 | 364k | return write_matrix(op, &mat); |
46 | 364k | } |
47 | | |
48 | | /* - .currentmatrix <xx> <xy> <yx> <yy> <tx> <ty> */ |
49 | | static int |
50 | | zcurrentmatrix(i_ctx_t *i_ctx_p) |
51 | 404k | { |
52 | 404k | os_ptr op = osp; |
53 | 404k | gs_matrix mat; |
54 | 404k | int code = gs_currentmatrix(igs, &mat); |
55 | | |
56 | 404k | if (code < 0) |
57 | 0 | return code; |
58 | 404k | push(6); |
59 | 404k | code = make_floats(op - 5, &mat.xx, 6); |
60 | 404k | if (code < 0) |
61 | 0 | pop(6); |
62 | 404k | return code; |
63 | 404k | } |
64 | | |
65 | | /* <xx> <xy> <yx> <yy> <tx> <ty> .setmatrix - */ |
66 | | static int |
67 | | zsetmatrix(i_ctx_t *i_ctx_p) |
68 | 29.4k | { |
69 | 29.4k | os_ptr op = osp; |
70 | 29.4k | gs_matrix mat; |
71 | 29.4k | int code = float_params(op, 6, &mat.xx); |
72 | | |
73 | 29.4k | if (code < 0) |
74 | 0 | return code; |
75 | 29.4k | if ((code = gs_setmatrix(igs, &mat)) < 0) |
76 | 0 | return code; |
77 | 29.4k | pop(6); |
78 | 29.4k | return 0; |
79 | 29.4k | } |
80 | | |
81 | | /* <matrix|null> .setdefaultmatrix - */ |
82 | | static int |
83 | | zsetdefaultmatrix(i_ctx_t *i_ctx_p) |
84 | 375k | { |
85 | 375k | os_ptr op = osp; |
86 | 375k | int code; |
87 | | |
88 | 375k | if (r_has_type(op, t_null)) |
89 | 0 | code = gs_setdefaultmatrix(igs, NULL); |
90 | 375k | else { |
91 | 375k | gs_matrix mat; |
92 | | |
93 | 375k | code = read_matrix(imemory, op, &mat); |
94 | 375k | if (code < 0) |
95 | 0 | return code; |
96 | 375k | code = gs_setdefaultmatrix(igs, &mat); |
97 | 375k | } |
98 | 375k | if (code < 0) |
99 | 0 | return code; |
100 | 375k | pop(1); |
101 | 375k | return 0; |
102 | 375k | } |
103 | | |
104 | | /* <tx> <ty> translate - */ |
105 | | /* <tx> <ty> <matrix> translate <matrix> */ |
106 | | static int |
107 | | ztranslate(i_ctx_t *i_ctx_p) |
108 | 611k | { |
109 | 611k | os_ptr op = osp; |
110 | 611k | int code; |
111 | 611k | double trans[2]; |
112 | | |
113 | 611k | if ((code = num_params(op, 2, trans)) >= 0) { |
114 | 610k | code = gs_translate(igs, trans[0], trans[1]); |
115 | 610k | if (code < 0) |
116 | 0 | return code; |
117 | 610k | } else { /* matrix operand */ |
118 | 777 | gs_matrix mat; |
119 | | |
120 | | /* The num_params failure might be a stack underflow. */ |
121 | 777 | check_op(2); |
122 | 764 | if ((code = num_params(op - 1, 2, trans)) < 0 || |
123 | 764 | (code = gs_make_translation(trans[0], trans[1], &mat)) < 0 || |
124 | 764 | (code = write_matrix(op, &mat)) < 0 |
125 | 764 | ) { /* Might be a stack underflow. */ |
126 | 31 | check_op(3); |
127 | 17 | return code; |
128 | 31 | } |
129 | 733 | op[-2] = *op; |
130 | 733 | } |
131 | 611k | pop(2); |
132 | 611k | return code; |
133 | 611k | } |
134 | | |
135 | | /* <sx> <sy> scale - */ |
136 | | /* <sx> <sy> <matrix> scale <matrix> */ |
137 | | static int |
138 | | zscale(i_ctx_t *i_ctx_p) |
139 | 7.26k | { |
140 | 7.26k | os_ptr op = osp; |
141 | 7.26k | int code; |
142 | 7.26k | double scale[2]; |
143 | | |
144 | 7.26k | if ((code = num_params(op, 2, scale)) >= 0) { |
145 | 6.97k | code = gs_scale(igs, scale[0], scale[1]); |
146 | 6.97k | if (code < 0) |
147 | 0 | return code; |
148 | 6.97k | } else { /* matrix operand */ |
149 | 284 | gs_matrix mat; |
150 | | |
151 | | /* The num_params failure might be a stack underflow. */ |
152 | 284 | check_op(2); |
153 | 270 | if ((code = num_params(op - 1, 2, scale)) < 0 || |
154 | 270 | (code = gs_make_scaling(scale[0], scale[1], &mat)) < 0 || |
155 | 270 | (code = write_matrix(op, &mat)) < 0 |
156 | 270 | ) { /* Might be a stack underflow. */ |
157 | 31 | check_op(3); |
158 | 19 | return code; |
159 | 31 | } |
160 | 239 | op[-2] = *op; |
161 | 239 | } |
162 | 7.21k | pop(2); |
163 | 7.21k | return code; |
164 | 7.26k | } |
165 | | |
166 | | /* <angle> rotate - */ |
167 | | /* <angle> <matrix> rotate <matrix> */ |
168 | | static int |
169 | | zrotate(i_ctx_t *i_ctx_p) |
170 | 111k | { |
171 | 111k | os_ptr op = osp; |
172 | 111k | int code; |
173 | 111k | double ang; |
174 | | |
175 | 111k | if ((code = real_param(op, &ang)) >= 0) { |
176 | 109k | code = gs_rotate(igs, ang); |
177 | 109k | if (code < 0) |
178 | 0 | return code; |
179 | 109k | } else { /* matrix operand */ |
180 | 2.09k | gs_matrix mat; |
181 | | |
182 | | /* The num_params failure might be a stack underflow. */ |
183 | 2.09k | check_op(1); |
184 | 2.08k | if ((code = num_params(op - 1, 1, &ang)) < 0 || |
185 | 2.08k | (code = gs_make_rotation(ang, &mat)) < 0 || |
186 | 2.08k | (code = write_matrix(op, &mat)) < 0 |
187 | 2.08k | ) { /* Might be a stack underflow. */ |
188 | 38 | check_op(2); |
189 | 28 | return code; |
190 | 38 | } |
191 | 2.04k | op[-1] = *op; |
192 | 2.04k | } |
193 | 111k | pop(1); |
194 | 111k | return code; |
195 | 111k | } |
196 | | |
197 | | /* <matrix> concat - */ |
198 | | static int |
199 | | zconcat(i_ctx_t *i_ctx_p) |
200 | 404k | { |
201 | 404k | os_ptr op = osp; |
202 | 404k | gs_matrix mat; |
203 | 404k | int code = read_matrix(imemory, op, &mat); |
204 | | |
205 | 404k | if (code < 0) |
206 | 18 | return code; |
207 | 404k | code = gs_concat(igs, &mat); |
208 | 404k | if (code < 0) |
209 | 0 | return code; |
210 | 404k | pop(1); |
211 | 404k | return 0; |
212 | 404k | } |
213 | | |
214 | | /* <matrix1> <matrix2> <matrix> concatmatrix <matrix> */ |
215 | | static int |
216 | | zconcatmatrix(i_ctx_t *i_ctx_p) |
217 | 6.08k | { |
218 | 6.08k | os_ptr op = osp; |
219 | 6.08k | gs_matrix m1, m2, mp; |
220 | 6.08k | int code; |
221 | | |
222 | 6.08k | if ((code = read_matrix(imemory, op - 2, &m1)) < 0 || |
223 | 6.08k | (code = read_matrix(imemory, op - 1, &m2)) < 0 || |
224 | 6.08k | (code = gs_matrix_multiply(&m1, &m2, &mp)) < 0 || |
225 | 6.08k | (code = write_matrix(op, &mp)) < 0 |
226 | 6.08k | ) |
227 | 10 | return code; |
228 | 6.07k | op[-2] = *op; |
229 | 6.07k | pop(2); |
230 | 6.07k | return code; |
231 | 6.08k | } |
232 | | |
233 | | /* <x> <y> transform <xt> <yt> */ |
234 | | /* <x> <y> <matrix> transform <xt> <yt> */ |
235 | | static int |
236 | | ztransform(i_ctx_t *i_ctx_p) |
237 | 566k | { |
238 | 566k | return common_transform(i_ctx_p, gs_transform, gs_point_transform); |
239 | 566k | } |
240 | | |
241 | | /* <dx> <dy> dtransform <dxt> <dyt> */ |
242 | | /* <dx> <dy> <matrix> dtransform <dxt> <dyt> */ |
243 | | static int |
244 | | zdtransform(i_ctx_t *i_ctx_p) |
245 | 457k | { |
246 | 457k | return common_transform(i_ctx_p, gs_dtransform, gs_distance_transform); |
247 | 457k | } |
248 | | |
249 | | /* <xt> <yt> itransform <x> <y> */ |
250 | | /* <xt> <yt> <matrix> itransform <x> <y> */ |
251 | | static int |
252 | | zitransform(i_ctx_t *i_ctx_p) |
253 | 50 | { |
254 | 50 | return common_transform(i_ctx_p, gs_itransform, gs_point_transform_inverse); |
255 | 50 | } |
256 | | |
257 | | /* <dxt> <dyt> idtransform <dx> <dy> */ |
258 | | /* <dxt> <dyt> <matrix> idtransform <dx> <dy> */ |
259 | | static int |
260 | | zidtransform(i_ctx_t *i_ctx_p) |
261 | 375k | { |
262 | 375k | return common_transform(i_ctx_p, gs_idtransform, gs_distance_transform_inverse); |
263 | 375k | } |
264 | | |
265 | | /* Common logic for [i][d]transform */ |
266 | | static int |
267 | | common_transform(i_ctx_t *i_ctx_p, |
268 | | int (*ptproc)(gs_gstate *, double, double, gs_point *), |
269 | | int (*matproc)(double, double, const gs_matrix *, gs_point *)) |
270 | 1.39M | { |
271 | 1.39M | os_ptr op = osp; |
272 | 1.39M | double opxy[2]; |
273 | 1.39M | gs_point pt; |
274 | 1.39M | int code; |
275 | | |
276 | | /* Optimize for the non-matrix case */ |
277 | 1.39M | switch (r_type(op)) { |
278 | 375k | case t_real: |
279 | 375k | opxy[1] = op->value.realval; |
280 | 375k | break; |
281 | 89.9k | case t_integer: |
282 | 89.9k | opxy[1] = (double)op->value.intval; |
283 | 89.9k | break; |
284 | 934k | case t_array: /* might be a matrix */ |
285 | 934k | case t_shortarray: |
286 | 934k | case t_mixedarray: { |
287 | 934k | gs_matrix mat; |
288 | 934k | gs_matrix *pmat = &mat; |
289 | | |
290 | 934k | if ((code = read_matrix(imemory, op, pmat)) < 0 || |
291 | 934k | (code = num_params(op - 1, 2, opxy)) < 0 || |
292 | 934k | (code = (*matproc) (opxy[0], opxy[1], pmat, &pt)) < 0 |
293 | 934k | ) { /* Might be a stack underflow. */ |
294 | 15 | check_op(3); |
295 | 9 | return code; |
296 | 15 | } |
297 | 934k | op--; |
298 | 934k | pop(1); |
299 | 934k | goto out; |
300 | 934k | } |
301 | 40 | default: |
302 | 40 | return_op_typecheck(op); |
303 | 1.39M | } |
304 | 465k | switch (r_type(op - 1)) { |
305 | 375k | case t_real: |
306 | 375k | opxy[0] = (op - 1)->value.realval; |
307 | 375k | break; |
308 | 89.8k | case t_integer: |
309 | 89.8k | opxy[0] = (double)(op - 1)->value.intval; |
310 | 89.8k | break; |
311 | 43 | default: |
312 | 43 | return_op_typecheck(op - 1); |
313 | 465k | } |
314 | 465k | if ((code = (*ptproc) (igs, opxy[0], opxy[1], &pt)) < 0) |
315 | 0 | return code; |
316 | 1.39M | out: |
317 | 1.39M | make_real(op - 1, pt.x); |
318 | 1.39M | make_real(op, pt.y); |
319 | 1.39M | return 0; |
320 | 465k | } |
321 | | |
322 | | /* <matrix> <inv_matrix> invertmatrix <inv_matrix> */ |
323 | | static int |
324 | | zinvertmatrix(i_ctx_t *i_ctx_p) |
325 | 20 | { |
326 | 20 | os_ptr op = osp; |
327 | 20 | gs_matrix m; |
328 | 20 | int code; |
329 | | |
330 | 20 | if ((code = read_matrix(imemory, op - 1, &m)) < 0 || |
331 | 20 | (code = gs_matrix_invert(&m, &m)) < 0 || |
332 | 20 | (code = write_matrix(op, &m)) < 0 |
333 | 20 | ) |
334 | 20 | return code; |
335 | 0 | op[-1] = *op; |
336 | 0 | pop(1); |
337 | 0 | return code; |
338 | 20 | } |
339 | | |
340 | | /* <bbox> <matrix> .bbox_transform <x0> <y0> <x1> <y1> */ |
341 | | /* Calculate bonding box of a box transformed by a matrix. */ |
342 | | static int |
343 | | zbbox_transform(i_ctx_t *i_ctx_p) |
344 | 0 | { |
345 | 0 | os_ptr op = osp; |
346 | 0 | gs_matrix m; |
347 | 0 | float bbox[4]; |
348 | 0 | gs_point aa, az, za, zz; |
349 | 0 | double temp; |
350 | 0 | int code; |
351 | |
|
352 | 0 | if ((code = read_matrix(imemory, op, &m)) < 0) |
353 | 0 | return code; |
354 | | |
355 | 0 | if (!r_is_array(op - 1)) |
356 | 0 | return_op_typecheck(op - 1); |
357 | 0 | check_read(op[-1]); |
358 | 0 | if (r_size(op - 1) != 4) |
359 | 0 | return_error(gs_error_rangecheck); |
360 | 0 | if ((code = process_float_array(imemory, op - 1, 4, bbox) < 0)) |
361 | 0 | return code; |
362 | | |
363 | 0 | gs_point_transform(bbox[0], bbox[1], &m, &aa); |
364 | 0 | gs_point_transform(bbox[0], bbox[3], &m, &az); |
365 | 0 | gs_point_transform(bbox[2], bbox[1], &m, &za); |
366 | 0 | gs_point_transform(bbox[2], bbox[3], &m, &zz); |
367 | |
|
368 | 0 | if ( aa.x > az.x) |
369 | 0 | temp = aa.x, aa.x = az.x, az.x = temp; |
370 | 0 | if ( za.x > zz.x) |
371 | 0 | temp = za.x, za.x = zz.x, zz.x = temp; |
372 | 0 | if ( za.x < aa.x) |
373 | 0 | aa.x = za.x; /* min */ |
374 | 0 | if ( az.x > zz.x) |
375 | 0 | zz.x = az.x; /* max */ |
376 | |
|
377 | 0 | if ( aa.y > az.y) |
378 | 0 | temp = aa.y, aa.y = az.y, az.y = temp; |
379 | 0 | if ( za.y > zz.y) |
380 | 0 | temp = za.y, za.y = zz.y, zz.y = temp; |
381 | 0 | if ( za.y < aa.y) |
382 | 0 | aa.y = za.y; /* min */ |
383 | 0 | if ( az.y > zz.y) |
384 | 0 | zz.y = az.y; /* max */ |
385 | |
|
386 | 0 | push(2); |
387 | 0 | make_real(op - 3, (float)aa.x); |
388 | 0 | make_real(op - 2, (float)aa.y); |
389 | 0 | make_real(op - 1, (float)zz.x); |
390 | 0 | make_real(op , (float)zz.y); |
391 | 0 | return 0; |
392 | 0 | } |
393 | | |
394 | | /* <matrix> .currenttextlinematrix <matrix> */ |
395 | | static int |
396 | | zcurrenttextlinematrix(i_ctx_t *i_ctx_p) |
397 | 0 | { |
398 | 0 | os_ptr op = osp; |
399 | 0 | gs_matrix mat; |
400 | |
|
401 | 0 | check_op(1); |
402 | 0 | if (!r_has_type(op, t_array)) |
403 | 0 | return_error(gs_error_typecheck); |
404 | | |
405 | 0 | gs_gettextlinematrix(igs, &mat); |
406 | 0 | return write_matrix(op, &mat); |
407 | 0 | } |
408 | | |
409 | | static int |
410 | | zsettextlinematrix(i_ctx_t *i_ctx_p) |
411 | 0 | { |
412 | 0 | os_ptr op = osp; |
413 | 0 | int code; |
414 | |
|
415 | 0 | check_op(1); |
416 | 0 | if (r_has_type(op, t_array)) { |
417 | 0 | gs_matrix mat; |
418 | |
|
419 | 0 | code = read_matrix(imemory, op, &mat); |
420 | 0 | if (code < 0) |
421 | 0 | return code; |
422 | 0 | code = gs_settextlinematrix(igs, &mat); |
423 | 0 | } else |
424 | 0 | code = gs_error_typecheck; |
425 | | |
426 | 0 | if (code < 0) |
427 | 0 | return code; |
428 | 0 | pop(1); |
429 | 0 | return 0; |
430 | 0 | } |
431 | | |
432 | | /* <matrix> .currenttextmatrix <matrix> */ |
433 | | static int |
434 | | zcurrenttextmatrix(i_ctx_t *i_ctx_p) |
435 | 0 | { |
436 | 0 | os_ptr op = osp; |
437 | 0 | gs_matrix mat; |
438 | |
|
439 | 0 | check_op(1); |
440 | 0 | if (!r_has_type(op, t_array)) |
441 | 0 | return_error(gs_error_typecheck); |
442 | | |
443 | 0 | gs_gettextmatrix(igs, &mat); |
444 | 0 | return write_matrix(op, &mat); |
445 | 0 | } |
446 | | |
447 | | static int |
448 | | zsettextmatrix(i_ctx_t *i_ctx_p) |
449 | 0 | { |
450 | 0 | os_ptr op = osp; |
451 | 0 | int code; |
452 | |
|
453 | 0 | check_op(1); |
454 | 0 | if (r_has_type(op, t_array)) { |
455 | 0 | gs_matrix mat; |
456 | |
|
457 | 0 | code = read_matrix(imemory, op, &mat); |
458 | 0 | if (code < 0) |
459 | 0 | return code; |
460 | 0 | code = gs_settextmatrix(igs, &mat); |
461 | 0 | } else |
462 | 0 | code = gs_error_typecheck; |
463 | | |
464 | 0 | if (code < 0) |
465 | 0 | return code; |
466 | 0 | pop(1); |
467 | 0 | return 0; |
468 | 0 | } |
469 | | |
470 | | static int |
471 | | zupdatematrices(i_ctx_t *i_ctx_p) |
472 | 996k | { |
473 | 996k | return gs_updatematrices(igs); |
474 | 996k | } |
475 | | |
476 | | /* ------ Initialization procedure ------ */ |
477 | | |
478 | | const op_def zmatrix_op_defs[] = |
479 | | { |
480 | | {"1concat", zconcat}, |
481 | | {"2dtransform", zdtransform}, |
482 | | {"3concatmatrix", zconcatmatrix}, |
483 | | {"0.currentmatrix", zcurrentmatrix}, |
484 | | {"1defaultmatrix", zdefaultmatrix}, |
485 | | {"2idtransform", zidtransform}, |
486 | | {"0initmatrix", zinitmatrix}, |
487 | | {"2invertmatrix", zinvertmatrix}, |
488 | | {"2itransform", zitransform}, |
489 | | {"1rotate", zrotate}, |
490 | | {"2scale", zscale}, |
491 | | {"6.setmatrix", zsetmatrix}, |
492 | | {"1.setdefaultmatrix", zsetdefaultmatrix}, |
493 | | {"2transform", ztransform}, |
494 | | {"2translate", ztranslate}, |
495 | | op_def_end(0) |
496 | | }; |
497 | | |
498 | | const op_def zmatrix2_op_defs[] = |
499 | | { |
500 | | {"2.bbox_transform", zbbox_transform}, |
501 | | {"1.currenttextlinematrix", zcurrenttextlinematrix}, |
502 | | {"1.settextlinematrix", zsettextlinematrix}, |
503 | | {"1.currenttextmatrix", zcurrenttextmatrix}, |
504 | | {"1.settextmatrix", zsettextmatrix}, |
505 | | {"1.updatematrices", zupdatematrices}, |
506 | | op_def_end(0) |
507 | | }; |