/src/ghostpdl/psi/zform.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 | | /* 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 | | */ |
37 | | static int zbeginform(i_ctx_t *i_ctx_p) |
38 | 0 | { |
39 | 0 | os_ptr op = osp; |
40 | 0 | gx_device *cdev = gs_currentdevice_inline(igs); |
41 | 0 | int code; |
42 | 0 | float BBox[4], Matrix[6]; |
43 | 0 | gs_form_template_t tmplate; |
44 | 0 | gs_point ll, ur; |
45 | 0 | gs_fixed_rect box; |
46 | |
|
47 | 0 | check_type(*op, t_dictionary); |
48 | 0 | check_dict_read(*op); |
49 | | |
50 | 0 | code = read_matrix(imemory, op - 1, &tmplate.CTM); |
51 | 0 | if (code < 0) |
52 | 0 | return code; |
53 | | |
54 | 0 | code = dict_floats_param(imemory, op, "BBox", 4, BBox, NULL); |
55 | 0 | if (code < 0) |
56 | 0 | return code; |
57 | 0 | if (code == 0) |
58 | 0 | return_error(gs_error_undefined); |
59 | 0 | tmplate.FormID = -1; |
60 | 0 | tmplate.BBox.p.x = BBox[0]; |
61 | 0 | tmplate.BBox.p.y = BBox[1]; |
62 | 0 | tmplate.BBox.q.x = BBox[2]; |
63 | 0 | tmplate.BBox.q.y = BBox[3]; |
64 | |
|
65 | 0 | code = dict_floats_param(imemory, op, "Matrix", 6, Matrix, NULL); |
66 | 0 | if (code < 0) |
67 | 0 | return code; |
68 | 0 | if (code == 0) |
69 | 0 | return_error(gs_error_undefined); |
70 | | |
71 | 0 | tmplate.form_matrix.xx = Matrix[0]; |
72 | 0 | tmplate.form_matrix.xy = Matrix[1]; |
73 | 0 | tmplate.form_matrix.yx = Matrix[2]; |
74 | 0 | tmplate.form_matrix.yy = Matrix[3]; |
75 | 0 | tmplate.form_matrix.tx = Matrix[4]; |
76 | 0 | tmplate.form_matrix.ty = Matrix[5]; |
77 | |
|
78 | 0 | tmplate.pcpath = igs->clip_path; |
79 | |
|
80 | 0 | tmplate.pgs = igs; |
81 | 0 | code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_form_begin, |
82 | 0 | &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 | 0 | if (code > 0) |
88 | 0 | { |
89 | 0 | gs_setmatrix(igs, &tmplate.CTM); |
90 | 0 | gs_distance_transform(tmplate.BBox.p.x, tmplate.BBox.p.y, &tmplate.CTM, &ll); |
91 | 0 | 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 | 0 | box.p.x = float2fixed(ll.x); |
106 | 0 | box.p.y = float2fixed(ll.y); |
107 | 0 | box.q.x = float2fixed(ur.x); |
108 | 0 | box.q.y = float2fixed(ur.y); |
109 | |
|
110 | 0 | if (box.p.x < 0) { |
111 | 0 | if(box.p.x * -1 > box.q.x) |
112 | 0 | box.q.x = box.p.x * -1; |
113 | 0 | } else { |
114 | 0 | if (fabs(ur.x) > fabs(ll.x)) |
115 | 0 | box.p.x = box.q.x * -1; |
116 | 0 | else { |
117 | 0 | box.p.x = float2fixed(ll.x * -1); |
118 | 0 | box.q.x = float2fixed(ll.x); |
119 | 0 | } |
120 | 0 | } |
121 | 0 | if (box.p.y < 0) { |
122 | 0 | if(box.p.y * -1 > box.q.y) |
123 | 0 | box.q.y = box.p.y * -1; |
124 | 0 | } else { |
125 | 0 | if (fabs(ur.y) > fabs(ll.y)) |
126 | 0 | box.p.y = box.q.y * -1; |
127 | 0 | else { |
128 | 0 | box.p.y = float2fixed(ll.y * -1); |
129 | 0 | box.q.y = float2fixed(ll.y); |
130 | 0 | } |
131 | 0 | } |
132 | | /* This gets undone when we grestore after the form is executed */ |
133 | 0 | code = gx_clip_to_rectangle(igs, &box); |
134 | 0 | } |
135 | |
|
136 | 0 | pop(2); |
137 | 0 | return code; |
138 | 0 | } |
139 | | |
140 | | /* - .endform - |
141 | | */ |
142 | | static int zendform(i_ctx_t *i_ctx_p) |
143 | 0 | { |
144 | 0 | gx_device *cdev = gs_currentdevice_inline(igs); |
145 | 0 | int code; |
146 | |
|
147 | 0 | code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_form_end, |
148 | 0 | 0, 0); |
149 | 0 | return code; |
150 | 0 | } |
151 | | |
152 | | /* |
153 | | * - .get_form_id <int> |
154 | | */ |
155 | | static int zget_form_id(i_ctx_t *i_ctx_p) |
156 | 0 | { |
157 | 0 | os_ptr op = osp; |
158 | 0 | gx_device *cdev = gs_currentdevice_inline(igs); |
159 | 0 | int code, ID; |
160 | |
|
161 | 0 | code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_get_form_ID, |
162 | 0 | &ID, sizeof(int)); |
163 | |
|
164 | 0 | if (code < 0){ |
165 | 0 | ID = -1; |
166 | 0 | code = 0; |
167 | 0 | } |
168 | |
|
169 | 0 | push(1); |
170 | 0 | make_int(op, ID); |
171 | 0 | return code; |
172 | 0 | } |
173 | | |
174 | | /* |
175 | | * [matrix] <dict> <int> .repeatform - |
176 | | */ |
177 | | static int zrepeatform(i_ctx_t *i_ctx_p) |
178 | 0 | { |
179 | 0 | os_ptr op = osp; |
180 | 0 | gx_device *cdev = gs_currentdevice_inline(igs); |
181 | 0 | int code; |
182 | 0 | gs_form_template_t tmplate; |
183 | 0 | float BBox[4], Matrix[6]; |
184 | |
|
185 | 0 | check_type(*op, t_integer); |
186 | | |
187 | 0 | code = read_matrix(imemory, op - 2, &tmplate.CTM); |
188 | 0 | if (code < 0) |
189 | 0 | return code; |
190 | | |
191 | 0 | check_type(op[- 1], t_dictionary); |
192 | 0 | check_dict_read(*(op - 1)); |
193 | | |
194 | 0 | code = dict_floats_param(imemory, op - 1, "BBox", 4, BBox, NULL); |
195 | 0 | if (code < 0) |
196 | 0 | return code; |
197 | 0 | if (code == 0) |
198 | 0 | return_error(gs_error_undefined); |
199 | | |
200 | 0 | tmplate.BBox.p.x = BBox[0]; |
201 | 0 | tmplate.BBox.p.y = BBox[1]; |
202 | |
|
203 | 0 | code = dict_floats_param(imemory, op - 1, "Matrix", 6, Matrix, NULL); |
204 | 0 | if (code < 0) |
205 | 0 | return code; |
206 | 0 | if (code == 0) |
207 | 0 | return_error(gs_error_undefined); |
208 | | |
209 | 0 | tmplate.form_matrix.xx = Matrix[0]; |
210 | 0 | tmplate.form_matrix.xy = Matrix[1]; |
211 | 0 | tmplate.form_matrix.yx = Matrix[2]; |
212 | 0 | tmplate.form_matrix.yy = Matrix[3]; |
213 | 0 | tmplate.form_matrix.tx = Matrix[4]; |
214 | 0 | tmplate.form_matrix.ty = Matrix[5]; |
215 | |
|
216 | 0 | tmplate.pcpath = igs->clip_path; |
217 | |
|
218 | 0 | tmplate.FormID = op->value.intval; |
219 | |
|
220 | 0 | code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_repeat_form, |
221 | 0 | &tmplate, sizeof(gs_form_template_t)); |
222 | |
|
223 | 0 | pop(3); |
224 | 0 | return code; |
225 | 0 | } |
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 | | }; |