From 7c3e7eee829cc3d2582e4aa7ae1fd495ca72cef1 Mon Sep 17 00:00:00 2001 From: Chris Liddell <chris.liddell@artifex.com> Date: Mon, 17 Sep 2018 14:06:12 +0100 Subject: [PATCH] Implement .currentoutputdevice operator The currentdevice operator returns the device currently installed in the graphics state. This can be the output/page device, but also could be a forwarding device (bbox device), compositor (pdf14) or subclass device (erasepage optimisation, First/Last page etc). In certain circumstances (for example during a setpagedevice) we want to be sure we're retrieving the *actual* output/page device. The new .currentoutputdevice operator uses the spec_op device method to traverse any chain of devices and retrieve the final device in the chain, which should always be the output/page device. --- Resource/Init/gs_init.ps | 2 +- Resource/Init/gs_setpd.ps | 8 +++++++- base/gdevdflt.c | 5 +++++ base/gxdevsop.h | 4 ++++ psi/zdevice.c | 30 ++++++++++++++++++++++++++++++ 5 files changed, 47 insertions(+), 2 deletions(-) diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps index 56b518a..d5b5584 100644 --- a/Resource/Init/gs_init.ps +++ b/Resource/Init/gs_init.ps @@ -2211,7 +2211,7 @@ SAFER { .setsafeglobal } if /.shfill /.argindex /.bytestring /.namestring /.stringbreak /.stringmatch /.globalvmarray /.globalvmdict /.globalvmpackedarray /.globalvmstring /.localvmarray /.localvmdict /.localvmpackedarray /.localvmstring /.systemvmarray /.systemvmdict /.systemvmpackedarray /.systemvmstring /.systemvmfile /.systemvmlibfile /.systemvmSFD /.settrapparams /.currentsystemparams /.currentuserparams /.getsystemparam /.getuserparam /.setsystemparams /.setuserparams - /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath + /.checkpassword /.locale_to_utf8 /.currentglobal /.gcheck /.imagepath /.currentoutputdevice % Used by a free user in the Library of Congress. Apparently this is used to % draw a partial page, which is then filled in by the results of a barcode diff --git a/Resource/Init/gs_setpd.ps b/Resource/Init/gs_setpd.ps index 8fa7c51..aa79b3f 100644 --- a/Resource/Init/gs_setpd.ps +++ b/Resource/Init/gs_setpd.ps @@ -877,7 +877,13 @@ SETPDDEBUG { (Selecting.) = pstack flush } if % Stack: mark <orig> <request> <merged> <failed> SETPDDEBUG { (Constructing.) = pstack flush } if - currentdevice .devicename 2 index /OutputDevice get eq + % Non-obvious: we need to check the name of the output device, to tell + % whether we're going to have to replace the entire device chain (which + % may be only one device, or may be multiple devices. + % If we're not replacing the entire change, we have to use the device in + % the graphics state, so the configuration of the entire device chain is + % correctly set. + .currentoutputdevice .devicename 2 index /OutputDevice get eq { currentdevice } { 1 index /OutputDevice get finddevice } ifelse diff --git a/base/gdevdflt.c b/base/gdevdflt.c index 3cb9fbd..b5bd82b 100644 --- a/base/gdevdflt.c +++ b/base/gdevdflt.c @@ -1044,6 +1044,11 @@ gx_default_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size) dev_param_req_t *request = (dev_param_req_t *)data; return gx_default_get_param(pdev, request->Param, request->list); } + case gxdso_current_output_device: + { + *(gx_device **)data = pdev; + return 0; + } } return_error(gs_error_undefined); } diff --git a/base/gxdevsop.h b/base/gxdevsop.h index cd3b632..27e3e84 100644 --- a/base/gxdevsop.h +++ b/base/gxdevsop.h @@ -327,6 +327,10 @@ enum { gxdso_JPEG_passthrough_data, gxdso_JPEG_passthrough_end, gxdso_supports_iccpostrender, + /* Retrieve the last device in a device chain + (either forwarding or subclass devices). + */ + gxdso_current_output_device, /* Add new gxdso_ keys above this. */ gxdso_pattern__LAST }; diff --git a/psi/zdevice.c b/psi/zdevice.c index 8d48b74..e5f4f1b 100644 --- a/psi/zdevice.c +++ b/psi/zdevice.c @@ -57,6 +57,7 @@ zcopydevice2(i_ctx_t *i_ctx_p) } /* - currentdevice <device> */ +/* Returns the current device in the graphics state */ int zcurrentdevice(i_ctx_t *i_ctx_p) { @@ -71,6 +72,34 @@ zcurrentdevice(i_ctx_t *i_ctx_p) return 0; } +/* - .currentoutputdevice <device> */ +/* Returns the *output* device - which will often + be the same as above, but not always: if a compositor + or other forwarding device, or subclassing device is + in force, that will be referenced by the graphics state + rather than the output device. + This is equivalent of currentdevice device, but returns + the *device* object, rather than the dictionary describing + the device and device state. + */ +static int +zcurrentoutputdevice(i_ctx_t *i_ctx_p) +{ + os_ptr op = osp; + gx_device *odev = NULL, *dev = gs_currentdevice(igs); + gs_ref_memory_t *mem = (gs_ref_memory_t *) dev->memory; + int code = dev_proc(dev, dev_spec_op)(dev, + gxdso_current_output_device, (void *)&odev, 0); + if (code < 0) + return code; + + push(1); + make_tav(op, t_device, + (mem == 0 ? avm_foreign : imemory_space(mem)) | a_all, + pdevice, odev); + return 0; +} + /* <device> .devicename <string> */ static int zdevicename(i_ctx_t *i_ctx_p) @@ -614,6 +643,7 @@ const op_def zdevice_op_defs[] = { {"1.copydevice2", zcopydevice2}, {"0currentdevice", zcurrentdevice}, + {"0.currentoutputdevice", zcurrentoutputdevice}, {"1.devicename", zdevicename}, {"0.doneshowpage", zdoneshowpage}, {"0flushpage", zflushpage}, -- 2.9.1