home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1989, 1990, 1991 Aladdin Enterprises. All rights reserved.
- Distributed by Free Software Foundation, Inc.
-
- This file is part of Ghostscript.
-
- Ghostscript is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
- to anyone for the consequences of using it or for whether it serves any
- particular purpose or works at all, unless he says so in writing. Refer
- to the Ghostscript General Public License for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- Ghostscript, but only under the conditions described in the Ghostscript
- General Public License. A copy of this license is supposed to have been
- given to you along with Ghostscript so you can know your rights and
- responsibilities. It should be in a file named COPYING. Among other
- things, the copyright notice and this notice must be preserved on all
- copies. */
-
- /* gdevmem.c */
- /* "Memory" (stored bitmap) device for Ghostscript library. */
- #include "memory_.h"
- #include "gs.h"
- #include "arch.h"
- #include "gxbitmap.h"
- #include "gsmatrix.h" /* for gxdevice.h */
- #include "gxdevice.h"
- #include "gxdevmem.h"
-
- /*
- The obvious representation for a "memory" device is simply a
- contiguous bitmap stored in something like the PostScript
- representation, i.e., each scan line (in left-to-right order), padded
- to a byte or word boundary, followed immediately by the next one.
- Unfortunately, we can't use this representation, for two reasons:
-
- - On PCs with segmented architectures, there is no way to
- obtain a contiguous block of storage larger than 64K bytes,
- which isn't big enough for a full-screen bitmap, even in
- monochrome.
-
- - The representation of strings in the Ghostscript
- interpreter limits the size of a string to 64K-1 bytes,
- which means we can't simply use a string for the contents
- of a memory device.
-
- We get around the former problem by representing a memory device
- as an array of strings: each string holds one scan line.
- We get around the latter problem by making the client read out the
- contents of a memory device bitmap in pieces.
- */
-
- /* ------ Generic macros ------ */
-
- /* Macro for declaring the essential device procedures. */
- #define declare_mem_map_procs(map_rgb_color, map_color_rgb)\
- private dev_proc_map_rgb_color(map_rgb_color);\
- private dev_proc_map_color_rgb(map_color_rgb)
- #define declare_mem_procs(copy_mono, copy_color, fill_rectangle)\
- private dev_proc_copy_mono(copy_mono);\
- private dev_proc_copy_color(copy_color);\
- private dev_proc_fill_rectangle(fill_rectangle)
-
- /* Macro for generating the procedure record in the device descriptor */
- #define mem_procs(map_rgb_color, map_color_rgb, copy_mono, copy_color, fill_rectangle)\
- { mem_open,\
- mem_get_initial_matrix,\
- gx_default_sync_output,\
- gx_default_output_page,\
- gx_default_close_device,\
- map_rgb_color, /* differs */\
- map_color_rgb, /* differs */\
- fill_rectangle, /* differs */\
- gx_default_tile_rectangle,\
- copy_mono, /* differs */\
- copy_color, /* differs */\
- gx_default_draw_line,\
- gx_default_fill_trapezoid,\
- gx_default_tile_trapezoid\
- }
-
- /* Macro for generating the device descriptor. */
- /* The "& 15" in max_value is bogus, to keep certain compilers */
- /* from complaining about a left shift by 32. */
- #define max_value(depth) (depth > 8 ? 255 : (1 << (depth & 15)) - 1)
- #define mem_device(name, depth, procs)\
- { sizeof(gx_device_memory),\
- &procs, /* differs */\
- name, /* differs */\
- 0, 0, /* x and y extent (filled in) */\
- 1, 1, /* density (irrelevant) */\
- no_margins, /* margins */\
- (depth > 1), /* has_color */\
- max_value(depth), /* max_rgb */\
- depth, /* depth differs */\
- 0, /* not open yet */\
- identity_matrix_body, /* initial matrix (filled in) */\
- 0, /* raster (filled in) */\
- (byte *)0, /* base (filled in) */\
- (byte **)0, /* line_ptrs (filled in by 'open') */\
- 0, /* initial bytes_le (filled in by 'open') */\
- 0, /* invert (filled in for mono) */\
- 0, (byte *)0 /* palette (filled in for color) */\
- }
-
- /* Macro for casting gx_device argument */
- #define mdev ((gx_device_memory *)dev)
-
- /* Macro for rectangle arguments (x,y,w,h) */
- #define check_rect()\
- if ( w <= 0 || h <= 0 ) return 0;\
- if ( x < 0 || x > mdev->width - w || y < 0 || y > mdev->height - h )\
- return -1
-
- /*
- * Macros for processing bitmaps in the largest possible chunks.
- * Bits within a byte are always stored big-endian;
- * bytes are normally stored in the natural order for the platform,
- * but the client can force them into big-endian order (which is required
- * for the source of copy_mono) by calling gdev_mem_ensure_byte_order.
- * (gdev_mem_copy_scan_lines swaps bytes if necessary.)
- * Note that we use type uint for register variables holding a chunk:
- * for this reason, the chunk size cannot be larger than uint.
- */
- /******
- ****** Note: we assume that ints are 2 or 4 bytes in size!
- ****** (This is required by the clog2_bits macro.)
- ******/
- /* Generic macros for chunk accessing. */
- #define cbytes(ct) ((int)sizeof(ct)) /* sizeof may be unsigned */
- # define chunk_bytes cbytes(chunk)
- #define clog2_bytes(ct) ((int)sizeof(ct)>>1) /* works for 1,2,4! */
- # define chunk_log2_bytes clog2_bytes(chunk)
- #define cbits(ct) ((int)sizeof(ct)*8) /* sizeof may be unsigned */
- # define chunk_bits cbits(chunk)
- #define clog2_bits(ct) (clog2_bytes(ct)+3)
- # define chunk_log2_bits clog2_bits(chunk)
- #define cbit_mask(ct) (cbits(ct)-1)
- # define chunk_bit_mask cbit_mask(chunk)
- #define chi_bit(ct) ((ct)1<<(cbits(ct)-1))
- # define chunk_hi_bit chi_bit(chunk)
- #define cmask(ct) ((ct)~0)
- # define chunk_all_bits cmask(chunk)
- #define chi_bits(ct,n) (cmask(ct)-(cmask(ct)>>(n)))
- # define chunk_hi_bits(n) chi_bits(chunk,n)
-
- /* Macros for scan line access. */
- /* x_to_byte is different for each number of bits per pixel. */
- /* Note that these macros depend on the definition of chunk: */
- /* each procedure that uses the scanning macros should #define */
- /* (not typedef) chunk as either uint or byte. */
- #define declare_scan_line(line,ptr)\
- byte **line; register chunk *ptr
- #define declare_scan_ptr(line,ptr,offset)\
- byte **line; chunk *ptr; int offset
- #define setup_scan_ptr(line,ptr,offset)\
- ptr = (chunk *)((*line) + (offset))
- #define setup_scan(line,ptr,offset)\
- line = mdev->line_ptrs + (y);\
- setup_scan_ptr(line,ptr,offset)
- #define next_scan_line(line,ptr,offset)\
- ++line; setup_scan_ptr(line,ptr,offset)
- #define setup_rect(line,ptr,offset)\
- offset = x_to_byte(x) & -chunk_bytes;\
- setup_scan(line,ptr,offset)
-
- /* ------ Generic code ------ */
-
- /* Compute the size of the bitmap storage, */
- /* including the space for the scan line index. */
- /* Note that scan lines are padded to a multiple of 4 bytes. */
- ulong
- gdev_mem_bitmap_size(gx_device_memory *dev)
- { unsigned raster =
- ((mdev->width * mdev->bits_per_color_pixel + 31) >> 5) << 2;
- mdev->raster = raster;
- return (ulong)mdev->height * (raster + sizeof(byte *));
- }
-
- /* 'Open' the memory device by creating the index table if needed. */
- private int
- mem_open(gx_device *dev)
- {
- #ifdef __MSDOS__ /* ****** NOTA BENE ****** */
- int z = 0;
- byte huge *scan_line = mdev->base + z; /* force normalization */
- #else /* ****** ****** */
- byte *scan_line = mdev->base;
- #endif /* ****** ****** */
- byte **pptr = (byte **)(scan_line + (ulong)mdev->height * mdev->raster);
- byte **pend = pptr + mdev->height;
- mdev->line_ptrs = pptr;
- while ( pptr != pend )
- { *pptr++ = (byte *)scan_line;
- scan_line += mdev->raster;
- }
- mdev->bytes_le =
- #if arch_is_big_endian
- 0
- #else
- !mdev->has_color
- #endif
- ;
- return 0;
- }
-
- /* Return the initial transformation matrix */
- void
- mem_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
- { *pmat = mdev->initial_matrix;
- }
-
- /* Test whether a device is a memory device */
- int
- gs_device_is_memory(gx_device *dev)
- { /* We can't just compare the procs, or even an individual proc, */
- /* because we might be tracing. Compare the device name, */
- /* and hope for the best. */
- char *name = dev->dname;
- int i;
- for ( i = 0; i < 6; i++ )
- if ( name[i] != "image("[i] ) return 0;
- return 1;
- }
-
- /* Compute the number of data bytes per scan line. */
- /* Note that this does not include the padding. */
- int
- gdev_mem_bytes_per_scan_line(gx_device *dev)
- { return (dev->width * dev->bits_per_color_pixel + 7) >> 3;
- }
-
- /* Ensure that the data bytes are in big-endian order. */
- /* This is never called on big-endian platforms; */
- /* on little-endian platforms, the chunk size is ushort, */
- /* regardless of the size of an int. */
- private void
- mem_swap_bytes(gx_device_memory *dev, byte *row)
- { register ushort *ptr = (ushort *)row;
- register ushort w;
- register int x;
- for ( x = dev->raster >> 1; --x >= 0; ptr++ )
- { w = *ptr;
- *ptr = (w >> 8) + (w << 8);
- }
- }
- void
- gdev_mem_ensure_byte_order(gx_device_memory *dev)
- {
- #if !arch_is_big_endian
- byte **lptr;
- int y;
- if ( !dev->bytes_le ) return; /* already in order */
- lptr = dev->line_ptrs;
- for ( y = dev->height; --y >= 0; )
- mem_swap_bytes(dev, *lptr++);
- dev->bytes_le = 0;
- #endif
- }
-
- /* Copy one or more scan lines to a client. */
- #undef chunk
- #define chunk byte
- int
- gdev_mem_copy_scan_lines(gx_device_memory *dev, int start_y, byte *str,
- uint size)
- { declare_scan_ptr(src_line, src, offset);
- uint bytes_per_line = gdev_mem_bytes_per_scan_line((gx_device *)dev);
- byte *dest = str;
- int y = start_y;
- uint count = min(size / bytes_per_line, dev->height - y);
- int swap = mdev->bytes_le;
- if ( !mdev->raster ) /* compute it now */
- (void)gdev_mem_bitmap_size(mdev);
- setup_scan(src_line, src, 0);
- while ( count-- != 0 )
- { if ( swap ) mem_swap_bytes(mdev, src);
- memcpy(dest, src, bytes_per_line);
- if ( swap ) mem_swap_bytes(mdev, src); /* swap back */
- next_scan_line(src_line, src, 0);
- dest += bytes_per_line;
- y++;
- }
- return y - start_y;
- }
-
- /* ------ Monochrome ------ */
-
- /* Procedures */
- declare_mem_procs(mem_mono_copy_mono, mem_mono_copy_color, mem_mono_fill_rectangle);
-
- /* The device descriptor. */
- private gx_device_procs mem_mono_procs =
- mem_procs(gx_default_map_rgb_color, gx_default_map_color_rgb,
- mem_mono_copy_mono, mem_mono_copy_color, mem_mono_fill_rectangle);
-
- /* The instance is public. */
- gx_device_memory mem_mono_device =
- mem_device("image(mono)", 1, mem_mono_procs);
-
- /* Convert x coordinate to byte offset in scan line. */
- #define x_to_byte(x) ((x) >> 3)
-
- /* Fill a rectangle with a color. */
- #undef chunk
- #if arch_is_big_endian
- # define chunk uint
- #else
- # define chunk ushort
- #endif
- private int
- mem_mono_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
- gx_color_index color)
- { uint bit;
- chunk right_mask;
- byte fill;
- declare_scan_ptr(dest_line, dest, offset);
- check_rect();
- setup_rect(dest_line, dest, offset);
- #define write_loop(stat)\
- { int line_count = h;\
- declare_scan_line(ptr_line, ptr);\
- ptr_line = dest_line;\
- setup_scan_ptr(ptr_line, ptr, offset);\
- do { stat; next_scan_line(ptr_line, ptr, offset); }\
- while ( --line_count );\
- }
- #define write_partial(msk)\
- if ( fill ) write_loop(*ptr |= msk)\
- else write_loop(*ptr &= ~msk)
- switch ( color )
- {
- case 0: fill = mdev->invert; break;
- case 1: fill = ~mdev->invert; break;
- case gx_no_color_index: return 0; /* transparent */
- default: return -1; /* invalid */
- }
- bit = x & chunk_bit_mask;
- if ( bit + w <= chunk_bits )
- { /* Only one word */
- right_mask = chunk_hi_bits(w) >> bit;
- }
- else
- { int byte_count;
- if ( bit )
- { chunk mask = chunk_all_bits >> bit;
- write_partial(mask);
- offset += chunk_bytes;
- w += bit - chunk_bits;
- }
- right_mask = chunk_hi_bits(w & chunk_bit_mask);
- if ( (byte_count = (w >> 3) & -chunk_bytes) != 0 )
- { write_loop(memset(ptr, fill, byte_count));
- offset += byte_count;
- }
- }
- if ( right_mask )
- write_partial(right_mask);
- return 0;
- }
-
- /* Copy a monochrome bitmap. */
-
- /* Fetch a chunk from the source. */
- /* Note that the source data are always stored big-endian. */
- #undef chunk
- #if arch_is_big_endian
- # define chunk uint
- # define cfetch(cptr) (*(chunk *)(cptr))
- #else
- # define chunk ushort
- # define cfetch(cptr)\
- ((chunk)(*(chunk *)(cptr) << 8) + (*(chunk *)(cptr) >> 8))
- #endif
- /* Fetch a chunk that straddles a chunk boundary. */
- #define cfetch2(cptr, cskew, skew)\
- ((cfetch(cptr) << cskew) + (cfetch((chunk *)cptr + 1) >> skew))
-
- /* Define the 9 possible cases of zero and one values. */
- /* Some of them are trivial. */
- typedef enum {
- copyNN = 0, copyN0 = 1, copyN1 = 2,
- copy0N = 3, copy00 = 4, copy01 = 5,
- copy1N = 6, copy10 = 7, copy11 = 8
- } copy_case;
- typedef enum {
- copy_and = -1, copy_store = 0, copy_or = 1
- } copy_function;
- private int
- mem_mono_copy_mono(gx_device *dev, byte *base, int sourcex, int raster,
- int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
- { byte *line; /* actually chunk * */
- int sleft, dleft, wleft;
- register int skew;
- uint mask;
- register uint invert;
- copy_case ccase;
- copy_function function;
- declare_scan_ptr(dest_line, dest, offset);
- #if gx_no_color_value != -1 /* hokey! */
- if ( zero == gx_no_color_index ) zero = -1;
- if ( one == gx_no_color_index ) one = -1;
- #endif
- #define izero (int)zero
- #define ione (int)one
- ccase = (copy_case)(izero + izero + izero + ione + 4);
- #undef izero
- #undef ione
- if ( mdev->invert )
- { static copy_case invert_ccase[9] =
- { copyNN, copyN1, copyN0,
- copy1N, copy11, copy10,
- copy0N, copy01, copy00
- };
- ccase = invert_ccase[(int)ccase];
- }
- switch ( (int)ccase )
- {
- case (int)copyNN: /* can't happen */
- return -1;
- case (int)copy00: /* just fill */
- case (int)copy11:
- return mem_mono_fill_rectangle(dev, x, y, w, h, zero);
- case (int)copy01:
- invert = 0, function = copy_store; break;
- case (int)copy0N:
- invert = 0, function = copy_and; break;
- case (int)copyN1:
- invert = 0, function = copy_or; break;
- case (int)copy10:
- invert = -1, function = copy_store; break;
- case (int)copyN0:
- invert = -1, function = copy_and; break;
- case (int)copy1N:
- invert = -1, function = copy_or; break;
- }
- check_rect();
- setup_rect(dest_line, dest, offset);
- line = base + (sourcex & ~chunk_bit_mask);
- sleft = chunk_bits - (sourcex & chunk_bit_mask);
- dleft = chunk_bits - (x & chunk_bit_mask);
- skew = sleft - dleft;
- mask = chunk_all_bits >> (chunk_bits - dleft);
- /* Macros for writing partial chunks. */
- /* The destination pointer is always named optr. */
- #define write_or_masked(bits, mask)\
- *optr |= (((bits) ^ invert) & mask)
- #define write_store_masked(bits, mask)\
- *optr = ((*optr & ~mask) | (((bits) ^ invert) & mask))
- #define write_and_masked(bits, mask)\
- *optr &= (((bits) ^ invert) | ~mask)
- #define write_chunk_masked(bits, mask)\
- switch ( function ) {\
- case copy_or: write_or_masked(bits, mask); break;\
- case copy_store: write_store_masked(bits, mask); break;\
- default: write_and_masked(bits, mask);\
- }
- #define write_or(bits) *optr |= (bits) ^ invert
- #define write_store(bits) *optr = (bits) ^ invert
- #define write_and(bits) *optr &= (bits) ^ invert
- if ( (wleft = w - dleft) <= 0 )
- { /* The entire operation fits in one chunk. */
- register byte *bptr = line; /* actually chunk * */
- register chunk *optr = dest;
- mask -= mask >> w;
- #define write1_loop(src)\
- for ( ; ; )\
- { write_chunk_masked(src, mask);\
- if ( --h == 0 ) break;\
- next_scan_line(dest_line, optr, offset);\
- bptr += raster;\
- }
- if ( skew >= 0 ) /* single -> single, right/no shift */
- { write1_loop(cfetch(bptr) >> skew);
- }
- else if ( w <= sleft ) /* single -> single, left shift */
- { skew = -skew;
- write1_loop(cfetch(bptr) << skew);
- }
- else /* single -> double */
- { int cskew = -skew;
- skew += chunk_bits;
- write1_loop(cfetch2(bptr, cskew, skew));
- }
- }
- else
- { /* More than one chunk is involved. */
- uint rmask = chunk_hi_bits(wleft & chunk_bit_mask);
- if ( sleft == dleft ) /* optimize the aligned case */
- { for ( ; ; )
- { register chunk *bptr = (chunk *)line;
- register chunk *optr = dest;
- int count = wleft;
- #define write_aligned(wr_op, wr_op_masked)\
- /* Do first partial chunk. */\
- wr_op_masked(cfetch(bptr), mask);\
- /* Do full chunks. */\
- while ( (count -= chunk_bits) >= 0 )\
- { ++bptr; ++optr; wr_op(cfetch(bptr)); }\
- /* Do last chunk */\
- if ( count > -chunk_bits )\
- { ++bptr; ++optr; wr_op_masked(cfetch(bptr), rmask); }
- switch ( function )
- {
- case copy_or:
- write_aligned(write_or, write_or_masked);
- break;
- case copy_store:
- write_aligned(write_store, write_store_masked);
- break;
- default: /* copy_and */
- write_aligned(write_and, write_and_masked);
- }
- #undef write_aligned
- if ( --h == 0 ) break;
- next_scan_line(dest_line, dest, offset);
- line += raster;
- }
- }
- else
- { int cskew = -skew & chunk_bit_mask;
- skew &= chunk_bit_mask;
- for ( ; ; )
- { register chunk *bptr = (chunk *)line;
- register uint bits;
- register chunk *optr = dest;
- int count = wleft;
- /* Do the first partial chunk */
- if ( sleft >= dleft )
- { bits = cfetch(bptr) >> skew;
- }
- else /* ( sleft < dleft ) */
- { bits = cfetch(bptr) << cskew;
- ++bptr;
- if ( w > sleft )
- bits += cfetch(bptr) >> skew;
- }
- #define write_unaligned(wr_op, wr_op_masked)\
- wr_op_masked(bits, mask);\
- /* Do full chunks. */\
- while ( count >= chunk_bits )\
- { bits = cfetch2(bptr, cskew, skew);\
- ++bptr; ++optr; wr_op(bits); count -= chunk_bits;\
- }\
- /* Do last chunk */\
- if ( count > 0 )\
- { bits = cfetch(bptr) << cskew;\
- ++bptr; if ( count > skew ) bits += cfetch(bptr) >> skew;\
- ++optr; wr_op_masked(bits, rmask);\
- }
- switch ( function )
- {
- case copy_or:
- write_unaligned(write_or, write_or_masked);
- break;
- case copy_store:
- write_unaligned(write_store, write_store_masked);
- break;
- default: /* copy_and */
- write_unaligned(write_and, write_and_masked);
- }
- #undef write_unaligned
- if ( --h == 0 ) break;
- next_scan_line(dest_line, dest, offset);
- line += raster;
- }
- }
- }
- return 0;
- }
-
- /* Copy a "color" bitmap. Since "color" is the same as monochrome, */
- /* this just reduces to copying a monochrome bitmap. */
- private int
- mem_mono_copy_color(gx_device *dev, byte *base, int sourcex, int raster,
- int x, int y, int w, int h)
- { return mem_mono_copy_mono(dev, base, sourcex, raster, x, y, w, h,
- (gx_color_index)0, (gx_color_index)1);
- }
-
- /* ------ Color (mapped or true) ------ */
-
- /* Copy a rectangle of bytes from a source to a destination. */
- #undef chunk
- #define chunk byte
- private int
- copy_byte_rect(gx_device *dev, byte *source, int sraster,
- int offset, int y, int w, int h)
- { declare_scan_line(dest_line, dest);
- setup_scan(dest_line, dest, offset);
- while ( h-- > 0 )
- { memcpy(dest, source, w);
- source += sraster;
- next_scan_line(dest_line, dest, offset);
- }
- return 0;
- }
-
- /* ------ Mapped 8-bit color ------ */
-
- /* Procedures */
- declare_mem_map_procs(mem_mapped_map_rgb_color, mem_mapped_map_color_rgb);
- declare_mem_procs(mem_mapped8_copy_mono, mem_mapped8_copy_color, mem_mapped8_fill_rectangle);
-
- /* The device descriptor. */
- private gx_device_procs mem_mapped8_procs =
- mem_procs(mem_mapped_map_rgb_color, mem_mapped_map_color_rgb,
- mem_mapped8_copy_mono, mem_mapped8_copy_color, mem_mapped8_fill_rectangle);
-
- /* The instance is public. */
- gx_device_memory mem_mapped8_color_device =
- mem_device("image(8)", 8, mem_mapped8_procs);
-
- /* Convert x coordinate to byte offset in scan line. */
- #undef x_to_byte
- #define x_to_byte(x) (x)
-
- /* Map a r-g-b color to a color index. */
- /* This requires searching the palette. */
- private gx_color_index
- mem_mapped_map_rgb_color(gx_device *dev, ushort r, ushort g, ushort b)
- { register byte *pptr = mdev->palette;
- int cnt = mdev->palette_size;
- byte *which;
- int best = 256*3;
- while ( cnt-- > 0 )
- { register int diff = *pptr - r;
- if ( diff < 0 ) diff = -diff;
- if ( diff < best ) /* quick rejection */
- { int dg = pptr[1] - g;
- if ( dg < 0 ) dg = -dg;
- if ( (diff += dg) < best ) /* quick rejection */
- { int db = pptr[2] - b;
- if ( db < 0 ) db = -db;
- if ( (diff += db) < best )
- which = pptr, best = diff;
- }
- }
- pptr += 3;
- }
- return (gx_color_index)((which - mdev->palette) / 3);
- }
-
- /* Map a color index to a r-g-b color. */
- private int
- mem_mapped_map_color_rgb(gx_device *dev, gx_color_index color, ushort prgb[3])
- { byte *pptr = mdev->palette + (int)color * 3;
- prgb[0] = pptr[0];
- prgb[1] = pptr[1];
- prgb[2] = pptr[2];
- return 0;
- }
-
- /* Fill a rectangle with a color. */
- private int
- mem_mapped8_fill_rectangle(gx_device *dev,
- int x, int y, int w, int h, gx_color_index color)
- { declare_scan_ptr(dest_line, dest, offset);
- check_rect();
- setup_rect(dest_line, dest, offset);
- while ( h-- > 0 )
- { memset(dest, (byte)color, w);
- next_scan_line(dest_line, dest, offset);
- }
- return 0;
- }
-
- /* Copy a monochrome bitmap. */
- private int
- mem_mapped8_copy_mono(gx_device *dev, byte *base, int sourcex, int raster,
- int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
- { byte *line;
- int first_bit;
- declare_scan_ptr(dest_line, dest, offset);
- check_rect();
- setup_rect(dest_line, dest, offset);
- line = base + (sourcex >> 3);
- first_bit = 0x80 >> (sourcex & 7);
- while ( h-- > 0 )
- { register byte *pptr = dest;
- byte *sptr = line;
- register int sbyte = *sptr++;
- register int bit = first_bit;
- int count = w;
- do
- { if ( sbyte & bit )
- { if ( (int)one != (int)gx_no_color_index )
- *pptr = (byte)one;
- }
- else
- { if ( (int)zero != (int)gx_no_color_index )
- *pptr = (byte)zero;
- }
- if ( (bit >>= 1) == 0 )
- bit = 0x80, sbyte = *sptr++;
- pptr++;
- }
- while ( --count > 0 );
- line += raster;
- next_scan_line(dest_line, dest, offset);
- }
- return 0;
- }
-
- /* Copy a color bitmap. */
- private int
- mem_mapped8_copy_color(gx_device *dev, byte *base, int sourcex, int raster,
- int x, int y, int w, int h)
- { check_rect();
- return copy_byte_rect(dev, base + x_to_byte(sourcex), raster,
- x_to_byte(x), y, x_to_byte(w), h);
- }
-
- /* ------ True (24- or 32-bit) color ------ */
-
- /* Procedures */
- declare_mem_map_procs(mem_true_map_rgb_color, mem_true_map_color_rgb);
-
- /* The device descriptor. */
- #define mem_true_procs(copy_mono, copy_color, fill_rectangle)\
- mem_procs(mem_true_map_rgb_color, mem_true_map_color_rgb,\
- copy_mono, copy_color, fill_rectangle)
-
- /* We want the bytes of a color always to be in the order -,r,g,b, */
- /* but we want to manipulate colors as longs. This requires careful */
- /* handling to be byte-order independent. */
- #define color_byte(cx,i) (((byte *)&(cx))[i])
-
- /* Map a r-g-b color to a color index. */
- private gx_color_index
- mem_true_map_rgb_color(gx_device *dev, ushort r, ushort g, ushort b)
- { gx_color_index color = 0;
- color_byte(color, 1) = r;
- color_byte(color, 2) = g;
- color_byte(color, 3) = b;
- return color;
- }
-
- /* Map a color index to a r-g-b color. */
- private int
- mem_true_map_color_rgb(gx_device *dev, gx_color_index color, ushort prgb[3])
- { prgb[0] = color_byte(color, 1);
- prgb[1] = color_byte(color, 2);
- prgb[2] = color_byte(color, 3);
- return 0;
- }
-
- /* ------ 24-bit color ------ */
- /* 24-bit takes less space than 32-bit, but is slower. */
-
- /* Procedures */
- declare_mem_procs(mem_true24_copy_mono, mem_true24_copy_color, mem_true24_fill_rectangle);
-
- /* The device descriptor. */
- private gx_device_procs mem_true24_procs =
- mem_true_procs(mem_true24_copy_mono, mem_true24_copy_color,
- mem_true24_fill_rectangle);
- gx_device_memory mem_true24_color_device =
- mem_device("image(24)", 24, mem_true24_procs);
-
- /* Convert x coordinate to byte offset in scan line. */
- #undef x_to_byte
- #define x_to_byte(x) ((x) * 3)
-
- /* Unpack a color into its bytes. */
- #define declare_unpack_color(r, g, b, color)\
- byte r = color_byte(color, 1);\
- byte g = color_byte(color, 2);\
- byte b = color_byte(color, 3)
- #define put3(ptr, r, g, b)\
- ptr[0] = r, ptr[1] = g, ptr[2] = b
-
- /* Fill a rectangle with a color. */
- private int
- mem_true24_fill_rectangle(gx_device *dev,
- int x, int y, int w, int h, gx_color_index color)
- { declare_unpack_color(r, g, b, color);
- declare_scan_ptr(dest_line, dest, offset);
- check_rect();
- setup_rect(dest_line, dest, offset);
- while ( h-- > 0 )
- { register int cnt = w;
- register byte *pptr = dest;
- do { put3(pptr, r, g, b); pptr += 3; } while ( --cnt > 0 );
- next_scan_line(dest_line, dest, offset);
- }
- return 0;
- }
-
- /* Copy a monochrome bitmap. */
- private int
- mem_true24_copy_mono(gx_device *dev, byte *base, int sourcex, int raster,
- int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
- { byte *line;
- int first_bit;
- declare_unpack_color(r0, g0, b0, zero);
- declare_unpack_color(r1, g1, b1, one);
- declare_scan_ptr(dest_line, dest, offset);
- check_rect();
- setup_rect(dest_line, dest, offset);
- line = base + (sourcex >> 3);
- first_bit = 0x80 >> (sourcex & 7);
- while ( h-- > 0 )
- { register byte *pptr = dest;
- byte *sptr = line;
- register int sbyte = *sptr++;
- register int bit = first_bit;
- int count = w;
- do
- { if ( sbyte & bit )
- { if ( one != gx_no_color_index )
- put3(pptr, r1, g1, b1);
- }
- else
- { if ( zero != gx_no_color_index )
- put3(pptr, r0, g0, b0);
- }
- pptr += 3;
- if ( (bit >>= 1) == 0 )
- bit = 0x80, sbyte = *sptr++;
- }
- while ( --count > 0 );
- line += raster;
- next_scan_line(dest_line, dest, offset);
- }
- return 0;
- }
-
- /* Copy a color bitmap. */
- private int
- mem_true24_copy_color(gx_device *dev, byte *base, int sourcex, int raster,
- int x, int y, int w, int h)
- { check_rect();
- return copy_byte_rect(dev, base + x_to_byte(sourcex), raster,
- x_to_byte(x), y, x_to_byte(w), h);
- }
-
- /* ------ 32-bit color ------ */
-
- /* Procedures */
- declare_mem_procs(mem_true32_copy_mono, mem_true32_copy_color, mem_true32_fill_rectangle);
-
- /* The device descriptor. */
- private gx_device_procs mem_true32_procs =
- mem_true_procs(mem_true32_copy_mono, mem_true32_copy_color,
- mem_true32_fill_rectangle);
- gx_device_memory mem_true32_color_device =
- mem_device("image(32)", 32, mem_true32_procs);
-
- /* Convert x coordinate to byte offset in scan line. */
- #undef x_to_byte
- #define x_to_byte(x) ((x) << 2)
-
- /* Fill a rectangle with a color. */
- private int
- mem_true32_fill_rectangle(gx_device *dev,
- int x, int y, int w, int h, gx_color_index color)
- { declare_scan_ptr(dest_line, dest, offset);
- check_rect();
- setup_rect(dest_line, dest, offset);
- while ( h-- > 0 )
- { gx_color_index *pptr = (gx_color_index *)dest;
- int cnt = w;
- do { *pptr++ = color; } while ( --cnt > 0 );
- next_scan_line(dest_line, dest, offset);
- }
- return 0;
- }
-
- /* Copy a monochrome bitmap. */
- private int
- mem_true32_copy_mono(gx_device *dev, byte *base, int sourcex, int raster,
- int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
- { byte *line;
- int first_bit;
- declare_scan_ptr(dest_line, dest, offset);
- check_rect();
- setup_rect(dest_line, dest, offset);
- line = base + (sourcex >> 3);
- first_bit = 0x80 >> (sourcex & 7);
- while ( h-- > 0 )
- { register gx_color_index *pptr = (gx_color_index *)dest;
- byte *sptr = line;
- register int sbyte = *sptr++;
- register int bit = first_bit;
- int count = w;
- do
- { if ( sbyte & bit )
- { if ( one != gx_no_color_index )
- *pptr = one;
- }
- else
- { if ( zero != gx_no_color_index )
- *pptr = zero;
- }
- if ( (bit >>= 1) == 0 )
- bit = 0x80, sbyte = *sptr++;
- pptr++;
- }
- while ( --count > 0 );
- line += raster;
- next_scan_line(dest_line, dest, offset);
- }
- return 0;
- }
-
- /* Copy a color bitmap. */
- private int
- mem_true32_copy_color(gx_device *dev, byte *base, int sourcex, int raster,
- int x, int y, int w, int h)
- { check_rect();
- return copy_byte_rect(dev, base + x_to_byte(sourcex), raster,
- x_to_byte(x), y, x_to_byte(w), h);
- }
-