summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'devices/gdevdsp.c')
-rw-r--r--devices/gdevdsp.c854
1 files changed, 643 insertions, 211 deletions
diff --git a/devices/gdevdsp.c b/devices/gdevdsp.c
index 8ac211d4..0a66a027 100644
--- a/devices/gdevdsp.c
+++ b/devices/gdevdsp.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2019 Artifex Software, Inc.
+/* Copyright (C) 2001-2020 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -54,6 +54,12 @@
#include "gsequivc.h"
#include "gdevdsp.h"
#include "gdevdsp2.h"
+#include "gxclist.h"
+#include "gxdevbuf.h"
+#include "gxgetbit.h"
+#include "gdevmpla.h"
+#include "gdevprn.h" /* For gdev_create_buf_device */
+#include "gsicc_manage.h"
#include "gdevkrnlsclass.h" /* 'standard' built in subclasses, currently First/Last Page and obejct filter */
@@ -108,12 +114,12 @@ static const gx_device_procs display_procs =
display_close,
gx_default_w_b_map_rgb_color,
gx_default_w_b_map_color_rgb,
- display_fill_rectangle,
+ NULL, /* display_fill_rectangle - will be inserted later */
NULL, /* tile rectangle */
- display_copy_mono,
- display_copy_color,
+ NULL, /* display_copy_mono - will be inserted later */
+ NULL, /* display_copy_color - will be inserted later */
NULL, /* draw line */
- display_get_bits,
+ NULL, /* display_get_bits - will be inserted later */
display_get_params,
display_put_params,
gx_default_cmyk_map_cmyk_color, /* map_cmyk_color */
@@ -175,24 +181,16 @@ public_st_device_display();
static
ENUM_PTRS_WITH(display_enum_ptrs, gx_device_display *ddev)
- if (index == 0) {
- if (ddev->mdev) {
- return ENUM_OBJ(gx_device_enum_ptr((gx_device *)ddev->mdev));
- }
- return 0;
- }
- else if (index-1 < ddev->devn_params.separations.num_separations)
- ENUM_RETURN(ddev->devn_params.separations.names[index-1].data);
+ if (index < ddev->devn_params.separations.num_separations)
+ ENUM_RETURN(ddev->devn_params.separations.names[index].data);
else
- return 0;
+ ENUM_PREFIX(st_device_clist_mutatable, ddev->devn_params.separations.num_separations);
+ return 0;
ENUM_PTRS_END
static
RELOC_PTRS_WITH(display_reloc_ptrs, gx_device_display *ddev)
- if (ddev->mdev) {
- ddev->mdev = (gx_device_memory *)
- gx_device_reloc_ptr((gx_device *)ddev->mdev, gcst);
- }
+ RELOC_PREFIX(st_device_clist_mutatable);
{ int i;
for (i = 0; i < ddev->devn_params.separations.num_separations; ++i) {
RELOC_PTR(gx_device_display, devn_params.separations.names[i].data);
@@ -207,12 +205,13 @@ const gx_device_display gs_display_device =
INITIAL_WIDTH, INITIAL_HEIGHT,
INITIAL_RESOLUTION, INITIAL_RESOLUTION),
{0}, /* std_procs */
- NULL, /* mdev */
+ GX_CLIST_MUTATABLE_DEVICE_DEFAULTS,
NULL, /* callback */
NULL, /* pHandle */
+ 0, /* pHandle_set */
0, /* nFormat */
NULL, /* pBitmap */
- 0, /* ulBitmapSize */
+ 0, /* zBitmapSize */
0, /* HWResolution_set */
{ /* devn_params specific parameters */
@@ -242,11 +241,34 @@ display_open(gx_device * dev)
{
gx_device_display *ddev = (gx_device_display *) dev;
int ccode;
+ gs_display_get_callback_t data;
/* Erase these, in case we are opening a copied device. */
- ddev->mdev = NULL;
ddev->pBitmap = NULL;
- ddev->ulBitmapSize = 0;
+ ddev->zBitmapSize = 0;
+
+ ddev->orig_procs = ddev->procs;
+
+ /* Fetch our callback procedures. */
+ data.callback = NULL;
+ data.caller_handle = NULL;
+ ccode = gx_callout(dev, DISPLAY_CALLOUT_GET_CALLBACK, sizeof(data), &data);
+ if (ccode < 0) {
+ ccode = gx_callout(dev, DISPLAY_CALLOUT_GET_CALLBACK_LEGACY, sizeof(data), &data);
+ if (ccode < 0) {
+ ddev->callback = NULL;
+ ddev->pHandle = NULL;
+ if (ccode != gs_error_unknownerror)
+ return ccode;
+ } else {
+ ddev->callback = data.callback;
+ ddev->pHandle_set = 0;
+ }
+ } else {
+ ddev->callback = data.callback;
+ ddev->pHandle = data.caller_handle;
+ ddev->pHandle_set = 1;
+ }
/* Allow device to be opened "disabled" without a callback. */
/* The callback will be set later and the device re-opened. */
@@ -290,9 +312,11 @@ display_open(gx_device * dev)
}
/* Tell caller the device parameters */
- ccode = (*(ddev->callback->display_size)) (ddev->pHandle, dev,
- dev->width, dev->height, display_raster(ddev), ddev->nFormat,
- ddev->mdev->base);
+ ccode = (*(ddev->callback->display_size))(ddev->pHandle, dev,
+ dev->width, dev->height,
+ display_raster(ddev), ddev->nFormat,
+ CLIST_MUTATABLE_HAS_MUTATED(ddev) ?
+ NULL : ((gx_device_memory *)ddev)->base);
if (ccode < 0) {
display_free_bitmap(ddev);
(*(ddev->callback->display_close))(ddev->pHandle, dev);
@@ -335,6 +359,10 @@ display_output_page(gx_device * dev, int copies, int flush)
{
gx_device_display *ddev = (gx_device_display *) dev;
int code;
+ int is_planar = (ddev->nFormat & (DISPLAY_PLANAR |
+ DISPLAY_PLANAR_INTERLEAVED)) &&
+ (ddev->color_info.num_components > 1);
+
if (ddev->callback == NULL)
return gs_error_Fatal;
display_set_separations(ddev);
@@ -342,8 +370,72 @@ display_output_page(gx_device * dev, int copies, int flush)
while(dev->parent)
dev = dev->parent;
- code = (*(ddev->callback->display_page))
+ if (CLIST_MUTATABLE_HAS_MUTATED(ddev)) {
+ /* Rectangle request mode! */
+ gs_get_bits_options_t options;
+
+ options = GB_RETURN_COPY | GB_ALIGN_STANDARD |
+ GB_OFFSET_SPECIFIED | GB_RASTER_SPECIFIED |
+ GB_COLORS_NATIVE;
+ switch (ddev->nFormat & DISPLAY_ALPHA_MASK) {
+ default:
+ case DISPLAY_ALPHA_NONE:
+ break;
+ case DISPLAY_ALPHA_FIRST:
+ case DISPLAY_UNUSED_FIRST:
+ options |= GB_ALPHA_FIRST;
+ break;
+ case DISPLAY_ALPHA_LAST:
+ case DISPLAY_UNUSED_LAST:
+ options |= GB_ALPHA_LAST;
+ break;
+ }
+ if (is_planar)
+ options |= GB_PACKING_PLANAR;
+ else
+ options |= GB_PACKING_CHUNKY;
+
+ while (1) {
+ void *mem = NULL;
+ int ox, oy, x, y, w, h, i, raster, plane_raster;
+ gs_int_rect rect;
+ gs_get_bits_params_t params;
+
+ code = ddev->callback->display_rectangle_request
+ (ddev->pHandle, dev,
+ &mem, &ox, &oy,
+ &raster, &plane_raster,
+ &x, &y, &w, &h);
+ if (w == 0 || h == 0)
+ break;
+ if (mem == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ break;
+ }
+ rect.p.x = x;
+ rect.p.y = y;
+ rect.q.x = x + w;
+ rect.q.y = y + h;
+ params.options = options;
+ if (is_planar) {
+ for (i = 0; i < ddev->color_info.num_components; i++)
+ params.data[i] = (byte *)mem + i * plane_raster;
+ } else {
+ params.data[0] = (byte *)mem;
+ }
+ params.x_offset = ox;
+ params.original_y = oy;
+ params.raster = raster;
+ code = dev_proc(ddev, get_bits_rectangle)((gx_device *)ddev,
+ &rect, &params, NULL);
+ if (code < 0)
+ break;
+ }
+ } else {
+ /* Full page mode. Just claim completion! */
+ code = (*(ddev->callback->display_page))
(ddev->pHandle, dev, copies, flush);
+ }
if (code >= 0)
code = gx_finish_output_page(dev, copies, flush);
@@ -358,19 +450,24 @@ display_close(gx_device * dev)
if (ddev->callback == NULL)
return 0; /* ignore the call since we were never properly opened */
+ while(dev->parent)
+ dev = dev->parent;
+
/* Tell caller that device is about to be closed. */
(*(ddev->callback->display_preclose))(ddev->pHandle, dev);
/* Release memory. */
display_free_bitmap(ddev);
- while(dev->parent)
- dev = dev->parent;
-
/* Tell caller that device is closed. */
/* This is always the last callback */
(*(ddev->callback->display_close))(ddev->pHandle, dev);
+ /* Reset device proc vector to default */
+ if (ddev->orig_procs.open_device != NULL)
+ ddev->procs = ddev->orig_procs;
+ ddev->orig_procs.open_device = NULL; /* prevent uninit'd restore of procs */
+
return 0;
}
@@ -726,13 +823,12 @@ display_map_color_rgb_bgr24(gx_device * dev, gx_color_index color,
/* Fill a rectangle */
static int
display_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
- gx_color_index color)
+ gx_color_index color)
{
gx_device_display *ddev = (gx_device_display *) dev;
if (ddev->callback == NULL)
return 0; /* ignore -- needed for fillpage when device wasn't really opened */
- dev_proc(ddev->mdev, fill_rectangle)((gx_device *)ddev->mdev,
- x, y, w, h, color);
+ ddev->mutated_procs.fill_rectangle(dev, x, y, w, h, color);
while(dev->parent)
dev = dev->parent;
@@ -745,15 +841,15 @@ display_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
/* Copy a monochrome bitmap */
static int
display_copy_mono(gx_device * dev,
- const byte * base, int sourcex, int raster, gx_bitmap_id id,
- int x, int y, int w, int h,
- gx_color_index zero, gx_color_index one)
+ const byte * base, int sourcex, int raster,
+ gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
{
gx_device_display *ddev = (gx_device_display *) dev;
if (ddev->callback == NULL)
return gs_error_Fatal;
- dev_proc(ddev->mdev, copy_mono)((gx_device *)ddev->mdev,
- base, sourcex, raster, id, x, y, w, h, zero, one);
+ ddev->mutated_procs.copy_mono(dev, base, sourcex, raster, id,
+ x, y, w, h, zero, one);
while(dev->parent)
dev = dev->parent;
@@ -766,14 +862,13 @@ display_copy_mono(gx_device * dev,
/* Copy a color pixel map */
static int
display_copy_color(gx_device * dev,
- const byte * base, int sourcex, int raster, gx_bitmap_id id,
- int x, int y, int w, int h)
+ const byte * base, int sourcex, int raster,
+ gx_bitmap_id id, int x, int y, int w, int h)
{
gx_device_display *ddev = (gx_device_display *) dev;
if (ddev->callback == NULL)
return gs_error_Fatal;
- dev_proc(ddev->mdev, copy_color)((gx_device *)ddev->mdev,
- base, sourcex, raster, id, x, y, w, h);
+ ddev->mutated_procs.copy_color(dev, base, sourcex, raster, id, x, y, w, h);
while(dev->parent)
dev = dev->parent;
@@ -789,8 +884,7 @@ display_get_bits(gx_device * dev, int y, byte * str, byte ** actual_data)
gx_device_display *ddev = (gx_device_display *) dev;
if (ddev->callback == NULL)
return gs_error_Fatal;
- return dev_proc(ddev->mdev, get_bits)((gx_device *)ddev->mdev,
- y, str, actual_data);
+ return ddev->mutated_procs.get_bits(dev, y, str, actual_data);
}
static int
@@ -805,27 +899,31 @@ display_get_params(gx_device * dev, gs_param_list * plist)
size_t dptr;
char buf[64];
- idx = ((int)sizeof(size_t)) * 8 - 4;
- buf[i++] = '1';
- buf[i++] = '6';
- buf[i++] = '#';
- dptr = (size_t)(ddev->pHandle);
- while (idx >= 0) {
- val = (int)(dptr >> idx) & 0xf;
- if (val <= 9)
- buf[i++] = '0' + val;
- else
- buf[i++] = 'a' - 10 + val;
- idx -= 4;
- }
- buf[i] = '\0';
+ code = gx_default_get_params(dev, plist);
+ if (code < 0)
+ return code;
+
+ if (!ddev->pHandle_set) {
+ idx = ((int)sizeof(size_t)) * 8 - 4;
+ buf[i++] = '1';
+ buf[i++] = '6';
+ buf[i++] = '#';
+ dptr = (size_t)(ddev->pHandle);
+ while (idx >= 0) {
+ val = (int)(dptr >> idx) & 0xf;
+ if (val <= 9)
+ buf[i++] = '0' + val;
+ else
+ buf[i++] = 'a' - 10 + val;
+ idx -= 4;
+ }
+ buf[i] = '\0';
- param_string_from_transient_string(dhandle, buf);
+ param_string_from_transient_string(dhandle, buf);
+ code = param_write_string(plist, "DisplayHandle", &dhandle);
+ }
- code = gx_default_get_params(dev, plist);
(void)(code < 0 ||
- (code = param_write_string(plist,
- "DisplayHandle", &dhandle)) < 0 ||
(code = param_write_int(plist,
"DisplayFormat", &ddev->nFormat)) < 0 ||
(code = param_write_float(plist,
@@ -890,96 +988,98 @@ display_put_params(gx_device * dev, gs_param_list * plist)
break;
}
- /* 64-bit systems need to use DisplayHandle as a string */
- switch (code = param_read_string(plist, "DisplayHandle", &dh)) {
- case 0:
- found_string_handle = 1;
- break;
- default:
- if ((code == gs_error_typecheck) && (sizeof(size_t) <= 4)) {
- /* 32-bit systems can use the older long type */
- switch (code = param_read_long(plist, "DisplayHandle",
- (long *)(&handle))) {
- case 0:
- if (dev->is_open) {
- if (ddev->pHandle != handle)
- ecode = gs_error_rangecheck;
- else
+ if (!ddev->pHandle_set) {
+ /* 64-bit systems need to use DisplayHandle as a string */
+ switch (code = param_read_string(plist, "DisplayHandle", &dh)) {
+ case 0:
+ found_string_handle = 1;
+ break;
+ default:
+ if ((code == gs_error_typecheck) && (sizeof(size_t) <= 4)) {
+ /* 32-bit systems can use the older long type */
+ switch (code = param_read_long(plist, "DisplayHandle",
+ (long *)(&handle))) {
+ case 0:
+ if (dev->is_open) {
+ if (ddev->pHandle != handle)
+ ecode = gs_error_rangecheck;
+ else
+ break;
+ }
+ else {
+ ddev->pHandle = handle;
break;
- }
- else {
- ddev->pHandle = handle;
+ }
+ goto hdle;
+ default:
+ ecode = code;
+ hdle:param_signal_error(plist, "DisplayHandle", ecode);
+ case 1:
break;
- }
- goto hdle;
- default:
- ecode = code;
- hdle:param_signal_error(plist, "DisplayHandle", ecode);
- case 1:
- break;
+ }
+ break;
}
+ ecode = code;
+ param_signal_error(plist, "DisplayHandle", ecode);
+ /* fall through */
+ case 1:
+ dh.data = 0;
break;
- }
- ecode = code;
- param_signal_error(plist, "DisplayHandle", ecode);
- /* fall through */
- case 1:
- dh.data = 0;
- break;
- }
- if (found_string_handle) {
- /*
- * Convert from a string to a pointer.
- * It is assumed that size_t has the same size as a pointer.
- * Allow formats (1234), (10#1234) or (16#04d2).
- */
- size_t ptr = 0;
- int i;
- int base = 10;
- int val;
- code = 0;
- for (i=0; i<dh.size; i++) {
- val = dh.data[i];
- if ((val >= '0') && (val <= '9'))
- val = val - '0';
- else if ((val >= 'A') && (val <= 'F'))
- val = val - 'A' + 10;
- else if ((val >= 'a') && (val <= 'f'))
- val = val - 'a' + 10;
- else if (val == '#') {
- base = (int)ptr;
- ptr = 0;
- if ((base != 10) && (base != 16)) {
+ }
+ if (found_string_handle) {
+ /*
+ * Convert from a string to a pointer.
+ * It is assumed that size_t has the same size as a pointer.
+ * Allow formats (1234), (10#1234) or (16#04d2).
+ */
+ size_t ptr = 0;
+ int i;
+ int base = 10;
+ int val;
+ code = 0;
+ for (i=0; i<dh.size; i++) {
+ val = dh.data[i];
+ if ((val >= '0') && (val <= '9'))
+ val = val - '0';
+ else if ((val >= 'A') && (val <= 'F'))
+ val = val - 'A' + 10;
+ else if ((val >= 'a') && (val <= 'f'))
+ val = val - 'a' + 10;
+ else if (val == '#') {
+ base = (int)ptr;
+ ptr = 0;
+ if ((base != 10) && (base != 16)) {
+ code = gs_error_rangecheck;
+ break;
+ }
+ continue;
+ }
+ else {
code = gs_error_rangecheck;
break;
}
- continue;
- }
- else {
- code = gs_error_rangecheck;
- break;
- }
- if (base == 10)
- ptr = ptr * 10 + val;
- else if (base == 16)
- ptr = ptr * 16 + val;
- else {
- code = gs_error_rangecheck;
- break;
- }
- }
- if (code == 0) {
- if (dev->is_open) {
- if (ddev->pHandle != (void *)ptr)
+ if (base == 10)
+ ptr = ptr * 10 + val;
+ else if (base == 16)
+ ptr = ptr * 16 + val;
+ else {
code = gs_error_rangecheck;
+ break;
+ }
+ }
+ if (code == 0) {
+ if (dev->is_open) {
+ if (ddev->pHandle != (void *)ptr)
+ code = gs_error_rangecheck;
+ }
+ else
+ ddev->pHandle = (void *)ptr;
+ }
+ if (code < 0) {
+ ecode = code;
+ param_signal_error(plist, "DisplayHandle", ecode);
}
- else
- ddev->pHandle = (void *)ptr;
- }
- if (code < 0) {
- ecode = code;
- param_signal_error(plist, "DisplayHandle", ecode);
}
}
@@ -1094,19 +1194,20 @@ display_put_params(gx_device * dev, gs_param_list * plist)
/* tell caller about the new size */
if ((*ddev->callback->display_size)(ddev->pHandle, dev,
- dev->width, dev->height, display_raster(ddev),
- ddev->nFormat, ddev->mdev->base) < 0)
+ dev->width, dev->height, display_raster(ddev), ddev->nFormat,
+ CLIST_MUTATABLE_HAS_MUTATED(ddev) ? NULL :
+ ((gx_device_memory *)ddev)->base) < 0)
return_error(gs_error_rangecheck);
}
- /*
- * Make the color_info.depth correct for the bpc and num_components since
- * devn mode always has the display bitmap set up for 64-bits, but others,
- * such as pdf14 compositor expect it to match (for "deep" detection).
- */
- if (ddev->icc_struct && ddev->icc_struct->supports_devn) {
- ddev->color_info.depth = ddev->devn_params.bitspercomponent *
- ddev->color_info.num_components;
- }
+ /*
+ * Make the color_info.depth correct for the bpc and num_components since
+ * devn mode always has the display bitmap set up for 64-bits, but others,
+ * such as pdf14 compositor expect it to match (for "deep" detection).
+ */
+ if (ddev->icc_struct && ddev->icc_struct->supports_devn) {
+ ddev->color_info.depth = ddev->devn_params.bitspercomponent *
+ ddev->color_info.num_components;
+ }
return 0;
}
@@ -1120,9 +1221,8 @@ display_finish_copydevice(gx_device *dev, const gx_device *from_dev)
ddev->is_open = false;
/* Clear pointers */
- ddev->mdev = NULL;
ddev->pBitmap = NULL;
- ddev->ulBitmapSize = 0;
+ ddev->zBitmapSize = 0;
return 0;
}
@@ -1245,10 +1345,23 @@ display_ret_devn_params(gx_device * dev)
static int
display_spec_op(gx_device *dev, int op, void *data, int datasize)
{
+ gx_device_display *ddev = (gx_device_display *)dev;
- if (op == gxdso_supports_devn) {
+ if (op == gxdso_supports_devn || op == gxdso_skip_icc_component_validation) {
return (dev_proc(dev, fill_rectangle_hl_color) == display_fill_rectangle_hl_color);
}
+ if (op == gxdso_reopen_after_init) {
+ return 1;
+ }
+ if (op == gxdso_adjust_bandheight)
+ {
+ if (ddev->callback->display_adjust_band_height)
+ return ddev->callback->display_adjust_band_height(ddev->pHandle,
+ ddev,
+ datasize);
+ return 0;
+ }
+
return gx_default_dev_spec_op(dev, op, data, datasize);
}
@@ -1269,8 +1382,8 @@ display_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect,
if (pdcolor->type != gx_dc_type_devn && pdcolor->type != &gx_dc_devn_masked) {
return gx_fill_rectangle_device_rop( x, y, w, h, pdcolor, dev, lop_default);
}
- pure_color = display_separation_encode_color(dev, pdcolor->colors.devn.values);
- return display_fill_rectangle(dev, x, y, w, h, pure_color);
+ pure_color = dev_proc(dev, encode_color)(dev, pdcolor->colors.devn.values);
+ return dev_proc(dev, fill_rectangle)(dev, x, y, w, h, pure_color);
}
/*
@@ -1303,7 +1416,7 @@ display_separation_get_color_comp_index(gx_device * dev,
/* Return 0 on success, gs_error_rangecheck on failure */
static int display_check_structure(gx_device_display *ddev)
{
- if (ddev->callback == 0)
+ if (ddev->callback == NULL)
return_error(gs_error_rangecheck);
if (ddev->callback->size == sizeof(struct display_callback_v1_s)) {
@@ -1315,11 +1428,23 @@ static int display_check_structure(gx_device_display *ddev)
if (ddev->callback->version_minor > DISPLAY_VERSION_MINOR_V1)
return_error(gs_error_rangecheck);
}
- else {
+ else if (ddev->callback->size == sizeof(struct display_callback_v2_s)) {
/* V2 structure with added display_separation callback */
if (ddev->callback->size != sizeof(display_callback))
return_error(gs_error_rangecheck);
+ if (ddev->callback->version_major != DISPLAY_VERSION_MAJOR_V2)
+ return_error(gs_error_rangecheck);
+
+ /* complain if caller asks for newer features */
+ if (ddev->callback->version_minor > DISPLAY_VERSION_MINOR_V2)
+ return_error(gs_error_rangecheck);
+ }
+ else {
+ /* V3 structure with added display_separation callback */
+ if (ddev->callback->size != sizeof(display_callback))
+ return_error(gs_error_rangecheck);
+
if (ddev->callback->version_major != DISPLAY_VERSION_MAJOR)
return_error(gs_error_rangecheck);
@@ -1362,13 +1487,33 @@ display_free_bitmap(gx_device_display * ddev)
ddev->pBitmap, "display_free_bitmap");
}
ddev->pBitmap = NULL;
- if (ddev->mdev)
- ddev->mdev->base = NULL;
+ if (!CLIST_MUTATABLE_HAS_MUTATED(ddev))
+ ((gx_device_memory *)ddev)->base = NULL;
}
- if (ddev->mdev) {
- dev_proc(ddev->mdev, close_device)((gx_device *)ddev->mdev);
- gx_device_retain((gx_device *)(ddev->mdev), false);
- ddev->mdev = NULL;
+
+ if (CLIST_MUTATABLE_HAS_MUTATED(ddev)) {
+ gx_device_clist *const pclist_dev = (gx_device_clist *)ddev;
+ gx_device_clist_common * const pcldev = &pclist_dev->common;
+ gx_device_clist_reader * const pcrdev = &pclist_dev->reader;
+ /* Close cmd list device & point to the storage */
+ (*gs_clist_device_procs.close_device)( (gx_device *)pcldev );
+ ddev->buf = NULL;
+ ddev->buffer_space = 0;
+
+ gs_free_object(pcldev->memory->non_gc_memory, pcldev->cache_chunk, "free tile cache for clist");
+ pcldev->cache_chunk = 0;
+
+ rc_decrement(pcldev->icc_cache_cl, "gdev_prn_tear_down");
+ pcldev->icc_cache_cl = NULL;
+
+ clist_free_icc_table(pcldev->icc_table, pcldev->memory);
+ pcldev->icc_table = NULL;
+
+ /* If the clist is a reader clist, free any color_usage_array
+ * memory used by same.
+ */
+ if (!CLIST_IS_WRITER(pclist_dev))
+ gs_free_object(pcrdev->memory, pcrdev->color_usage_array, "clist_color_usage_array");
}
}
@@ -1377,7 +1522,9 @@ static int
display_raster(gx_device_display *dev)
{
int align = 0;
- int bytewidth = ((dev->width * dev->color_info.depth) + 7) /8;
+ int n = (dev->nFormat & (DISPLAY_PLANAR | DISPLAY_PLANAR_INTERLEAVED)) ?
+ dev->color_info.num_components : 1;
+ int bytewidth = ((dev->width * dev->color_info.depth / n) + 7) /8;
switch (dev->nFormat & DISPLAY_ROW_ALIGN_MASK) {
case DISPLAY_ROW_ALIGN_4:
align = 4;
@@ -1399,79 +1546,340 @@ display_raster(gx_device_display *dev)
align = ARCH_ALIGN_PTR_MOD;
align -= 1;
bytewidth = (bytewidth + align) & (~align);
+ if (dev->nFormat & DISPLAY_PLANAR_INTERLEAVED)
+ bytewidth *= n;
return bytewidth;
}
-/* Allocate the backing bitmap. */
+/* Set the buffer device to planar mode. */
static int
-display_alloc_bitmap(gx_device_display * ddev, gx_device * param_dev)
+set_planar(gx_device_memory *mdev, const gx_device *tdev, int interleaved)
{
- int ccode;
- const gx_device_memory *mdproto;
+ int num_comp = tdev->color_info.num_components;
+ gx_render_plane_t planes[GX_DEVICE_COLOR_MAX_COMPONENTS];
+ int depth = tdev->color_info.depth / num_comp;
+ int k;
- if (ddev->callback == NULL)
- return gs_error_Fatal;
+ if (num_comp < 1 || num_comp > GX_DEVICE_COLOR_MAX_COMPONENTS)
+ return_error(gs_error_rangecheck);
+ /* Round up the depth per plane to a power of 2. */
+ while (depth & (depth - 1))
+ --depth, depth = (depth | (depth >> 1)) + 1;
+
+ /* We want the most significant plane to come out first. */
+ planes[num_comp-1].shift = 0;
+ planes[num_comp-1].depth = depth;
+ for (k = (num_comp - 2); k >= 0; k--) {
+ planes[k].depth = depth;
+ planes[k].shift = planes[k + 1].shift + depth;
+ }
+ return gdev_mem_set_planar_interleaved(mdev, num_comp, planes,
+ interleaved);
+}
- /* free old bitmap (if any) */
- display_free_bitmap(ddev);
+static int
+display_create_buf_device(gx_device **pbdev, gx_device *target, int y,
+ const gx_render_plane_t *render_plane,
+ gs_memory_t *mem, gx_color_usage_t *color_usage)
+{
+ int depth;
+ const gx_device_memory *mdproto;
+ gx_device_memory *mdev;
+ gx_device_display *ddev = (gx_device_display *)target;
+
+ depth = target->color_info.depth;
+ if (target->is_planar)
+ depth /= target->color_info.num_components;
- /* allocate a memory device for rendering */
- mdproto = gdev_mem_device_for_bits(ddev->color_info.depth);
- if (mdproto == 0)
+ mdproto = gdev_mem_device_for_bits(depth);
+ if (mdproto == NULL)
return_error(gs_error_rangecheck);
+ if (mem) {
+ mdev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
+ "create_buf_device");
+ if (mdev == NULL)
+ return_error(gs_error_VMerror);
+ } else {
+ mdev = (gx_device_memory *)*pbdev;
+ }
+ if (target == (gx_device *)mdev) {
+ dev_t_proc_dev_spec_op((*orig_dso), gx_device) = dev_proc(mdev, dev_spec_op);
+ /* The following is a special hack for setting up printer devices. */
+ assign_dev_procs(mdev, mdproto);
+ /* Do not override the dev_spec_op! */
+ dev_proc(mdev, dev_spec_op) = orig_dso;
+ check_device_separable((gx_device *)mdev);
+ gx_device_fill_in_procs((gx_device *)mdev);
+ } else {
+ gs_make_mem_device(mdev, mdproto, mem, (color_usage == NULL ? 1 : 0),
+ target);
+ if (ddev->nFormat & DISPLAY_COLORS_SEPARATION)
+ mdev->procs.fill_rectangle_hl_color = display_fill_rectangle_hl_color;
+ }
+ mdev->width = target->width;
+ mdev->band_y = y;
+ mdev->log2_align_mod = target->log2_align_mod;
+ mdev->pad = target->pad;
+ mdev->is_planar = target->is_planar;
+ /*
+ * The matrix in the memory device is irrelevant,
+ * because all we do with the device is call the device-level
+ * output procedures, but we may as well set it to
+ * something halfway reasonable.
+ */
+ gs_deviceinitialmatrix(target, &mdev->initial_matrix);
+ /****** QUESTIONABLE, BUT BETTER THAN OMITTING ******/
+ if (&mdev->color_info != &target->color_info) /* Pacify Valgrind */
+ mdev->color_info = target->color_info;
+ *pbdev = (gx_device *)mdev;
+
+ if (ddev->nFormat & (DISPLAY_PLANAR | DISPLAY_PLANAR_INTERLEAVED)) {
+ int interleaved = (ddev->nFormat & DISPLAY_PLANAR_INTERLEAVED);
+ if (gs_device_is_memory(*pbdev) /* == render_plane->index < 0 */) {
+ return set_planar((gx_device_memory *)*pbdev, *pbdev, interleaved);
+ }
+ }
+
+ return 0;
+}
- ddev->mdev = gs_alloc_struct(gs_memory_stable(ddev->memory),
- gx_device_memory, &st_device_memory, "display_memory_device");
- if (ddev->mdev == 0)
+static int
+display_size_buf_device(gx_device_buf_space_t *space, gx_device *target,
+ const gx_render_plane_t *render_plane,
+ int height, bool for_band)
+{
+ gx_device_display *ddev = (gx_device_display *)target;
+ gx_device_memory mdev;
+ int code;
+ int planar = ddev->nFormat & (DISPLAY_PLANAR | DISPLAY_PLANAR_INTERLEAVED);
+ int interleaved = (ddev->nFormat & DISPLAY_PLANAR_INTERLEAVED);
+
+ if (!planar || (render_plane && render_plane->index >= 0))
+ return gx_default_size_buf_device(space, target, render_plane,
+ height, for_band);
+
+ /* Planar case */
+ mdev.color_info = target->color_info;
+ mdev.pad = target->pad;
+ mdev.log2_align_mod = target->log2_align_mod;
+ mdev.is_planar = target->is_planar;
+ code = set_planar(&mdev, target, interleaved);
+ if (code < 0)
+ return code;
+ if (gdev_mem_bits_size(&mdev, target->width, height, &(space->bits)) < 0)
return_error(gs_error_VMerror);
+ space->line_ptrs = gdev_mem_line_ptrs_size(&mdev, target->width, height);
+ space->raster = display_raster(ddev);
+ return 0;
+}
- gs_make_mem_device(ddev->mdev, mdproto, gs_memory_stable(ddev->memory),
- 0, (gx_device *) NULL);
- check_device_separable((gx_device *)(ddev->mdev));
- gx_device_fill_in_procs((gx_device *)(ddev->mdev));
- /* Mark the memory device as retained. When the bitmap is closed,
- * we will clear this and the memory device will be then be freed.
- */
- gx_device_retain((gx_device *)(ddev->mdev), true);
+static gx_device_buf_procs_t display_buf_procs = {
+ display_create_buf_device,
+ display_size_buf_device,
+ gx_default_setup_buf_device,
+ gx_default_destroy_buf_device
+};
- /* Memory device width may be larger than device width
- * if row alignment is not 4.
- */
- ddev->mdev->width = param_dev->width;
- ddev->mdev->width = display_raster(ddev) * 8 / ddev->color_info.depth;
- ddev->mdev->height = param_dev->height;
+static int /* returns 0 ok, else -ve error cde */
+setup_as_clist(gx_device_display *ddev, gs_memory_t *buffer_memory)
+{
+ gdev_space_params space_params = ddev->space_params;
+ gx_device *target = (gx_device *)ddev;
+ uint space;
+ int code;
+ gx_device_clist *const pclist_dev = (gx_device_clist *)ddev;
+ gx_device_clist_common * const pcldev = &pclist_dev->common;
+ byte *base;
+ bool save_is_open = ddev->is_open; /* Save around temporary failure in open_c loop */
+
+ while (target->parent != NULL) {
+ target = target->parent;
+ gx_update_from_subclass(target);
+ }
- /* Tell the memory device to allocate the line pointers separately
- * so we can place the bitmap in special memory.
- */
- ddev->mdev->line_pointer_memory = ddev->mdev->memory;
- if (gdev_mem_bits_size(ddev->mdev, ddev->mdev->width, ddev->mdev->height,
- &(ddev->ulBitmapSize)) < 0)
+ /* Try to allocate based simply on param-requested buffer size */
+ for ( space = space_params.BufferSpace; ; ) {
+ base = gs_alloc_bytes(buffer_memory, space,
+ "cmd list buffer");
+ if (base != NULL)
+ break;
+ if ((space >>= 1) < MIN_BUFFER_SPACE)
+ break;
+ }
+ if (base == NULL)
return_error(gs_error_VMerror);
+ /* Try opening the command list, to see if we allocated */
+ /* enough buffer space. */
+open_c:
+ ddev->buf = base;
+ ddev->buffer_space = space;
+ pclist_dev->common.orig_spec_op = ddev->orig_procs.dev_spec_op;
+ clist_init_io_procs(pclist_dev, ddev->BLS_force_memory);
+ clist_init_params(pclist_dev, base, space, target,
+ display_buf_procs,
+ space_params.band,
+ false, /* do_not_open_or_close_bandfiles */
+ (ddev->bandlist_memory == NULL ?
+ ddev->memory->non_gc_memory:
+ ddev->bandlist_memory),
+ ddev->clist_disable_mask,
+ ddev->page_uses_transparency);
+ code = (*gs_clist_device_procs.open_device)( (gx_device *)pcldev );
+ if (code < 0) {
+ /* If there wasn't enough room, and we haven't */
+ /* already shrunk the buffer, try enlarging it. */
+ if (code == gs_error_rangecheck &&
+ space >= space_params.BufferSpace) {
+ space += space / 8;
+ gs_free_object(buffer_memory, base,
+ "cmd list buf(retry open)");
+ base = gs_alloc_bytes(buffer_memory, space,
+ "cmd list buf(retry open)");
+ ddev->buf = base;
+ if (base != NULL) {
+ ddev->is_open = save_is_open; /* allow for success when we loop */
+ goto open_c;
+ }
+ }
+ /* Failure. */
+ gs_free_object(buffer_memory, base, "cmd list buf");
+ ddev->buffer_space = 0;
+ }
+ return code;
+}
+
+/* Allocate the backing bitmap. */
+static int
+display_alloc_bitmap(gx_device_display * ddev, gx_device * param_dev)
+{
+ int ccode;
+ gx_device_buf_space_t buf_space;
+
+ if (ddev->callback == NULL)
+ return gs_error_Fatal;
+
+ /* free old bitmap (if any) */
+ display_free_bitmap(ddev);
+
+ /* Initialise the clist/memory device specific fields. */
+ memset(ddev->skip, 0, sizeof(ddev->skip));
+ /* Calculate the size required for the a memory device. */
+ display_size_buf_device(&buf_space, (gx_device *)ddev,
+ NULL, ddev->height, false);
+ ddev->zBitmapSize = buf_space.bits + buf_space.line_ptrs;
+
+ if (ddev->callback->version_major > DISPLAY_VERSION_MAJOR_V2 ||
+ ddev->callback->display_rectangle_request != NULL) {
+ /* Clist mode is a possibility. Maybe check in here whether
+ * we want to suggest clist? */
+ /* FIXME: For now, we'll just assume that the memalloc callback
+ * is smart enough to make a sensible decision. */
+ }
+
/* allocate bitmap using an allocator not subject to GC */
if (ddev->callback->display_memalloc
&& ddev->callback->display_memfree) {
- ddev->pBitmap = (*ddev->callback->display_memalloc)(ddev->pHandle,
- ddev, ddev->ulBitmapSize);
+ /* Note: For Planar buffers, we allocate the linepointers
+ * as part of this allocation, just after the bitmap. Maybe we
+ * want to allocate them ourselves, so they aren't exposed to
+ * the caller? (Or the caller can pass in a pointer to a
+ * structure of it's own without having to allow for these
+ * pointers?)*/
+ if (ddev->callback->version_major > DISPLAY_VERSION_MAJOR_V2)
+ ddev->pBitmap = (*ddev->callback->display_memalloc)(ddev->pHandle,
+ ddev, ddev->zBitmapSize);
+ else if (ddev->zBitmapSize > ARCH_MAX_ULONG)
+ ddev->pBitmap = NULL;
+ else {
+ struct display_callback_v2_s *v2;
+ v2 = (struct display_callback_v2_s *)(ddev->callback);
+ ddev->pBitmap = (v2->display_memalloc)(ddev->pHandle,
+ ddev, (unsigned long)ddev->zBitmapSize);
+ }
}
else {
ddev->pBitmap = gs_alloc_byte_array_immovable(ddev->memory->non_gc_memory,
- (uint)ddev->ulBitmapSize, 1, "display_alloc_bitmap");
+ ddev->zBitmapSize, 1, "display_alloc_bitmap");
}
if (ddev->pBitmap == NULL) {
- ddev->mdev->width = 0;
- ddev->mdev->height = 0;
- return_error(gs_error_VMerror);
+ /* Bitmap failed to allocate. Can we recover by using rectangle
+ * request mode? */
+ if (ddev->callback->version_major <= DISPLAY_VERSION_MAJOR_V2 ||
+ ddev->callback->display_rectangle_request == NULL) {
+ /* No. Hard fail. */
+ ddev->width = 0;
+ ddev->height = 0;
+ return_error(gs_error_VMerror);
+ }
+ /* Let's set up as a clist. */
+ ccode = setup_as_clist(ddev, ddev->memory->non_gc_memory);
+ if (ccode >= 0)
+ ddev->procs = gs_clist_device_procs;
+ } else {
+ /* Set up as PageMode. */
+ gx_device *bdev = (gx_device *)ddev;
+
+ /* Ensure we're not seen as a clist device. */
+ ddev->buffer_space = 0;
+ if ((ccode = gdev_create_buf_device
+ (display_create_buf_device,
+ &bdev, bdev, 0, NULL, NULL, NULL)) < 0 ||
+ (ccode = gx_default_setup_buf_device
+ (bdev, ddev->pBitmap, buf_space.raster,
+ (byte **)((byte *)ddev->pBitmap + buf_space.bits), 0, ddev->height,
+ ddev->height)) < 0
+ ) {
+ /* Catastrophic. Shouldn't ever happen */
+ display_free_bitmap(ddev);
+ return_error(ccode);
+ }
}
- ddev->mdev->base = (byte *) ddev->pBitmap;
- ddev->mdev->foreign_bits = true;
+#define COPY_PROC(p) set_dev_proc(ddev, p, ddev->orig_procs.p)
+ COPY_PROC(get_initial_matrix);
+ COPY_PROC(output_page);
+ COPY_PROC(close_device);
+ COPY_PROC(map_rgb_color);
+ COPY_PROC(map_color_rgb);
+ COPY_PROC(get_params);
+ COPY_PROC(put_params);
+ COPY_PROC(map_cmyk_color);
+ COPY_PROC(get_xfont_procs);
+ COPY_PROC(get_xfont_device);
+ COPY_PROC(map_rgb_alpha_color);
+ set_dev_proc(ddev, get_page_device, gx_page_device_get_page_device);
+ COPY_PROC(get_clipping_box);
+ COPY_PROC(map_color_rgb_alpha);
+ COPY_PROC(get_hardware_params);
+ COPY_PROC(get_color_mapping_procs);
+ COPY_PROC(get_color_comp_index);
+ COPY_PROC(encode_color);
+ COPY_PROC(decode_color);
+ COPY_PROC(update_spot_equivalent_colors);
+ COPY_PROC(ret_devn_params);
+ /* This can be set from the memory device (planar) or target */
+ if ( dev_proc(ddev, put_image) == gx_default_put_image )
+ set_dev_proc(ddev, put_image, ddev->orig_procs.put_image);
+#undef COPY_PROC
+
+ /* Now, we want to hook various procs to give the callbacks
+ * progress reports. But only in non-clist mode. */
+ if (!CLIST_MUTATABLE_HAS_MUTATED(ddev)) {
+ ddev->mutated_procs = ddev->procs;
+ ddev->procs.fill_rectangle = display_fill_rectangle;
+ ddev->procs.copy_mono = display_copy_mono;
+ ddev->procs.copy_color = display_copy_color;
+ ddev->procs.get_bits = display_get_bits;
+ }
- ccode = dev_proc(ddev->mdev, open_device)((gx_device *)ddev->mdev);
- if (ccode < 0)
- display_free_bitmap(ddev);
+ /* In command list mode, we've already opened the device. */
+ if (!CLIST_MUTATABLE_HAS_MUTATED(ddev)) {
+ ccode = dev_proc(ddev, open_device)((gx_device *)ddev);
+ if (ccode < 0)
+ display_free_bitmap(ddev);
+ }
/* erase bitmap - before display gets redrawn */
/*
@@ -1741,21 +2149,30 @@ display_set_color_format(gx_device_display *ddev, int nFormat)
switch (ddev->nFormat & DISPLAY_ROW_ALIGN_MASK) {
case DISPLAY_ROW_ALIGN_DEFAULT:
align = ARCH_ALIGN_PTR_MOD;
+ if (sizeof(void *) == 4)
+ ddev->log2_align_mod = 2;
+ else
+ ddev->log2_align_mod = 3;
break;
case DISPLAY_ROW_ALIGN_4:
align = 4;
+ ddev->log2_align_mod = 2;
break;
case DISPLAY_ROW_ALIGN_8:
align = 8;
+ ddev->log2_align_mod = 3;
break;
case DISPLAY_ROW_ALIGN_16:
align = 16;
+ ddev->log2_align_mod = 4;
break;
case DISPLAY_ROW_ALIGN_32:
align = 32;
+ ddev->log2_align_mod = 5;
break;
case DISPLAY_ROW_ALIGN_64:
align = 64;
+ ddev->log2_align_mod = 6;
break;
default:
align = 0; /* not permitted */
@@ -1867,6 +2284,11 @@ display_set_color_format(gx_device_display *ddev, int nFormat)
maxvalue, maxvalue);
if ((nFormat & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) {
ddev->devn_params.bitspercomponent = bpc;
+ if (ddev->icc_struct == NULL) {
+ ddev->icc_struct = gsicc_new_device_profile_array(ddev->memory);
+ if (ddev->icc_struct == NULL)
+ return_error(gs_error_VMerror);
+ }
ddev->icc_struct->supports_devn = true;
set_color_procs(pdev,
display_separation_encode_color,
@@ -1882,6 +2304,16 @@ display_set_color_format(gx_device_display *ddev, int nFormat)
return_error(gs_error_rangecheck);
}
+ switch (nFormat & (DISPLAY_PLANAR | DISPLAY_PLANAR_INTERLEAVED))
+ {
+ case DISPLAY_CHUNKY:
+ ddev->is_planar = 0;
+ break;
+ default:
+ ddev->is_planar = 1;
+ break;
+ }
+
/* restore old anti_alias info */
dci.anti_alias = ddev->color_info.anti_alias;
ddev->color_info = dci;