summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'base/gdevdbit.c')
-rw-r--r--base/gdevdbit.c931
1 files changed, 931 insertions, 0 deletions
diff --git a/base/gdevdbit.c b/base/gdevdbit.c
new file mode 100644
index 00000000..8b5fa2f9
--- /dev/null
+++ b/base/gdevdbit.c
@@ -0,0 +1,931 @@
+/* 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.
+*/
+
+/* Default device bitmap copying implementation */
+#include "gx.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsbittab.h"
+#include "gsrect.h"
+#include "gsropt.h"
+#include "gxdcolor.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gdevmem.h"
+#include "gxgetbit.h"
+#undef mdev
+#include "gxcpath.h"
+
+/* By default, implement tile_rectangle using strip_tile_rectangle. */
+int
+gx_default_tile_rectangle(gx_device * dev, const gx_tile_bitmap * tile,
+ int x, int y, int w, int h, gx_color_index color0, gx_color_index color1,
+ int px, int py)
+{
+ gx_strip_bitmap tiles;
+
+ *(gx_tile_bitmap *) & tiles = *tile;
+ tiles.shift = tiles.rep_shift = 0;
+ tiles.num_planes = 1;
+ return (*dev_proc(dev, strip_tile_rectangle))
+ (dev, &tiles, x, y, w, h, color0, color1, px, py);
+}
+
+/* Implement copy_mono by filling lots of small rectangles. */
+/* This is very inefficient, but it works as a default. */
+int
+gx_default_copy_mono(gx_device * dev, const byte * data,
+ int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{
+ bool invert;
+ gx_color_index color;
+ gx_device_color devc;
+
+ if (!data)
+ return gs_throw_code(gs_error_unknownerror);
+ fit_copy(dev, data, dx, raster, id, x, y, w, h);
+ if (!data)
+ return gs_throw_code(gs_error_unknownerror);
+ if (one != gx_no_color_index) {
+ invert = false;
+ color = one;
+ if (zero != gx_no_color_index) {
+ int code = (*dev_proc(dev, fill_rectangle))
+ (dev, x, y, w, h, zero);
+
+ if (code < 0)
+ return code;
+ }
+ } else {
+ invert = true;
+ color = zero;
+ }
+ if (!data)
+ return gs_throw_code(gs_error_unknownerror);
+ set_nonclient_dev_color(&devc, color);
+ if (!data)
+ return gs_throw_code(gs_error_unknownerror);
+ return gx_dc_default_fill_masked
+ (&devc, data, dx, raster, id, x, y, w, h, dev, rop3_T, invert);
+}
+
+/* Implement copy_color by filling lots of small rectangles. */
+/* This is very inefficient, but it works as a default. */
+int
+gx_default_copy_color(gx_device * dev, const byte * data,
+ int dx, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ int depth = dev->color_info.depth;
+ byte mask;
+
+ dev_proc_fill_rectangle((*fill));
+ const byte *row;
+ int iy;
+
+ if (depth == 1)
+ return (*dev_proc(dev, copy_mono)) (dev, data, dx, raster, id,
+ x, y, w, h,
+ (gx_color_index) 0, (gx_color_index) 1);
+ fit_copy(dev, data, dx, raster, id, x, y, w, h);
+ fill = dev_proc(dev, fill_rectangle);
+ mask = (byte) ((1 << depth) - 1);
+ for (row = data, iy = 0; iy < h; row += raster, ++iy) {
+ int ix;
+ gx_color_index c0 = gx_no_color_index;
+ const byte *ptr = row + ((dx * depth) >> 3);
+ int i0;
+
+ for (i0 = ix = 0; ix < w; ++ix) {
+ gx_color_index color;
+
+ if (depth >= 8) {
+ color = *ptr++;
+ switch (depth) {
+ case 64:
+ color = (color << 8) + *ptr++;
+ case 56:
+ color = (color << 8) + *ptr++;
+ case 48:
+ color = (color << 8) + *ptr++;
+ case 40:
+ color = (color << 8) + *ptr++;
+ case 32:
+ color = (color << 8) + *ptr++;
+ case 24:
+ color = (color << 8) + *ptr++;
+ case 16:
+ color = (color << 8) + *ptr++;
+ }
+ } else {
+ uint dbit = (-(ix + dx + 1) * depth) & 7;
+
+ color = (*ptr >> dbit) & mask;
+ if (dbit == 0)
+ ptr++;
+ }
+ if (color != c0) {
+ if (ix > i0) {
+ int code = (*fill)
+ (dev, i0 + x, iy + y, ix - i0, 1, c0);
+
+ if (code < 0)
+ return code;
+ }
+ c0 = color;
+ i0 = ix;
+ }
+ }
+ if (ix > i0) {
+ int code = (*fill) (dev, i0 + x, iy + y, ix - i0, 1, c0);
+
+ if (code < 0)
+ return code;
+ }
+ }
+ return 0;
+}
+
+int
+gx_no_copy_alpha(gx_device * dev, const byte * data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color, int depth)
+{
+ return_error(gs_error_unknownerror);
+}
+
+/* Currently we really should only be here if the target device is planar
+ AND it supports devn colors AND is 8 or 16 bit. For example tiffsep
+ and psdcmyk may make use of this if AA is enabled. It is basically
+ designed for devices that need more than 64 bits for color support
+
+ So that I can follow things and make it readable for future generations,
+ I am not using the macro nightmare that default_copy_alpha uses. */
+int
+gx_default_copy_alpha_hl_color(gx_device * dev, const byte * data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ const gx_drawing_color *pdcolor, int depth)
+{
+ const byte *row_alpha;
+ gs_memory_t *mem = dev->memory;
+ int bpp = dev->color_info.depth;
+ uchar ncomps = dev->color_info.num_components;
+ uint out_raster;
+ int code = 0;
+ gx_color_value src_cv[GS_CLIENT_COLOR_MAX_COMPONENTS];
+ gx_color_value curr_cv[GS_CLIENT_COLOR_MAX_COMPONENTS];
+ gx_color_value blend_cv[GS_CLIENT_COLOR_MAX_COMPONENTS];
+ int ry;
+ uchar k, j;
+ gs_get_bits_params_t gb_params;
+ byte *src_planes[GS_CLIENT_COLOR_MAX_COMPONENTS];
+ gs_int_rect gb_rect;
+ int byte_depth;
+ gx_color_index mask;
+ int shift, word_width;
+ gx_color_value *composite;
+ byte *gb_buff;
+ int x_curr, w_curr, gb_buff_start;
+
+ byte_depth = bpp / ncomps;
+ mask = ((gx_color_index)1 << byte_depth) - 1;
+ shift = 16 - byte_depth;
+ word_width = byte_depth >> 3;
+
+ fit_copy(dev, data, data_x, raster, id, x, y, width, height);
+ row_alpha = data;
+ out_raster = bitmap_raster(width * byte_depth);
+ gb_buff = gs_alloc_bytes(mem, out_raster * ncomps, "copy_alpha_hl_color(gb_buff)");
+ if (gb_buff == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ return code;
+ }
+ for (k = 0; k < ncomps; k++) {
+ src_cv[k] = pdcolor->colors.devn.values[k];
+ }
+ /* Initialize the get_bits parameters. Here we just get a plane at a time. */
+ gb_params.options = GB_COLORS_NATIVE
+ | GB_ALPHA_NONE
+ | GB_DEPTH_ALL
+ | GB_PACKING_PLANAR
+ | GB_RETURN_COPY
+ | GB_ALIGN_STANDARD
+ | GB_OFFSET_0
+ | GB_RASTER_STANDARD
+ | GB_SELECT_PLANES;
+ gb_rect.p.x = x;
+ gb_rect.q.x = x + width;
+ for (ry = y; ry < y + height; row_alpha += raster, ++ry) {
+ int sx, rx;
+
+ gb_rect.p.y = ry;
+ gb_rect.q.y = ry+1;
+ for (k = 0; k < ncomps; k++) {
+ /* First set the params to zero for all planes except the one we want */
+ /* I am not sure why get_bits_rectangle for the planar device can
+ not hand back the data in a proper planar form. To get the
+ individual planes seems that I need to jump through some hoops
+ here */
+ for (j = 0; j < ncomps; j++)
+ gb_params.data[j] = 0;
+ gb_params.data[k] = gb_buff + k * out_raster;
+ code = dev_proc(dev, get_bits_rectangle) (dev, &gb_rect,
+ &gb_params, 0);
+ src_planes[k] = gb_params.data[k];
+ if (code < 0) {
+ gs_free_object(mem, gb_buff, "copy_alpha_hl_color");
+ return code;
+ }
+ }
+ /* At this point we have to carry around some additional variables
+ so that we can handle any buffer flushes due to alpha == 0 values.
+ See below why this is needed */
+ x_curr = x;
+ w_curr = 0;
+ gb_buff_start = 0;
+ for (sx = data_x, rx = x; sx < data_x + width; ++sx, ++rx) {
+ int alpha2, alpha;
+
+ w_curr += 1;
+ switch (depth)
+ {
+ case 2:
+ alpha = ((row_alpha[sx >> 2] >> ((3 - (sx & 3)) << 1)) & 3) * 85;
+ break;
+ case 4:
+ alpha2 = row_alpha[sx >> 1];
+ alpha = (sx & 1 ? alpha2 & 0xf : alpha2 >> 4) * 17;
+ break;
+ case 8:
+ alpha = row_alpha[sx];
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+
+ if (alpha == 0) {
+ /* With alpha 0 we want to avoid writing out this value.
+ * While it is true that writting it out leaves the color
+ * unchanged, any device that's watching what pixels are
+ * written (such as the pattern tile devices) may have problems.
+ * As in gx_default_copy_alpha the right thing to do is to write
+ * out what we have so far and then continue to collect when we
+ * get back to non zero alpha. */
+ code = dev_proc(dev, copy_planes)(dev, &(gb_buff[gb_buff_start]),
+ 0, out_raster, gs_no_bitmap_id,
+ x_curr, ry, w_curr-1, 1, 1);
+ if (code < 0) {
+ gs_free_object(mem, gb_buff, "copy_alpha_hl_color");
+ return code;
+ }
+ /* reset ourselves */
+ gb_buff_start = gb_buff_start + w_curr;
+ w_curr = 0;
+ x_curr = rx + 1;
+ } else {
+ if (alpha == 255) {
+ /* Just use the new color. */
+ composite = &(src_cv[0]);
+ } else {
+ /* We need to do the weighting by the alpha value */
+ alpha += (alpha>>7); /* Expand from 0..255->0..256 */
+ /* First get the old color */
+ for (k = 0; k < ncomps; k++) {
+ /* We only have 8 and 16 bit depth to worry about.
+ However, this stuff should really be done with
+ the device encode/decode procedure. */
+ byte *ptr = ((src_planes[k]) + (sx - data_x) * word_width);
+ curr_cv[k] = 0;
+ switch (word_width) {
+ case 2:
+ curr_cv[k] += (*ptr++ << 8);
+ curr_cv[k] += *ptr;
+ break;
+ case 1:
+ curr_cv[k] += *ptr;
+ curr_cv[k] += curr_cv[k] << 8;
+ }
+ /* Now compute the new color which is a blend of
+ the old and the new */
+ blend_cv[k] = ((curr_cv[k]<<8) +
+ (((long) src_cv[k] - (long) curr_cv[k]) * alpha))>>8;
+ composite = &(blend_cv[0]);
+ }
+ }
+ /* Update our plane data buffers. Just reuse the current one */
+ for (k = 0; k < ncomps; k++) {
+ byte *ptr = ((src_planes[k]) + (sx - data_x) * word_width);
+ switch (word_width) {
+ case 2:
+ *ptr++ = composite[k] & mask;
+ case 1:
+ *ptr++ = (composite[k] >> shift) & mask;
+ }
+ }
+ } /* else on alpha != 0 */
+ } /* loop on x */
+ /* Flush what ever we have left. We may only have a partial due to
+ the presence of alpha = 0 values */
+ code = dev_proc(dev, copy_planes)(dev, &(gb_buff[gb_buff_start]),
+ 0, out_raster, gs_no_bitmap_id,
+ x_curr, ry, w_curr, 1, 1);
+ } /* loop on y */
+ gs_free_object(mem, gb_buff, "copy_alpha_hl_color");
+ return code;
+}
+
+int
+gx_default_copy_alpha(gx_device * dev, const byte * data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color, int depth)
+{ /* This might be called with depth = 1.... */
+ if (depth == 1)
+ return (*dev_proc(dev, copy_mono)) (dev, data, data_x, raster, id,
+ x, y, width, height,
+ gx_no_color_index, color);
+ /*
+ * Simulate alpha by weighted averaging of RGB values.
+ * This is very slow, but functionally correct.
+ */
+ {
+ const byte *row;
+ gs_memory_t *mem = dev->memory;
+ int bpp = dev->color_info.depth;
+ uchar ncomps = dev->color_info.num_components;
+ uint in_size = gx_device_raster_chunky(dev, false);
+ byte *lin;
+ uint out_size;
+ byte *lout;
+ int code = 0;
+ gx_color_value color_cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
+ int ry, lx;
+
+ fit_copy(dev, data, data_x, raster, id, x, y, width, height);
+ row = data;
+ out_size = bitmap_raster(width * bpp);
+ lin = gs_alloc_bytes(mem, in_size, "copy_alpha(lin)");
+ lout = gs_alloc_bytes(mem, out_size, "copy_alpha(lout)");
+ if (lin == 0 || lout == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ (*dev_proc(dev, decode_color)) (dev, color, color_cv);
+ for (ry = y; ry < y + height; row += raster, ++ry) {
+ byte *line;
+ int sx, rx;
+
+ byte *l_dptr = lout;
+ int l_dbit = 0;
+ byte l_dbyte = ((l_dbit) ? (byte)(*(l_dptr) & (0xff00 >> (l_dbit))) : 0);
+ int l_xprev = x;
+
+ code = (*dev_proc(dev, get_bits)) (dev, ry, lin, &line);
+ if (code < 0)
+ break;
+ lx = x;
+ for (sx = data_x, rx = x; sx < data_x + width; ++sx, ++rx) {
+ gx_color_index previous = gx_no_color_index;
+ gx_color_index composite;
+ int alpha2, alpha;
+
+ switch(depth)
+ {
+ case 2:
+ /* map 0 - 3 to 0 - 15 */
+ alpha = ((row[sx >> 2] >> ((3 - (sx & 3)) << 1)) & 3) * 85;
+ break;
+ case 4:
+ alpha2 = row[sx >> 1],
+ alpha = (sx & 1 ? alpha2 & 0xf : alpha2 >> 4) * 17;
+ break;
+ case 8:
+ alpha = row[sx];
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ blend:
+ if (alpha == 0) {
+ /* Previously the code used to just write out the previous
+ * colour when the alpha was 0, but that's wrong. It leaves
+ * the underlying colour unchanged, but has the effect of
+ * making this pixel appear solid in any device that's
+ * watching what pixels are written (such as the pattern
+ * tile devices). The right thing to do is to write out
+ * the buffered accumulator, and skip over any pixels that
+ * are completely clear. */
+ if (rx > l_xprev ) {
+ sample_store_flush(l_dptr, l_dbit, l_dbyte);
+ code = (*dev_proc(dev, copy_color))
+ (dev, lout, l_xprev - (lx), out_size,
+ gx_no_bitmap_id, l_xprev, ry, (rx) - l_xprev, 1);
+ if ( code < 0 )
+ return code;
+ }
+ l_dptr = lout;
+ l_dbit = 0;
+ l_dbyte = (l_dbit ? (byte)(*l_dptr & (0xff00 >> l_dbit)) : 0);
+ l_xprev = rx+1;
+ lx = rx+1;
+ } else {
+ if (alpha == 255) { /* Just write the new color. */
+ composite = color;
+ } else {
+ gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
+ uchar i;
+ int alpha2 = alpha + (alpha>>7);
+
+ if (previous == gx_no_color_index) { /* Extract the old color. */
+ if (bpp < 8) {
+ const uint bit = rx * bpp;
+ const byte *src = line + (bit >> 3);
+
+ previous =
+ (*src >> (8 - ((bit & 7) + bpp))) &
+ ((1 << bpp) - 1);
+ } else {
+ const byte *src = line + (rx * (bpp >> 3));
+
+ previous = 0;
+ switch (bpp >> 3) {
+ case 8:
+ previous += (gx_color_index) * src++
+ << SAMPLE_BOUND_SHIFT(previous, 56);
+ case 7:
+ previous += (gx_color_index) * src++
+ << SAMPLE_BOUND_SHIFT(previous, 48);
+ case 6:
+ previous += (gx_color_index) * src++
+ << SAMPLE_BOUND_SHIFT(previous, 40);
+ case 5:
+ previous += (gx_color_index) * src++
+ << SAMPLE_BOUND_SHIFT(previous, 32);
+ case 4:
+ previous += (gx_color_index) * src++ << 24;
+ case 3:
+ previous += (gx_color_index) * src++ << 16;
+ case 2:
+ previous += (gx_color_index) * src++ << 8;
+ case 1:
+ previous += *src++;
+ }
+ }
+ }
+ (*dev_proc(dev, decode_color)) (dev, previous, cv);
+#if ARCH_INTS_ARE_SHORT
+# define b_int long
+#else
+# define b_int int
+#endif
+#define make_shade(old, clr, alpha) \
+ (((((b_int)(old))<<8) + (((b_int)(clr) - (b_int)(old)) * (alpha)))>>8)
+ for (i=0; i<ncomps; i++)
+ cv[i] = make_shade(cv[i], color_cv[i], alpha2);
+#undef b_int
+#undef make_shade
+ composite =
+ (*dev_proc(dev, encode_color)) (dev, cv);
+ if (composite == gx_no_color_index) { /* The device can't represent this color. */
+ /* Move the alpha value towards 0 or 1. */
+ if (alpha == 127) /* move 1/2 towards 1 */
+ ++alpha;
+ alpha = (alpha & 128) | (alpha >> 1);
+ goto blend;
+ }
+ }
+ if (sizeof(composite) > 4) {
+ if (sample_store_next64(composite, &l_dptr, &l_dbit, bpp, &l_dbyte) < 0)
+ return_error(gs_error_rangecheck);
+ }
+ else {
+ if (sample_store_next32(composite, &l_dptr, &l_dbit, bpp, &l_dbyte) < 0)
+ return_error(gs_error_rangecheck);
+ }
+ }
+ }
+ if ( rx > l_xprev ) {
+ sample_store_flush(l_dptr, l_dbit, l_dbyte);
+ code = (*dev_proc(dev, copy_color))
+ (dev, lout, l_xprev - lx, out_size,
+ gx_no_bitmap_id, l_xprev, ry, rx - l_xprev, 1);
+ if (code < 0)
+ return code;
+ }
+ }
+ out:gs_free_object(mem, lout, "copy_alpha(lout)");
+ gs_free_object(mem, lin, "copy_alpha(lin)");
+ return code;
+ }
+}
+
+int
+gx_no_copy_rop(gx_device * dev,
+ const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index * scolors,
+ const gx_tile_bitmap * texture, 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_error(gs_error_unknownerror); /* not implemented */
+}
+
+int
+gx_default_fill_mask(gx_device * orig_dev,
+ const byte * data, int dx, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ const gx_drawing_color * pdcolor, int depth,
+ gs_logical_operation_t lop, const gx_clip_path * pcpath)
+{
+ gx_device *dev = orig_dev;
+ gx_device_clip cdev;
+
+ if (w == 0 || h == 0)
+ return 0;
+
+ if (pcpath != 0)
+ {
+ gs_fixed_rect rect;
+ int tmp;
+
+ rect.p.x = int2fixed(x);
+ rect.p.y = int2fixed(y);
+ rect.q.x = int2fixed(x+w);
+ rect.q.y = int2fixed(y+h);
+ dev = gx_make_clip_device_on_stack_if_needed(&cdev, pcpath, dev, &rect);
+ if (dev == NULL)
+ return 0;
+ /* Clip region if possible */
+ tmp = fixed2int(rect.p.x);
+ if (tmp > x)
+ {
+ dx += tmp-x;
+ x = tmp;
+ }
+ tmp = fixed2int(rect.q.x);
+ if (tmp < x+w)
+ w = tmp-x;
+ tmp = fixed2int(rect.p.y);
+ if (tmp > y)
+ {
+ data += (tmp-y) * raster;
+ y = tmp;
+ }
+ tmp = fixed2int(rect.q.y);
+ if (tmp < y+h)
+ h = tmp-y;
+ }
+ if (depth > 1) {
+ /****** CAN'T DO ROP OR HALFTONE WITH ALPHA ******/
+ return (*dev_proc(dev, copy_alpha))
+ (dev, data, dx, raster, id, x, y, w, h,
+ gx_dc_pure_color(pdcolor), depth);
+ } else
+ return pdcolor->type->fill_masked(pdcolor, data, dx, raster, id,
+ x, y, w, h, dev, lop, false);
+}
+
+/* Default implementation of strip_tile_rect_devn. With the current design
+ only devices that support devn color will be making use of this
+ procedure and those are planar devices. So we have an implemenation
+ for planar devices and not a default implemenetation at this time. */
+int
+gx_default_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)
+{
+ return_error(gs_error_unregistered);
+}
+
+/* Default implementation of strip_tile_rectangle */
+int
+gx_default_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)
+{ /* Fill the rectangle in chunks. */
+ int width = tiles->size.x;
+ int height = tiles->size.y;
+ int raster = tiles->raster;
+ int rwidth = tiles->rep_width;
+ int rheight = tiles->rep_height;
+ int shift = tiles->shift;
+ gs_id tile_id = tiles->id;
+
+ if (rwidth == 0 || rheight == 0)
+ return_error(gs_error_unregistered); /* Must not happen. */
+ fit_fill_xy(dev, x, y, w, h);
+
+#ifdef DEBUG
+ if (gs_debug_c('t')) {
+ int ptx, pty;
+ const byte *ptp = tiles->data;
+
+ dmlprintf4(dev->memory, "[t]tile %dx%d raster=%d id=%lu;",
+ tiles->size.x, tiles->size.y, tiles->raster, tiles->id);
+ dmlprintf6(dev->memory, " x,y=%d,%d w,h=%d,%d p=%d,%d\n",
+ x, y, w, h, px, py);
+ dmlputs(dev->memory, "");
+ for (pty = 0; pty < tiles->size.y; pty++) {
+ dmprintf(dev->memory, " ");
+ for (ptx = 0; ptx < tiles->raster; ptx++)
+ dmprintf1(dev->memory, "%3x", *ptp++);
+ }
+ dmputc(dev->memory, '\n');
+ }
+#endif
+
+ if (dev_proc(dev, tile_rectangle) != gx_default_tile_rectangle) {
+ if (shift == 0) { /*
+ * Temporarily patch the tile_rectangle procedure in the
+ * device so we don't get into a recursion loop if the
+ * device has a tile_rectangle procedure that conditionally
+ * calls the strip_tile_rectangle procedure.
+ */
+ dev_proc_tile_rectangle((*tile_proc)) =
+ dev_proc(dev, tile_rectangle);
+ int code = 0;
+
+ set_dev_proc(dev, tile_rectangle, gx_default_tile_rectangle);
+ code = (*tile_proc)
+ (dev, (const gx_tile_bitmap *)tiles, x, y, w, h,
+ color0, color1, px, py);
+ set_dev_proc(dev, tile_rectangle, tile_proc);
+ return code;
+ }
+ /* We should probably optimize this case too, for the benefit */
+ /* of window systems, but we don't yet. */
+ } { /*
+ * Note: we can't do the following computations until after
+ * the fit_fill_xy.
+ */
+ int xoff =
+ (shift == 0 ? px :
+ px + (y + py) / rheight * tiles->rep_shift);
+ int irx = ((rwidth & (rwidth - 1)) == 0 ? /* power of 2 */
+ (x + xoff) & (rwidth - 1) :
+ (x + xoff) % rwidth);
+ int ry = ((rheight & (rheight - 1)) == 0 ? /* power of 2 */
+ (y + py) & (rheight - 1) :
+ (y + py) % rheight);
+ int icw = width - irx;
+ int ch = height - ry;
+ byte *row = tiles->data + ry * raster;
+
+ dev_proc_copy_mono((*proc_mono));
+ dev_proc_copy_color((*proc_color));
+ dev_proc_copy_planes((*proc_planes));
+ int code = 0;
+
+ if (color0 == gx_no_color_index && color1 == gx_no_color_index) {
+ if (tiles->num_planes > 1) {
+ proc_mono = 0;
+ proc_color = 0;
+ proc_planes = dev_proc(dev, copy_planes);
+ } else {
+ proc_planes = 0;
+ proc_color = dev_proc(dev, copy_color);
+ proc_mono = 0;
+ }
+ } else {
+ proc_planes = 0;
+ proc_color = 0;
+ proc_mono = dev_proc(dev, copy_mono);
+ }
+
+#define GX_DEFAULT_COPY_TILE(dev, srcx, tx, ty, tw, th, tid) do {\
+ if_debug6m('t', (dev)->memory, " copy id=%lu sx=%d => x=%d y=%d w=%d h=%d\n", tid, srcx, tx, ty, tw, th);\
+ if (tiles->num_planes > 1) {\
+ if (proc_planes)\
+ code = (*proc_planes)(dev, row, srcx, raster, tid, tx, ty, tw, th, height);\
+ } else {\
+ if (proc_color != 0) {\
+ code = (*proc_color)(dev, row, srcx, raster, tid, tx, ty, tw, th);\
+ } else {\
+ if (proc_mono)\
+ code = (*proc_mono)(dev, row, srcx, raster, tid, tx, ty, tw, th, color0, color1);\
+ else code = 0;\
+ }\
+ }\
+ if (code < 0) return_error(code);\
+ } while (0);
+
+
+ if (ch >= h) { /* Shallow operation */
+ if (icw >= w) { /* Just one (partial) tile to transfer. */
+ GX_DEFAULT_COPY_TILE(dev, irx, x, y, w, h, (w == width && h == height ? tile_id : gs_no_bitmap_id));
+ } else {
+ int ex = x + w;
+ int fex = ex - width;
+ int cx = x + icw;
+ ulong id = (h == height ? tile_id : gs_no_bitmap_id);
+
+ GX_DEFAULT_COPY_TILE(dev, irx, x, y, icw, h, gs_no_bitmap_id);
+ while (cx <= fex) {
+ GX_DEFAULT_COPY_TILE(dev, 0, cx, y, width, h, id);
+ cx += width;
+ }
+ if (cx < ex) {
+ GX_DEFAULT_COPY_TILE(dev, 0, cx, y, ex - cx, h, gs_no_bitmap_id);
+ }
+ }
+ } else if (icw >= w && shift == 0) {
+ /* Narrow operation, no shift */
+ int ey = y + h;
+ int fey = ey - height;
+ int cy = y + ch;
+ ulong id = (w == width ? tile_id : gs_no_bitmap_id);
+
+ GX_DEFAULT_COPY_TILE(dev, irx, x, y, w, ch, (ch == height ? id : gs_no_bitmap_id));
+ row = tiles->data;
+ do {
+ ch = (cy > fey ? ey - cy : height);
+ GX_DEFAULT_COPY_TILE(dev, irx, x, cy, w, ch,
+ (ch == height ? id : gs_no_bitmap_id));
+ }
+ while ((cy += ch) < ey);
+ } else {
+ /* Full operation. If shift != 0, some scan lines */
+ /* may be narrow. We could test shift == 0 in advance */
+ /* and use a slightly faster loop, but right now */
+ /* we don't bother. */
+ int ex = x + w, ey = y + h;
+ int fex = ex - width, fey = ey - height;
+ int cx, cy;
+
+ for (cy = y;;) {
+ ulong id = (ch == height ? tile_id : gs_no_bitmap_id);
+
+ if (icw >= w) {
+ GX_DEFAULT_COPY_TILE(dev, irx, x, cy, w, ch,
+ (w == width ? id : gs_no_bitmap_id));
+ } else {
+ GX_DEFAULT_COPY_TILE(dev, irx, x, cy, icw, ch, gs_no_bitmap_id);
+ cx = x + icw;
+ while (cx <= fex) {
+ GX_DEFAULT_COPY_TILE(dev, 0, cx, cy, width, ch, id);
+ cx += width;
+ }
+ if (cx < ex) {
+ GX_DEFAULT_COPY_TILE(dev, 0, cx, cy, ex - cx, ch, gs_no_bitmap_id);
+ }
+ }
+ if ((cy += ch) >= ey)
+ break;
+ ch = (cy > fey ? ey - cy : height);
+ if ((irx += shift) >= rwidth)
+ irx -= rwidth;
+ icw = width - irx;
+ row = tiles->data;
+ }
+ }
+#undef GX_DEFAULT_COPY_TILE
+ }
+ return 0;
+}
+
+int
+gx_no_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_error(gs_error_unknownerror); /* not implemented */
+}
+
+/* ---------------- Unaligned copy operations ---------------- */
+
+/*
+ * Implementing unaligned operations in terms of the standard aligned
+ * operations requires adjusting the bitmap origin and/or the raster to be
+ * aligned. Adjusting the origin is simple; adjusting the raster requires
+ * doing the operation one scan line at a time.
+ */
+int
+gx_copy_mono_unaligned(gx_device * dev, const byte * data,
+ int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_color_index zero, gx_color_index one)
+{
+ dev_proc_copy_mono((*copy_mono)) = dev_proc(dev, copy_mono);
+ uint offset = ALIGNMENT_MOD(data, align_bitmap_mod);
+ int step = raster & (align_bitmap_mod - 1);
+
+ /* Adjust the origin. */
+ data -= offset;
+ dx += offset << 3;
+
+ /* Adjust the raster. */
+ if (!step) { /* No adjustment needed. */
+ return (*copy_mono) (dev, data, dx, raster, id,
+ x, y, w, h, zero, one);
+ }
+ /* Do the transfer one scan line at a time. */
+ {
+ const byte *p = data;
+ int d = dx;
+ int code = 0;
+ int i;
+
+ for (i = 0; i < h && code >= 0;
+ ++i, p += raster - step, d += step << 3
+ )
+ code = (*copy_mono) (dev, p, d, raster, gx_no_bitmap_id,
+ x, y + i, w, 1, zero, one);
+ return code;
+ }
+}
+
+int
+gx_copy_color_unaligned(gx_device * dev, const byte * data,
+ int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int width, int height)
+{
+ dev_proc_copy_color((*copy_color)) = dev_proc(dev, copy_color);
+ int depth = dev->color_info.depth;
+ uint offset = (uint) (data - (const byte *)0) & (align_bitmap_mod - 1);
+ int step = raster & (align_bitmap_mod - 1);
+
+ /*
+ * Adjust the origin.
+ * We have to do something very special for 24-bit data,
+ * because that is the only depth that doesn't divide
+ * align_bitmap_mod exactly. In particular, we need to find
+ * M*B + R == 0 mod 3, where M is align_bitmap_mod, R is the
+ * offset value just calculated, and B is an integer unknown;
+ * the new value of offset will be M*B + R.
+ */
+ if (depth == 24)
+ offset += (offset % 3) *
+ (align_bitmap_mod * (3 - (align_bitmap_mod % 3)));
+ data -= offset;
+ data_x += (offset << 3) / depth;
+
+ /* Adjust the raster. */
+ if (!step) { /* No adjustment needed. */
+ return (*copy_color) (dev, data, data_x, raster, id,
+ x, y, width, height);
+ }
+ /* Do the transfer one scan line at a time. */
+ {
+ const byte *p = data;
+ int d = data_x;
+ int dstep = (step << 3) / depth;
+ int code = 0;
+ int i;
+
+ for (i = 0; i < height && code >= 0;
+ ++i, p += raster - step, d += dstep
+ )
+ code = (*copy_color) (dev, p, d, raster, gx_no_bitmap_id,
+ x, y + i, width, 1);
+ return code;
+ }
+}
+
+int
+gx_copy_alpha_unaligned(gx_device * dev, const byte * data, int data_x,
+ int raster, gx_bitmap_id id, int x, int y, int width, int height,
+ gx_color_index color, int depth)
+{
+ dev_proc_copy_alpha((*copy_alpha)) = dev_proc(dev, copy_alpha);
+ uint offset = (uint) (data - (const byte *)0) & (align_bitmap_mod - 1);
+ int step = raster & (align_bitmap_mod - 1);
+
+ /* Adjust the origin. */
+ data -= offset;
+ data_x += (offset << 3) / depth;
+
+ /* Adjust the raster. */
+ if (!step) { /* No adjustment needed. */
+ return (*copy_alpha) (dev, data, data_x, raster, id,
+ x, y, width, height, color, depth);
+ }
+ /* Do the transfer one scan line at a time. */
+ {
+ const byte *p = data;
+ int d = data_x;
+ int dstep = (step << 3) / depth;
+ int code = 0;
+ int i;
+
+ for (i = 0; i < height && code >= 0;
+ ++i, p += raster - step, d += dstep
+ )
+ code = (*copy_alpha) (dev, p, d, raster, gx_no_bitmap_id,
+ x, y + i, width, 1, color, depth);
+ return code;
+ }
+}