summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Deutschmann <whissi@gentoo.org>2019-10-15 12:24:12 +0200
committerThomas Deutschmann <whissi@gentoo.org>2020-08-13 11:26:55 +0200
commite088156d5b620e5e639580dacf85c6dc13823c74 (patch)
tree57f5c025e203279944da512166c20bc0521d8ccd /base/gdevmpla.c
downloadghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.tar.gz
ghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.tar.bz2
ghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.zip
Import Ghostscript 9.50ghostscript-9.50
Signed-off-by: Thomas Deutschmann <whissi@gentoo.org>
Diffstat (limited to 'base/gdevmpla.c')
-rw-r--r--base/gdevmpla.c2251
1 files changed, 2251 insertions, 0 deletions
diff --git a/base/gdevmpla.c b/base/gdevmpla.c
new file mode 100644
index 00000000..3bcbf491
--- /dev/null
+++ b/base/gdevmpla.c
@@ -0,0 +1,2251 @@
+/* Copyright (C) 2001-2019 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 the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+/* Any-depth planar "memory" (stored bitmap) device */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsbitops.h"
+#include "gxdevice.h"
+#include "gxdcolor.h" /* for gx_fill_rectangle_device_rop */
+#include "gxpcolor.h" /* for gx_dc_devn_masked */
+#include "gxdevmem.h" /* semi-public definitions */
+#include "gxgetbit.h"
+#include "gdevmem.h" /* private definitions */
+#include "gdevmpla.h" /* interface */
+#include "gxdevsop.h"
+
+/* procedures */
+static dev_proc_open_device(mem_planar_open);
+declare_mem_procs(mem_planar_copy_mono, mem_planar_copy_color, mem_planar_fill_rectangle);
+static dev_proc_copy_color(mem_planar_copy_color_24to8);
+static dev_proc_copy_color(mem_planar_copy_color_4to1);
+static dev_proc_copy_planes(mem_planar_copy_planes);
+/* Not static due to an optimized case in tile_clip_fill_rectangle_hl_color*/
+static dev_proc_strip_tile_rectangle(mem_planar_strip_tile_rectangle);
+static dev_proc_strip_tile_rect_devn(mem_planar_strip_tile_rect_devn);
+static dev_proc_strip_copy_rop(mem_planar_strip_copy_rop);
+static dev_proc_strip_copy_rop2(mem_planar_strip_copy_rop2);
+static dev_proc_get_bits_rectangle(mem_planar_get_bits_rectangle);
+static dev_proc_fill_rectangle_hl_color(mem_planar_fill_rectangle_hl_color);
+static dev_proc_put_image(mem_planar_put_image);
+
+static int
+mem_planar_dev_spec_op(gx_device *pdev, int dev_spec_op,
+ void *data, int size)
+{
+ cmm_dev_profile_t *dev_profile;
+
+ if (dev_spec_op == gxdso_supports_devn) {
+ dev_proc(pdev, get_profile)(pdev, &dev_profile);
+ if (dev_profile != NULL && dev_profile->supports_devn &&
+ dev_proc(pdev, fill_rectangle_hl_color) == mem_planar_fill_rectangle_hl_color)
+ return 1;
+ }
+ return gx_default_dev_spec_op(pdev, dev_spec_op, data, size);
+}
+
+static int
+mem_planar_dev_spec_op_cmyk4(gx_device *pdev, int dev_spec_op,
+ void *data, int size)
+{
+ if (dev_spec_op == gxdso_is_std_cmyk_1bit)
+ return 1;
+ return gx_default_dev_spec_op(pdev, dev_spec_op, data, size);
+}
+
+/*
+ * Set up a planar memory device, after calling gs_make_mem_device but
+ * before opening the device. The pre-existing device provides the color
+ * mapping procedures, but not the drawing procedures. Requires: num_planes
+ * > 0, plane_depths[0 .. num_planes - 1] > 0, sum of plane depths =
+ * mdev->color_info.depth.
+ *
+ * Note that this is the only public procedure in this file, and the only
+ * sanctioned way to set up a planar memory device.
+ */
+int
+gdev_mem_set_planar(gx_device_memory * mdev, int num_planes,
+ const gx_render_plane_t *planes /*[num_planes]*/)
+{
+ int total_depth;
+ int same_depth = planes[0].depth;
+ gx_color_index covered = 0;
+ int pi;
+ const gx_device_memory *mdproto = gdev_mem_device_for_bits(mdev->color_info.depth);
+
+ if (num_planes < 1 || num_planes > GX_DEVICE_COLOR_MAX_COMPONENTS || num_planes != mdev->color_info.num_components)
+ return_error(gs_error_rangecheck);
+ for (pi = 0, total_depth = 0; pi < num_planes; ++pi) {
+ int shift = planes[pi].shift;
+ int plane_depth = planes[pi].depth;
+ gx_color_index mask;
+
+ if (shift < 0 || plane_depth > 16 ||
+ !gdev_mem_device_for_bits(plane_depth))
+ return_error(gs_error_rangecheck);
+ /* Don't test overlap if shift is too large to fit in the variable */
+ if (shift < 8*sizeof(gx_color_index))
+ {
+ mask = (((gx_color_index)1 << plane_depth) - 1) << shift;
+ if (covered & mask)
+ return_error(gs_error_rangecheck);
+ covered |= mask;
+ }
+ if (plane_depth != same_depth)
+ same_depth = 0;
+ total_depth += plane_depth;
+ }
+ if (total_depth > mdev->color_info.depth)
+ return_error(gs_error_rangecheck);
+ mdev->is_planar = 1;
+ memcpy(mdev->planes, planes, num_planes * sizeof(planes[0]));
+ mdev->plane_depth = same_depth;
+ /* Change the drawing procedures. */
+ set_dev_proc(mdev, open_device, mem_planar_open);
+ /* Regardless of how many planes we are using, always let the
+ * device know how to handle hl_color. Even if we spot that we
+ * can get away with a normal device, our callers may want to
+ * feed us single component devn data. */
+ set_dev_proc(mdev, fill_rectangle_hl_color,
+ mem_planar_fill_rectangle_hl_color);
+ if (num_planes == 1) {
+ /* For 1 plane, just use a normal device */
+ set_dev_proc(mdev, fill_rectangle, dev_proc(mdproto, fill_rectangle));
+ set_dev_proc(mdev, copy_mono, dev_proc(mdproto, copy_mono));
+ set_dev_proc(mdev, copy_color, dev_proc(mdproto, copy_color));
+ set_dev_proc(mdev, copy_alpha, dev_proc(mdproto, copy_alpha));
+ set_dev_proc(mdev, strip_tile_rectangle, dev_proc(mdproto, strip_tile_rectangle));
+ set_dev_proc(mdev, strip_copy_rop, dev_proc(mdproto, strip_copy_rop));
+ set_dev_proc(mdev, strip_copy_rop2, dev_proc(mdproto, strip_copy_rop2));
+ set_dev_proc(mdev, get_bits_rectangle, dev_proc(mdproto, get_bits_rectangle));
+ } else {
+ /* If we are going out to a separation device or one that has more than
+ four planes then use the high level color filling procedure. Also
+ make use of the put_image operation to go from the pdf14 device
+ directly to the planar buffer. */
+ if (num_planes >= 4) {
+ set_dev_proc(mdev, put_image, mem_planar_put_image);
+ }
+ set_dev_proc(mdev, fill_rectangle, mem_planar_fill_rectangle);
+ set_dev_proc(mdev, copy_alpha_hl_color, gx_default_copy_alpha_hl_color);
+ set_dev_proc(mdev, copy_mono, mem_planar_copy_mono);
+ set_dev_proc(mdev, dev_spec_op, mem_planar_dev_spec_op);
+ if ((mdev->color_info.depth == 24) &&
+ (num_planes == 3) &&
+ (mdev->planes[0].depth == 8) && (mdev->planes[0].shift == 16) &&
+ (mdev->planes[1].depth == 8) && (mdev->planes[1].shift == 8) &&
+ (mdev->planes[2].depth == 8) && (mdev->planes[2].shift == 0))
+ set_dev_proc(mdev, copy_color, mem_planar_copy_color_24to8);
+ else if ((mdev->color_info.depth == 4) &&
+ (num_planes == 4) &&
+ (mdev->planes[0].depth == 1) && (mdev->planes[0].shift == 3) &&
+ (mdev->planes[1].depth == 1) && (mdev->planes[1].shift == 2) &&
+ (mdev->planes[2].depth == 1) && (mdev->planes[2].shift == 1) &&
+ (mdev->planes[3].depth == 1) && (mdev->planes[3].shift == 0)) {
+ set_dev_proc(mdev, copy_color, mem_planar_copy_color_4to1);
+ set_dev_proc(mdev, dev_spec_op, mem_planar_dev_spec_op_cmyk4);
+ } else
+ set_dev_proc(mdev, copy_color, mem_planar_copy_color);
+ set_dev_proc(mdev, copy_alpha, gx_default_copy_alpha);
+ set_dev_proc(mdev, strip_tile_rectangle, mem_planar_strip_tile_rectangle);
+ set_dev_proc(mdev, strip_tile_rect_devn, mem_planar_strip_tile_rect_devn);
+ set_dev_proc(mdev, strip_copy_rop, mem_planar_strip_copy_rop);
+ set_dev_proc(mdev, strip_copy_rop2, mem_planar_strip_copy_rop2);
+ set_dev_proc(mdev, get_bits_rectangle, mem_planar_get_bits_rectangle);
+ }
+ set_dev_proc(mdev, copy_planes, mem_planar_copy_planes);
+ return 0;
+}
+
+/* Open a planar memory device. */
+static int
+mem_planar_open(gx_device * dev)
+{
+ gx_device_memory *const mdev = (gx_device_memory *)dev;
+
+ /* Check that we aren't trying to open a chunky device as planar. */
+ if (!dev->is_planar)
+ return_error(gs_error_rangecheck);
+ return gdev_mem_open_scan_lines(mdev, dev->height);
+}
+
+/*
+ * We execute drawing operations by patching a few parameters in the
+ * device structure and then calling the procedure appropriate to the
+ * plane depth.
+ */
+typedef struct mem_save_params_s {
+ int depth; /* color_info.depth */
+ byte *base;
+ byte **line_ptrs;
+} mem_save_params_t;
+#define MEM_SAVE_PARAMS(mdev, msp)\
+ (msp.depth = mdev->color_info.depth,\
+ msp.base = mdev->base,\
+ msp.line_ptrs = mdev->line_ptrs)
+/* Previous versions of MEM_SET_PARAMS calculated raster as
+ * bitmap_raster(mdev->width * plane_depth), but this restricts us to
+ * non interleaved frame buffers. Now we calculate it from the difference
+ * between the first 2 line pointers; this clearly only works if there are
+ * at least 2 line pointers to use. Otherwise, we fall back to the old
+ * method.
+ */
+/* FIXME: Find a nicer way of calculating raster. This is only required if
+ * we allow the plane_depth to vary per plane, and the rest of the code
+ * assumes that it never does. This can probably be simplified now. */
+#define MEM_SET_PARAMS(mdev, plane_depth)\
+ (mdev->color_info.depth = plane_depth, /* maybe not needed */\
+ mdev->base = mdev->line_ptrs[0],\
+ mdev->raster = (mdev->height > 1 ? mdev->line_ptrs[1]-mdev->line_ptrs[0] : bitmap_raster(mdev->width * plane_depth)))
+#define MEM_RESTORE_PARAMS(mdev, msp)\
+ (mdev->color_info.depth = msp.depth,\
+ mdev->base = msp.base,\
+ mdev->line_ptrs = msp.line_ptrs)
+
+static int
+put_image_copy_planes(gx_device * dev, const byte **base_ptr, int sourcex,
+ int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ int plane_depth;
+ mem_save_params_t save;
+ const gx_device_memory *mdproto;
+ int code = 0;
+ uchar plane;
+
+ MEM_SAVE_PARAMS(mdev, save);
+ for (plane = 0; plane < mdev->color_info.num_components; plane++)
+ {
+ const byte *base = base_ptr[plane];
+ plane_depth = mdev->planes[plane].depth;
+ mdproto = gdev_mem_device_for_bits(plane_depth);
+ if (base == NULL) {
+ /* Blank the plane */
+ code = dev_proc(mdproto, fill_rectangle)(dev, x, y, w, h,
+ (gx_color_index)(dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE ? 0 : -1));
+ } else if (plane_depth == 1)
+ code = dev_proc(mdproto, copy_mono)(dev, base, sourcex, sraster, id,
+ x, y, w, h,
+ (gx_color_index)0,
+ (gx_color_index)1);
+ else
+ code = dev_proc(mdproto, copy_color)(dev, base, sourcex, sraster,
+ id, x, y, w, h);
+ mdev->line_ptrs += mdev->height;
+ }
+ MEM_RESTORE_PARAMS(mdev, save);
+ return code;
+}
+
+/* Put image command for copying the planar image buffers with or without
+ alpha directly to the device buffer */
+static int
+mem_planar_put_image(gx_device *pdev, gx_device *pmdev, const byte **buffers, int num_chan, int xstart,
+ int ystart, int width, int height, int row_stride,
+ int alpha_plane_index, int tag_plane_index)
+{
+ /* We don't want alpha, return 0 to ask for the pdf14 device to do the
+ alpha composition. We also do not want chunky data coming in */
+ if (alpha_plane_index != 0)
+ return 0;
+
+ put_image_copy_planes(pdev, buffers, 0, row_stride,
+ gx_no_bitmap_id, xstart, ystart,
+ width, height);
+ /* we used all of the data */
+ return height;
+}
+
+/* Fill a rectangle with a high level color. This is used for separation
+ devices. (e.g. tiffsep, psdcmyk) */
+static int
+mem_planar_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect,
+ const gs_gstate *pgs, const gx_drawing_color *pdcolor,
+ const gx_clip_path *pcpath)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ mem_save_params_t save;
+ uchar pi;
+ int x = fixed2int(rect->p.x);
+ int y = fixed2int(rect->p.y);
+ int w = fixed2int(rect->q.x) - x;
+ int h = fixed2int(rect->q.y) - y;
+
+ /* We can only handle devn cases, so use the default if not */
+ /* We can get called here from gx_dc_devn_masked_fill_rectangle */
+ 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);
+ }
+ MEM_SAVE_PARAMS(mdev, save);
+ for (pi = 0; pi < mdev->color_info.num_components; ++pi) {
+ int plane_depth = mdev->planes[pi].depth;
+ gx_color_index mask = ((gx_color_index)1 << plane_depth) - 1;
+ int shift = 16 - plane_depth;
+ const gx_device_memory *mdproto = gdev_mem_device_for_bits(plane_depth);
+
+ MEM_SET_PARAMS(mdev, plane_depth);
+ dev_proc(mdproto, fill_rectangle)(dev, x, y, w, h,
+ (pdcolor->colors.devn.values[pi]) >> shift & mask);
+ mdev->line_ptrs += mdev->height;
+ }
+ MEM_RESTORE_PARAMS(mdev, save);
+ return 0;
+}
+
+/* Fill a rectangle with a color. */
+static int
+mem_planar_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ mem_save_params_t save;
+ uchar pi;
+
+ MEM_SAVE_PARAMS(mdev, save);
+ for (pi = 0; pi < mdev->color_info.num_components; ++pi) {
+ int plane_depth = mdev->planes[pi].depth;
+ gx_color_index mask = ((gx_color_index)1 << plane_depth) - 1;
+ const gx_device_memory *mdproto =
+ gdev_mem_device_for_bits(plane_depth);
+
+ MEM_SET_PARAMS(mdev, plane_depth);
+ dev_proc(mdproto, fill_rectangle)(dev, x, y, w, h,
+ (color >> mdev->planes[pi].shift) &
+ mask);
+ mdev->line_ptrs += mdev->height;
+ }
+ MEM_RESTORE_PARAMS(mdev, save);
+ return 0;
+}
+
+/* Copy a bitmap. */
+static int
+mem_planar_copy_mono(gx_device * dev, const byte * base, int sourcex,
+ int sraster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index color0, gx_color_index color1)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ mem_save_params_t save;
+ uchar pi;
+
+ MEM_SAVE_PARAMS(mdev, save);
+ for (pi = 0; pi < mdev->color_info.num_components; ++pi) {
+ int plane_depth = mdev->planes[pi].depth;
+ int shift = mdev->planes[pi].shift;
+ gx_color_index mask = ((gx_color_index)1 << plane_depth) - 1;
+ const gx_device_memory *mdproto =
+ gdev_mem_device_for_bits(plane_depth);
+ gx_color_index c0 =
+ (color0 == gx_no_color_index ? gx_no_color_index :
+ (color0 >> shift) & mask);
+ gx_color_index c1 =
+ (color1 == gx_no_color_index ? gx_no_color_index :
+ (color1 >> shift) & mask);
+
+ MEM_SET_PARAMS(mdev, plane_depth);
+ if (c0 == c1)
+ dev_proc(mdproto, fill_rectangle)(dev, x, y, w, h, c0);
+ else
+ dev_proc(mdproto, copy_mono)
+ (dev, base, sourcex, sraster, id, x, y, w, h, c0, c1);
+ mdev->line_ptrs += mdev->height;
+ }
+ MEM_RESTORE_PARAMS(mdev, save);
+ return 0;
+}
+
+/* Copy color: Special case the 24 -> 8+8+8 case. */
+static int
+mem_planar_copy_color_24to8(gx_device * dev, const byte * base, int sourcex,
+ int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+#define BUF_LONGS 100 /* arbitrary, >= 1 */
+#define BUF_BYTES (BUF_LONGS * ARCH_SIZEOF_LONG)
+ union b_ {
+ ulong l[BUF_LONGS];
+ byte b[BUF_BYTES];
+ } buf, buf1, buf2;
+ mem_save_params_t save;
+ const gx_device_memory *mdproto = gdev_mem_device_for_bits(8);
+ uint plane_raster = bitmap_raster(w<<3);
+ int br, bw, bh, cx, cy, cw, ch, ix, iy;
+
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ MEM_SAVE_PARAMS(mdev, save);
+ MEM_SET_PARAMS(mdev, 8);
+ if (plane_raster > BUF_BYTES) {
+ br = BUF_BYTES;
+ bw = BUF_BYTES;
+ bh = 1;
+ } else {
+ br = plane_raster;
+ bw = w;
+ bh = BUF_BYTES / plane_raster;
+ }
+ for (cy = y; cy < y + h; cy += ch) {
+ ch = min(bh, y + h - cy);
+ for (cx = x; cx < x + w; cx += cw) {
+ int sx = sourcex + cx - x;
+ const byte *source_base = base + sraster * (cy - y);
+
+ cw = min(bw, x + w - cx);
+ source_base += sx * 3;
+ for (iy = 0; iy < ch; ++iy) {
+ const byte *sptr = source_base;
+ byte *dptr0 = buf.b + br * iy;
+ byte *dptr1 = buf1.b + br * iy;
+ byte *dptr2 = buf2.b + br * iy;
+ ix = cw;
+ do {
+ /* Use the temporary variables below to free the C compiler
+ * to interleave load/stores for latencies sake despite the
+ * pointer aliasing rules. */
+ byte r = *sptr++;
+ byte g = *sptr++;
+ byte b = *sptr++;
+ *dptr0++ = r;
+ *dptr1++ = g;
+ *dptr2++ = b;
+ } while (--ix);
+ source_base += sraster;
+ }
+ dev_proc(mdproto, copy_color)
+ (dev, buf.b, 0, br, gx_no_bitmap_id, cx, cy, cw, ch);
+ mdev->line_ptrs += mdev->height;
+ dev_proc(mdproto, copy_color)
+ (dev, buf1.b, 0, br, gx_no_bitmap_id, cx, cy, cw, ch);
+ mdev->line_ptrs += mdev->height;
+ dev_proc(mdproto, copy_color)
+ (dev, buf2.b, 0, br, gx_no_bitmap_id, cx, cy, cw, ch);
+ mdev->line_ptrs -= 2*mdev->height;
+ }
+ }
+ MEM_RESTORE_PARAMS(mdev, save);
+ return 0;
+}
+
+/* Copy color: Special case the 4 -> 1+1+1+1 case. */
+/* Two versions of this routine; the first does bit comparisons. This should
+ * work well on architectures with small cache and conditional execution
+ * (such as ARM). Hurts on x86 due to the ifs in the loop all causing small
+ * skips ahead that defeat the branch predictor.
+ * Second version uses a table lookup; 1K of table is nothing on x86, and
+ * so this runs much faster. */
+#ifdef PREFER_ALTERNATIION_TO_TABLES
+static int
+mem_planar_copy_color_4to1(gx_device * dev, const byte * base, int sourcex,
+ int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+#define BUF_LONGS 100 /* arbitrary, >= 1 */
+#define BUF_BYTES (BUF_LONGS * ARCH_SIZEOF_LONG)
+ union b_ {
+ ulong l[BUF_LONGS];
+ byte b[BUF_BYTES];
+ } buf0, buf1, buf2, buf3;
+ mem_save_params_t save;
+ const gx_device_memory *mdproto = gdev_mem_device_for_bits(1);
+ uint plane_raster = bitmap_raster(w);
+ int br, bw, bh, cx, cy, cw, ch, ix, iy;
+
+#ifdef MEMENTO
+ /* Pacify valgrind */
+ memset(buf0.l, 0, sizeof(ulong) * BUF_LONGS);
+ memset(buf1.l, 0, sizeof(ulong) * BUF_LONGS);
+ memset(buf2.l, 0, sizeof(ulong) * BUF_LONGS);
+ memset(buf3.l, 0, sizeof(ulong) * BUF_LONGS);
+#endif
+
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ MEM_SAVE_PARAMS(mdev, save);
+ MEM_SET_PARAMS(mdev, 1);
+ if (plane_raster > BUF_BYTES) {
+ br = BUF_BYTES;
+ bw = BUF_BYTES<<3;
+ bh = 1;
+ } else {
+ br = plane_raster;
+ bw = w;
+ bh = BUF_BYTES / plane_raster;
+ }
+ for (cy = y; cy < y + h; cy += ch) {
+ ch = min(bh, y + h - cy);
+ for (cx = x; cx < x + w; cx += cw) {
+ int sx = sourcex + cx - x;
+ const byte *source_base = base + sraster * (cy - y) + (sx>>1);
+
+ cw = min(bw, x + w - cx);
+ if ((sx & 1) == 0) {
+ for (iy = 0; iy < ch; ++iy) {
+ const byte *sptr = source_base;
+ byte *dptr0 = buf0.b + br * iy;
+ byte *dptr1 = buf1.b + br * iy;
+ byte *dptr2 = buf2.b + br * iy;
+ byte *dptr3 = buf3.b + br * iy;
+ byte roll = 0x80;
+ byte bc = 0;
+ byte bm = 0;
+ byte by = 0;
+ byte bk = 0;
+ ix = cw;
+ do {
+ byte b = *sptr++;
+ if (b & 0x80)
+ bc |= roll;
+ if (b & 0x40)
+ bm |= roll;
+ if (b & 0x20)
+ by |= roll;
+ if (b & 0x10)
+ bk |= roll;
+ roll >>= 1;
+ if (b & 0x08)
+ bc |= roll;
+ if (b & 0x04)
+ bm |= roll;
+ if (b & 0x02)
+ by |= roll;
+ if (b & 0x01)
+ bk |= roll;
+ roll >>= 1;
+ if (roll == 0) {
+ *dptr0++ = bc;
+ *dptr1++ = bm;
+ *dptr2++ = by;
+ *dptr3++ = bk;
+ bc = 0;
+ bm = 0;
+ by = 0;
+ bk = 0;
+ roll = 0x80;
+ }
+ ix -= 2;
+ } while (ix > 0);
+ if (roll != 0x80) {
+ *dptr0++ = bc;
+ *dptr1++ = bm;
+ *dptr2++ = by;
+ *dptr3++ = bk;
+ }
+ source_base += sraster;
+ }
+ } else {
+ for (iy = 0; iy < ch; ++iy) {
+ const byte *sptr = source_base;
+ byte *dptr0 = buf0.b + br * iy;
+ byte *dptr1 = buf1.b + br * iy;
+ byte *dptr2 = buf2.b + br * iy;
+ byte *dptr3 = buf3.b + br * iy;
+ byte roll = 0x80;
+ byte bc = 0;
+ byte bm = 0;
+ byte by = 0;
+ byte bk = 0;
+ byte b = *sptr++;
+ ix = cw;
+ goto loop_entry;
+ do {
+ b = *sptr++;
+ if (b & 0x80)
+ bc |= roll;
+ if (b & 0x40)
+ bm |= roll;
+ if (b & 0x20)
+ by |= roll;
+ if (b & 0x10)
+ bk |= roll;
+ roll >>= 1;
+ if (roll == 0) {
+ *dptr0++ = bc;
+ *dptr1++ = bm;
+ *dptr2++ = by;
+ *dptr3++ = bk;
+ bc = 0;
+ bm = 0;
+ by = 0;
+ bk = 0;
+ roll = 0x80;
+ }
+loop_entry:
+ if (b & 0x08)
+ bc |= roll;
+ if (b & 0x04)
+ bm |= roll;
+ if (b & 0x02)
+ by |= roll;
+ if (b & 0x01)
+ bk |= roll;
+ roll >>= 1;
+ ix -= 2;
+ } while (ix >= 0); /* ix == -2 means 1 extra done */
+ if ((ix == -2) && (roll == 0x40)) {
+ /* We did an extra one, and it was the last thing
+ * we did. Nothing to store. */
+ } else {
+ /* Flush the stored bytes */
+ *dptr0++ = bc;
+ *dptr1++ = bm;
+ *dptr2++ = by;
+ *dptr3++ = bk;
+ }
+ source_base += sraster;
+ }
+ }
+ dev_proc(mdproto, copy_mono)
+ (dev, buf0.b, 0, br, gx_no_bitmap_id, cx, cy, cw, ch,
+ (gx_color_index)0, (gx_color_index)1);
+ mdev->line_ptrs += mdev->height;
+ dev_proc(mdproto, copy_mono)
+ (dev, buf1.b, 0, br, gx_no_bitmap_id, cx, cy, cw, ch,
+ (gx_color_index)0, (gx_color_index)1);
+ mdev->line_ptrs += mdev->height;
+ dev_proc(mdproto, copy_mono)
+ (dev, buf2.b, 0, br, gx_no_bitmap_id, cx, cy, cw, ch,
+ (gx_color_index)0, (gx_color_index)1);
+ mdev->line_ptrs += mdev->height;
+ dev_proc(mdproto, copy_mono)
+ (dev, buf3.b, 0, br, gx_no_bitmap_id, cx, cy, cw, ch,
+ (gx_color_index)0, (gx_color_index)1);
+ mdev->line_ptrs -= 3*mdev->height;
+ }
+ }
+ MEM_RESTORE_PARAMS(mdev, save);
+ return 0;
+}
+#else
+
+static bits32 expand_4to1[256] =
+{
+0x00000000,0x00000001,0x00000100,0x00000101,
+0x00010000,0x00010001,0x00010100,0x00010101,
+0x01000000,0x01000001,0x01000100,0x01000101,
+0x01010000,0x01010001,0x01010100,0x01010101,
+0x00000002,0x00000003,0x00000102,0x00000103,
+0x00010002,0x00010003,0x00010102,0x00010103,
+0x01000002,0x01000003,0x01000102,0x01000103,
+0x01010002,0x01010003,0x01010102,0x01010103,
+0x00000200,0x00000201,0x00000300,0x00000301,
+0x00010200,0x00010201,0x00010300,0x00010301,
+0x01000200,0x01000201,0x01000300,0x01000301,
+0x01010200,0x01010201,0x01010300,0x01010301,
+0x00000202,0x00000203,0x00000302,0x00000303,
+0x00010202,0x00010203,0x00010302,0x00010303,
+0x01000202,0x01000203,0x01000302,0x01000303,
+0x01010202,0x01010203,0x01010302,0x01010303,
+0x00020000,0x00020001,0x00020100,0x00020101,
+0x00030000,0x00030001,0x00030100,0x00030101,
+0x01020000,0x01020001,0x01020100,0x01020101,
+0x01030000,0x01030001,0x01030100,0x01030101,
+0x00020002,0x00020003,0x00020102,0x00020103,
+0x00030002,0x00030003,0x00030102,0x00030103,
+0x01020002,0x01020003,0x01020102,0x01020103,
+0x01030002,0x01030003,0x01030102,0x01030103,
+0x00020200,0x00020201,0x00020300,0x00020301,
+0x00030200,0x00030201,0x00030300,0x00030301,
+0x01020200,0x01020201,0x01020300,0x01020301,
+0x01030200,0x01030201,0x01030300,0x01030301,
+0x00020202,0x00020203,0x00020302,0x00020303,
+0x00030202,0x00030203,0x00030302,0x00030303,
+0x01020202,0x01020203,0x01020302,0x01020303,
+0x01030202,0x01030203,0x01030302,0x01030303,
+0x02000000,0x02000001,0x02000100,0x02000101,
+0x02010000,0x02010001,0x02010100,0x02010101,
+0x03000000,0x03000001,0x03000100,0x03000101,
+0x03010000,0x03010001,0x03010100,0x03010101,
+0x02000002,0x02000003,0x02000102,0x02000103,
+0x02010002,0x02010003,0x02010102,0x02010103,
+0x03000002,0x03000003,0x03000102,0x03000103,
+0x03010002,0x03010003,0x03010102,0x03010103,
+0x02000200,0x02000201,0x02000300,0x02000301,
+0x02010200,0x02010201,0x02010300,0x02010301,
+0x03000200,0x03000201,0x03000300,0x03000301,
+0x03010200,0x03010201,0x03010300,0x03010301,
+0x02000202,0x02000203,0x02000302,0x02000303,
+0x02010202,0x02010203,0x02010302,0x02010303,
+0x03000202,0x03000203,0x03000302,0x03000303,
+0x03010202,0x03010203,0x03010302,0x03010303,
+0x02020000,0x02020001,0x02020100,0x02020101,
+0x02030000,0x02030001,0x02030100,0x02030101,
+0x03020000,0x03020001,0x03020100,0x03020101,
+0x03030000,0x03030001,0x03030100,0x03030101,
+0x02020002,0x02020003,0x02020102,0x02020103,
+0x02030002,0x02030003,0x02030102,0x02030103,
+0x03020002,0x03020003,0x03020102,0x03020103,
+0x03030002,0x03030003,0x03030102,0x03030103,
+0x02020200,0x02020201,0x02020300,0x02020301,
+0x02030200,0x02030201,0x02030300,0x02030301,
+0x03020200,0x03020201,0x03020300,0x03020301,
+0x03030200,0x03030201,0x03030300,0x03030301,
+0x02020202,0x02020203,0x02020302,0x02020303,
+0x02030202,0x02030203,0x02030302,0x02030303,
+0x03020202,0x03020203,0x03020302,0x03020303,
+0x03030202,0x03030203,0x03030302,0x03030303
+};
+
+static int
+mem_planar_copy_color_4to1(gx_device * dev, const byte * base, int sourcex,
+ int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+#define BUF_LONGS 100 /* arbitrary, >= 1 */
+#define BUF_BYTES (BUF_LONGS * ARCH_SIZEOF_LONG)
+ union b_ {
+ ulong l[BUF_LONGS];
+ byte b[BUF_BYTES];
+ } buf0, buf1, buf2, buf3;
+ mem_save_params_t save;
+ const gx_device_memory *mdproto = gdev_mem_device_for_bits(1);
+ uint plane_raster = bitmap_raster(w);
+ int br, bw, bh, cx, cy, cw, ch, ix, iy;
+
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ MEM_SAVE_PARAMS(mdev, save);
+ MEM_SET_PARAMS(mdev, 1);
+ if (plane_raster > BUF_BYTES) {
+ br = BUF_BYTES;
+ bw = BUF_BYTES<<3;
+ bh = 1;
+ } else {
+ br = plane_raster;
+ bw = w;
+ bh = BUF_BYTES / plane_raster;
+ }
+ for (cy = y; cy < y + h; cy += ch) {
+ ch = min(bh, y + h - cy);
+ for (cx = x; cx < x + w; cx += cw) {
+ int sx = sourcex + cx - x;
+ const byte *source_base = base + sraster * (cy - y) + (sx>>1);
+
+ cw = min(bw, x + w - cx);
+ if ((sx & 1) == 0) {
+ for (iy = 0; iy < ch; ++iy) {
+ const byte *sptr = source_base;
+ byte *dptr0 = buf0.b + br * iy;
+ byte *dptr1 = buf1.b + br * iy;
+ byte *dptr2 = buf2.b + br * iy;
+ byte *dptr3 = buf3.b + br * iy;
+ int roll = 6;
+ int cmyk = 0;
+ ix = cw;
+ do {
+ cmyk |= expand_4to1[*sptr++]<<roll;
+ roll -= 2;
+ if (roll < 0) {
+ *dptr0++ = cmyk>>24;
+ *dptr1++ = cmyk>>16;
+ *dptr2++ = cmyk>>8;
+ *dptr3++ = cmyk;
+ cmyk = 0;
+ roll = 6;
+ }
+ ix -= 2;
+ } while (ix > 0);
+ if (roll != 6) {
+ *dptr0++ = cmyk>>24;
+ *dptr1++ = cmyk>>16;
+ *dptr2++ = cmyk>>8;
+ *dptr3++ = cmyk;
+ }
+ source_base += sraster;
+ }
+ } else {
+ for (iy = 0; iy < ch; ++iy) {
+ const byte *sptr = source_base;
+ byte *dptr0 = buf0.b + br * iy;
+ byte *dptr1 = buf1.b + br * iy;
+ byte *dptr2 = buf2.b + br * iy;
+ byte *dptr3 = buf3.b + br * iy;
+ int roll = 7;
+ int cmyk = 0;
+ byte b = *sptr++ & 0x0f;
+ ix = cw;
+ goto loop_entry;
+ do {
+ b = *sptr++;
+ roll -= 2;
+ if (roll < 0)
+ {
+ cmyk |= expand_4to1[b & 0xf0]>>1;
+ *dptr0++ = cmyk>>24;
+ *dptr1++ = cmyk>>16;
+ *dptr2++ = cmyk>>8;
+ *dptr3++ = cmyk;
+ cmyk = 0;
+ roll = 7;
+ b &= 0x0f;
+ }
+loop_entry:
+ cmyk |= expand_4to1[b]<<roll;
+ ix -= 2;
+ } while (ix >= 0); /* ix == -2 means 1 extra done */
+ if ((ix == -2) && (roll == 7)) {
+ /* We did an extra one, and it was the last thing
+ * we did. Nothing to store. */
+ } else {
+ /* Flush the stored bytes */
+ *dptr0++ = cmyk>>24;
+ *dptr1++ = cmyk>>16;
+ *dptr2++ = cmyk>>8;
+ *dptr3++ = cmyk;
+ }
+ source_base += sraster;
+ }
+ }
+ dev_proc(mdproto, copy_mono)
+ (dev, buf0.b, 0, br, gx_no_bitmap_id, cx, cy, cw, ch,
+ (gx_color_index)0, (gx_color_index)1);
+ mdev->line_ptrs += mdev->height;
+ dev_proc(mdproto, copy_mono)
+ (dev, buf1.b, 0, br, gx_no_bitmap_id, cx, cy, cw, ch,
+ (gx_color_index)0, (gx_color_index)1);
+ mdev->line_ptrs += mdev->height;
+ dev_proc(mdproto, copy_mono)
+ (dev, buf2.b, 0, br, gx_no_bitmap_id, cx, cy, cw, ch,
+ (gx_color_index)0, (gx_color_index)1);
+ mdev->line_ptrs += mdev->height;
+ dev_proc(mdproto, copy_mono)
+ (dev, buf3.b, 0, br, gx_no_bitmap_id, cx, cy, cw, ch,
+ (gx_color_index)0, (gx_color_index)1);
+ mdev->line_ptrs -= 3*mdev->height;
+ }
+ }
+ MEM_RESTORE_PARAMS(mdev, save);
+ return 0;
+}
+#endif
+
+/* Copy a color bitmap. */
+/* This is slow and messy. */
+static int
+mem_planar_copy_color(gx_device * dev, const byte * base, int sourcex,
+ int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+#define BUF_LONGS 100 /* arbitrary, >= 1 */
+#define BUF_BYTES (BUF_LONGS * ARCH_SIZEOF_LONG)
+ union b_ {
+ ulong l[BUF_LONGS];
+ byte b[BUF_BYTES];
+ } buf;
+ int source_depth = dev->color_info.depth;
+ mem_save_params_t save;
+ uchar pi;
+
+ /* This routine cannot copy from 3bit chunky data, as 3 bit
+ * things don't pack nicely into bytes or words. Accordingly
+ * treat 3 bit things as 4 bit things. This is appropriate as
+ * 3 bit data will generally have been passed to us as 4bit
+ * data - such as halftones. */
+ if (source_depth == 3)
+ source_depth = 4;
+
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ MEM_SAVE_PARAMS(mdev, save);
+ for (pi = 0; pi < mdev->color_info.num_components; ++pi) {
+ int plane_depth = mdev->planes[pi].depth;
+ int shift = mdev->planes[pi].shift;
+ gx_color_index mask = ((gx_color_index)1 << plane_depth) - 1;
+ const gx_device_memory *mdproto =
+ gdev_mem_device_for_bits(plane_depth);
+ /*
+ * Divide up the transfer into chunks that can be assembled
+ * within the fixed-size buffer. This code can be simplified
+ * a lot if all planes have the same depth, by simply using
+ * copy_color to transfer one column at a time, but it might
+ * be very inefficient.
+ */
+ uint plane_raster = bitmap_raster(plane_depth * w);
+ int br, bw, bh, cx, cy, cw, ch, ix, iy;
+
+ MEM_SET_PARAMS(mdev, plane_depth);
+ if (plane_raster > BUF_BYTES) {
+ br = BUF_BYTES;
+ bw = BUF_BYTES * 8 / plane_depth;
+ bh = 1;
+ } else {
+ br = plane_raster;
+ bw = w;
+ bh = BUF_BYTES / plane_raster;
+ }
+ /*
+ * We could do the extraction with get_bits_rectangle
+ * selecting a single plane, but this is critical enough
+ * code that we more or less replicate it here.
+ */
+ for (cy = y; cy < y + h; cy += ch) {
+ ch = min(bh, y + h - cy);
+ for (cx = x; cx < x + w; cx += cw) {
+ int sx = sourcex + cx - x;
+ const byte *source_base = base + sraster * (cy - y);
+ int source_bit = 0;
+
+ cw = min(bw, x + w - cx);
+ if (sx) {
+ int xbit = sx * source_depth;
+
+ source_base += xbit >> 3;
+ source_bit = xbit & 7;
+ }
+ for (iy = 0; iy < ch; ++iy) {
+ const byte *sptr =source_base;
+ int sbit = source_bit;
+ byte *dptr = buf.b + br * iy;
+ int dbit = 0;
+ byte dbbyte = (dbit ? (byte)(*dptr & (0xff00 >> dbit)) : 0);
+
+ for (ix = 0; ix < cw; ++ix) {
+ gx_color_index value;
+
+ if (sizeof(value) > 4){
+ if (sample_load_next64((uint64_t *)&value, &sptr, &sbit, source_depth) < 0)
+ return_error(gs_error_rangecheck);
+ }
+ else {
+ if (sample_load_next32((uint32_t *)&value, &sptr, &sbit, source_depth) < 0)
+ return_error(gs_error_rangecheck);
+ }
+ value = (value >> shift) & mask;
+ if (sample_store_next16(value, &dptr, &dbit, plane_depth,
+ &dbbyte) < 0)
+ return_error(gs_error_rangecheck);
+ }
+ sample_store_flush(dptr, dbit, dbbyte);
+ source_base += sraster;
+ }
+ /*
+ * Detect and bypass the possibility that copy_color is
+ * defined in terms of copy_mono.
+ */
+ if (plane_depth == 1)
+ dev_proc(mdproto, copy_mono)
+ (dev, buf.b, 0, br, gx_no_bitmap_id, cx, cy, cw, ch,
+ (gx_color_index)0, (gx_color_index)1);
+ else
+ dev_proc(mdproto, copy_color)
+ (dev, buf.b, 0, br, gx_no_bitmap_id, cx, cy, cw, ch);
+ }
+ }
+ mdev->line_ptrs += mdev->height;
+ }
+ MEM_RESTORE_PARAMS(mdev, save);
+ return 0;
+#undef BUF_BYTES
+#undef BUF_LONGS
+}
+
+/* Copy a given bitmap into a bitmap. */
+static int
+mem_planar_copy_planes(gx_device * dev, const byte * base, int sourcex,
+ int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, int plane_height)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ int plane_depth;
+ mem_save_params_t save;
+ const gx_device_memory *mdproto;
+ int code = 0;
+ uchar plane;
+
+ MEM_SAVE_PARAMS(mdev, save);
+ for (plane = 0; plane < mdev->color_info.num_components; plane++)
+ {
+ plane_depth = mdev->planes[plane].depth;
+ mdproto = gdev_mem_device_for_bits(plane_depth);
+ if (plane_depth == 1)
+ code = dev_proc(mdproto, copy_mono)(dev, base, sourcex, sraster, id,
+ x, y, w, h,
+ (gx_color_index)0,
+ (gx_color_index)1);
+ else
+ code = dev_proc(mdproto, copy_color)(dev, base, sourcex, sraster,
+ id, x, y, w, h);
+ base += sraster * plane_height;
+ mdev->line_ptrs += mdev->height;
+ }
+ MEM_RESTORE_PARAMS(mdev, save);
+ return code;
+}
+
+int
+mem_planar_strip_tile_rect_devn(gx_device * dev, const gx_strip_bitmap * tiles,
+ int x, int y, int w, int h,
+ const gx_drawing_color *pdcolor0,
+ const gx_drawing_color *pdcolor1, int px, int py)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ mem_save_params_t save;
+ uchar pi;
+
+ MEM_SAVE_PARAMS(mdev, save);
+ for (pi = 0; pi < mdev->color_info.num_components; ++pi) {
+ int plane_depth = mdev->planes[pi].depth;
+ gx_color_index mask = ((gx_color_index)1 << plane_depth) - 1;
+ int shift = 16 - plane_depth;
+ const gx_device_memory *mdproto =
+ gdev_mem_device_for_bits(plane_depth);
+ gx_color_index c1, c0;
+
+ if (pdcolor0->type == gx_dc_type_devn) {
+ c0 = (pdcolor0->colors.devn.values[pi]) >> shift & mask;
+ } else {
+ c0 = gx_no_color_index;
+ }
+ if (pdcolor1->type == gx_dc_type_devn) {
+ c1 = (pdcolor1->colors.devn.values[pi]) >> shift & mask;
+ } else {
+ c1 = gx_no_color_index;
+ }
+#ifdef DEBUG
+ if (c0 == gx_no_color_index && c1 == gx_no_color_index) {
+ dprintf("mem_planar_strip_tile_rect_dev called with two non-devn colors\n");
+ }
+#endif
+ MEM_SET_PARAMS(mdev, plane_depth);
+ if (c0 == c1)
+ dev_proc(mdproto, fill_rectangle)(dev, x, y, w, h, c0);
+ else {
+ /*
+ * Temporarily replace copy_mono in case strip_tile_rectangle is
+ * defined in terms of it.
+ */
+ set_dev_proc(dev, copy_mono, dev_proc(mdproto, copy_mono));
+ dev_proc(mdproto, strip_tile_rectangle)
+ (dev, tiles, x, y, w, h, c0, c1, px, py);
+ }
+ mdev->line_ptrs += mdev->height;
+ }
+ MEM_RESTORE_PARAMS(mdev, save);
+ set_dev_proc(dev, copy_mono, mem_planar_copy_mono);
+ return 0;
+}
+
+int
+mem_planar_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles,
+ int x, int y, int w, int h,
+ gx_color_index color0, gx_color_index color1,
+ int px, int py)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ mem_save_params_t save;
+ uchar pi;
+
+ /* We can't split up the transfer if the tile is colored. */
+ if (color0 == gx_no_color_index && color1 == gx_no_color_index)
+ return gx_default_strip_tile_rectangle
+ (dev, tiles, x, y, w, h, color0, color1, px, py);
+ MEM_SAVE_PARAMS(mdev, save);
+ for (pi = 0; pi < mdev->color_info.num_components; ++pi) {
+ int plane_depth = mdev->planes[pi].depth;
+ int shift = mdev->planes[pi].shift;
+ gx_color_index mask = ((gx_color_index)1 << plane_depth) - 1;
+ const gx_device_memory *mdproto =
+ gdev_mem_device_for_bits(plane_depth);
+ gx_color_index c0 =
+ (color0 == gx_no_color_index ? gx_no_color_index :
+ (color0 >> shift) & mask);
+ gx_color_index c1 =
+ (color1 == gx_no_color_index ? gx_no_color_index :
+ (color1 >> shift) & mask);
+
+ MEM_SET_PARAMS(mdev, plane_depth);
+ if (c0 == c1)
+ dev_proc(mdproto, fill_rectangle)(dev, x, y, w, h, c0);
+ else {
+ /*
+ * Temporarily replace copy_mono in case strip_tile_rectangle is
+ * defined in terms of it.
+ */
+ set_dev_proc(dev, copy_mono, dev_proc(mdproto, copy_mono));
+ dev_proc(mdproto, strip_tile_rectangle)
+ (dev, tiles, x, y, w, h, c0, c1, px, py);
+ }
+ mdev->line_ptrs += mdev->height;
+ }
+ MEM_RESTORE_PARAMS(mdev, save);
+ set_dev_proc(dev, copy_mono, mem_planar_copy_mono);
+ return 0;
+}
+
+static int
+planar_cmyk4bit_strip_copy_rop(gx_device_memory * mdev,
+ const byte * srow, int sourcex, uint sraster,
+ gx_bitmap_id id, const gx_color_index * scolors,
+ const gx_strip_bitmap * textures,
+ const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y,
+ gs_logical_operation_t lop)
+{
+ gs_rop3_t rop = (gs_rop3_t)lop;
+ uint draster = mdev->raster;
+ int line_count;
+ byte *cdrow, *mdrow, *ydrow, *kdrow;
+ byte lmask, rmask;
+ rop_proc cproc = NULL, mproc = NULL, yproc = NULL;
+ int dbit;
+ int cscolor = 0, mscolor = 0, yscolor = 0, kscolor = 0;
+ int ctcolor = 0, mtcolor = 0, ytcolor = 0, ktcolor = 0;
+ int constant_s = 0;
+
+ /* Modify the raster operation according to the source palette. */
+ fit_copy(mdev, srow, sourcex, sraster, id, x, y, width, height);
+
+ /* This function assumes constant (or unused) scolors and tcolors */
+ if (scolors)
+ {
+ if (scolors[0] == scolors[1]) {
+ kscolor = ((scolors[0] & 1) ? -1 : 0);
+ cscolor = ((scolors[0] & 8) ? -1 : 0) | kscolor;
+ mscolor = ((scolors[0] & 4) ? -1 : 0) | kscolor;
+ yscolor = ((scolors[0] & 2) ? -1 : 0) | kscolor;
+ constant_s = 1;
+ } else {
+ kscolor = (scolors[0] & 1) | ((scolors[1] & 1)<<1);
+ cscolor = ((scolors[0] & 8)>>3) | ((scolors[1] & 8)>>2) | kscolor;
+ mscolor = ((scolors[0] & 4)>>2) | ((scolors[1] & 4)>>1) | kscolor;
+ yscolor = ((scolors[0] & 2)>>1) | (scolors[1] & 2) | kscolor;
+ switch (cscolor) {
+ case 0:
+ cproc = rop_proc_table[rop3_know_S_0(rop)];
+ break;
+ case 1:
+ cproc = rop_proc_table[rop3_invert_S(rop)];
+ break;
+ case 2:
+ cproc = rop_proc_table[rop];
+ break;
+ default: /* 3 */
+ cproc = rop_proc_table[rop3_know_S_1(rop)];
+ break;
+ }
+ switch (mscolor) {
+ case 0:
+ mproc = rop_proc_table[rop3_know_S_0(rop)];
+ break;
+ case 1:
+ mproc = rop_proc_table[rop3_invert_S(rop)];
+ break;
+ case 2:
+ mproc = rop_proc_table[rop];
+ break;
+ default: /* 3 */
+ mproc = rop_proc_table[rop3_know_S_1(rop)];
+ break;
+ }
+ switch (yscolor) {
+ case 0:
+ yproc = rop_proc_table[rop3_know_S_0(rop)];
+ break;
+ case 1:
+ yproc = rop_proc_table[rop3_invert_S(rop)];
+ break;
+ case 2:
+ yproc = rop_proc_table[rop];
+ break;
+ default: /* 3 */
+ yproc = rop_proc_table[rop3_know_S_1(rop)];
+ break;
+ }
+ }
+ }
+ if (tcolors)
+ {
+ ktcolor = ((tcolors[0] & 1) ? -1 : 0);
+ ctcolor = ((tcolors[0] & 8) ? -1 : 0) | ktcolor;
+ mtcolor = ((tcolors[0] & 4) ? -1 : 0) | ktcolor;
+ ytcolor = ((tcolors[0] & 2) ? -1 : 0) | ktcolor;
+ }
+
+ /* Set up transfer parameters. */
+ line_count = height;
+ if (lop_uses_T(lop) && (tcolors == NULL)) { /* && (textures != NULL) */
+ /* Pixmap textures. For now we'll only get into this routine if
+ * textures is a pixmap (or constant, in which case we'll do it
+ * below). */
+ int ty;
+ uint traster;
+
+/* Calculate the X offset for a given Y value, */
+/* taking shift into account if necessary. */
+#define x_offset(px, ty, textures)\
+ ((textures)->shift == 0 ? (px) :\
+ (px) + (ty) / (textures)->rep_height * (textures)->rep_shift)
+
+ cdrow = scan_line_base(mdev, y);
+ mdrow = cdrow + mdev->height * draster;
+ ydrow = mdrow + mdev->height * draster;
+ kdrow = ydrow + mdev->height * draster;
+ if (!textures)
+ return 0;
+ traster = textures->raster;
+ ty = y + phase_y;
+ for (; line_count-- > 0; cdrow += draster, mdrow += draster, ydrow += draster, kdrow += draster, srow += sraster, ++ty) {
+ int sx = sourcex;
+ int dx = x;
+ int w = width;
+ const byte *trow = textures->data + (ty % textures->rep_height) * traster;
+ int xoff = x_offset(phase_x, ty, textures);
+ int nw;
+ int tx = (dx + xoff) % textures->rep_width;
+
+ /* Loop over (horizontal) copies of the tile. */
+ for (; w > 0; sx += nw, dx += nw, w -= nw, tx = 0) {
+ /* sptr and tptr point to bytes of cmykcmyk. Need to convert
+ * these to planar format. */
+ int dbit = dx & 7;
+ int tbit = tx & 1;
+ int tskew = tbit - dbit; /* -7 >= tskew >= 1 */
+ int left = (nw = min(w, textures->size.x - tx))-8+dbit;
+ int sbit = sx & 1;
+ int sskew = sbit - dbit; /* -7 >= sskew >= 1 */
+ byte lmask = 0xff >> dbit;
+ byte rmask = 0xff << (~(dbit + nw - 1) & 7);
+ byte *cdptr = cdrow + (dx>>3);
+ byte *mdptr = mdrow + (dx>>3);
+ byte *ydptr = ydrow + (dx>>3);
+ byte *kdptr = kdrow + (dx>>3);
+ const byte *tptr = trow;
+ const rop_proc proc = rop_proc_table[rop];
+ const byte *sptr = srow;
+ sptr += (sskew>>1); /* Backtrack sptr if required. */
+ sptr += (sx>>1);
+ tptr += (tskew>>1); /* Backtrack tptr if required. */
+ tptr += (tx>>1);
+ if (left < 0)
+ lmask &= rmask;
+ {
+ /* Left hand bytes */
+ byte kdbyte = *kdptr;
+ byte cdbyte = *cdptr;
+ byte mdbyte = *mdptr;
+ byte ydbyte = *ydptr;
+ byte cresult, mresult, yresult, kresult;
+ bits32 scol = 0, tcol = 0;
+ if ((sskew & 1) == 0) {
+ if (sskew >= 0)
+ scol = expand_4to1[sptr[0]]<<6;
+ if ((sskew >= -2) && (left > -6))
+ scol |= expand_4to1[sptr[1]]<<4;
+ if ((sskew >= -4) && (left > -4))
+ scol |= expand_4to1[sptr[2]]<<2;
+ if (left > -2)
+ scol |= expand_4to1[sptr[3]];
+ } else {
+ if (sskew >= 0)
+ scol = expand_4to1[sptr[0] & 0x0f]<<7;
+ if ((sskew >= -2) && (left > -7))
+ scol |= expand_4to1[sptr[1]]<<5;
+ if ((sskew >= -4) && (left > -5))
+ scol |= expand_4to1[sptr[2]]<<3;
+ if ((sskew >= -6) && (left > -3))
+ scol |= expand_4to1[sptr[3]]<<1;
+ if (left > -1)
+ scol |= expand_4to1[sptr[4] & 0xf0]>>1;
+ }
+ if ((tskew & 1) == 0) {
+ if (tskew >= 0)
+ tcol = expand_4to1[tptr[0]]<<6;
+ if ((tskew >= -2) && (left > -6))
+ tcol |= expand_4to1[tptr[1]]<<4;
+ if ((tskew >= -4) && (left > -4))
+ tcol |= expand_4to1[tptr[2]]<<2;
+ if (left > -2)
+ tcol |= expand_4to1[tptr[3]];
+ } else {
+ if (tskew >= 0)
+ tcol = expand_4to1[tptr[0] & 0x0f]<<7;
+ if ((tskew >= -2) && (left > -7))
+ tcol |= expand_4to1[tptr[1]]<<5;
+ if ((tskew >= -4) && (left > -5))
+ tcol |= expand_4to1[tptr[2]]<<3;
+ if ((tskew >= -6) && (left > -3))
+ tcol |= expand_4to1[tptr[3]]<<1;
+ if (left > -1)
+ tcol |= expand_4to1[tptr[4] & 0xf0]>>1;
+ }
+ cresult = (*proc)(cdbyte | kdbyte,scol|(scol>>24),tcol|(tcol>>24));
+ mresult = (*proc)(mdbyte | kdbyte,scol|(scol>>16),tcol|(tcol>>16));
+ yresult = (*proc)(ydbyte | kdbyte,scol|(scol>> 8),tcol|(tcol>> 8));
+ kresult = cresult & mresult & yresult;
+ cresult &= ~kresult;
+ mresult &= ~kresult;
+ yresult &= ~kresult;
+ *cdptr++ = (cresult & lmask) | (cdbyte & ~lmask);
+ *mdptr++ = (mresult & lmask) | (mdbyte & ~lmask);
+ *ydptr++ = (yresult & lmask) | (ydbyte & ~lmask);
+ *kdptr++ = (kresult & lmask) | (kdbyte & ~lmask);
+ }
+ if (left <= 0) /* if (width <= 8) we're done */
+ continue;
+ sptr += 4;
+ tptr += 4;
+ left -= 8; /* left = bits to go - 8 */
+ while (left > 0)
+ {
+ byte kdbyte = *kdptr;
+ byte cdbyte = *cdptr | kdbyte;
+ byte mdbyte = *mdptr | kdbyte;
+ byte ydbyte = *ydptr | kdbyte;
+ byte cresult, mresult, yresult, kresult;
+ bits32 scol, tcol;
+ if ((sskew & 1) == 0) {
+ scol = expand_4to1[sptr[0]]<<6;
+ scol |= expand_4to1[sptr[1]]<<4;
+ scol |= expand_4to1[sptr[2]]<<2;
+ scol |= expand_4to1[sptr[3]];
+ } else {
+ scol = expand_4to1[sptr[0] & 0x0f]<<7;
+ scol |= expand_4to1[sptr[1]]<<5;
+ scol |= expand_4to1[sptr[2]]<<3;
+ scol |= expand_4to1[sptr[3]]<<1;
+ scol |= expand_4to1[sptr[4] & 0xf0]>>1;
+ }
+ if ((tskew & 1) == 0) {
+ tcol = expand_4to1[tptr[0]]<<6;
+ tcol |= expand_4to1[tptr[1]]<<4;
+ tcol |= expand_4to1[tptr[2]]<<2;
+ tcol |= expand_4to1[tptr[3]];
+ } else {
+ tcol = expand_4to1[tptr[0] & 0x0f]<<7;
+ tcol |= expand_4to1[tptr[1]]<<5;
+ tcol |= expand_4to1[tptr[2]]<<3;
+ tcol |= expand_4to1[tptr[3]]<<1;
+ tcol |= expand_4to1[tptr[4] & 0xf0]>>1;
+ }
+ cresult = (*proc)(cdbyte | kdbyte,scol|(scol>>24),tcol|(tcol>>24));
+ mresult = (*proc)(mdbyte | kdbyte,scol|(scol>>16),tcol|(tcol>>16));
+ yresult = (*proc)(ydbyte | kdbyte,scol|(scol>> 8),tcol|(tcol>> 8));
+ kresult = cresult & mresult & yresult;
+ cresult &= ~kresult;
+ mresult &= ~kresult;
+ yresult &= ~kresult;
+ *cdptr++ = cresult & ~kresult;
+ *mdptr++ = mresult & ~kresult;
+ *ydptr++ = yresult & ~kresult;
+ *kdptr++ = kresult;
+ sptr += 4;
+ tptr += 4;
+ left -= 8;
+ }
+ {
+ byte kdbyte = *kdptr;
+ byte cdbyte = *cdptr;
+ byte mdbyte = *mdptr;
+ byte ydbyte = *ydptr;
+ byte cresult, mresult, yresult, kresult;
+ bits32 scol, tcol;
+ if ((sskew & 1) == 0) {
+ scol = expand_4to1[sptr[0]]<<6;
+ if (left > -6)
+ scol |= expand_4to1[sptr[1]]<<4;
+ if (left > -4)
+ scol |= expand_4to1[sptr[2]]<<2;
+ if (left > -2)
+ scol |= expand_4to1[sptr[3]];
+ } else {
+ scol = expand_4to1[sptr[0] & 0x0f]<<7;
+ if (left > -7)
+ scol |= expand_4to1[sptr[1]]<<5;
+ if (left > -5)
+ scol |= expand_4to1[sptr[2]]<<3;
+ if (left > -3)
+ scol |= expand_4to1[sptr[3]]<<1;
+ if (left > -1)
+ scol |= expand_4to1[sptr[4] & 0xf0]>>1;
+ }
+ if ((tskew & 1) == 0) {
+ tcol = expand_4to1[tptr[0]]<<6;
+ if (left > -6)
+ tcol |= expand_4to1[tptr[1]]<<4;
+ if (left > -4)
+ tcol |= expand_4to1[tptr[2]]<<2;
+ if (left > -2)
+ tcol |= expand_4to1[tptr[3]];
+ } else {
+ tcol = expand_4to1[tptr[0] & 0x0f]<<7;
+ if (left > -7)
+ tcol |= expand_4to1[tptr[1]]<<5;
+ if (left > -5)
+ tcol |= expand_4to1[tptr[2]]<<3;
+ if (left > -3)
+ tcol |= expand_4to1[tptr[3]]<<1;
+ if (left > -1)
+ tcol |= expand_4to1[tptr[4] & 0xf0]>>1;
+ }
+ cresult = (*proc)(cdbyte | kdbyte,scol|(scol>>24),tcol|(tcol>>24));
+ mresult = (*proc)(mdbyte | kdbyte,scol|(scol>>16),tcol|(tcol>>16));
+ yresult = (*proc)(ydbyte | kdbyte,scol|(scol>> 8),tcol|(tcol>> 8));
+ kresult = cresult & mresult & yresult;
+ cresult &= ~kresult;
+ mresult &= ~kresult;
+ yresult &= ~kresult;
+ *cdptr++ = (cresult & rmask) | (cdbyte & ~rmask);
+ *mdptr++ = (mresult & rmask) | (mdbyte & ~rmask);
+ *ydptr++ = (yresult & rmask) | (ydbyte & ~rmask);
+ *kdptr++ = (kresult & rmask) | (kdbyte & ~rmask);
+ }
+ }
+ }
+ return 0;
+ }
+ /* Texture constant (or unimportant) cases */
+ dbit = x & 7;
+ cdrow = scan_line_base(mdev, y) + (x>>3);
+ mdrow = cdrow + mdev->height * draster;
+ ydrow = mdrow + mdev->height * draster;
+ kdrow = ydrow + mdev->height * draster;
+ lmask = 0xff >> dbit;
+ width += dbit;
+ rmask = 0xff << (~(width - 1) & 7);
+ if (width < 8)
+ lmask &= rmask;
+ if (scolors == NULL) {
+ /* sptr points to bytes of cmykcmyk. Need to convert these to
+ * planar format. */
+ const rop_proc proc = rop_proc_table[rop];
+ int sbit = sourcex & 1;
+ int sskew = sbit - dbit; /* -7 >= sskew >= 1 */
+ srow += (sskew>>1); /* Backtrack srow if required. */
+ srow += (sourcex>>1);
+ for (; line_count-- > 0; cdrow += draster, mdrow += draster, ydrow += draster, kdrow += draster, srow += sraster) {
+ byte *cdptr = cdrow;
+ byte *mdptr = mdrow;
+ byte *ydptr = ydrow;
+ byte *kdptr = kdrow;
+ const byte *sptr = srow;
+ int left = width-8;
+ {
+ /* Left hand bytes */
+ byte kdbyte = *kdptr;
+ byte cdbyte = *cdptr;
+ byte mdbyte = *mdptr;
+ byte ydbyte = *ydptr;
+ byte cresult, mresult, yresult, kresult;
+ bits32 scol = 0;
+ if ((sskew & 1) == 0) {
+ if (sskew >= 0)
+ scol = expand_4to1[sptr[0]]<<6;
+ if ((sskew >= -2) && (left > -6))
+ scol |= expand_4to1[sptr[1]]<<4;
+ if ((sskew >= -4) && (left > -4))
+ scol |= expand_4to1[sptr[2]]<<2;
+ if (left > -2)
+ scol |= expand_4to1[sptr[3]];
+ } else {
+ if (sskew >= 0)
+ scol = expand_4to1[sptr[0] & 0x0f]<<7;
+ if ((sskew >= -2) && (left > -7))
+ scol |= expand_4to1[sptr[1]]<<5;
+ if ((sskew >= -4) && (left > -5))
+ scol |= expand_4to1[sptr[2]]<<3;
+ if ((sskew >= -6) && (left > -3))
+ scol |= expand_4to1[sptr[3]]<<1;
+ if (left > -1)
+ scol |= expand_4to1[sptr[4] & 0xf0]>>1;
+ }
+ cresult = (*proc)(cdbyte | kdbyte,scol|(scol>>24),ctcolor);
+ mresult = (*proc)(mdbyte | kdbyte,scol|(scol>>16),mtcolor);
+ yresult = (*proc)(ydbyte | kdbyte,scol|(scol>> 8),ytcolor);
+ kresult = cresult & mresult & yresult;
+ cresult &= ~kresult;
+ mresult &= ~kresult;
+ yresult &= ~kresult;
+ *cdptr++ = (cresult & lmask) | (cdbyte & ~lmask);
+ *mdptr++ = (mresult & lmask) | (mdbyte & ~lmask);
+ *ydptr++ = (yresult & lmask) | (ydbyte & ~lmask);
+ *kdptr++ = (kresult & lmask) | (kdbyte & ~lmask);
+ }
+ if (left <= 0) /* if (width <= 8) we're done */
+ continue;
+ sptr += 4;
+ left -= 8; /* left = bits to go - 8 */
+ while (left > 0)
+ {
+ byte kdbyte = *kdptr;
+ byte cdbyte = *cdptr | kdbyte;
+ byte mdbyte = *mdptr | kdbyte;
+ byte ydbyte = *ydptr | kdbyte;
+ byte cresult, mresult, yresult, kresult;
+ bits32 scol;
+ if ((sskew & 1) == 0) {
+ scol = expand_4to1[sptr[0]]<<6;
+ scol |= expand_4to1[sptr[1]]<<4;
+ scol |= expand_4to1[sptr[2]]<<2;
+ scol |= expand_4to1[sptr[3]];
+ } else {
+ scol = expand_4to1[sptr[0] & 0x0f]<<7;
+ scol |= expand_4to1[sptr[1]]<<5;
+ scol |= expand_4to1[sptr[2]]<<3;
+ scol |= expand_4to1[sptr[3]]<<1;
+ scol |= expand_4to1[sptr[4] & 0xf0]>>1;
+ }
+ cresult = (*proc)(cdbyte | kdbyte,scol|(scol>>24),ctcolor);
+ mresult = (*proc)(mdbyte | kdbyte,scol|(scol>>16),mtcolor);
+ yresult = (*proc)(ydbyte | kdbyte,scol|(scol>> 8),ytcolor);
+ kresult = cresult & mresult & yresult;
+ cresult &= ~kresult;
+ mresult &= ~kresult;
+ yresult &= ~kresult;
+ *cdptr++ = cresult & ~kresult;
+ *mdptr++ = mresult & ~kresult;
+ *ydptr++ = yresult & ~kresult;
+ *kdptr++ = kresult;
+ sptr += 4;
+ left -= 8;
+ }
+ {
+ byte kdbyte = *kdptr;
+ byte cdbyte = *cdptr;
+ byte mdbyte = *mdptr;
+ byte ydbyte = *ydptr;
+ byte cresult, mresult, yresult, kresult;
+ bits32 scol;
+ if ((sskew & 1) == 0) {
+ scol = expand_4to1[sptr[0]]<<6;
+ if (left > -6)
+ scol |= expand_4to1[sptr[1]]<<4;
+ if (left > -4)
+ scol |= expand_4to1[sptr[2]]<<2;
+ if (left > -2)
+ scol |= expand_4to1[sptr[3]];
+ } else {
+ scol = expand_4to1[sptr[0] & 0x0f]<<7;
+ if (left > -7)
+ scol |= expand_4to1[sptr[1]]<<5;
+ if (left > -5)
+ scol |= expand_4to1[sptr[2]]<<3;
+ if (left > -3)
+ scol |= expand_4to1[sptr[3]]<<1;
+ if (left > -1)
+ scol |= expand_4to1[sptr[4] & 0xf0]>>1;
+ }
+ cresult = (*proc)(cdbyte | kdbyte,scol|(scol>>24),ctcolor);
+ mresult = (*proc)(mdbyte | kdbyte,scol|(scol>>16),mtcolor);
+ yresult = (*proc)(ydbyte | kdbyte,scol|(scol>> 8),ytcolor);
+ kresult = cresult & mresult & yresult;
+ cresult &= ~kresult;
+ mresult &= ~kresult;
+ yresult &= ~kresult;
+ *cdptr++ = (cresult & rmask) | (cdbyte & ~rmask);
+ *mdptr++ = (mresult & rmask) | (mdbyte & ~rmask);
+ *ydptr++ = (yresult & rmask) | (ydbyte & ~rmask);
+ *kdptr++ = (kresult & rmask) | (kdbyte & ~rmask);
+ }
+ }
+ } else if (constant_s) {
+ const rop_proc proc = rop_proc_table[rop];
+ for (; line_count-- > 0; cdrow += draster, mdrow += draster, ydrow += draster, kdrow += draster) {
+ byte *cdptr = cdrow;
+ byte *mdptr = mdrow;
+ byte *ydptr = ydrow;
+ byte *kdptr = kdrow;
+ int left = width-8;
+ {
+ /* Left hand bytes */
+ byte kdbyte = *kdptr;
+ byte cdbyte = *cdptr;
+ byte mdbyte = *mdptr;
+ byte ydbyte = *ydptr;
+ byte cresult = (*proc)(cdbyte | kdbyte,cscolor,ctcolor);
+ byte mresult = (*proc)(mdbyte | kdbyte,mscolor,mtcolor);
+ byte yresult = (*proc)(ydbyte | kdbyte,yscolor,ytcolor);
+ byte kresult = cresult & mresult & yresult;
+ cresult &= ~kresult;
+ mresult &= ~kresult;
+ yresult &= ~kresult;
+ *cdptr++ = (cresult & lmask) | (cdbyte & ~lmask);
+ *mdptr++ = (mresult & lmask) | (mdbyte & ~lmask);
+ *ydptr++ = (yresult & lmask) | (ydbyte & ~lmask);
+ *kdptr++ = (kresult & lmask) | (kdbyte & ~lmask);
+ }
+ if (left <= 0) /* if (width <= 8) we're done */
+ continue;
+ left -= 8; /* left = bits to go - 8 */
+ while (left > 0)
+ {
+ byte kdbyte = *kdptr;
+ byte cdbyte = *cdptr | kdbyte;
+ byte mdbyte = *mdptr | kdbyte;
+ byte ydbyte = *ydptr | kdbyte;
+ byte cresult = (*proc)(cdbyte,cscolor,ctcolor);
+ byte mresult = (*proc)(mdbyte,mscolor,mtcolor);
+ byte yresult = (*proc)(ydbyte,yscolor,ytcolor);
+ byte kresult = cresult & mresult & yresult;
+ cresult &= ~kresult;
+ mresult &= ~kresult;
+ yresult &= ~kresult;
+ *cdptr++ = cresult & ~kresult;
+ *mdptr++ = mresult & ~kresult;
+ *ydptr++ = yresult & ~kresult;
+ *kdptr++ = kresult;
+ left -= 8;
+ }
+ {
+ byte kdbyte = *kdptr;
+ byte cdbyte = *cdptr;
+ byte mdbyte = *mdptr;
+ byte ydbyte = *ydptr;
+ byte cresult = (*proc)(cdbyte | kdbyte,cscolor,ctcolor);
+ byte mresult = (*proc)(mdbyte | kdbyte,mscolor,mtcolor);
+ byte yresult = (*proc)(ydbyte | kdbyte,yscolor,ytcolor);
+ byte kresult = cresult & mresult & yresult;
+ cresult &= ~kresult;
+ mresult &= ~kresult;
+ yresult &= ~kresult;
+ *cdptr++ = (cresult & rmask) | (cdbyte & ~rmask);
+ *mdptr++ = (mresult & rmask) | (mdbyte & ~rmask);
+ *ydptr++ = (yresult & rmask) | (ydbyte & ~rmask);
+ *kdptr++ = (kresult & rmask) | (kdbyte & ~rmask);
+ }
+ }
+ } else {
+ /* Constant T, bitmap S */
+ int sbit = sourcex & 7;
+ int sskew = sbit - dbit;
+ if (sskew < 0)
+ --srow, sskew += 8;
+ srow += (sourcex>>3);
+ for (; line_count-- > 0; cdrow += draster, mdrow += draster, ydrow += draster, kdrow += draster, srow += sraster) {
+ const byte *sptr = srow;
+ byte *cdptr = cdrow;
+ byte *mdptr = mdrow;
+ byte *ydptr = ydrow;
+ byte *kdptr = kdrow;
+ int left = width-8;
+ {
+ /* Left hand byte (maybe the only one) */
+ byte kdbyte = *kdptr;
+ byte cdbyte = *cdptr;
+ byte mdbyte = *mdptr;
+ byte ydbyte = *ydptr;
+#define fetch1(ptr, skew)\
+ (skew ? (ptr[0] << skew) + (ptr[1] >> (8 - skew)) : *ptr)
+ byte sbyte = fetch1(sptr, sskew);
+ byte cresult = (*cproc)(cdbyte|kdbyte,sbyte,ctcolor);
+ byte mresult = (*mproc)(mdbyte|kdbyte,sbyte,mtcolor);
+ byte yresult = (*yproc)(ydbyte|kdbyte,sbyte,ytcolor);
+ byte kresult = cresult & mresult & yresult;
+ cresult &= ~kresult;
+ mresult &= ~kresult;
+ yresult &= ~kresult;
+ *cdptr++ = (cresult & lmask) | (cdbyte & ~lmask);
+ *mdptr++ = (mresult & lmask) | (mdbyte & ~lmask);
+ *ydptr++ = (yresult & lmask) | (ydbyte & ~lmask);
+ *kdptr++ = (kresult & lmask) | (kdbyte & ~lmask);
+ sptr++;
+ left -= 8;
+ }
+ while (left > 0) {
+ /* Bytes where all 8 bits of S are needed */
+ byte kdbyte = *kdptr;
+ byte cdbyte = *cdptr | kdbyte;
+ byte mdbyte = *mdptr | kdbyte;
+ byte ydbyte = *ydptr | kdbyte;
+ byte sbyte = fetch1(sptr, sskew);
+ byte cresult = (*cproc)(cdbyte,sbyte,ctcolor);
+ byte mresult = (*mproc)(mdbyte,sbyte,mtcolor);
+ byte yresult = (*yproc)(ydbyte,sbyte,ytcolor);
+ byte kresult = cresult & mresult & yresult;
+ *cdptr++ = cresult & ~kresult;
+ *mdptr++ = mresult & ~kresult;
+ *ydptr++ = yresult & ~kresult;
+ *kdptr++ = kresult;
+ sptr++;
+ left -= 8;
+ }
+ /* Final byte */
+ if (left > -8) {
+ byte kdbyte = *kdptr;
+ byte cdbyte = *cdptr;
+ byte mdbyte = *mdptr;
+ byte ydbyte = *ydptr;
+ byte sbyte = fetch1(sptr, sskew);
+#undef fetch1
+ byte cresult = (*cproc)(cdbyte | kdbyte,sbyte,ctcolor);
+ byte mresult = (*mproc)(mdbyte | kdbyte,sbyte,mtcolor);
+ byte yresult = (*yproc)(ydbyte | kdbyte,sbyte,ytcolor);
+ byte kresult = cresult & mresult & yresult;
+ cresult &= ~kresult;
+ mresult &= ~kresult;
+ yresult &= ~kresult;
+ *cdptr++ = (cresult & rmask) | (cdbyte & ~rmask);
+ *mdptr++ = (mresult & rmask) | (mdbyte & ~rmask);
+ *ydptr++ = (yresult & rmask) | (ydbyte & ~rmask);
+ *kdptr++ = (kresult & rmask) | (kdbyte & ~rmask);
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+plane_strip_copy_rop(gx_device_memory * mdev,
+ const byte * sdata, int sourcex, uint sraster,
+ gx_bitmap_id id, const gx_color_index * scolors,
+ const gx_strip_bitmap * textures,
+ const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y,
+ gs_logical_operation_t lop, int plane)
+{
+ mem_save_params_t save;
+ int code;
+ const gx_device_memory *mdproto;
+
+ MEM_SAVE_PARAMS(mdev, save);
+ mdev->line_ptrs += mdev->height * plane;
+ mdproto = gdev_mem_device_for_bits(mdev->planes[plane].depth);
+ /* strip_copy_rop might end up calling get_bits_rectangle or fill_rectangle,
+ * so ensure we have the right ones in there. */
+ set_dev_proc(mdev, get_bits_rectangle, dev_proc(mdproto, get_bits_rectangle));
+ set_dev_proc(mdev, fill_rectangle, dev_proc(mdproto, fill_rectangle));
+ code = dev_proc(mdproto, strip_copy_rop)((gx_device *)mdev, sdata, sourcex, sraster,
+ id, scolors, textures, tcolors,
+ x, y, width, height,
+ phase_x, phase_y, lop);
+ set_dev_proc(mdev, get_bits_rectangle, mem_planar_get_bits_rectangle);
+ set_dev_proc(mdev, fill_rectangle, mem_planar_fill_rectangle);
+ /* The following effectively does: mdev->line_ptrs -= mdev->height * plane; */
+ MEM_RESTORE_PARAMS(mdev, save);
+ return code;
+}
+
+/*
+ * Repack planar into chunky format. This is an internal procedure that
+ * implements the straightforward chunky case of get_bits_rectangle, and
+ * is also used for the general cases.
+ */
+static int
+planar_to_chunky(gx_device_memory *mdev, int x, int y, int w, int h,
+ int offset, uint draster, byte *dest, byte **line_ptrs,
+ int plane_height)
+{
+ int num_planes = mdev->color_info.num_components;
+ const byte *sptr[GX_DEVICE_COLOR_MAX_COMPONENTS];
+ int sbit[GX_DEVICE_COLOR_MAX_COMPONENTS];
+ byte *dptr;
+ int dbit;
+ byte dbbyte;
+ int ddepth = mdev->color_info.depth;
+ int direct =
+ (mdev->color_info.depth != num_planes * mdev->plane_depth ? 0 :
+ mdev->planes[0].shift == 0 ? -mdev->plane_depth : mdev->plane_depth);
+ int pi, ix, iy;
+
+ /* Check whether the planes are of equal size and sequential. */
+ /* If direct != 0, we already know they exactly fill the depth. */
+ if (direct < 0) {
+ for (pi = 0; pi < num_planes; ++pi)
+ if (mdev->planes[pi].shift != pi * -direct) {
+ direct = 0; break;
+ }
+ } else if (direct > 0) {
+ for (pi = 0; pi < num_planes; ++pi)
+ if (mdev->planes[num_planes - 1 - pi].shift != pi * direct) {
+ direct = 0; break;
+ }
+ }
+ for (iy = y; iy < y + h; ++iy) {
+ byte **line_ptr = line_ptrs + iy;
+
+ for (pi = 0; pi < num_planes; ++pi, line_ptr += plane_height) {
+ int plane_depth = mdev->planes[pi].depth;
+ int xbit = x * plane_depth;
+
+ sptr[pi] = *line_ptr + (xbit >> 3);
+ sbit[pi] = xbit & 7;
+ }
+ {
+ int xbit = offset * ddepth;
+
+ dptr = dest + (iy - y) * draster + (xbit >> 3);
+ dbit = xbit & 7;
+ }
+ if (direct == -8) {
+ /* 1 byte per component, lsb first. */
+ switch (num_planes) {
+ case 3: {
+ const byte *p0 = sptr[2];
+ const byte *p1 = sptr[1];
+ const byte *p2 = sptr[0];
+
+ for (ix = w; ix > 0; --ix, dptr += 3) {
+ dptr[0] = *p0++;
+ dptr[1] = *p1++;
+ dptr[2] = *p2++;
+ }
+ }
+ continue;
+ case 4:
+ for (ix = w; ix > 0; --ix, dptr += 4) {
+ dptr[0] = *sptr[3]++;
+ dptr[1] = *sptr[2]++;
+ dptr[2] = *sptr[1]++;
+ dptr[3] = *sptr[0]++;
+ }
+ continue;
+ default:
+ break;
+ }
+ }
+ dbbyte = (dbit ? (byte)(*dptr & (0xff00 >> dbit)) : 0);
+/* sample_store_preload(dbbyte, dptr, dbit, ddepth);*/
+ for (ix = w; ix > 0; --ix) {
+ gx_color_index color = 0;
+
+ for (pi = 0; pi < num_planes; ++pi) {
+ int plane_depth = mdev->planes[pi].depth;
+ ushort value;
+
+ if (sample_load_next16(&value, &sptr[pi], &sbit[pi], plane_depth) < 0)
+ return_error(gs_error_rangecheck);
+ color |= (gx_color_index)value << mdev->planes[pi].shift;
+ }
+ if (sizeof(color) > 4) {
+ if (sample_store_next64(color, &dptr, &dbit, ddepth, &dbbyte) < 0)
+ return_error(gs_error_rangecheck);
+ }
+ else {
+ if (sample_store_next32(color, &dptr, &dbit, ddepth, &dbbyte) < 0)
+ return_error(gs_error_rangecheck);
+ }
+ }
+ sample_store_flush(dptr, dbit, dbbyte);
+ }
+ return 0;
+}
+
+static byte cmykrop[256] =
+{
+ 255,127,191,63,223,95,159,31,239,111,175,47,207,79,143,15,
+ 247,119,183,55,215,87,151,23,231,103,167,39,199,71,135,7,
+ 251,123,187,59,219,91,155,27,235,107,171,43,203,75,139,11,
+ 243,115,179,51,211,83,147,19,227,99,163,35,195,67,131,3,
+ 253,125,189,61,221,93,157,29,237,109,173,45,205,77,141,13,
+ 245,117,181,53,213,85,149,21,229,101,165,37,197,69,133,5,
+ 249,121,185,57,217,89,153,25,233,105,169,41,201,73,137,9,
+ 241,113,177,49,209,81,145,17,225,97,161,33,193,65,129,1,
+ 254,126,190,62,222,94,158,30,238,110,174,46,206,78,142,14,
+ 246,118,182,54,214,86,150,22,230,102,166,38,198,70,134,6,
+ 250,122,186,58,218,90,154,26,234,106,170,42,202,74,138,10,
+ 242,114,178,50,210,82,146,18,226,98,162,34,194,66,130,2,
+ 252,124,188,60,220,92,156,28,236,108,172,44,204,76,140,12,
+ 244,116,180,52,212,84,148,20,228,100,164,36,196,68,132,4,
+ 248,120,184,56,216,88,152,24,232,104,168,40,200,72,136,8,
+ 240,112,176,48,208,80,144,16,224,96,160,32,192,64,128,0
+};
+
+static int
+mem_planar_strip_copy_rop(gx_device * dev,
+ const byte * sdata, int sourcex, uint sraster,
+ gx_bitmap_id id, const gx_color_index * scolors,
+ const gx_strip_bitmap * textures,
+ const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y,
+ gs_logical_operation_t lop)
+{
+ return mem_planar_strip_copy_rop2(dev, sdata, sourcex, sraster,
+ id, scolors, textures, tcolors,
+ x, y, width, height,
+ phase_x, phase_y, lop, 0);
+}
+
+static int
+mem_planar_strip_copy_rop2(gx_device * dev,
+ const byte * sdata, int sourcex, uint sraster,
+ gx_bitmap_id id, const gx_color_index * scolors,
+ const gx_strip_bitmap * textures,
+ const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y,
+ gs_logical_operation_t lop,
+ uint planar_height)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ int code;
+
+ lop = lop_sanitize(lop);
+ if (planar_height != 0) {
+ /* S is in planar format; expand it to a temporary buffer, then
+ * call ourselves back with a modified rop to use it, then free
+ * the temporary buffer, and return. */
+ /* Make a temporary buffer that contains both the raster and the line
+ * pointers for the buffer. For now, for the sake of sanity, we
+ * convert whole lines of s, but only as many lines as we have to. */
+ /* We assume that scolors == NULL here */
+ int i;
+ uchar j;
+ uint chunky_sraster;
+ uint nbytes;
+ byte **line_ptrs;
+ byte *sbuf, *buf;
+
+ chunky_sraster = sraster * mdev->color_info.num_components;
+ nbytes = height * chunky_sraster;
+ buf = gs_alloc_bytes(mdev->memory, nbytes, "mem_planar_strip_copy_rop(buf)");
+ if (buf == NULL) {
+ return gs_note_error(gs_error_VMerror);
+ }
+ nbytes = sizeof(byte *) * mdev->color_info.num_components * height;
+ line_ptrs = (byte **)gs_alloc_bytes(mdev->memory, nbytes, "mem_planar_strip_copy_rop(line_ptrs)");
+ if (line_ptrs == NULL) {
+ gs_free_object(mdev->memory, buf, "mem_planar_strip_copy_rop(buf)");
+ return gs_note_error(gs_error_VMerror);
+ }
+ for (j = 0; j < mdev->color_info.num_components; j++) {
+ sbuf = (byte *)sdata + j * sraster;
+ for (i = height; i > 0; i--) {
+ *line_ptrs++ = sbuf;
+ sbuf += sraster;
+ }
+ }
+ line_ptrs -= height * mdev->color_info.num_components;
+ planar_to_chunky(mdev, sourcex, 0, width, height,
+ 0, chunky_sraster, buf, line_ptrs, planar_height);
+ gs_free_object(mdev->memory, line_ptrs, "mem_planar_strip_copy_rop(line_ptrs)");
+ code = mem_planar_strip_copy_rop2(dev, buf, 0, chunky_sraster,
+ id, scolors, textures, tcolors,
+ x, y, width, height, phase_x, phase_y,
+ lop, 0);
+ gs_free_object(mdev->memory, buf, "mem_planar_strip_copy_rop(buf)");
+ return code;
+ }
+
+ if (textures && textures->num_planes > 1) {
+ /* T is in planar format; expand it to a temporary buffer, then
+ * call ourselves back with a modified rop to use it, then free
+ * the temporary buffer, and return. */
+ /* Make a temporary buffer that contains both the raster and the line
+ * pointers for the buffer. For now, for the sake of sanity, we
+ * convert whole lines of t, but only as many lines as we have to
+ * (unless it loops). */
+ /* We assume that tcolors == NULL here */
+ int ty, i;
+ uint chunky_t_raster;
+ uint chunky_t_height;
+ uint nbytes;
+ byte **line_ptrs;
+ byte *tbuf, *buf;
+ gx_strip_bitmap newtex;
+
+ ty = (y + phase_y) % textures->rep_height;
+ if (ty < 0)
+ ty += textures->rep_height;
+ chunky_t_raster = bitmap_raster(textures->rep_width * mdev->color_info.depth);
+ if (ty + height <= textures->rep_height) {
+ chunky_t_height = height;
+ phase_y = -y;
+ } else {
+ ty = 0;
+ chunky_t_height = textures->rep_height;
+ }
+ nbytes = chunky_t_height * chunky_t_raster;
+ buf = gs_alloc_bytes(mdev->memory, nbytes, "mem_planar_strip_copy_rop(buf)");
+ if (buf == NULL) {
+ return gs_note_error(gs_error_VMerror);
+ }
+ nbytes = sizeof(byte *) * mdev->color_info.num_components * textures->rep_height;
+ line_ptrs = (byte **)gs_alloc_bytes(mdev->memory, nbytes, "mem_planar_strip_copy_rop(line_ptrs)");
+ if (line_ptrs == NULL) {
+ gs_free_object(mdev->memory, buf, "mem_planar_strip_copy_rop(buf)");
+ return gs_note_error(gs_error_VMerror);
+ }
+ tbuf = textures->data;
+ for (i = textures->rep_height * mdev->color_info.num_components; i > 0; i--) {
+ *line_ptrs++ = tbuf;
+ tbuf += textures->raster;
+ }
+ line_ptrs -= textures->rep_height * mdev->color_info.num_components;
+ planar_to_chunky(mdev, 0, ty, textures->rep_width, chunky_t_height,
+ 0, chunky_t_raster, buf, line_ptrs, textures->rep_height);
+ gs_free_object(mdev->memory, line_ptrs, "mem_planar_strip_copy_rop(line_ptrs)");
+ newtex = *textures;
+ newtex.data = buf;
+ newtex.raster = chunky_t_raster;
+ newtex.num_planes = 1;
+ newtex.size.x = textures->rep_width;
+ newtex.size.y = textures->rep_height;
+ code = mem_planar_strip_copy_rop2(dev, sdata, sourcex, sraster,
+ id, scolors, &newtex, tcolors,
+ x, y, width, height, phase_x, phase_y,
+ lop, planar_height);
+ gs_free_object(mdev->memory, buf, "mem_planar_strip_copy_rop(buf)");
+ return code;
+ }
+
+ /* Not doing a planar lop. If we carry on down the default path here,
+ * we'll end up doing a planar_to_chunky; we may be able to sidestep
+ * that by spotting cases where we can operate directly. */
+ if (!lop_uses_T(lop) || (tcolors && (tcolors[0] == tcolors[1]))) {
+ /* No T in use, or constant T. */
+ if ((!lop_uses_S(lop) || (scolors && (scolors[0] == scolors[1]))) &&
+ ((mdev->color_info.num_components == 1) || (mdev->color_info.num_components == 3))) {
+ uchar plane;
+ /* No S in use, or constant S. And either greyscale or rgb,
+ * so we can just do the rop on each plane in turn. */
+ for (plane=0; plane < mdev->color_info.num_components; plane++)
+ {
+ gx_color_index tcolors2[2], scolors2[2];
+ int shift = mdev->planes[plane].shift;
+ int mask = (1<<mdev->planes[plane].depth)-1;
+
+ if (tcolors) {
+ tcolors2[0] = (tcolors[0] >> shift) & mask;
+ tcolors2[1] = (tcolors[1] >> shift) & mask;
+ }
+ if (scolors) {
+ scolors2[0] = (scolors[0] >> shift) & mask;
+ scolors2[1] = (scolors[1] >> shift) & mask;
+ }
+ code = plane_strip_copy_rop(mdev, sdata, sourcex, sraster,
+ id, (scolors ? scolors2 : NULL),
+ textures, (tcolors ? tcolors2 : NULL),
+ x, y, width, height,
+ phase_x, phase_y, lop, plane);
+ if (code < 0)
+ return code;
+ }
+ return 0;
+ }
+ if ((mdev->color_info.num_components == 4) && (mdev->plane_depth == 1))
+ {
+ lop = cmykrop[lop & 0xff] | (lop & ~0xff);
+ return planar_cmyk4bit_strip_copy_rop(mdev, sdata, sourcex,
+ sraster, id, scolors,
+ textures, tcolors,
+ x, y, width, height,
+ phase_x, phase_y,
+ lop);
+ }
+ }
+ if (!tcolors && !scolors &&
+ (mdev->color_info.num_components == 4) && (mdev->plane_depth == 1)) {
+ lop = cmykrop[lop & 0xff] | (lop & ~0xff);
+ return planar_cmyk4bit_strip_copy_rop(mdev, sdata, sourcex,
+ sraster, id, scolors,
+ textures, tcolors,
+ x, y, width, height,
+ phase_x, phase_y,
+ lop);
+ }
+ /* Fall back to the default implementation (the only one that
+ * guarantees to properly cope with D being planar). */
+ return mem_default_strip_copy_rop(dev, sdata, sourcex, sraster,
+ id, scolors, textures, tcolors,
+ x, y, width, height,
+ phase_x, phase_y, lop);
+}
+
+/* Copy bits back from a planar memory device. */
+static int
+mem_planar_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
+ gs_get_bits_params_t * params,
+ gs_int_rect ** unread)
+{
+ /* This duplicates most of mem_get_bits_rectangle. Tant pgs. */
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ gs_get_bits_options_t options = params->options;
+ int x = prect->p.x, w = prect->q.x - x, y = prect->p.y, h = prect->q.y - y;
+ uchar num_planes = mdev->color_info.num_components;
+ gs_get_bits_params_t copy_params;
+ int code;
+
+ if (options == 0) {
+ /*
+ * Unfortunately, as things stand, we have to support
+ * GB_PACKING_CHUNKY. In fact, we can't even claim to support
+ * GB_PACKING_PLANAR, because there is currently no way to
+ * describe the particular planar packing format that the device
+ * actually stores.
+ */
+ params->options =
+ (GB_ALIGN_STANDARD | GB_ALIGN_ANY) |
+ (GB_RETURN_COPY | GB_RETURN_POINTER) |
+ (GB_OFFSET_0 | GB_OFFSET_SPECIFIED | GB_OFFSET_ANY) |
+ (GB_RASTER_STANDARD | GB_RASTER_SPECIFIED | GB_RASTER_ANY) |
+ /*
+ (mdev->num_planes == mdev->color_info.depth ?
+ GB_PACKING_CHUNKY | GB_PACKING_PLANAR | GB_PACKING_BIT_PLANAR :
+ GB_PACKING_CHUNKY | GB_PACKING_PLANAR)
+ */
+ GB_PACKING_CHUNKY |
+ GB_COLORS_NATIVE | GB_ALPHA_NONE;
+ return_error(gs_error_rangecheck);
+ }
+
+ if (mdev->line_ptrs == 0x00)
+ return_error(gs_error_rangecheck);
+
+ if ((w <= 0) | (h <= 0)) {
+ if ((w | h) < 0)
+ return_error(gs_error_rangecheck);
+ return 0;
+ }
+ if (x < 0 || w > dev->width - x ||
+ y < 0 || h > dev->height - y
+ )
+ return_error(gs_error_rangecheck);
+
+ /* First off, see if we can satisfy get_bits_rectangle with just returning
+ * pointers to the existing data. */
+ {
+ gs_get_bits_params_t copy_params;
+ byte **base = &scan_line_base(mdev, y);
+ int code;
+
+ copy_params.options =
+ GB_COLORS_NATIVE | GB_PACKING_PLANAR | GB_ALPHA_NONE |
+ (mdev->raster ==
+ bitmap_raster(mdev->width * mdev->color_info.depth) ?
+ GB_RASTER_STANDARD : GB_RASTER_SPECIFIED);
+ copy_params.raster = mdev->raster;
+ code = gx_get_bits_return_pointer(dev, x, h, params,
+ &copy_params, base);
+ if (code >= 0)
+ return code;
+ }
+
+ /*
+ * If the request is for exactly one plane, hand it off to a device
+ * temporarily tweaked to return just that plane.
+ */
+ if (!(~options & (GB_PACKING_PLANAR | GB_SELECT_PLANES))) {
+ /* Check that only a single plane is being requested. */
+ uchar pi;
+
+ for (pi = 0; pi < num_planes; ++pi)
+ if (params->data[pi] != 0)
+ break;
+ if (pi < num_planes) {
+ uchar plane = pi++;
+
+ for (; pi < num_planes; ++pi)
+ if (params->data[pi] != 0)
+ break;
+ if (pi == num_planes) {
+ mem_save_params_t save;
+
+ copy_params = *params;
+ copy_params.options =
+ (options & ~(GB_PACKING_ALL | GB_SELECT_PLANES)) |
+ GB_PACKING_CHUNKY;
+ copy_params.data[0] = copy_params.data[plane];
+ MEM_SAVE_PARAMS(mdev, save);
+ mdev->line_ptrs += mdev->height * plane;
+ MEM_SET_PARAMS(mdev, mdev->planes[plane].depth);
+ code = mem_get_bits_rectangle(dev, prect, &copy_params,
+ unread);
+ MEM_RESTORE_PARAMS(mdev, save);
+ if (code >= 0) {
+ params->data[plane] = copy_params.data[0];
+ return code;
+ }
+ }
+ }
+ }
+ /*
+ * We can't return the requested plane by itself. Fall back to
+ * chunky format. This is somewhat painful.
+ *
+ * The code here knows how to produce just one chunky format:
+ * GB_COLORS_NATIVE, GB_ALPHA_NONE, GB_RETURN_COPY.
+ * For any other format, we generate this one in a buffer and
+ * hand it off to gx_get_bits_copy. This is *really* painful.
+ */
+ if (!(~options & (GB_COLORS_NATIVE | GB_ALPHA_NONE |
+ GB_PACKING_CHUNKY | GB_RETURN_COPY))) {
+ int offset = (options & GB_OFFSET_SPECIFIED ? params->x_offset : 0);
+ uint draster =
+ (options & GB_RASTER_SPECIFIED ? params->raster :
+ bitmap_raster((offset + w) * mdev->color_info.depth));
+
+ planar_to_chunky(mdev, x, y, w, h, offset, draster, params->data[0],
+ mdev->line_ptrs, mdev->height);
+ } else {
+ /*
+ * Do the transfer through an intermediate buffer.
+ * The buffer must be large enough to hold at least one pixel,
+ * i.e., GX_DEVICE_COLOR_MAX_COMPONENTS 16-bit values.
+ * The algorithms are very similar to those in copy_color.
+ */
+#define BUF_LONGS\
+ max(100, (GX_DEVICE_COLOR_MAX_COMPONENTS * 2 + sizeof(long) - 1) /\
+ sizeof(long))
+#define BUF_BYTES (BUF_LONGS * ARCH_SIZEOF_LONG)
+ union b_ {
+ ulong l[BUF_LONGS];
+ byte b[BUF_BYTES];
+ } buf;
+ int br, bw, bh, cx, cy, cw, ch;
+ int ddepth = mdev->color_info.depth;
+ uint raster = bitmap_raster(ddepth * mdev->width);
+ gs_get_bits_params_t dest_params;
+ int dest_bytes;
+
+ if (raster > BUF_BYTES) {
+ br = BUF_BYTES;
+ bw = BUF_BYTES * 8 / ddepth;
+ bh = 1;
+ } else {
+ br = raster;
+ bw = w;
+ bh = BUF_BYTES / raster;
+ }
+ copy_params.options =
+ GB_COLORS_NATIVE | GB_PACKING_CHUNKY | GB_ALPHA_NONE |
+ GB_RASTER_STANDARD;
+ copy_params.raster = raster;
+ /* The options passed in from above may have GB_OFFSET_0, and what's
+ * more, the code below may insist on GB_OFFSET_0 being set. Hence we
+ * can't rely on x_offset to allow for the block size we are using.
+ * We'll have to adjust the pointer by steam. */
+ dest_params = *params;
+ dest_params.x_offset = params->x_offset;
+ if (options & GB_COLORS_RGB)
+ dest_bytes = 3;
+ else if (options & GB_COLORS_CMYK)
+ dest_bytes = 4;
+ else if (options & GB_COLORS_GRAY)
+ dest_bytes = 1;
+ else
+ dest_bytes = mdev->color_info.depth / mdev->plane_depth;
+ /* We assume options & GB_DEPTH_8 */
+ for (cy = y; cy < y + h; cy += ch) {
+ ch = min(bh, y + h - cy);
+ for (cx = x; cx < x + w; cx += cw) {
+ cw = min(bw, x + w - cx);
+ planar_to_chunky(mdev, cx, cy, cw, ch, 0, br, buf.b,
+ mdev->line_ptrs, mdev->height);
+ code = gx_get_bits_copy(dev, 0, cw, ch, &dest_params,
+ &copy_params, buf.b, br);
+ if (code < 0)
+ return code;
+ dest_params.data[0] += cw * dest_bytes;
+ }
+ dest_params.data[0] += ch * dest_params.raster - (w*dest_bytes);
+ }
+#undef BUF_BYTES
+#undef BUF_LONGS
+ }
+ return 0;
+}