diff options
Diffstat (limited to 'base/gdevm4.c')
-rw-r--r-- | base/gdevm4.c | 306 |
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 */ |