DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T g

⟦66ec11e05⟧ TextFile

    Length: 17255 (0x4367)
    Types: TextFile
    Names: »gdevmem.c«

Derivation

└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
    └─⟦ff23ba0e6⟧ »./ghostscript-1.3.tar.Z« 
        └─⟦a24a58cd3⟧ 
            └─⟦this⟧ »gdevmem.c« 

TextFile

/* Copyright (C) 1989 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 "gx.h"			/* should be std.h, but needs gx_bitmap */
#include "gsmatrix.h"			/* for gxdevice.h */
#include "gxdevice.h"
#include "gxdevmem.h"

typedef struct gx_device_s gx_device;

/*
   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 always use this representation, for two
   reasons:
	- On PCs with segmented architectures, there is no way to
   obtain a contiguous block of storage larger then 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 (on PCs) 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.
*/
#ifdef __MSDOS__
#  define use_pieces 1
#else
#  define use_pieces 0
#endif

/* ------ Generic code ------ */

/* Macro for casting gx_device argument */
#define md ((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 > md->width - w || y < 0 || y > md->height - h )\
		return -1
#define unpack_rect(dest_line, dest)\
	check_rect();\
	setup_rect(dest_line, dest)

/* Macros for scan line access. */
/* x_to_byte is representation-specific. */
#if use_pieces
#  define declare_scan_ptr(line,ptr)  byte **line; byte *ptr
#  define setup_scan(line,ptr,offset)\
	line = md->line_ptrs + (y);\
	ptr = *line + (offset)
#  define next_scan_line(line,ptr)  ++line; ptr = *line + (ptr - line[-1])
#else
#  define declare_scan_ptr(line,ptr)	int line; byte *ptr
#  define setup_scan(line,ptr,offset)\
	line = md->raster;\
	ptr = md->base + y * line + (offset)
#  define next_scan_line(line,ptr)  ptr += line
#endif
#define setup_rect(line,ptr)	setup_scan(line,ptr,x_to_byte(x))

/* Compute the size of the bitmap storage. */
/* This may require space for the scan line index. */
/* Note that scan lines are padded to a multiple of 4 bytes. */
uint
gx_device_memory_bitmap_size(gx_device_memory *dev)
{	unsigned raster =
		((md->width * md->bits_per_color_pixel + 31) >> 5) << 2;
	md->raster = raster;
	return
#if use_pieces
		md->height * sizeof(byte **) +
#endif
		raster * md->height;
}

/* 'Open' the memory device by creating the index table if needed. */
private int
mem_open(gx_device *dev)
{
#if use_pieces				/* ONLY FOR MS-DOS */
#include <dos.h>
#define make_huge_ptr(ptr) ((byte huge *)MK_FP(FP_SEG(ptr), 0) + FP_OFF(ptr))
	byte huge *scan_line = make_huge_ptr(md->base);
	byte **pptr = (byte **)(scan_line + (long)md->raster * md->height);
	byte **pend = pptr + md->height;
	md->line_ptrs = pptr;
	while ( pptr != pend )
	   {	*pptr++ = (byte *)scan_line;
		scan_line += md->raster;
	   }	
#endif
	return 0;
}

/* ------ Monochrome ------ */

/* Procedures */
private int
	mem_mono_copy_mono(P10(gx_device *,
		byte *, int, int, int, int, int, int,
		gx_color_index, gx_color_index)),
	mem_mono_copy_color(P8(gx_device *,
		byte *, int, int, int, int, int, int)),
	mem_mono_fill_rectangle(P6(gx_device *,
		int, int, int, int, gx_color_index));

/* The device descriptor. */
private gx_device_procs mem_mono_procs = {
	mem_open,
	gx_default_close_device,
	gx_default_map_rgb_color,
	gx_default_map_color_rgb,
	gx_default_sync_output,
	mem_mono_fill_rectangle,
	gx_default_tile_rectangle,
	mem_mono_copy_mono,
	mem_mono_copy_color,
	gx_default_draw_line,
	gx_default_fill_trapezoid,
	gx_default_tile_trapezoid
};
/* The instance is public. */
gx_device_memory mem_mono_device = {
	sizeof(gx_device_memory),
	&mem_mono_procs,
	identity_matrix_body,
	0, 0,			/* x and y extent (filled in) */
	0, 1, 1,		/* monochrome */
	1,			/* bit-big-endian */
	0,			/* not open yet */
	0,			/* raster (filled in) */
	(byte *)0,		/* base (filled in) */
	(byte **)0,		/* line_ptrs (filled in by 'open') */
	0,			/* invert (filled in) */
	0, (byte *)0		/* palette (unused) */
};

/* Convert x coordinate to byte offset in scan line. */
#define x_to_byte(x) ((x) >> 3)

/* Fill a rectangle with a color. */
private int
mem_mono_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
  gx_color_index color)
{	int bit;
	byte right_mask;
	byte fill;
	declare_scan_ptr(dest_line, dest);
	unpack_rect(dest_line, dest);
#define write_loop(stat)\
 { int line_count = h;\
   declare_scan_ptr(ptr_line, ptr);\
   ptr_line = dest_line, ptr = dest;\
   do { stat; next_scan_line(ptr_line, ptr); } while ( --line_count );\
 }
#define write_partial(msk)\
   if ( fill ) write_loop(*ptr |= msk)\
   else write_loop(*ptr &= ~msk)
	switch ( color )
	   {
	case 0: fill = md->invert; break;
	case 1: fill = ~md->invert; break;
	case gx_no_color_index: return 0;		/* transparent */
	default: return -1;		/* invalid */
	   }
	bit = x & 7;
	if ( bit + w <= 8 )
	   {	/* Only one word */
		right_mask = ((0xff00 >> w) & 0xff) >> bit;
	   }
	else
	   {	int byte_count;
		if ( bit )
		   {	byte mask = 0xff >> bit;
			write_partial(mask);
			dest++;
			w += bit - 8;
		   }
		right_mask = (0xff00 >> (w & 7)) & 0xff;
		if ( (byte_count = w >> 3) != 0 )
		   {	write_loop(memset(ptr, fill, byte_count));
			dest += byte_count;
		   }
	   }
	if ( right_mask )
		write_partial(right_mask);
	return 0;
}

/* Copy a monochrome bitmap. */
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;
	int sleft, dleft;
	int mask, rmask;
	int invert, zmask, omask;
	declare_scan_ptr(dest_line, dest);
	if ( one == zero )		/* vacuous case */
		return mem_mono_fill_rectangle(dev, x, y, w, h, zero);
	unpack_rect(dest_line, dest);
	line = base + (sourcex >> 3);
	sleft = 8 - (sourcex & 7);
	dleft = 8 - (x & 7);
	mask = 0xff >> (8 - dleft);
	if ( w < dleft )
		mask -= mask >> w;
	else
		rmask = 0xff00 >> ((w - dleft) & 7);
/* Macros for writing partial bytes. */
/* bits has already been inverted by xor'ing with invert. */
#define write_byte_masked(ptr, bits, mask)\
  *ptr = ((bits | ~mask | zmask) & *ptr | (bits & mask & omask))
#define write_byte(ptr, bits)\
  *ptr = ((bits | zmask) & *ptr | (bits & omask))
	invert = (zero == 1 || one == 0 ? -1 : 0) ^ md->invert;
	zmask = (zero == 0 || one == 0 ? 0 : -1);
	omask = (zero == 1 || one == 1 ? -1 : 0);
	if ( sleft == dleft )		/* optimize the aligned case */
	   {	w -= dleft;
		while ( --h >= 0 )
		   {	register byte *bptr = line;
			int count = w;
			register byte *optr = dest;
			register int bits = *bptr ^ invert;	/* first partial byte */
			write_byte_masked(optr, bits, mask);
			/* Do full bytes. */
			while ( (count -= 8) >= 0 )
			   {	bits = *++bptr ^ invert;
				++optr;
				write_byte(optr, bits);
			   }
			/* Do last byte */
			if ( count > 0 )
			   {	bits = *++bptr ^ invert;
				++optr;
				write_byte_masked(optr, bits, rmask);
			   }
			next_scan_line(dest_line, dest);
			line += raster;
		   }
	   }
	else
	   {	int skew = (sleft - dleft) & 7;
		int cskew = 8 - skew;
		while ( --h >= 0 )
		   {	byte *bptr = line;
			int count = w;
			byte *optr = dest;
			register int bits;
			/* Do the first partial byte */
			if ( sleft >= dleft )
			   {	bits = *bptr >> skew;
			   }
			else /* ( sleft < dleft ) */
			   {	bits = *bptr++ << cskew;
				if ( count > sleft )
					bits += *bptr >> skew;
			   }
			bits ^= invert;
			write_byte_masked(optr, bits, mask);
			count -= dleft;
			optr++;
			/* Do full bytes. */
			while ( count >= 8 )
			   {	bits = *bptr++ << cskew;
				bits += *bptr >> skew;
				bits ^= invert;
				write_byte(optr, bits);
				count -= 8;
				optr++;
			   }
			/* Do last byte */
			if ( count > 0 )
			   {	bits = *bptr++ << cskew;
				if ( count > skew ) bits += *bptr >> skew;
				bits ^= invert;
				write_byte_masked(optr, bits, rmask);
			   }
			next_scan_line(dest_line, dest);
			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. */
private int
copy_byte_rect(gx_device *dev, byte *source, int sraster,
  int offset, int y, int w, int h)
{	declare_scan_ptr(dest_line, dest);
	setup_scan(dest_line, dest, offset);
	while ( h-- > 0 )
	   {	memcpy(dest_line, source, w);
		source += sraster;
		next_scan_line(dest_line, dest);
	   }
}

/* ------ Mapped color ------ */

/* Procedures */
private gx_color_index
	mem_mapped_map_rgb_color(P4(gx_device *, ushort, ushort, ushort));
private int
	mem_mapped_map_color_rgb(P3(gx_device *, gx_color_index, ushort *)),
	mem_mapped_copy_mono(P10(gx_device *,
		byte *, int, int, int, int, int, int,
		  gx_color_index, gx_color_index)),
	mem_mapped_copy_color(P8(gx_device *,
		byte *, int, int, int, int, int, int)),
	mem_mapped_fill_rectangle(P6(gx_device *,
		int, int, int, int, gx_color_index));

/* The device descriptor. */
private gx_device_procs mem_mapped_procs = {
	mem_open,
	gx_default_close_device,
	mem_mapped_map_rgb_color,
	mem_mapped_map_color_rgb,
	gx_default_sync_output,
	mem_mapped_fill_rectangle,
	gx_default_tile_rectangle,
	mem_mapped_copy_mono,
	mem_mapped_copy_color,
	gx_default_draw_line,
	gx_default_fill_trapezoid,
	gx_default_tile_trapezoid
};
/* The instance is public. */
gx_device_memory mem_mapped_device = {
	sizeof(gx_device_memory),
	&mem_mapped_procs,
	identity_matrix_body,
	0, 0,			/* x and y extent (filled in) */
	1, 255, 8,		/* 8-bit mapped color */
	1,			/* bit-big-endian */
	0,			/* not open yet */
	0,			/* raster (filled in) */
	(byte *)0,		/* base (filled in) */
	(byte **)0,		/* line_ptrs (filled in by 'open') */
	0,			/* invert (unused) */
	0, (byte *)0		/* palette (filled in) */
};

/* 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 = md->palette;
	int cnt = md->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;
			   }
		   }
	   }
	return (gx_color_index)((which - md->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)
{	byte *pptr = md->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_mapped_fill_rectangle(gx_device *dev,
  int x, int y, int w, int h, gx_color_index color)
{	declare_scan_ptr(dest_line, dest);
	setup_rect(dest_line, dest);
	while ( h-- > 0 )
	   {	memset(dest, (byte)color, w);
		next_scan_line(dest_line, dest);
	   }
}

/* Copy a monochrome bitmap. */
private int
mem_mapped_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);
	setup_rect(dest_line, dest);
	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 )
				  *pptr = (byte)one;
			   }
			else
			   {	if ( zero != 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);
	   }
}

/* Copy a color bitmap. */
private int
mem_mapped_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 (32-bit) color ------ */

/* Procedures */
private gx_color_index
	mem_true_map_rgb_color(P4(gx_device *, ushort, ushort, ushort));
private int
	mem_true_map_color_rgb(P3(gx_device *, gx_color_index, ushort *)),
	mem_true_copy_mono(P10(gx_device *,
		byte *, int, int, int, int, int, int,
		  gx_color_index, gx_color_index)),
	mem_true_copy_color(P8(gx_device *,
		byte *, int, int, int, int, int, int)),
	mem_true_fill_rectangle(P6(gx_device *,
		int, int, int, int, gx_color_index));

/* The device descriptor. */
private gx_device_procs mem_true_procs = {
	mem_open,
	gx_default_close_device,
	mem_true_map_rgb_color,
	mem_true_map_color_rgb,
	gx_default_sync_output,
	mem_true_fill_rectangle,
	gx_default_tile_rectangle,
	mem_true_copy_mono,
	mem_true_copy_color,
	gx_default_draw_line,
	gx_default_fill_trapezoid,
	gx_default_tile_trapezoid
};
/* The instance is public. */
gx_device_memory mem_true_device = {
	sizeof(gx_device_memory),
	&mem_true_procs,
	identity_matrix_body,
	0, 0,			/* x and y extent (filled in) */
	1, 255, 32,		/* 32-bit true color */
	1,			/* bit-big-endian */
	0,			/* not open yet */
	0,			/* raster (filled in) */
	(byte *)0,		/* base (filled in) */
	(byte **)0,		/* line_ptrs (filled in by 'open') */
	0,			/* invert (unused) */
	0, (byte *)0		/* palette (unused) */
};

/* Convert x coordinate to byte offset in scan line. */
#undef x_to_byte
#define x_to_byte(x) ((x) << 2)

/* 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)
{	return ((gx_color_index)r << 16) + (g << 8) + b;
}

/* 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)
{	prgb[0] = (color >> 16) & 0xff;
	prgb[1] = (color >> 8) & 0xff;
	prgb[2] = color & 0xff;
	return 0;
}

/* Fill a rectangle with a color. */
private int
mem_true_fill_rectangle(gx_device *dev,
  int x, int y, int w, int h, gx_color_index color)
{	declare_scan_ptr(dest_line, dest);
	setup_rect(dest_line, dest);
	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);
	   }
}

/* Copy a monochrome bitmap. */
private int
mem_true_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);
	setup_rect(dest_line, dest);
	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);
	   }
}

/* Copy a color bitmap. */
private int
mem_true_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);
}