1 /* Copyright (C) 1989, 2000 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: zdevice.c,v 1.10 2004/09/15 19:41:01 ray Exp $ */
18 /* Device-related operators */
19 #include "string_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "ialloc.h"
23 #include "idict.h"
24 #include "igstate.h"
25 #include "iname.h"
26 #include "interp.h"
27 #include "iparam.h"
28 #include "ivmspace.h"
29 #include "gsmatrix.h"
30 #include "gsstate.h"
31 #include "gxdevice.h"
32 #include "gxgetbit.h"
33 #include "store.h"
34
35 /* <device> <keep_open> .copydevice2 <newdevice> */
36 private int
zcopydevice2(i_ctx_t * i_ctx_p)37 zcopydevice2(i_ctx_t *i_ctx_p)
38 {
39 os_ptr op = osp;
40 gx_device *new_dev;
41 int code;
42
43 check_read_type(op[-1], t_device);
44 check_type(*op, t_boolean);
45 code = gs_copydevice2(&new_dev, op[-1].value.pdevice, op->value.boolval,
46 imemory);
47 if (code < 0)
48 return code;
49 new_dev->memory = imemory;
50 make_tav(op - 1, t_device, icurrent_space | a_all, pdevice, new_dev);
51 pop(1);
52 return 0;
53 }
54
55 /* - currentdevice <device> */
56 int
zcurrentdevice(i_ctx_t * i_ctx_p)57 zcurrentdevice(i_ctx_t *i_ctx_p)
58 {
59 os_ptr op = osp;
60 gx_device *dev = gs_currentdevice(igs);
61 gs_ref_memory_t *mem = (gs_ref_memory_t *) dev->memory;
62
63 push(1);
64 make_tav(op, t_device,
65 (mem == 0 ? avm_foreign : imemory_space(mem)) | a_all,
66 pdevice, dev);
67 return 0;
68 }
69
70 /* <device> .devicename <string> */
71 private int
zdevicename(i_ctx_t * i_ctx_p)72 zdevicename(i_ctx_t *i_ctx_p)
73 {
74 os_ptr op = osp;
75 const char *dname;
76
77 check_read_type(*op, t_device);
78 dname = op->value.pdevice->dname;
79 make_const_string(op, avm_foreign | a_readonly, strlen(dname),
80 (const byte *)dname);
81 return 0;
82 }
83
84 /* - .doneshowpage - */
85 private int
zdoneshowpage(i_ctx_t * i_ctx_p)86 zdoneshowpage(i_ctx_t *i_ctx_p)
87 {
88 gx_device *dev = gs_currentdevice(igs);
89 gx_device *tdev = (*dev_proc(dev, get_page_device)) (dev);
90
91 if (tdev != 0)
92 tdev->ShowpageCount++;
93 return 0;
94 }
95
96 /* - flushpage - */
97 int
zflushpage(i_ctx_t * i_ctx_p)98 zflushpage(i_ctx_t *i_ctx_p)
99 {
100 return gs_flushpage(igs);
101 }
102
103 /* <device> <x> <y> <width> <max_height> <alpha?> <std_depth|null> <string> */
104 /* .getbitsrect <height> <substring> */
105 private int
zgetbitsrect(i_ctx_t * i_ctx_p)106 zgetbitsrect(i_ctx_t *i_ctx_p)
107 { /*
108 * alpha? is 0 for no alpha, -1 for alpha first, 1 for alpha last.
109 * std_depth is null for native pixels, depth/component for
110 * standard color space.
111 */
112 os_ptr op = osp;
113 gx_device *dev;
114 gs_int_rect rect;
115 gs_get_bits_params_t params;
116 int w, h;
117 gs_get_bits_options_t options =
118 GB_ALIGN_ANY | GB_RETURN_COPY | GB_OFFSET_0 | GB_RASTER_STANDARD |
119 GB_PACKING_CHUNKY;
120 int depth;
121 uint raster;
122 int num_rows;
123 int code;
124
125 check_read_type(op[-7], t_device);
126 dev = op[-7].value.pdevice;
127 check_int_leu(op[-6], dev->width);
128 rect.p.x = op[-6].value.intval;
129 check_int_leu(op[-5], dev->height);
130 rect.p.y = op[-5].value.intval;
131 check_int_leu(op[-4], dev->width);
132 w = op[-4].value.intval;
133 check_int_leu(op[-3], dev->height);
134 h = op[-3].value.intval;
135 check_type(op[-2], t_integer);
136 /*
137 * We use if/else rather than switch because the value is long,
138 * which is not supported as a switch value in pre-ANSI C.
139 */
140 if (op[-2].value.intval == -1)
141 options |= GB_ALPHA_FIRST;
142 else if (op[-2].value.intval == 0)
143 options |= GB_ALPHA_NONE;
144 else if (op[-2].value.intval == 1)
145 options |= GB_ALPHA_LAST;
146 else
147 return_error(e_rangecheck);
148 if (r_has_type(op - 1, t_null)) {
149 options |= GB_COLORS_NATIVE;
150 depth = dev->color_info.depth;
151 } else {
152 static const gs_get_bits_options_t depths[17] = {
153 0, GB_DEPTH_1, GB_DEPTH_2, 0, GB_DEPTH_4, 0, 0, 0, GB_DEPTH_8,
154 0, 0, 0, GB_DEPTH_12, 0, 0, 0, GB_DEPTH_16
155 };
156 gs_get_bits_options_t depth_option;
157 int std_depth;
158
159 check_int_leu(op[-1], 16);
160 std_depth = (int)op[-1].value.intval;
161 depth_option = depths[std_depth];
162 if (depth_option == 0)
163 return_error(e_rangecheck);
164 options |= depth_option | GB_COLORS_NATIVE;
165 depth = (dev->color_info.num_components +
166 (options & GB_ALPHA_NONE ? 0 : 1)) * std_depth;
167 }
168 if (w == 0)
169 return_error(e_rangecheck);
170 raster = (w * depth + 7) >> 3;
171 check_write_type(*op, t_string);
172 num_rows = r_size(op) / raster;
173 h = min(h, num_rows);
174 if (h == 0)
175 return_error(e_rangecheck);
176 rect.q.x = rect.p.x + w;
177 rect.q.y = rect.p.y + h;
178 params.options = options;
179 params.data[0] = op->value.bytes;
180 code = (*dev_proc(dev, get_bits_rectangle))(dev, &rect, ¶ms, NULL);
181 if (code < 0)
182 return code;
183 make_int(op - 7, h);
184 op[-6] = *op;
185 r_set_size(op - 6, h * raster);
186 pop(6);
187 return 0;
188 }
189
190 /* <int> .getdevice <device> */
191 private int
zgetdevice(i_ctx_t * i_ctx_p)192 zgetdevice(i_ctx_t *i_ctx_p)
193 {
194 os_ptr op = osp;
195 const gx_device *dev;
196
197 check_type(*op, t_integer);
198 if (op->value.intval != (int)(op->value.intval))
199 return_error(e_rangecheck); /* won't fit in an int */
200 dev = gs_getdevice((int)(op->value.intval));
201 if (dev == 0) /* index out of range */
202 return_error(e_rangecheck);
203 /* Device prototypes are read-only; */
204 /* the cast is logically unnecessary. */
205 make_tav(op, t_device, avm_foreign | a_readonly, pdevice,
206 (gx_device *) dev);
207 return 0;
208 }
209
210 /* Common functionality of zgethardwareparms & zgetdeviceparams */
211 private int
zget_device_params(i_ctx_t * i_ctx_p,bool is_hardware)212 zget_device_params(i_ctx_t *i_ctx_p, bool is_hardware)
213 {
214 os_ptr op = osp;
215 ref rkeys;
216 gx_device *dev;
217 stack_param_list list;
218 int code;
219 ref *pmark;
220
221 check_read_type(op[-1], t_device);
222 rkeys = *op;
223 dev = op[-1].value.pdevice;
224 pop(1);
225 stack_param_list_write(&list, &o_stack, &rkeys, iimemory);
226 code = gs_get_device_or_hardware_params(dev, (gs_param_list *) & list,
227 is_hardware);
228 if (code < 0) {
229 /* We have to put back the top argument. */
230 if (list.count > 0)
231 ref_stack_pop(&o_stack, list.count * 2 - 1);
232 else
233 ref_stack_push(&o_stack, 1);
234 *osp = rkeys;
235 return code;
236 }
237 pmark = ref_stack_index(&o_stack, list.count * 2);
238 make_mark(pmark);
239 return 0;
240 }
241 /* <device> <key_dict|null> .getdeviceparams <mark> <name> <value> ... */
242 private int
zgetdeviceparams(i_ctx_t * i_ctx_p)243 zgetdeviceparams(i_ctx_t *i_ctx_p)
244 {
245 return zget_device_params(i_ctx_p, false);
246 }
247 /* <device> <key_dict|null> .gethardwareparams <mark> <name> <value> ... */
248 private int
zgethardwareparams(i_ctx_t * i_ctx_p)249 zgethardwareparams(i_ctx_t *i_ctx_p)
250 {
251 return zget_device_params(i_ctx_p, true);
252 }
253
254 /* <matrix> <width> <height> <palette> <word?> makewordimagedevice <device> */
255 private int
zmakewordimagedevice(i_ctx_t * i_ctx_p)256 zmakewordimagedevice(i_ctx_t *i_ctx_p)
257 {
258 os_ptr op = osp;
259 os_ptr op1 = op - 1;
260 gs_matrix imat;
261 gx_device *new_dev;
262 const byte *colors;
263 int colors_size;
264 int code;
265
266 check_int_leu(op[-3], max_uint >> 1); /* width */
267 check_int_leu(op[-2], max_uint >> 1); /* height */
268 check_type(*op, t_boolean);
269 if (r_has_type(op1, t_null)) { /* true color */
270 colors = 0;
271 colors_size = -24; /* 24-bit true color */
272 } else if (r_has_type(op1, t_integer)) {
273 /*
274 * We use if/else rather than switch because the value is long,
275 * which is not supported as a switch value in pre-ANSI C.
276 */
277 if (op1->value.intval != 16 && op1->value.intval != 24 &&
278 op1->value.intval != 32
279 )
280 return_error(e_rangecheck);
281 colors = 0;
282 colors_size = -op1->value.intval;
283 } else {
284 check_type(*op1, t_string); /* palette */
285 if (r_size(op1) > 3 * 256)
286 return_error(e_rangecheck);
287 colors = op1->value.bytes;
288 colors_size = r_size(op1);
289 }
290 if ((code = read_matrix(imemory, op - 4, &imat)) < 0)
291 return code;
292 /* Everything OK, create device */
293 code = gs_makewordimagedevice(&new_dev, &imat,
294 (int)op[-3].value.intval,
295 (int)op[-2].value.intval,
296 colors, colors_size,
297 op->value.boolval, true, imemory);
298 if (code == 0) {
299 new_dev->memory = imemory;
300 make_tav(op - 4, t_device, imemory_space(iimemory) | a_all,
301 pdevice, new_dev);
302 pop(4);
303 }
304 return code;
305 }
306
307 /* - nulldevice - */
308 /* Note that nulldevice clears the current pagedevice. */
309 private int
znulldevice(i_ctx_t * i_ctx_p)310 znulldevice(i_ctx_t *i_ctx_p)
311 {
312 gs_nulldevice(igs);
313 clear_pagedevice(istate);
314 return 0;
315 }
316
317 /* <num_copies> <flush_bool> .outputpage - */
318 private int
zoutputpage(i_ctx_t * i_ctx_p)319 zoutputpage(i_ctx_t *i_ctx_p)
320 {
321 os_ptr op = osp;
322 int code;
323
324 check_type(op[-1], t_integer);
325 check_type(*op, t_boolean);
326 code = gs_output_page(igs, (int)op[-1].value.intval,
327 op->value.boolval);
328 if (code < 0)
329 return code;
330 pop(2);
331 return 0;
332 }
333
334 /* <device> <policy_dict|null> <require_all> <mark> <name> <value> ... */
335 /* .putdeviceparams */
336 /* (on success) <device> <eraseflag> */
337 /* (on failure) <device> <policy_dict|null> <require_all> <mark> */
338 /* <name1> <error1> ... */
339 /* For a key that simply was not recognized, if require_all is true, */
340 /* the result will be an /undefined error; if require_all is false, */
341 /* the key will be ignored. */
342 /* Note that .putdeviceparams clears the current pagedevice. */
343 private int
zputdeviceparams(i_ctx_t * i_ctx_p)344 zputdeviceparams(i_ctx_t *i_ctx_p)
345 {
346 uint count = ref_stack_counttomark(&o_stack);
347 ref *prequire_all;
348 ref *ppolicy;
349 ref *pdev;
350 gx_device *dev;
351 stack_param_list list;
352 int code;
353 int old_width, old_height;
354 int i, dest;
355
356 if (count == 0)
357 return_error(e_unmatchedmark);
358 prequire_all = ref_stack_index(&o_stack, count);
359 ppolicy = ref_stack_index(&o_stack, count + 1);
360 pdev = ref_stack_index(&o_stack, count + 2);
361 if (pdev == 0)
362 return_error(e_stackunderflow);
363 check_type_only(*prequire_all, t_boolean);
364 check_write_type_only(*pdev, t_device);
365 dev = pdev->value.pdevice;
366 code = stack_param_list_read(&list, &o_stack, 0, ppolicy,
367 prequire_all->value.boolval, iimemory);
368 if (code < 0)
369 return code;
370 old_width = dev->width;
371 old_height = dev->height;
372 code = gs_putdeviceparams(dev, (gs_param_list *) & list);
373 /* Check for names that were undefined or caused errors. */
374 for (dest = count - 2, i = 0; i < count >> 1; i++)
375 if (list.results[i] < 0) {
376 *ref_stack_index(&o_stack, dest) =
377 *ref_stack_index(&o_stack, count - (i << 1) - 2);
378 gs_errorname(i_ctx_p, list.results[i],
379 ref_stack_index(&o_stack, dest - 1));
380 dest -= 2;
381 }
382 iparam_list_release(&list);
383 if (code < 0) { /* There were errors reported. */
384 ref_stack_pop(&o_stack, dest + 1);
385 return 0;
386 }
387 if (code > 0 || (code == 0 && (dev->width != old_width || dev->height != old_height))) {
388 /*
389 * The device was open and is now closed, or its dimensions have
390 * changed. If it was the current device, call setdevice to
391 * reinstall it and erase the page.
392 */
393 /****** DOESN'T FIND ALL THE GSTATES THAT REFERENCE THE DEVICE. ******/
394 if (gs_currentdevice(igs) == dev) {
395 bool was_open = dev->is_open;
396
397 code = gs_setdevice_no_erase(igs, dev);
398 /* If the device wasn't closed, setdevice won't erase the page. */
399 if (was_open && code >= 0)
400 code = 1;
401 }
402 }
403 if (code < 0)
404 return code;
405 ref_stack_pop(&o_stack, count + 1);
406 make_bool(osp, code);
407 clear_pagedevice(istate);
408 return 0;
409 }
410
411 /* <device> .setdevice <eraseflag> */
412 /* Note that .setdevice clears the current pagedevice. */
413 int
zsetdevice(i_ctx_t * i_ctx_p)414 zsetdevice(i_ctx_t *i_ctx_p)
415 {
416 gx_device *dev = gs_currentdevice(igs);
417 os_ptr op = osp;
418 int code;
419
420 check_write_type(*op, t_device);
421 if (dev->LockSafetyParams) { /* do additional checking if locked */
422 if(op->value.pdevice != dev) /* don't allow a different device */
423 return_error(e_invalidaccess);
424 }
425 code = gs_setdevice_no_erase(igs, op->value.pdevice);
426 if (code < 0)
427 return code;
428 make_bool(op, code != 0); /* erase page if 1 */
429 clear_pagedevice(istate);
430 return code;
431 }
432
433 /* ------ Initialization procedure ------ */
434
435 const op_def zdevice_op_defs[] =
436 {
437 {"1.copydevice2", zcopydevice2},
438 {"0currentdevice", zcurrentdevice},
439 {"1.devicename", zdevicename},
440 {"0.doneshowpage", zdoneshowpage},
441 {"0flushpage", zflushpage},
442 {"7.getbitsrect", zgetbitsrect},
443 {"1.getdevice", zgetdevice},
444 {"2.getdeviceparams", zgetdeviceparams},
445 {"2.gethardwareparams", zgethardwareparams},
446 {"5makewordimagedevice", zmakewordimagedevice},
447 {"0nulldevice", znulldevice},
448 {"2.outputpage", zoutputpage},
449 {"3.putdeviceparams", zputdeviceparams},
450 {"1.setdevice", zsetdevice},
451 op_def_end(0)
452 };
453