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