1 /* Copyright (C) 2001-2019 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 /* Simple high level forms */
18 #include "ghost.h"
19 #include "oper.h"
20 #include "gxdevice.h"
21 #include "ialloc.h"
22 #include "idict.h"
23 #include "idparam.h"
24 #include "igstate.h"
25 #include "gxdevsop.h"
26 #include "gscoord.h"
27 #include "gsform1.h"
28 #include "gspath.h"
29 #include "gxpath.h"
30 #include "gzstate.h"
31 #include "store.h"
32
33 /* support for high level formss */
34
35 /* [CTM before Form Matrix applied] <<Form dictionary>> .beginform -
36 */
zbeginform(i_ctx_t * i_ctx_p)37 static int zbeginform(i_ctx_t *i_ctx_p)
38 {
39 os_ptr op = osp;
40 gx_device *cdev = gs_currentdevice_inline(igs);
41 int code;
42 float BBox[4], Matrix[6];
43 gs_form_template_t tmplate;
44 gs_point ll, ur;
45 gs_fixed_rect box;
46
47 check_type(*op, t_dictionary);
48 check_dict_read(*op);
49
50 code = read_matrix(imemory, op - 1, &tmplate.CTM);
51 if (code < 0)
52 return code;
53
54 code = dict_floats_param(imemory, op, "BBox", 4, BBox, NULL);
55 if (code < 0)
56 return code;
57 if (code == 0)
58 return_error(gs_error_undefined);
59 tmplate.FormID = -1;
60 tmplate.BBox.p.x = BBox[0];
61 tmplate.BBox.p.y = BBox[1];
62 tmplate.BBox.q.x = BBox[2];
63 tmplate.BBox.q.y = BBox[3];
64
65 code = dict_floats_param(imemory, op, "Matrix", 6, Matrix, NULL);
66 if (code < 0)
67 return code;
68 if (code == 0)
69 return_error(gs_error_undefined);
70
71 tmplate.form_matrix.xx = Matrix[0];
72 tmplate.form_matrix.xy = Matrix[1];
73 tmplate.form_matrix.yx = Matrix[2];
74 tmplate.form_matrix.yy = Matrix[3];
75 tmplate.form_matrix.tx = Matrix[4];
76 tmplate.form_matrix.ty = Matrix[5];
77
78 tmplate.pcpath = igs->clip_path;
79
80 tmplate.pgs = igs;
81 code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_form_begin,
82 &tmplate, 0);
83
84 /* return value > 0 means the device sent us back a matrix
85 * and wants the CTM set to that.
86 */
87 if (code > 0)
88 {
89 gs_setmatrix(igs, &tmplate.CTM);
90 gs_distance_transform(tmplate.BBox.p.x, tmplate.BBox.p.y, &tmplate.CTM, &ll);
91 gs_distance_transform(tmplate.BBox.q.x, tmplate.BBox.q.y, &tmplate.CTM, &ur);
92
93 /* A form can legitimately have negative co-ordinates in paths
94 * because it can be translated. But we always clip paths to the
95 * page which (clearly) can't have negative co-ordinates. NB this
96 * wouldn't be a problem if we didn't reset the CTM, but that would
97 * break the form capture.
98 * So here we temporarily set the clip to permit negative values,
99 * fortunately this works.....
100 */
101 /* We choose to permit negative values of the same magnitude as the
102 * positive ones.
103 */
104
105 box.p.x = float2fixed(ll.x);
106 box.p.y = float2fixed(ll.y);
107 box.q.x = float2fixed(ur.x);
108 box.q.y = float2fixed(ur.y);
109
110 if (box.p.x < 0) {
111 if(box.p.x * -1 > box.q.x)
112 box.q.x = box.p.x * -1;
113 } else {
114 if (fabs(ur.x) > fabs(ll.x))
115 box.p.x = box.q.x * -1;
116 else {
117 box.p.x = float2fixed(ll.x * -1);
118 box.q.x = float2fixed(ll.x);
119 }
120 }
121 if (box.p.y < 0) {
122 if(box.p.y * -1 > box.q.y)
123 box.q.y = box.p.y * -1;
124 } else {
125 if (fabs(ur.y) > fabs(ll.y))
126 box.p.y = box.q.y * -1;
127 else {
128 box.p.y = float2fixed(ll.y * -1);
129 box.q.y = float2fixed(ll.y);
130 }
131 }
132 /* This gets undone when we grestore after the form is executed */
133 code = gx_clip_to_rectangle(igs, &box);
134 }
135
136 pop(2);
137 return code;
138 }
139
140 /* - .endform -
141 */
zendform(i_ctx_t * i_ctx_p)142 static int zendform(i_ctx_t *i_ctx_p)
143 {
144 gx_device *cdev = gs_currentdevice_inline(igs);
145 int code;
146
147 code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_form_end,
148 0, 0);
149 return code;
150 }
151
152 /*
153 * - .get_form_id <int>
154 */
zget_form_id(i_ctx_t * i_ctx_p)155 static int zget_form_id(i_ctx_t *i_ctx_p)
156 {
157 os_ptr op = osp;
158 gx_device *cdev = gs_currentdevice_inline(igs);
159 int code, ID;
160
161 code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_get_form_ID,
162 &ID, sizeof(int));
163
164 if (code < 0){
165 ID = -1;
166 code = 0;
167 }
168
169 push(1);
170 make_int(op, ID);
171 return code;
172 }
173
174 /*
175 * [matrix] <dict> <int> .repeatform -
176 */
zrepeatform(i_ctx_t * i_ctx_p)177 static int zrepeatform(i_ctx_t *i_ctx_p)
178 {
179 os_ptr op = osp;
180 gx_device *cdev = gs_currentdevice_inline(igs);
181 int code;
182 gs_form_template_t tmplate;
183 float BBox[4], Matrix[6];
184
185 check_type(*op, t_integer);
186
187 code = read_matrix(imemory, op - 2, &tmplate.CTM);
188 if (code < 0)
189 return code;
190
191 check_type(op[- 1], t_dictionary);
192 check_dict_read(*(op - 1));
193
194 code = dict_floats_param(imemory, op - 1, "BBox", 4, BBox, NULL);
195 if (code < 0)
196 return code;
197 if (code == 0)
198 return_error(gs_error_undefined);
199
200 tmplate.BBox.p.x = BBox[0];
201 tmplate.BBox.p.y = BBox[1];
202
203 code = dict_floats_param(imemory, op - 1, "Matrix", 6, Matrix, NULL);
204 if (code < 0)
205 return code;
206 if (code == 0)
207 return_error(gs_error_undefined);
208
209 tmplate.form_matrix.xx = Matrix[0];
210 tmplate.form_matrix.xy = Matrix[1];
211 tmplate.form_matrix.yx = Matrix[2];
212 tmplate.form_matrix.yy = Matrix[3];
213 tmplate.form_matrix.tx = Matrix[4];
214 tmplate.form_matrix.ty = Matrix[5];
215
216 tmplate.pcpath = igs->clip_path;
217
218 tmplate.FormID = op->value.intval;
219
220 code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_repeat_form,
221 &tmplate, sizeof(gs_form_template_t));
222
223 pop(3);
224 return code;
225 }
226
227 const op_def zform_op_defs[] =
228 {
229 {"0.beginform", zbeginform},
230 {"0.endform", zendform},
231 {"0.get_form_id", zget_form_id},
232 {"3.repeatform", zrepeatform},
233 op_def_end(0)
234 };
235