Commit | Line | Data |
---|---|---|
1d8a1861 WJ |
1 | /* Copyright (C) 1990, 1992 Aladdin Enterprises. All rights reserved. |
2 | Distributed by Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of Ghostscript. | |
5 | ||
6 | Ghostscript is distributed in the hope that it will be useful, but | |
7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility | |
8 | to anyone for the consequences of using it or for whether it serves any | |
9 | particular purpose or works at all, unless he says so in writing. Refer | |
10 | to the Ghostscript General Public License for full details. | |
11 | ||
12 | Everyone is granted permission to copy, modify and redistribute | |
13 | Ghostscript, but only under the conditions described in the Ghostscript | |
14 | General Public License. A copy of this license is supposed to have been | |
15 | given to you along with Ghostscript so you can know your rights and | |
16 | responsibilities. It should be in a file named COPYING. Among other | |
17 | things, the copyright notice and this notice must be preserved on all | |
18 | copies. */ | |
19 | ||
20 | /* zdps1.c */ | |
21 | /* Display PostScript graphics extensions */ | |
22 | #include "ghost.h" | |
23 | #include "errors.h" | |
24 | #include "oper.h" | |
25 | #include "gsmatrix.h" | |
26 | #include "gspath.h" | |
27 | #include "gsstate.h" | |
28 | #include "state.h" | |
29 | #include "store.h" | |
30 | #include "stream.h" | |
31 | #include "bnum.h" | |
32 | ||
33 | /* ------ Graphics states ------ */ | |
34 | ||
35 | /* Structure for saving a graphics state. */ | |
36 | typedef struct gstate_obj_s { | |
37 | int_gstate istate; | |
38 | gs_state *pgs; | |
39 | } gstate_obj; | |
40 | ||
41 | /* gstate */ | |
42 | int | |
43 | zgstate(register os_ptr op) | |
44 | { gs_state *pnew = gs_gstate(igs); | |
45 | gstate_obj *pso = | |
46 | (gstate_obj *)alloc(1, sizeof(gstate_obj), "gstate"); | |
47 | if ( pnew == 0 || pso == 0 ) return e_VMerror; | |
48 | pso->istate = istate; | |
49 | int_gstate_map_refs(&pso->istate, ref_mark_new); | |
50 | pso->pgs = pnew; | |
51 | push(1); | |
52 | make_tv(op, t_gstate, pgstate, pso); | |
53 | return 0; | |
54 | } | |
55 | ||
56 | /* currentgstate */ | |
57 | int | |
58 | zcurrentgstate(register os_ptr op) | |
59 | { int code; | |
60 | int_gstate *pistate; | |
61 | check_type(*op, t_gstate); | |
62 | /****** DOESN'T GET FULLY UNDONE BY RESTORE ******/ | |
63 | code = gs_currentgstate(op->value.pgstate->pgs, igs); | |
64 | if ( code < 0 ) return code; | |
65 | pistate = &op->value.pgstate->istate; | |
66 | #define gsref_save(p) ref_save(p, "currentgstate") | |
67 | int_gstate_map_refs(pistate, gsref_save); | |
68 | #undef gsref_save | |
69 | *pistate = istate; | |
70 | int_gstate_map_refs(pistate, ref_mark_new); | |
71 | return 0; | |
72 | } | |
73 | ||
74 | /* setgstate */ | |
75 | int | |
76 | zsetgstate(register os_ptr op) | |
77 | { int code; | |
78 | check_type(*op, t_gstate); | |
79 | code = gs_setgstate(igs, op->value.pgstate->pgs); | |
80 | if ( code < 0 ) return code; | |
81 | istate = op->value.pgstate->istate; | |
82 | pop(1); | |
83 | return 0; | |
84 | } | |
85 | ||
86 | /* ------ Rectangles ------- */ | |
87 | ||
88 | /* We preallocate a short list for rectangles, because */ | |
89 | /* the rectangle operators usually will involve very few rectangles. */ | |
90 | #define max_local_rect 5 | |
91 | typedef struct local_rects_s { | |
92 | gs_rect *pr; | |
93 | uint count; | |
94 | gs_rect rl[max_local_rect]; | |
95 | } local_rects; | |
96 | ||
97 | /* Forward references */ | |
98 | private int rect_get(P2(local_rects *, os_ptr)); | |
99 | private void rect_release(P1(local_rects *)); | |
100 | ||
101 | /* rectappend */ | |
102 | int | |
103 | zrectappend(os_ptr op) | |
104 | { local_rects lr; | |
105 | int npop = rect_get(&lr, op); | |
106 | int code; | |
107 | if ( npop < 0 ) return npop; | |
108 | code = gs_rectappend(igs, lr.pr, lr.count); | |
109 | rect_release(&lr); | |
110 | if ( code < 0 ) return code; | |
111 | pop(npop); | |
112 | return 0; | |
113 | } | |
114 | ||
115 | /* rectclip */ | |
116 | int | |
117 | zrectclip(os_ptr op) | |
118 | { local_rects lr; | |
119 | int npop = rect_get(&lr, op); | |
120 | int code; | |
121 | if ( npop < 0 ) return npop; | |
122 | code = gs_rectclip(igs, lr.pr, lr.count); | |
123 | rect_release(&lr); | |
124 | if ( code < 0 ) return code; | |
125 | pop(npop); | |
126 | return 0; | |
127 | } | |
128 | ||
129 | /* rectfill */ | |
130 | int | |
131 | zrectfill(os_ptr op) | |
132 | { local_rects lr; | |
133 | int npop = rect_get(&lr, op); | |
134 | int code; | |
135 | if ( npop < 0 ) return npop; | |
136 | code = gs_rectfill(igs, lr.pr, lr.count); | |
137 | rect_release(&lr); | |
138 | if ( code < 0 ) return code; | |
139 | pop(npop); | |
140 | return 0; | |
141 | } | |
142 | ||
143 | /* rectstroke */ | |
144 | int | |
145 | zrectstroke(os_ptr op) | |
146 | { gs_matrix mat; | |
147 | local_rects lr; | |
148 | int npop, code; | |
149 | if ( read_matrix(op, &mat) >= 0 ) | |
150 | { /* Concatenate the matrix to the CTM just before */ | |
151 | /* stroking the path. */ | |
152 | npop = rect_get(&lr, op - 1); | |
153 | if ( npop < 0 ) return npop; | |
154 | code = gs_rectstroke(igs, lr.pr, lr.count, &mat); | |
155 | npop++; | |
156 | } | |
157 | else | |
158 | { /* No matrix. */ | |
159 | npop = rect_get(&lr, op); | |
160 | if ( npop < 0 ) return npop; | |
161 | code = gs_rectstroke(igs, lr.pr, lr.count, (gs_matrix *)0); | |
162 | } | |
163 | rect_release(&lr); | |
164 | if ( code < 0 ) return code; | |
165 | pop(npop); | |
166 | return 0; | |
167 | } | |
168 | ||
169 | /* --- Internal routines --- */ | |
170 | ||
171 | /* Get rectangles from the stack. */ | |
172 | /* Return the number of elements to pop (>0) if OK, <0 if error. */ | |
173 | private int | |
174 | rect_get(local_rects *plr, os_ptr op) | |
175 | { int code, npop; | |
176 | stream st; | |
177 | uint n, count; | |
178 | gs_rect *pr; | |
179 | switch ( r_type(op) ) | |
180 | { | |
181 | case t_array: | |
182 | case t_string: | |
183 | code = sread_num_array(&st, op); | |
184 | if ( code < 0 ) return code; | |
185 | count = scount_num_stream(&st); | |
186 | if ( count % 4 ) return e_typecheck; | |
187 | count /= 4, npop = 1; | |
188 | break; | |
189 | default: /* better be 4 numbers */ | |
190 | sread_string(&st, (byte *)(op - 3), sizeof(ref) * 4); | |
191 | st.num_format = num_array; | |
192 | count = 1, npop = 4; | |
193 | break; | |
194 | } | |
195 | plr->count = count; | |
196 | if ( count <= max_local_rect ) | |
197 | pr = plr->rl; | |
198 | else | |
199 | { pr = (gs_rect *)alloc(count, sizeof(gs_rect), "rect_get"); | |
200 | if ( pr == 0 ) return e_VMerror; | |
201 | } | |
202 | plr->pr = pr; | |
203 | for ( n = 0; n < count; n++, pr++ ) | |
204 | { ref rnum; | |
205 | float rv[4]; | |
206 | int i; | |
207 | for ( i = 0; i < 4; i++ ) | |
208 | { switch ( code = sget_encoded_number(&st, &rnum) ) | |
209 | { | |
210 | case t_integer: | |
211 | rv[i] = rnum.value.intval; | |
212 | break; | |
213 | case t_real: | |
214 | rv[i] = rnum.value.realval; | |
215 | break; | |
216 | default: /* code < 0 */ | |
217 | return code; | |
218 | } | |
219 | } | |
220 | pr->q.x = (pr->p.x = rv[0]) + rv[2]; | |
221 | pr->q.y = (pr->p.y = rv[1]) + rv[3]; | |
222 | } | |
223 | return npop; | |
224 | } | |
225 | ||
226 | /* Release the rectangle list if needed. */ | |
227 | private void | |
228 | rect_release(local_rects *plr) | |
229 | { if ( plr->pr != plr->rl ) | |
230 | alloc_free((char *)plr->pr, plr->count, sizeof(gs_rect), | |
231 | "rect_release"); | |
232 | } | |
233 | ||
234 | /* ------ Graphics state ------ */ | |
235 | ||
236 | /* currentstrokeadjust */ | |
237 | int | |
238 | zcurrentstrokeadjust(register os_ptr op) | |
239 | { push(1); | |
240 | make_bool(op, gs_currentstrokeadjust(igs)); | |
241 | return 0; | |
242 | } | |
243 | ||
244 | /* setbbox */ | |
245 | int | |
246 | zsetbbox(register os_ptr op) | |
247 | { float box[4]; | |
248 | int code = num_params(op, 4, box); | |
249 | if ( code < 0 ) return code; | |
250 | if ( (code = gs_setbbox(igs, box[0], box[1], box[2], box[3])) < 0 ) | |
251 | return code; | |
252 | pop(4); | |
253 | return 0; | |
254 | } | |
255 | ||
256 | /* setstrokeadjust */ | |
257 | int | |
258 | zsetstrokeadjust(register os_ptr op) | |
259 | { check_type(*op, t_boolean); | |
260 | gs_setstrokeadjust(igs, op->value.index); | |
261 | pop(1); | |
262 | return 0; | |
263 | } | |
264 | ||
265 | /* ------ Initialization procedure ------ */ | |
266 | ||
267 | op_def zdps1_op_defs[] = { | |
268 | /* Graphics state objects */ | |
269 | {"0gstate", zgstate}, | |
270 | {"1currentgstate", zcurrentgstate}, | |
271 | {"1setgstate", zsetgstate}, | |
272 | /* Rectangles */ | |
273 | {"1rectappend", zrectappend}, | |
274 | {"1rectclip", zrectclip}, | |
275 | {"1rectfill", zrectfill}, | |
276 | {"1rectstroke", zrectstroke}, | |
277 | /* Graphics state components */ | |
278 | {"0currentstrokeadjust", zcurrentstrokeadjust}, | |
279 | {"4setbbox", zsetbbox}, | |
280 | {"1setstrokeadjust", zsetstrokeadjust}, | |
281 | op_def_end(0) | |
282 | }; |