summaryrefslogtreecommitdiff
path: root/base/gxclip.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2018-05-04 19:37:24 +0100
committerRobin Watts <robin.watts@artifex.com>2018-10-18 15:41:16 +0100
commit1e926e47d349d0c962c6c64c64804d18c20bf9ba (patch)
tree43d58c3aee92806f9ca343b050afff7229cc5582 /base/gxclip.c
parenteefae1a50eb451584c2e17600933b723dbc68a0e (diff)
downloadghostpdl-1e926e47d349d0c962c6c64c64804d18c20bf9ba.tar.gz
Update clip device to be smarter about transform_pixel_region.
When the clip device is for a single rectangle (a very common case) we can avoid resorting to the default transform_pixel_region routine, and still use the device's (possibly) optimised one.
Diffstat (limited to 'base/gxclip.c')
-rw-r--r--base/gxclip.c68
1 files changed, 67 insertions, 1 deletions
diff --git a/base/gxclip.c b/base/gxclip.c
index 0cf2c67f9..47b9be32e 100644
--- a/base/gxclip.c
+++ b/base/gxclip.c
@@ -46,6 +46,7 @@ static dev_proc_strip_copy_rop2(clip_strip_copy_rop2);
static dev_proc_get_clipping_box(clip_get_clipping_box);
static dev_proc_get_bits_rectangle(clip_get_bits_rectangle);
static dev_proc_fill_path(clip_fill_path);
+static dev_proc_transform_pixel_region(clip_transform_pixel_region);
/* The device descriptor. */
static const gx_device_clip gs_clip_device =
@@ -124,7 +125,7 @@ static const gx_device_clip gs_clip_device =
clip_strip_tile_rect_devn,
clip_copy_alpha_hl_color,
NULL,
- gx_default_transform_pixel_region
+ clip_transform_pixel_region
}
};
@@ -1543,3 +1544,68 @@ clip_fill_path(gx_device * dev, const gs_gstate * pgs,
fixed2int(box.q.y - box.p.y),
clip_call_fill_path, &ccdata);
}
+
+typedef struct {
+ int use_default;
+ void *child_state;
+} clip_transform_pixel_region_data;
+
+static int
+clip_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data)
+{
+ clip_transform_pixel_region_data *state = (clip_transform_pixel_region_data *)data->state;
+ gx_device_clip *cdev = (gx_device_clip *)dev;
+ transform_pixel_region_data local_data;
+ gs_int_rect local_clip;
+ int ret;
+
+ if (reason == transform_pixel_region_begin) {
+ int skewed = 1;
+ if (data->u.init.pixels->y.step.dQ == 0 && data->u.init.pixels->y.step.dR == 0 &&
+ data->u.init.rows->x.step.dQ == 0 && data->u.init.rows->x.step.dR == 0)
+ skewed = 0;
+ else if (data->u.init.pixels->x.step.dQ == 0 && data->u.init.pixels->x.step.dR == 0 &&
+ data->u.init.rows->y.step.dQ == 0 && data->u.init.rows->y.step.dR == 0)
+ skewed = 0;
+ state = (clip_transform_pixel_region_data *)gs_alloc_bytes(dev->memory->non_gc_memory, sizeof(*state), "clip_transform_pixel_region_data");
+ if (state == NULL)
+ return gs_error_VMerror;
+ local_data = *data;
+ if (cdev->list.count == 1 && skewed == 0) {
+ /* Single unskewed rectangle - we can use the underlying device direct */
+ local_data.u.init.clip = &local_clip;
+ local_clip = *data->u.init.clip;
+ if (local_clip.p.x < cdev->current->xmin)
+ local_clip.p.x = cdev->current->xmin;
+ if (local_clip.q.x > cdev->current->xmax)
+ local_clip.q.x = cdev->current->xmax;
+ if (local_clip.p.y < cdev->current->ymin)
+ local_clip.p.y = cdev->current->ymin;
+ if (local_clip.q.y > cdev->current->ymax)
+ local_clip.q.y = cdev->current->ymax;
+ state->use_default = 0;
+ ret = dev_proc(cdev->target, transform_pixel_region)(cdev->target, reason, &local_data);
+ } else {
+ /* Multiple rectangles - we need to use the default */
+ state->use_default = 1;
+ ret = gx_default_transform_pixel_region(dev, reason, &local_data);
+ }
+ state->child_state = local_data.state;
+ data->state = state;
+ return ret;
+ }
+
+ data->state = state->child_state;
+ if (state->use_default)
+ ret = gx_default_transform_pixel_region(dev, reason, data);
+ else
+ ret = dev_proc(cdev->target, transform_pixel_region)(cdev->target, reason, data);
+
+ if (reason == transform_pixel_region_end) {
+ gs_free_object(dev->memory->non_gc_memory, state, "clip_transform_pixel_region_data");
+ state = NULL;
+ }
+ data->state = state;
+
+ return ret;
+}