summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'base/gdevm4.c')
-rw-r--r--base/gdevm4.c306
1 files changed, 306 insertions, 0 deletions
diff --git a/base/gdevm4.c b/base/gdevm4.c
new file mode 100644
index 00000000..646f352f
--- /dev/null
+++ b/base/gdevm4.c
@@ -0,0 +1,306 @@
+/* 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.
+*/
+
+/* 4-bit-per-pixel "memory" (stored bitmap) device */
+#include "memory_.h"
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* semi-public definitions */
+#include "gdevmem.h" /* private definitions */
+
+/* ================ Standard (byte-oriented) device ================ */
+
+#undef chunk
+#define chunk byte
+#define fpat(byt) mono_fill_make_pattern(byt)
+
+/* Procedures */
+declare_mem_procs(mem_mapped4_copy_mono, mem_mapped4_copy_color, mem_mapped4_fill_rectangle);
+
+/* The device descriptor. */
+const gx_device_memory mem_mapped4_device =
+mem_device("image4", 3, 1,
+ mem_mapped_map_rgb_color, mem_mapped_map_color_rgb,
+ mem_mapped4_copy_mono, mem_mapped4_copy_color, mem_mapped4_fill_rectangle,
+ mem_gray_strip_copy_rop);
+
+/* Convert x coordinate to byte offset in scan line. */
+#undef x_to_byte
+#define x_to_byte(x) ((x) >> 1)
+
+/* Define the 4-bit fill patterns. */
+static const mono_fill_chunk tile_patterns[16] =
+{fpat(0x00), fpat(0x11), fpat(0x22), fpat(0x33),
+ fpat(0x44), fpat(0x55), fpat(0x66), fpat(0x77),
+ fpat(0x88), fpat(0x99), fpat(0xaa), fpat(0xbb),
+ fpat(0xcc), fpat(0xdd), fpat(0xee), fpat(0xff)
+};
+
+/* Fill a rectangle with a color. */
+static int
+mem_mapped4_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;
+
+ fit_fill(dev, x, y, w, h);
+ bits_fill_rectangle(scan_line_base(mdev, y), x << 2, mdev->raster,
+ tile_patterns[color], w << 2, h);
+ return 0;
+}
+
+/* Copy a bitmap. */
+static int
+mem_mapped4_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 zero, gx_color_index one)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ const byte *line;
+ declare_scan_ptr(dest);
+ byte invert, bb;
+
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ setup_rect(dest);
+ line = base + (sourcex >> 3);
+ /* Divide into opaque and masked cases. */
+ if (one == gx_no_color_index) {
+ if (zero == gx_no_color_index)
+ return 0; /* nothing to do */
+ invert = 0xff;
+ bb = ((byte) zero << 4) | (byte) zero;
+ } else if (zero == gx_no_color_index) {
+ invert = 0;
+ bb = ((byte) one << 4) | (byte) one;
+ } else {
+ /* Opaque case. */
+ int shift = ~(sourcex ^ x) & 1;
+ byte oz[4];
+
+ oz[0] = (byte)((zero << 4) | zero);
+ oz[1] = (byte)((zero << 4) | one);
+ oz[2] = (byte)((one << 4) | zero);
+ oz[3] = (byte)((one << 4) | one);
+ do {
+ register byte *dptr = (byte *) dest;
+ const byte *sptr = line;
+ register uint sbyte = *sptr++;
+ register int sbit = ~sourcex & 7;
+ int count = w;
+
+ /*
+ * If the first source bit corresponds to an odd X in the
+ * destination, process it now.
+ */
+ if (x & 1) {
+ *dptr = (*dptr & 0xf0) |
+ ((sbyte >> sbit) & 1 ? one : zero);
+ --count; /* may now be 0 */
+ if (--sbit < 0)
+ sbit = 7, sbyte = *sptr++;
+ ++dptr;
+ }
+ /*
+ * Now we know the next destination X is even. We want to
+ * process 2 source bits at a time from now on, so set things up
+ * properly depending on whether the next source X (bit) is even
+ * or odd. In both even and odd cases, the active source bits
+ * are in bits 8..1 of sbyte.
+ */
+ sbyte <<= shift;
+ sbit += shift - 1;
+ /*
+ * Now bit # sbit+1 is the most significant unprocessed bit
+ * in sbyte. -1 <= sbit <= 7; sbit is odd.
+ * Note that if sbit = -1, all of sbyte has been processed.
+ *
+ * Continue processing pairs of bits in the first source byte.
+ */
+ while (count >= 2 && sbit >= 0) {
+ *dptr++ = oz[(sbyte >> sbit) & 3];
+ sbit -= 2, count -= 2;
+ }
+ /*
+ * Now sbit = -1 iff we have processed the entire first source
+ * byte.
+ *
+ * Process full source bytes.
+ */
+ if (shift) {
+ sbyte >>= 1; /* in case count < 8 */
+ for (; count >= 8; dptr += 4, count -= 8) {
+ sbyte = *sptr++;
+ dptr[0] = oz[sbyte >> 6];
+ dptr[1] = oz[(sbyte >> 4) & 3];
+ dptr[2] = oz[(sbyte >> 2) & 3];
+ dptr[3] = oz[sbyte & 3];
+ }
+ sbyte <<= 1;
+ } else {
+ for (; count >= 8; dptr += 4, count -= 8) {
+ sbyte = (sbyte << 8) | *sptr++;
+ dptr[0] = oz[(sbyte >> 7) & 3];
+ dptr[1] = oz[(sbyte >> 5) & 3];
+ dptr[2] = oz[(sbyte >> 3) & 3];
+ dptr[3] = oz[(sbyte >> 1) & 3];
+ }
+ }
+ if (!count)
+ continue;
+ /*
+ * Process pairs of bits in the final source byte. Note that
+ * if sbit > 0, this is still the first source byte (the
+ * full-byte loop wasn't executed).
+ */
+ if (sbit < 0) {
+ sbyte = (sbyte << 8) | (*sptr << shift);
+ sbit = 7;
+ }
+ while (count >= 2) {
+ *dptr++ = oz[(sbyte >> sbit) & 3];
+ sbit -= 2, count -= 2;
+ }
+ /*
+ * If the final source bit corresponds to an even X value,
+ * process it now.
+ */
+ if (count) {
+ *dptr = (*dptr & 0x0f) |
+ (((sbyte >> sbit) & 2 ? one : zero) << 4);
+ }
+ } while ((line += sraster, inc_ptr(dest, draster), --h) > 0);
+ return 0;
+ }
+ /* Masked case. */
+ do {
+ register byte *dptr = (byte *) dest;
+ const byte *sptr = line;
+ register int sbyte = *sptr++ ^ invert;
+ register int sbit = 0x80 >> (sourcex & 7);
+ register byte mask = (x & 1 ? 0x0f : 0xf0);
+ int count = w;
+
+ do {
+ if (sbyte & sbit)
+ *dptr = (*dptr & ~mask) | (bb & mask);
+ if ((sbit >>= 1) == 0)
+ sbit = 0x80, sbyte = *sptr++ ^ invert;
+ dptr += (mask = ~mask) >> 7;
+ } while (--count > 0);
+ line += sraster;
+ inc_ptr(dest, draster);
+ } while (--h > 0);
+ return 0;
+}
+
+/* Copy a color bitmap. */
+static int
+mem_mapped4_copy_color(gx_device * dev,
+ const byte * base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ /* Use monobit copy_mono. */
+ int code;
+
+ /* Patch the width in the device temporarily. */
+ dev->width <<= 2;
+ code = (*dev_proc(&mem_mono_device, copy_mono))
+ (dev, base, sourcex << 2, sraster, id,
+ x << 2, y, w << 2, h, (gx_color_index) 0, (gx_color_index) 1);
+ /* Restore the correct width. */
+ dev->width >>= 2;
+ return code;
+}
+
+/* ================ "Word"-oriented device ================ */
+
+/* Note that on a big-endian machine, this is the same as the */
+/* standard byte-oriented-device. */
+
+#if !ARCH_IS_BIG_ENDIAN
+
+/* Procedures */
+declare_mem_procs(mem4_word_copy_mono, mem4_word_copy_color, mem4_word_fill_rectangle);
+
+/* Here is the device descriptor. */
+const gx_device_memory mem_mapped4_word_device =
+mem_full_device("image4w", 4, 0, mem_open,
+ mem_mapped_map_rgb_color, mem_mapped_map_color_rgb,
+ mem4_word_copy_mono, mem4_word_copy_color, mem4_word_fill_rectangle,
+ gx_default_map_cmyk_color, gx_default_strip_tile_rectangle,
+ gx_no_strip_copy_rop, mem_word_get_bits_rectangle);
+
+/* Fill a rectangle with a color. */
+static int
+mem4_word_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;
+ byte *base;
+ uint raster;
+
+ fit_fill(dev, x, y, w, h);
+ base = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ mem_swap_byte_rect(base, raster, x << 2, w << 2, h, true);
+ bits_fill_rectangle(base, x << 2, raster,
+ tile_patterns[color], w << 2, h);
+ mem_swap_byte_rect(base, raster, x << 2, w << 2, h, true);
+ return 0;
+}
+
+/* Copy a bitmap. */
+static int
+mem4_word_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 zero, gx_color_index one)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ byte *row;
+ uint raster;
+ bool store;
+
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ row = scan_line_base(mdev, y);
+ raster = mdev->raster;
+ store = (zero != gx_no_color_index && one != gx_no_color_index);
+ mem_swap_byte_rect(row, raster, x << 2, w << 2, h, store);
+ mem_mapped4_copy_mono(dev, base, sourcex, sraster, id,
+ x, y, w, h, zero, one);
+ mem_swap_byte_rect(row, raster, x << 2, w << 2, h, false);
+ return 0;
+}
+
+/* Copy a color bitmap. */
+static int
+mem4_word_copy_color(gx_device * dev,
+ const byte * base, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ int code;
+
+ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
+ /* Use monobit copy_mono. */
+ /* Patch the width in the device temporarily. */
+ dev->width <<= 2;
+ code = (*dev_proc(&mem_mono_word_device, copy_mono))
+ (dev, base, sourcex << 2, sraster, id,
+ x << 2, y, w << 2, h, (gx_color_index) 0, (gx_color_index) 1);
+ /* Restore the correct width. */
+ dev->width >>= 2;
+ return code;
+}
+
+#endif /* !ARCH_IS_BIG_ENDIAN */