diff options
Diffstat (limited to 'gs/psi/zdevice.c')
-rw-r--r-- | gs/psi/zdevice.c | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/gs/psi/zdevice.c b/gs/psi/zdevice.c new file mode 100644 index 000000000..4553128ef --- /dev/null +++ b/gs/psi/zdevice.c @@ -0,0 +1,493 @@ +/* Copyright (C) 2001-2006 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com/ + or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, + San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. +*/ + +/* $Id$ */ +/* Device-related operators */ +#include "string_.h" +#include "ghost.h" +#include "oper.h" +#include "ialloc.h" +#include "idict.h" +#include "igstate.h" +#include "imain.h" +#include "imemory.h" +#include "iname.h" +#include "interp.h" +#include "iparam.h" +#include "ivmspace.h" +#include "gsmatrix.h" +#include "gsstate.h" +#include "gxdevice.h" +#include "gxalloc.h" +#include "gxgetbit.h" +#include "store.h" + +/* <device> <keep_open> .copydevice2 <newdevice> */ +static int +zcopydevice2(i_ctx_t *i_ctx_p) +{ + os_ptr op = osp; + gx_device *new_dev; + int code; + + check_read_type(op[-1], t_device); + check_type(*op, t_boolean); + code = gs_copydevice2(&new_dev, op[-1].value.pdevice, op->value.boolval, + imemory); + if (code < 0) + return code; + new_dev->memory = imemory; + make_tav(op - 1, t_device, icurrent_space | a_all, pdevice, new_dev); + pop(1); + return 0; +} + +/* - currentdevice <device> */ +int +zcurrentdevice(i_ctx_t *i_ctx_p) +{ + os_ptr op = osp; + gx_device *dev = gs_currentdevice(igs); + gs_ref_memory_t *mem = (gs_ref_memory_t *) dev->memory; + + push(1); + make_tav(op, t_device, + (mem == 0 ? avm_foreign : imemory_space(mem)) | a_all, + pdevice, dev); + return 0; +} + +/* <device> .devicename <string> */ +static int +zdevicename(i_ctx_t *i_ctx_p) +{ + os_ptr op = osp; + const char *dname; + + check_read_type(*op, t_device); + dname = op->value.pdevice->dname; + make_const_string(op, avm_foreign | a_readonly, strlen(dname), + (const byte *)dname); + return 0; +} + +/* - .doneshowpage - */ +static int +zdoneshowpage(i_ctx_t *i_ctx_p) +{ + gx_device *dev = gs_currentdevice(igs); + gx_device *tdev = (*dev_proc(dev, get_page_device)) (dev); + + if (tdev != 0) + tdev->ShowpageCount++; + return 0; +} + +/* - flushpage - */ +int +zflushpage(i_ctx_t *i_ctx_p) +{ + return gs_flushpage(igs); +} + +/* <device> <x> <y> <width> <max_height> <alpha?> <std_depth|null> <string> */ +/* .getbitsrect <height> <substring> */ +static int +zgetbitsrect(i_ctx_t *i_ctx_p) +{ /* + * alpha? is 0 for no alpha, -1 for alpha first, 1 for alpha last. + * std_depth is null for native pixels, depth/component for + * standard color space. + */ + os_ptr op = osp; + gx_device *dev; + gs_int_rect rect; + gs_get_bits_params_t params; + int w, h; + gs_get_bits_options_t options = + GB_ALIGN_ANY | GB_RETURN_COPY | GB_OFFSET_0 | GB_RASTER_STANDARD | + GB_PACKING_CHUNKY; + int depth; + uint raster; + int num_rows; + int code; + + check_read_type(op[-7], t_device); + dev = op[-7].value.pdevice; + check_int_leu(op[-6], dev->width); + rect.p.x = op[-6].value.intval; + check_int_leu(op[-5], dev->height); + rect.p.y = op[-5].value.intval; + check_int_leu(op[-4], dev->width); + w = op[-4].value.intval; + check_int_leu(op[-3], dev->height); + h = op[-3].value.intval; + check_type(op[-2], t_integer); + /* + * We use if/else rather than switch because the value is long, + * which is not supported as a switch value in pre-ANSI C. + */ + if (op[-2].value.intval == -1) + options |= GB_ALPHA_FIRST; + else if (op[-2].value.intval == 0) + options |= GB_ALPHA_NONE; + else if (op[-2].value.intval == 1) + options |= GB_ALPHA_LAST; + else + return_error(e_rangecheck); + if (r_has_type(op - 1, t_null)) { + options |= GB_COLORS_NATIVE; + depth = dev->color_info.depth; + } else { + static const gs_get_bits_options_t depths[17] = { + 0, GB_DEPTH_1, GB_DEPTH_2, 0, GB_DEPTH_4, 0, 0, 0, GB_DEPTH_8, + 0, 0, 0, GB_DEPTH_12, 0, 0, 0, GB_DEPTH_16 + }; + gs_get_bits_options_t depth_option; + int std_depth; + + check_int_leu(op[-1], 16); + std_depth = (int)op[-1].value.intval; + depth_option = depths[std_depth]; + if (depth_option == 0) + return_error(e_rangecheck); + options |= depth_option | GB_COLORS_NATIVE; + depth = (dev->color_info.num_components + + (options & GB_ALPHA_NONE ? 0 : 1)) * std_depth; + } + if (w == 0) + return_error(e_rangecheck); + raster = (w * depth + 7) >> 3; + check_write_type(*op, t_string); + num_rows = r_size(op) / raster; + h = min(h, num_rows); + if (h == 0) + return_error(e_rangecheck); + rect.q.x = rect.p.x + w; + rect.q.y = rect.p.y + h; + params.options = options; + params.data[0] = op->value.bytes; + code = (*dev_proc(dev, get_bits_rectangle))(dev, &rect, ¶ms, NULL); + if (code < 0) + return code; + make_int(op - 7, h); + op[-6] = *op; + r_set_size(op - 6, h * raster); + pop(6); + return 0; +} + +/* <int> .getdevice <device> */ +static int +zgetdevice(i_ctx_t *i_ctx_p) +{ + os_ptr op = osp; + const gx_device *dev; + + check_type(*op, t_integer); + if (op->value.intval != (int)(op->value.intval)) + return_error(e_rangecheck); /* won't fit in an int */ + dev = gs_getdevice((int)(op->value.intval)); + if (dev == 0) /* index out of range */ + return_error(e_rangecheck); + /* Device prototypes are read-only; */ + /* the cast is logically unnecessary. */ + make_tav(op, t_device, avm_foreign | a_readonly, pdevice, + (gx_device *) dev); + return 0; +} + +/* - .getdefaultdevice <device> */ +static int +zgetdefaultdevice(i_ctx_t *i_ctx_p) +{ + os_ptr op = osp; + const gx_device *dev; + + dev = gs_getdefaultdevice(); + if (dev == 0) /* couldn't find a default device */ + return_error(e_unknownerror); + push(1); + make_tav(op, t_device, avm_foreign | a_readonly, pdevice, + (gx_device *) dev); + return 0; +} + +/* Common functionality of zgethardwareparms & zgetdeviceparams */ +static int +zget_device_params(i_ctx_t *i_ctx_p, bool is_hardware) +{ + os_ptr op = osp; + ref rkeys; + gx_device *dev; + stack_param_list list; + int code; + ref *pmark; + + check_read_type(op[-1], t_device); + rkeys = *op; + dev = op[-1].value.pdevice; + pop(1); + stack_param_list_write(&list, &o_stack, &rkeys, iimemory); + code = gs_get_device_or_hardware_params(dev, (gs_param_list *) & list, + is_hardware); + if (code < 0) { + /* We have to put back the top argument. */ + if (list.count > 0) + ref_stack_pop(&o_stack, list.count * 2 - 1); + else + ref_stack_push(&o_stack, 1); + *osp = rkeys; + return code; + } + pmark = ref_stack_index(&o_stack, list.count * 2); + make_mark(pmark); + return 0; +} +/* <device> <key_dict|null> .getdeviceparams <mark> <name> <value> ... */ +static int +zgetdeviceparams(i_ctx_t *i_ctx_p) +{ + return zget_device_params(i_ctx_p, false); +} +/* <device> <key_dict|null> .gethardwareparams <mark> <name> <value> ... */ +static int +zgethardwareparams(i_ctx_t *i_ctx_p) +{ + return zget_device_params(i_ctx_p, true); +} + +/* <matrix> <width> <height> <palette> <word?> makewordimagedevice <device> */ +static int +zmakewordimagedevice(i_ctx_t *i_ctx_p) +{ + os_ptr op = osp; + os_ptr op1 = op - 1; + gs_matrix imat; + gx_device *new_dev; + const byte *colors; + int colors_size; + int code; + + check_int_leu(op[-3], max_uint >> 1); /* width */ + check_int_leu(op[-2], max_uint >> 1); /* height */ + check_type(*op, t_boolean); + if (r_has_type(op1, t_null)) { /* true color */ + colors = 0; + colors_size = -24; /* 24-bit true color */ + } else if (r_has_type(op1, t_integer)) { + /* + * We use if/else rather than switch because the value is long, + * which is not supported as a switch value in pre-ANSI C. + */ + if (op1->value.intval != 16 && op1->value.intval != 24 && + op1->value.intval != 32 + ) + return_error(e_rangecheck); + colors = 0; + colors_size = -op1->value.intval; + } else { + check_type(*op1, t_string); /* palette */ + if (r_size(op1) > 3 * 256) + return_error(e_rangecheck); + colors = op1->value.bytes; + colors_size = r_size(op1); + } + if ((code = read_matrix(imemory, op - 4, &imat)) < 0) + return code; + /* Everything OK, create device */ + code = gs_makewordimagedevice(&new_dev, &imat, + (int)op[-3].value.intval, + (int)op[-2].value.intval, + colors, colors_size, + op->value.boolval, true, imemory); + if (code == 0) { + new_dev->memory = imemory; + make_tav(op - 4, t_device, imemory_space(iimemory) | a_all, + pdevice, new_dev); + pop(4); + } + return code; +} + +/* - nulldevice - */ +/* Note that nulldevice clears the current pagedevice. */ +static int +znulldevice(i_ctx_t *i_ctx_p) +{ + gs_nulldevice(igs); + clear_pagedevice(istate); + return 0; +} + +extern void print_resource_usage(const gs_main_instance *, gs_dual_memory_t *, + const char *); + +/* <num_copies> <flush_bool> .outputpage - */ +static int +zoutputpage(i_ctx_t *i_ctx_p) +{ + os_ptr op = osp; + int code; + + check_type(op[-1], t_integer); + check_type(*op, t_boolean); + if (gs_debug[':']) { + gs_main_instance *minst = get_minst_from_memory((gs_memory_t *)i_ctx_p->memory.current->non_gc_memory); + + print_resource_usage(minst, &(i_ctx_p->memory), "Outputpage start"); + } +#ifdef PSI_INCLUDED + code = ps_end_page_top(imemory, + (int)op[-1].value.intval, op->value.boolval); +#else + code = gs_output_page(igs, (int)op[-1].value.intval, + op->value.boolval); +#endif + if (code < 0) + return code; + pop(2); + if (gs_debug[':']) { + gs_main_instance *minst = get_minst_from_memory((gs_memory_t *)i_ctx_p->memory.current->non_gc_memory); + + print_resource_usage(minst, &(i_ctx_p->memory), "Outputpage end"); + } + return 0; +} + +/* <device> <policy_dict|null> <require_all> <mark> <name> <value> ... */ +/* .putdeviceparams */ +/* (on success) <device> <eraseflag> */ +/* (on failure) <device> <policy_dict|null> <require_all> <mark> */ +/* <name1> <error1> ... */ +/* For a key that simply was not recognized, if require_all is true, */ +/* the result will be an /undefined error; if require_all is false, */ +/* the key will be ignored. */ +/* Note that .putdeviceparams clears the current pagedevice. */ +static int +zputdeviceparams(i_ctx_t *i_ctx_p) +{ + uint count = ref_stack_counttomark(&o_stack); + ref *prequire_all; + ref *ppolicy; + ref *pdev; + gx_device *dev; + stack_param_list list; + int code; + int old_width, old_height; + int i, dest; + + if (count == 0) + return_error(e_unmatchedmark); + prequire_all = ref_stack_index(&o_stack, count); + ppolicy = ref_stack_index(&o_stack, count + 1); + pdev = ref_stack_index(&o_stack, count + 2); + if (pdev == 0) + return_error(e_stackunderflow); + check_type_only(*prequire_all, t_boolean); + check_write_type_only(*pdev, t_device); + dev = pdev->value.pdevice; + code = stack_param_list_read(&list, &o_stack, 0, ppolicy, + prequire_all->value.boolval, iimemory); + if (code < 0) + return code; + old_width = dev->width; + old_height = dev->height; + code = gs_putdeviceparams(dev, (gs_param_list *) & list); + /* Check for names that were undefined or caused errors. */ + for (dest = count - 2, i = 0; i < count >> 1; i++) + if (list.results[i] < 0) { + *ref_stack_index(&o_stack, dest) = + *ref_stack_index(&o_stack, count - (i << 1) - 2); + gs_errorname(i_ctx_p, list.results[i], + ref_stack_index(&o_stack, dest - 1)); + dest -= 2; + } + iparam_list_release(&list); + if (code < 0) { /* There were errors reported. */ + ref_stack_pop(&o_stack, dest + 1); + return 0; + } + if (code > 0 || (code == 0 && (dev->width != old_width || dev->height != old_height))) { + /* + * The device was open and is now closed, or its dimensions have + * changed. If it was the current device, call setdevice to + * reinstall it and erase the page. + */ + /****** DOESN'T FIND ALL THE GSTATES THAT REFERENCE THE DEVICE. ******/ + if (gs_currentdevice(igs) == dev) { + bool was_open = dev->is_open; + + code = gs_setdevice_no_erase(igs, dev); + /* If the device wasn't closed, setdevice won't erase the page. */ + if (was_open && code >= 0) + code = 1; + } + } + if (code < 0) + return code; + ref_stack_pop(&o_stack, count + 1); + make_bool(osp, code); + clear_pagedevice(istate); + return 0; +} + +/* <device> .setdevice <eraseflag> */ +/* Note that .setdevice clears the current pagedevice. */ +int +zsetdevice(i_ctx_t *i_ctx_p) +{ + gx_device *dev = gs_currentdevice(igs); + os_ptr op = osp; + int code = 0; + + check_write_type(*op, t_device); + if (dev->LockSafetyParams) { /* do additional checking if locked */ + if(op->value.pdevice != dev) /* don't allow a different device */ + return_error(e_invalidaccess); + } +#ifndef PSI_INCLUDED + /* the language switching build shouldn't install a new device + here. The language switching machinery installs a shared + device. */ + + code = gs_setdevice_no_erase(igs, op->value.pdevice); +#endif + if (code < 0) + return code; + make_bool(op, code != 0); /* erase page if 1 */ + clear_pagedevice(istate); + return code; +} + +/* ------ Initialization procedure ------ */ + +const op_def zdevice_op_defs[] = +{ + {"1.copydevice2", zcopydevice2}, + {"0currentdevice", zcurrentdevice}, + {"1.devicename", zdevicename}, + {"0.doneshowpage", zdoneshowpage}, + {"0flushpage", zflushpage}, + {"7.getbitsrect", zgetbitsrect}, + {"1.getdevice", zgetdevice}, + {"1.getdefaultdevice", zgetdefaultdevice}, + {"2.getdeviceparams", zgetdeviceparams}, + {"2.gethardwareparams", zgethardwareparams}, + {"5makewordimagedevice", zmakewordimagedevice}, + {"0nulldevice", znulldevice}, + {"2.outputpage", zoutputpage}, + {"3.putdeviceparams", zputdeviceparams}, + {"1.setdevice", zsetdevice}, + op_def_end(0) +}; |