diff options
author | Robin Watts <robin.watts@artifex.com> | 2018-05-04 19:37:24 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2018-10-18 15:41:16 +0100 |
commit | 1e926e47d349d0c962c6c64c64804d18c20bf9ba (patch) | |
tree | 43d58c3aee92806f9ca343b050afff7229cc5582 /base/gxclip.c | |
parent | eefae1a50eb451584c2e17600933b723dbc68a0e (diff) | |
download | ghostpdl-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.c | 68 |
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; +} |