xref: /plan9/sys/src/cmd/gs/src/zmatrix.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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