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