[gs-cvs] gs/src

Henry Stiles henrys at casper.ghostscript.com
Thu Aug 22 00:12:33 PDT 2002


Update of /cvs/ghostscript/gs/src
In directory casper:/tmp/cvs-serv7660/src

Modified Files:
	devs.mak gconf.c gdev4693.c gdevabuf.c gdevbbox.c gdevbit.c 
	gdevbmpc.c gdevcdj.c gdevcmap.c gdevdbit.c gdevdflt.c 
	gdevdgbr.c gdevdrop.c gdevdsp.c gdevepsc.c gdevm1.c gdevm16.c 
	gdevmem.c gdevmem.h gdevmr1.c gdevnfwd.c gdevp14.c gdevpbm.c 
	gdevpccm.c gdevpcl.c gdevpdf.c gdevpdfc.c gdevpdfg.c 
	gdevplnx.c gdevprn.c gdevprn.h gdevps.c gdevpsdf.h gdevpsdi.c 
	gdevpsdu.c gdevrops.c gdevstc.c gdevtknk.c gdevupd.c gdevvec.c 
	gdevx.c gdevxalt.c gdevxcmp.c genconf.c gs.mak gsalphac.c 
	gsbitops.c gsbitops.h gsccolor.h gscdevn.c gscdevn.h gscolor.c 
	gscolor1.c gscolor2.c gscolor2.h gscpixel.c gscscie.c 
	gscsepr.c gscsepr.h gscspace.c gscspace.h gsdcolor.h 
	gsdevice.c gsdfilt.c gsdfilt.h gsdparam.c gsdps1.c gsht.c 
	gsht1.c gshtscr.c gshtx.c gshtx.h gsicc.c gsimage.c gsiparam.h 
	gsistate.c gslib.c gspcolor.c gsptype1.c gsptype2.c gsshade.c 
	gsstate.c gsstate.h gxacpath.c gxbitfmt.h gxcdevn.h gxcht.c 
	gxcindex.h gxclbits.c gxcldev.h gxclimag.c gxclip.c gxclip2.c 
	gxclipm.c gxclist.c gxclpath.c gxclpath.h gxclrast.c 
	gxclread.c gxclutil.c gxcmap.c gxcmap.h gxcomp.h gxcspace.h 
	gxdcconv.c gxdcolor.c gxdcolor.h gxdevcli.h gxdevice.h 
	gxdevmem.h gxdht.h gxdither.h gxht.c gxht.h gxicolor.c 
	gximag3x.c gximage2.c gximono.c gxipixel.c gxiscale.c 
	gxistate.h gxpcmap.c gxpcolor.h gxshade.c gxstate.h gzht.h 
	gzstate.h idparam.c igstate.h iimage.h iimage2.h int.mak 
	iutil.c iutil.h lib.mak msvc32.mak openvms.mak unix-gcc.mak 
	watclib.mak zcolor.c zcolor1.c zcolor2.c zcsdevn.c zcssepr.c 
	zdevice.c zdfilter.c zdpnext.c zfsample.c zgstate.c zht.c 
	zht1.c zht2.c zimage.c zimage2.c zimage3.c zmisc.c zmisc3.c 
	zpcolor.c zshade.c ztrans.c 
Added Files:
	gdevdevn.c gdevht.c gdevht.h gdevm40.c gdevm48.c gdevm56.c 
	gdevm64.c gdevxcf.c gsgraph.icx gsovrc.c gsovrc.h gsserial.c 
	gsserial.h gswts.c gswts.h gxdevndi.c gxdevndi.h gxdhtserial.c 
	gxdhtserial.h gxoprect.c gxoprect.h gxwts.c gxwts.h zcolor3.c 
Removed Files:
	gscsepnm.h gxdither.c 
Log Message:
DeviceN.


--- NEW FILE: gdevdevn.c ---
/* Copyright (C) 1991, 1995 to 1999 Aladdin Enterprises. 2001 ArtifexSoftware 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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/

/*$Id: gdevdevn.c,v 1.1 2002/08/22 07:12:28 henrys Exp $ */
/* Example DeviceN process color model devices. */
#include "math_.h"
[...1270 lines suppressed...]
	    if (data >= 0xc0)
		putc(0xc1, file);
	} else {
	    const byte *start = from;

	    while ((from < end) && (*from == data))
		from += step;
	    /* Now (from - start) / step + 1 is the run length. */
	    while (from - start >= max_run) {
		putc(0xc0 + MAX_RUN_COUNT, file);
		putc(data, file);
		start += max_run;
	    }
	    if (from > start || data >= 0xc0)
		putc((from - start) / step + 0xc1, file);
	}
	putc(data, file);
    }
#undef MAX_RUN_COUNT
}



--- NEW FILE: gdevm40.c ---
/* Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises, 2001 Artifex Software.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/

/*$Id: gdevm40.c,v 1.1 2002/08/22 07:12:28 henrys Exp $ */
/* 40-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 */

/* Define debugging statistics. */
#ifdef DEBUG
struct stats_mem40_s {
    long
	fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
	fprevc[257];
    double ftotal;
} stats_mem40;
static int prev_count;
static gx_color_index prev_colors[256];
# define INCR(v) (++(stats_mem40.v))
#else
# define INCR(v) DO_NOTHING
#endif


/* ================ Standard (byte-oriented) device ================ */

#undef chunk
#define chunk byte
#define PIXEL_SIZE 5

/* Procedures */
declare_mem_procs(mem_true40_copy_mono, mem_true40_copy_color, mem_true40_fill_rectangle);
private dev_proc_copy_alpha(mem_true40_copy_alpha);

/* The device descriptor. */
const gx_device_memory mem_true40_device =
mem_full_alpha_device("image40", 40, 0, mem_open,
		 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
     mem_true40_copy_mono, mem_true40_copy_color, mem_true40_fill_rectangle,
		      gx_default_map_cmyk_color, mem_true40_copy_alpha,
		 gx_default_strip_tile_rectangle, mem_default_strip_copy_rop,
		      mem_get_bits_rectangle);

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

/* Unpack a color into its bytes. */
#define declare_unpack_color(a, b, c, d, e, color)\
	byte a = (byte)(color >> 32);\
	byte b = (byte)((uint)color >> 24);\
	byte c = (byte)((uint)color >> 16);\
	byte d = (byte)((uint)color >> 8);\
	byte e = (byte)color
/* Put a 40-bit color into the bitmap. */
#define put5(ptr, a, b, c, d, e)\
	(ptr)[0] = a, (ptr)[1] = b, (ptr)[2] = c, (ptr)[3] = d, (ptr)[4] = e
/* Put 4 bytes of color into the bitmap. */
#define putw(ptr, wxyz)\
	*(bits32 *)(ptr) = (wxyz)
/* Load the 5-word 40-bit-color cache. */
/* Free variables: [m]dev, abcd, bcde, cdea, deab, earc. */
#if arch_is_big_endian
#  define set_color40_cache(color, a, b, c, d, e)\
	mdev->color40.abcd = abcd = (color) >> 8, \
	mdev->color40.bcde = bcde = (abcd << 8) | (e),\
	mdev->color40.cdea = cdea = (bcde << 8) | (a),\
	mdev->color40.deab = deab = (cdea << 8) | (b),\
	mdev->color40.eabc = eabc = (deab << 8) | (c),\
	mdev->color40.abcde = (color)
#else
#  define set_color40_cache(color, a, b, c, d, e)\
	mdev->color40.abcd = abcd =\
		((bits32)(d) << 24) | ((bits32)(c) << 16) |\
		((bits16)(b) << 8) | (a),\
	mdev->color40.eabc = eabc = (abcd << 8) | (e),\
	mdev->color40.deab = deab = (eabc << 8) | (d),\
	mdev->color40.cdea = cdea = (deab << 8) | (c),\
	mdev->color40.bcde = bcde = (cdea << 8) | (b),\
	mdev->color40.abcde = (color)
#endif

/* Fill a rectangle with a color. */
private int
mem_true40_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;
    declare_unpack_color(a, b, c, d, e, color);
    declare_scan_ptr(dest);

    /*
     * In order to avoid testing w > 0 and h > 0 twice, we defer
     * executing setup_rect, and use fit_fill_xywh instead of
     * fit_fill.
     */
    fit_fill_xywh(dev, x, y, w, h);
    INCR(fill);
#ifdef DEBUG
    stats_mem40.ftotal += w;
#endif
    if (w >= 5) {
	if (h <= 0)
	    return 0;
	INCR(fwide);
	setup_rect(dest);
	if (a == b && b == c && c == d && d == e) {
	    int bcnt = w * PIXEL_SIZE;

	    INCR(fgray[min(w, 100)]);
	    while (h-- > 0) {
		memset(dest, a, bcnt);
		inc_ptr(dest, draster);
	    }
	} else {
	    int x3 = -x & 3, ww = w - x3;	/* we know ww >= 2 */
	    bits32 abcd, bcde, cdea, deab, eabc;

	    if (mdev->color40.abcde == color) {
		abcd = mdev->color40.abcd;
		bcde = mdev->color40.bcde;
		cdea = mdev->color40.cdea;
		deab = mdev->color40.deab;
		eabc = mdev->color40.eabc;
	    } else {
		INCR(fsetc);
		set_color40_cache(color, a, b, c, d, e);
	    }
#ifdef DEBUG
	    {
		int ci;
		for (ci = 0; ci < prev_count; ++ci)
		    if (prev_colors[ci] == color)
			break;
		INCR(fprevc[ci]);
		if (ci == prev_count) {
		    if (ci < countof(prev_colors))
			++prev_count;
		    else
			--ci;
		}
		if (ci) {
		    memmove(&prev_colors[1], &prev_colors[0],
			    ci * sizeof(prev_colors[0]));
		    prev_colors[0] = color;
		}
	    }
#endif
	    INCR(fcolor[min(w, 100)]);
	    while (h-- > 0) {
		register byte *pptr = dest;
		int w1 = ww;

		switch (x3) {
		    case 1:
			pptr[0] = a;
			putw(pptr + 1, bcde);
			pptr += PIXEL_SIZE;
			break;
		    case 2:
			pptr[0] = a;
			pptr[1] = b;
			putw(pptr + 2, cdea);
			putw(pptr + 6, bcde);
			pptr += 2 * PIXEL_SIZE;
			break;
		    case 3:
			pptr[0] = a;
			pptr[1] = b;
			pptr[2] = c;
			putw(pptr + 3, deab);
			putw(pptr + 7, cdea);
			putw(pptr + 11, bcde);
			pptr += 3 * PIXEL_SIZE;
			break;
		    case 0:
			;
		}
		while (w1 >= 4) {
		    putw(pptr, abcd);
		    putw(pptr + 4, eabc);
		    putw(pptr + 8, deab);
		    putw(pptr + 12, cdea);
		    putw(pptr + 16, bcde);
		    pptr += 4 * PIXEL_SIZE;
		    w1 -= 4;
		}
		switch (w1) {
		    case 1:
			putw(pptr, abcd);
			pptr[4] = e;
			break;
		    case 2:
			putw(pptr, abcd);
			putw(pptr + 4, eabc);
			pptr[8] = d;
			pptr[9] = e;
			break;
		    case 3:
			putw(pptr, abcd);
			putw(pptr + 4, eabc);
			putw(pptr + 8, deab);
			pptr[12] = c;
			pptr[13] = d;
			pptr[14] = e;
			break;
		    case 0:
			;
		}
		inc_ptr(dest, draster);
	    }
	}
    } else if (h > 0) {		/* w < 5 */
	INCR(fnarrow[max(w, 0)]);
	setup_rect(dest);
	switch (w) {
	    case 4:
		do {
		    dest[15] = dest[10] = dest[5] = dest[0] = a;
		    dest[16] = dest[11] = dest[6] = dest[1] = b;
		    dest[17] = dest[12] = dest[7] = dest[2] = c;
		    dest[18] = dest[13] = dest[8] = dest[3] = d;
		    dest[19] = dest[14] = dest[9] = dest[4] = e;
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 3:
		do {
		    dest[10] = dest[5] = dest[0] = a;
		    dest[11] = dest[6] = dest[1] = b;
		    dest[12] = dest[7] = dest[2] = c;
		    dest[13] = dest[8] = dest[3] = d;
		    dest[14] = dest[9] = dest[4] = e;
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 2:
		do {
		    dest[5] = dest[0] = a;
		    dest[6] = dest[1] = b;
		    dest[7] = dest[2] = c;
		    dest[8] = dest[3] = d;
		    dest[9] = dest[4] = e;
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 1:
		do {
		    dest[0] = a; dest[1] = b; dest[2] = c; dest[3] = d; dest[4] = e;
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 0:
	    default:
		;
	}
    }
    return 0;
}

/* Copy a monochrome bitmap. */
private int
mem_true40_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;
    int sbit;
    int first_bit;

    declare_scan_ptr(dest);

    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
    setup_rect(dest);
    line = base + (sourcex >> 3);
    sbit = sourcex & 7;
    first_bit = 0x80 >> sbit;
    if (zero != gx_no_color_index) {	/* Loop for halftones or inverted masks */
	/* (never used). */
	declare_unpack_color(a0, b0, c0, d0, e0, zero);
	declare_unpack_color(a1, b1, c1, d1, e1, one);
	while (h-- > 0) {
	    register byte *pptr = dest;
	    const 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)
			put5(pptr, a1, b1, c1, d1, e1);
		} else
		    put5(pptr, a0, b0, c0, d0, e0);
		pptr += PIXEL_SIZE;
		if ((bit >>= 1) == 0)
		    bit = 0x80, sbyte = *sptr++;
	    }
	    while (--count > 0);
	    line += sraster;
	    inc_ptr(dest, draster);
	}
    } else if (one != gx_no_color_index) {	/* Loop for character and pattern masks. */
	/* This is used heavily. */
	declare_unpack_color(a1, b1, c1, d1, e1, one);
	int first_mask = first_bit << 1;
	int first_count, first_skip;

	if (sbit + w > 8)
	    first_mask -= 1,
		first_count = 8 - sbit;
	else
	    first_mask -= first_mask >> w,
		first_count = w;
	first_skip = first_count * PIXEL_SIZE;
	while (h-- > 0) {
	    register byte *pptr = dest;
	    const byte *sptr = line;
	    register int sbyte = *sptr++ & first_mask;
	    int count = w - first_count;

	    if (sbyte) {
		register int bit = first_bit;

		do {
		    if (sbyte & bit)
			put5(pptr, a1, b1, c1, d1, e1);
		    pptr += PIXEL_SIZE;
		}
		while ((bit >>= 1) & first_mask);
	    } else
		pptr += first_skip;
	    while (count >= 8) {
		sbyte = *sptr++;
		if (sbyte & 0xf0) {
		    if (sbyte & 0x80)
			put5(pptr, a1, b1, c1, d1, e1);
		    if (sbyte & 0x40)
			put5(pptr + 5, a1, b1, c1, d1, e1);
		    if (sbyte & 0x20)
			put5(pptr + 10, a1, b1, c1, d1, e1);
		    if (sbyte & 0x10)
			put5(pptr + 15, a1, b1, c1, d1, e1);
		}
		if (sbyte & 0xf) {
		    if (sbyte & 8)
			put5(pptr + 20, a1, b1, c1, d1, e1);
		    if (sbyte & 4)
			put5(pptr + 25, a1, b1, c1, d1, e1);
		    if (sbyte & 2)
			put5(pptr + 30, a1, b1, c1, d1, e1);
		    if (sbyte & 1)
			put5(pptr + 35, a1, b1, c1, d1, e1);
		}
		pptr += 8 * PIXEL_SIZE;
		count -= 8;
	    }
	    if (count > 0) {
		register int bit = 0x80;

		sbyte = *sptr++;
		do {
		    if (sbyte & bit)
			put5(pptr, a1, b1, c1, d1, e1);
		    pptr += PIXEL_SIZE;
		    bit >>= 1;
		}
		while (--count > 0);
	    }
	    line += sraster;
	    inc_ptr(dest, draster);
	}
    }
    return 0;
}

/* Copy a color bitmap. */
private int
mem_true40_copy_color(gx_device * dev,
	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
		      int x, int y, int w, int h)
{
    gx_device_memory * const mdev = (gx_device_memory *)dev;

    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
    mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
    return 0;
}

/* Copy an alpha map. */
private int
mem_true40_copy_alpha(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 color, int depth)
{
    /*
     * I do not know what to do about alpha.
     */
    return 0;
}

/* ================ "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(mem40_word_copy_mono, mem40_word_copy_color, mem40_word_fill_rectangle);

/* Here is the device descriptor. */
const gx_device_memory mem_true40_word_device =
mem_full_device("image40w", 40, 0, mem_open,
		gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
     mem40_word_copy_mono, mem40_word_copy_color, mem40_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. */
private int
mem40_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 * 40, w * 40, h, true);
    mem_true40_fill_rectangle(dev, x, y, w, h, color);
    mem_swap_byte_rect(base, raster, x * 40, w * 40, h, false);
    return 0;
}

/* Copy a bitmap. */
private int
mem40_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 * 40, w * 40, h, store);
    mem_true40_copy_mono(dev, base, sourcex, sraster, id,
			 x, y, w, h, zero, one);
    mem_swap_byte_rect(row, raster, x * 40, w * 40, h, false);
    return 0;
}

/* Copy a color bitmap. */
private int
mem40_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)
{
    gx_device_memory * const mdev = (gx_device_memory *)dev;
    byte *row;
    uint raster;

    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
    row = scan_line_base(mdev, y);
    raster = mdev->raster;
    mem_swap_byte_rect(row, raster, x * 40, w * 40, h, true);
    bytes_copy_rectangle(row + x * PIXEL_SIZE, raster, base + sourcex * PIXEL_SIZE,
    				sraster, w * PIXEL_SIZE, h);
    mem_swap_byte_rect(row, raster, x * 40, w * 40, h, false);
    return 0;
}

#endif /* !arch_is_big_endian */

--- NEW FILE: gdevm48.c ---
/* Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises, 2001 Artifex Software.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/

/*$Id: gdevm48.c,v 1.1 2002/08/22 07:12:28 henrys Exp $ */
/* 48-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 */

/* Define debugging statistics. */
#ifdef DEBUG
struct stats_mem48_s {
    long
	fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
	fprevc[257];
    double ftotal;
} stats_mem48;
static int prev_count;
static gx_color_index prev_colors[256];
# define INCR(v) (++(stats_mem48.v))
#else
# define INCR(v) DO_NOTHING
#endif


/* ================ Standard (byte-oriented) device ================ */

#undef chunk
#define chunk byte
#define PIXEL_SIZE 6

/* Procedures */
declare_mem_procs(mem_true48_copy_mono, mem_true48_copy_color, mem_true48_fill_rectangle);
private dev_proc_copy_alpha(mem_true48_copy_alpha);

/* The device descriptor. */
const gx_device_memory mem_true48_device =
mem_full_alpha_device("image48", 48, 0, mem_open,
		 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
     mem_true48_copy_mono, mem_true48_copy_color, mem_true48_fill_rectangle,
		      gx_default_map_cmyk_color, mem_true48_copy_alpha,
		 gx_default_strip_tile_rectangle, mem_default_strip_copy_rop,
		      mem_get_bits_rectangle);

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

/* Unpack a color into its bytes. */
#define declare_unpack_color(a, b, c, d, e, f, color)\
	byte a = (byte)(color >> 40);\
	byte b = (byte)(color >> 32);\
	byte c = (byte)((uint)color >> 24);\
	byte d = (byte)((uint)color >> 16);\
	byte e = (byte)((uint)color >> 8);\
	byte f = (byte)color
/* Put a 48-bit color into the bitmap. */
#define put6(ptr, a, b, c, d, e, f)\
	(ptr)[0] = a, (ptr)[1] = b, (ptr)[2] = c, (ptr)[3] = d, (ptr)[4] = e, (ptr)[5] = f
/* Put 4 bytes of color into the bitmap. */
#define putw(ptr, wxyz)\
	*(bits32 *)(ptr) = (wxyz)
/* Load the 3-word 48-bit-color cache. */
/* Free variables: [m]dev, abcd, bcde, cdea, deab, earc. */
#if arch_is_big_endian
#  define set_color48_cache(color, a, b, c, d, e, f)\
	mdev->color48.abcd = abcd = (color) >> 16, \
	mdev->color48.cdef = cdef = (abcd << 16) | ((e) <<8) | (f),\
	mdev->color48.efab = efab = (cdef << 16) | ((a) <<8) | (b),\
	mdev->color48.abcdef = (color)
#else
#  define set_color48_cache(color, a, b, c, d, e, f)\
	mdev->color48.abcd = abcd =\
		((bits32)(d) << 24) | ((bits32)(c) << 16) |\
		((bits16)(b) << 8) | (a),\
	mdev->color48.efab = efab = (abcd << 16) | ((f) <<8) | (e),\
	mdev->color48.cdef = cdef = (efab << 16) | ((d) <<8) | (c),\
	mdev->color48.abcdef = (color)
#endif

/* Fill a rectangle with a color. */
private int
mem_true48_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;
    declare_unpack_color(a, b, c, d, e, f, color);
    declare_scan_ptr(dest);

    /*
     * In order to avoid testing w > 0 and h > 0 twice, we defer
     * executing setup_rect, and use fit_fill_xywh instead of
     * fit_fill.
     */
    fit_fill_xywh(dev, x, y, w, h);
    INCR(fill);
#ifdef DEBUG
    stats_mem48.ftotal += w;
#endif
    if (w >= 5) {
	if (h <= 0)
	    return 0;
	INCR(fwide);
	setup_rect(dest);
	if (a == b && b == c && c == d && d == e && e == f) {
	    int bcnt = w * PIXEL_SIZE;

	    INCR(fgray[min(w, 100)]);
	    while (h-- > 0) {
		memset(dest, a, bcnt);
		inc_ptr(dest, draster);
	    }
	} else {
	    int x1 = -x & 1, ww = w - x1;	/* we know ww >= 4 */
	    bits32 abcd, cdef, efab;

	    if (mdev->color48.abcdef == color) {
		abcd = mdev->color48.abcd;
		cdef = mdev->color48.cdef;
		efab = mdev->color48.efab;
	    } else {
		INCR(fsetc);
		set_color48_cache(color, a, b, c, d, e, f);
	    }
#ifdef DEBUG
	    {
		int ci;
		for (ci = 0; ci < prev_count; ++ci)
		    if (prev_colors[ci] == color)
			break;
		INCR(fprevc[ci]);
		if (ci == prev_count) {
		    if (ci < countof(prev_colors))
			++prev_count;
		    else
			--ci;
		}
		if (ci) {
		    memmove(&prev_colors[1], &prev_colors[0],
			    ci * sizeof(prev_colors[0]));
		    prev_colors[0] = color;
		}
	    }
#endif
	    INCR(fcolor[min(w, 100)]);
	    while (h-- > 0) {
		register byte *pptr = dest;
		int w1 = ww;

		switch (x1) {
		    case 1:
			pptr[0] = a;
			pptr[1] = b;
			putw(pptr + 2, cdef);
			pptr += PIXEL_SIZE;
			break;
		    case 0:
			;
		}
		while (w1 >= 2) {
		    putw(pptr, abcd);
		    putw(pptr + 4, efab);
		    putw(pptr + 8, cdef);
		    pptr += 2 * PIXEL_SIZE;
		    w1 -= 2;
		}
		switch (w1) {
		    case 1:
			putw(pptr, abcd);
			pptr[4] = e;
			pptr[5] = f;
			break;
		    case 0:
			;
		}
		inc_ptr(dest, draster);
	    }
	}
    } else if (h > 0) {		/* w < 5 */
	INCR(fnarrow[max(w, 0)]);
	setup_rect(dest);
	switch (w) {
	    case 4:
		do {
		    dest[18] = dest[12] = dest[6] = dest[0] = a;
		    dest[19] = dest[13] = dest[7] = dest[1] = b;
		    dest[20] = dest[14] = dest[8] = dest[2] = c;
		    dest[21] = dest[15] = dest[9] = dest[3] = d;
		    dest[22] = dest[16] = dest[10] = dest[4] = e;
		    dest[23] = dest[17] = dest[11] = dest[5] = f;
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 3:
		do {
		    dest[12] = dest[6] = dest[0] = a;
		    dest[13] = dest[7] = dest[1] = b;
		    dest[14] = dest[8] = dest[2] = c;
		    dest[15] = dest[9] = dest[3] = d;
		    dest[16] = dest[10] = dest[4] = e;
		    dest[17] = dest[11] = dest[5] = f;
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 2:
		do {
		    dest[6] = dest[0] = a;
		    dest[7] = dest[1] = b;
		    dest[8] = dest[2] = c;
		    dest[9] = dest[3] = d;
		    dest[10] = dest[4] = e;
		    dest[11] = dest[5] = f;
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 1:
		do {
		    dest[0] = a; dest[1] = b; dest[2] = c;
		    dest[3] = d; dest[4] = e; dest[5] = f;
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 0:
	    default:
		;
	}
    }
    return 0;
}

/* Copy a monochrome bitmap. */
private int
mem_true48_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;
    int sbit;
    int first_bit;

    declare_scan_ptr(dest);

    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
    setup_rect(dest);
    line = base + (sourcex >> 3);
    sbit = sourcex & 7;
    first_bit = 0x80 >> sbit;
    if (zero != gx_no_color_index) {	/* Loop for halftones or inverted masks */
	/* (never used). */
	declare_unpack_color(a0, b0, c0, d0, e0, f0, zero);
	declare_unpack_color(a1, b1, c1, d1, e1, f1, one);
	while (h-- > 0) {
	    register byte *pptr = dest;
	    const 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)
			put6(pptr, a1, b1, c1, d1, e1, f1);
		} else
		    put6(pptr, a0, b0, c0, d0, e0, f0);
		pptr += PIXEL_SIZE;
		if ((bit >>= 1) == 0)
		    bit = 0x80, sbyte = *sptr++;
	    }
	    while (--count > 0);
	    line += sraster;
	    inc_ptr(dest, draster);
	}
    } else if (one != gx_no_color_index) {	/* Loop for character and pattern masks. */
	/* This is used heavily. */
	declare_unpack_color(a1, b1, c1, d1, e1, f1, one);
	int first_mask = first_bit << 1;
	int first_count, first_skip;

	if (sbit + w > 8)
	    first_mask -= 1,
		first_count = 8 - sbit;
	else
	    first_mask -= first_mask >> w,
		first_count = w;
	first_skip = first_count * PIXEL_SIZE;
	while (h-- > 0) {
	    register byte *pptr = dest;
	    const byte *sptr = line;
	    register int sbyte = *sptr++ & first_mask;
	    int count = w - first_count;

	    if (sbyte) {
		register int bit = first_bit;

		do {
		    if (sbyte & bit)
			put6(pptr, a1, b1, c1, d1, e1, f1);
		    pptr += PIXEL_SIZE;
		}
		while ((bit >>= 1) & first_mask);
	    } else
		pptr += first_skip;
	    while (count >= 8) {
		sbyte = *sptr++;
		if (sbyte & 0xf0) {
		    if (sbyte & 0x80)
			put6(pptr, a1, b1, c1, d1, e1, f1);
		    if (sbyte & 0x40)
			put6(pptr + 6, a1, b1, c1, d1, e1, f1);
		    if (sbyte & 0x20)
			put6(pptr + 12, a1, b1, c1, d1, e1, f1);
		    if (sbyte & 0x10)
			put6(pptr + 18, a1, b1, c1, d1, e1, f1);
		}
		if (sbyte & 0xf) {
		    if (sbyte & 8)
			put6(pptr + 24, a1, b1, c1, d1, e1, f1);
		    if (sbyte & 4)
			put6(pptr + 30, a1, b1, c1, d1, e1, f1);
		    if (sbyte & 2)
			put6(pptr + 36, a1, b1, c1, d1, e1, f1);
		    if (sbyte & 1)
			put6(pptr + 42, a1, b1, c1, d1, e1, f1);
		}
		pptr += 8 * PIXEL_SIZE;
		count -= 8;
	    }
	    if (count > 0) {
		register int bit = 0x80;

		sbyte = *sptr++;
		do {
		    if (sbyte & bit)
			put6(pptr, a1, b1, c1, d1, e1, f1);
		    pptr += PIXEL_SIZE;
		    bit >>= 1;
		}
		while (--count > 0);
	    }
	    line += sraster;
	    inc_ptr(dest, draster);
	}
    }
    return 0;
}

/* Copy a color bitmap. */
private int
mem_true48_copy_color(gx_device * dev,
	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
		      int x, int y, int w, int h)
{
    gx_device_memory * const mdev = (gx_device_memory *)dev;

    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
    mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
    return 0;
}

/* Copy an alpha map. */
private int
mem_true48_copy_alpha(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 color, int depth)
{
    /*
     * I do not know what to do about alpha.
     */
    return 0;
}

/* ================ "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(mem48_word_copy_mono, mem48_word_copy_color, mem48_word_fill_rectangle);

/* Here is the device descriptor. */
const gx_device_memory mem_true48_word_device =
mem_full_device("image48w", 48, 0, mem_open,
		gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
     mem48_word_copy_mono, mem48_word_copy_color, mem48_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. */
private int
mem48_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 * 48, w * 48, h, true);
    mem_true48_fill_rectangle(dev, x, y, w, h, color);
    mem_swap_byte_rect(base, raster, x * 48, w * 48, h, false);
    return 0;
}

/* Copy a bitmap. */
private int
mem48_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 * 48, w * 48, h, store);
    mem_true48_copy_mono(dev, base, sourcex, sraster, id,
			 x, y, w, h, zero, one);
    mem_swap_byte_rect(row, raster, x * 48, w * 48, h, false);
    return 0;
}

/* Copy a color bitmap. */
private int
mem48_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)
{
    gx_device_memory * const mdev = (gx_device_memory *)dev;
    byte *row;
    uint raster;

    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
    row = scan_line_base(mdev, y);
    raster = mdev->raster;
    mem_swap_byte_rect(row, raster, x * 48, w * 48, h, true);
    bytes_copy_rectangle(row + x * PIXEL_SIZE, raster, base + sourcex * PIXEL_SIZE,
    				sraster, w * PIXEL_SIZE, h);
    mem_swap_byte_rect(row, raster, x * 48, w * 48, h, false);
    return 0;
}

#endif /* !arch_is_big_endian */

--- NEW FILE: gdevm56.c ---
/* Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises, 2001 Artifex Software.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/

/*$Id: gdevm56.c,v 1.1 2002/08/22 07:12:28 henrys Exp $ */
/* 56-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 */

/* Define debugging statistics. */
#ifdef DEBUG
struct stats_mem56_s {
    long
	fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
	fprevc[257];
    double ftotal;
} stats_mem56;
static int prev_count;
static gx_color_index prev_colors[256];
# define INCR(v) (++(stats_mem56.v))
#else
# define INCR(v) DO_NOTHING
#endif


/* ================ Standard (byte-oriented) device ================ */

#undef chunk
#define chunk byte
#define PIXEL_SIZE 7

/* Procedures */
declare_mem_procs(mem_true56_copy_mono, mem_true56_copy_color, mem_true56_fill_rectangle);
private dev_proc_copy_alpha(mem_true56_copy_alpha);

/* The device descriptor. */
const gx_device_memory mem_true56_device =
mem_full_alpha_device("image56", 56, 0, mem_open,
		 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
     mem_true56_copy_mono, mem_true56_copy_color, mem_true56_fill_rectangle,
		      gx_default_map_cmyk_color, mem_true56_copy_alpha,
		 gx_default_strip_tile_rectangle, mem_default_strip_copy_rop,
		      mem_get_bits_rectangle);

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

/* Unpack a color into its bytes. */
#define declare_unpack_color(a, b, c, d, e, f, g, color)\
	byte a = (byte)(color >> 48);\
	byte b = (byte)(color >> 40);\
	byte c = (byte)(color >> 32);\
	byte d = (byte)((uint)color >> 24);\
	byte e = (byte)((uint)color >> 16);\
	byte f = (byte)((uint)color >> 8);\
	byte g = (byte)color
/* Put a 56-bit color into the bitmap. */
#define put7(ptr, a, b, c, d, e, f, g)\
	(ptr)[0] = a, (ptr)[1] = b, (ptr)[2] = c, (ptr)[3] = d, (ptr)[4] = e, \
	(ptr)[5] = f, (ptr)[6] = g
/* Put 4 bytes of color into the bitmap. */
#define putw(ptr, wxyz)\
	*(bits32 *)(ptr) = (wxyz)
/* Load the 7-word 56-bit-color cache. */
/* Free variables: [m]dev, abcd, bcde, cdea, deab, earc. */
#if arch_is_big_endian
#  define set_color56_cache(color, a, b, c, d, e, f, g)\
	mdev->color56.abcd = abcd = (color) >> 24, \
	mdev->color56.bcde = bcde = (abcd << 8) | (e),\
	mdev->color56.cdef = cdef = (bcde << 8) | (f),\
	mdev->color56.defg = defg = (cdef << 8) | (g),\
	mdev->color56.efga = efga = (defg << 8) | (a),\
	mdev->color56.fgab = fgab = (efga << 8) | (b),\
	mdev->color56.gabc = gabc = (fgab << 8) | (c),\
	mdev->color56.abcdefg = (color)
#else
#  define set_color56_cache(color, a, b, c, d, e, f, g)\
	mdev->color56.abcd = abcd =\
		((bits32)(d) << 24) | ((bits32)(c) << 16) |\
		((bits16)(b) << 8) | (a),\
	mdev->color56.gabc = gabc = (abcd << 8) | (g),\
	mdev->color56.fgab = fgab = (gabc << 8) | (f),\
	mdev->color56.efga = efga = (fgab << 8) | (e),\
	mdev->color56.defg = defg = (efga << 8) | (d),\
	mdev->color56.cdef = cdef = (defg << 8) | (c),\
	mdev->color56.bcde = bcde = (cdef << 8) | (b),\
	mdev->color56.abcdefg = (color)
#endif

/* Fill a rectangle with a color. */
private int
mem_true56_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;
    declare_unpack_color(a, b, c, d, e, f, g, color);
    declare_scan_ptr(dest);

    /*
     * In order to avoid testing w > 0 and h > 0 twice, we defer
     * executing setup_rect, and use fit_fill_xywh instead of
     * fit_fill.
     */
    fit_fill_xywh(dev, x, y, w, h);
    INCR(fill);
#ifdef DEBUG
    stats_mem56.ftotal += w;
#endif
    if (w >= 5) {
	if (h <= 0)
	    return 0;
	INCR(fwide);
	setup_rect(dest);
	if (a == b && b == c && c == d && d == e && e == f && f == g) {
	    int bcnt = w * PIXEL_SIZE;

	    INCR(fgray[min(w, 100)]);
	    while (h-- > 0) {
		memset(dest, a, bcnt);
		inc_ptr(dest, draster);
	    }
	} else {
	    int x3 = -x & 3, ww = w - x3;	/* we know ww >= 2 */
	    bits32 abcd, bcde, cdef, defg, efga, fgab, gabc;

	    if (mdev->color56.abcdefg == color) {
		abcd = mdev->color56.abcd;
		bcde = mdev->color56.bcde;
		cdef = mdev->color56.cdef;
		defg = mdev->color56.defg;
		efga = mdev->color56.efga;
		fgab = mdev->color56.fgab;
		gabc = mdev->color56.gabc;
	    } else {
		INCR(fsetc);
		set_color56_cache(color, a, b, c, d, e, f, g);
	    }
#ifdef DEBUG
	    {
		int ci;
		for (ci = 0; ci < prev_count; ++ci)
		    if (prev_colors[ci] == color)
			break;
		INCR(fprevc[ci]);
		if (ci == prev_count) {
		    if (ci < countof(prev_colors))
			++prev_count;
		    else
			--ci;
		}
		if (ci) {
		    memmove(&prev_colors[1], &prev_colors[0],
			    ci * sizeof(prev_colors[0]));
		    prev_colors[0] = color;
		}
	    }
#endif
	    INCR(fcolor[min(w, 100)]);
	    while (h-- > 0) {
		register byte *pptr = dest;
		int w1 = ww;

		switch (x3) {
		    case 1:
			pptr[0] = a;
			pptr[1] = b;
			pptr[2] = c;
			putw(pptr + 3, defg);
			pptr += PIXEL_SIZE;
			break;
		    case 2:
			pptr[0] = a;
			pptr[1] = b;
			putw(pptr + 2, cdef);
			putw(pptr + 6, gabc);
			putw(pptr + 10, defg);
			pptr += 2 * PIXEL_SIZE;
			break;
		    case 3:
			pptr[0] = a;
			putw(pptr + 1, bcde);
			putw(pptr + 5, fgab);
			putw(pptr + 9, cdef);
			putw(pptr + 13, gabc);
			putw(pptr + 17, defg);
			pptr += 3 * PIXEL_SIZE;
			break;
		    case 0:
			;
		}
		while (w1 >= 4) {
		    putw(pptr, abcd);
		    putw(pptr + 4, efga);
		    putw(pptr + 8, bcde);
		    putw(pptr + 12, fgab);
		    putw(pptr + 16, cdef);
		    putw(pptr + 20, gabc);
		    putw(pptr + 24, defg);
		    pptr += 4 * PIXEL_SIZE;
		    w1 -= 4;
		}
		switch (w1) {
		    case 1:
			putw(pptr, abcd);
			pptr[4] = e;
			pptr[5] = f;
			pptr[6] = g;
			break;
		    case 2:
			putw(pptr, abcd);
			putw(pptr + 4, efga);
			putw(pptr + 8, bcde);
			pptr[12] = f;
			pptr[13] = g;
			break;
		    case 3:
			putw(pptr, abcd);
			putw(pptr + 4, efga);
			putw(pptr + 8, bcde);
			putw(pptr + 12, fgab);
			putw(pptr + 16, cdef);
			pptr[20] = g;
			break;
		    case 0:
			;
		}
		inc_ptr(dest, draster);
	    }
	}
    } else if (h > 0) {		/* w < 5 */
	INCR(fnarrow[max(w, 0)]);
	setup_rect(dest);
	switch (w) {
	    case 4:
		do {
		    dest[21] = dest[14] = dest[7] = dest[0] = a;
		    dest[22] = dest[15] = dest[8] = dest[1] = b;
		    dest[23] = dest[16] = dest[9] = dest[2] = c;
		    dest[24] = dest[17] = dest[10] = dest[3] = d;
		    dest[25] = dest[18] = dest[11] = dest[4] = e;
		    dest[26] = dest[19] = dest[12] = dest[5] = f;
		    dest[27] = dest[20] = dest[13] = dest[6] = g;
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 3:
		do {
		    dest[14] = dest[7] = dest[0] = a;
		    dest[15] = dest[8] = dest[1] = b;
		    dest[16] = dest[9] = dest[2] = c;
		    dest[17] = dest[10] = dest[3] = d;
		    dest[18] = dest[11] = dest[4] = e;
		    dest[19] = dest[12] = dest[5] = f;
		    dest[20] = dest[13] = dest[6] = g;
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 2:
		do {
		    dest[7] = dest[0] = a;
		    dest[8] = dest[1] = b;
		    dest[9] = dest[2] = c;
		    dest[10] = dest[3] = d;
		    dest[11] = dest[4] = e;
		    dest[12] = dest[5] = f;
		    dest[13] = dest[6] = g;
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 1:
		do {
		    dest[0] = a; dest[1] = b; dest[2] = c; dest[3] = d;
		    dest[4] = e; dest[5] = f; dest[6] = g;
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 0:
	    default:
		;
	}
    }
    return 0;
}

/* Copy a monochrome bitmap. */
private int
mem_true56_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;
    int sbit;
    int first_bit;

    declare_scan_ptr(dest);

    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
    setup_rect(dest);
    line = base + (sourcex >> 3);
    sbit = sourcex & 7;
    first_bit = 0x80 >> sbit;
    if (zero != gx_no_color_index) {	/* Loop for halftones or inverted masks */
	/* (never used). */
	declare_unpack_color(a0, b0, c0, d0, e0, f0, g0, zero);
	declare_unpack_color(a1, b1, c1, d1, e1, f1, g1, one);
	while (h-- > 0) {
	    register byte *pptr = dest;
	    const 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)
			put7(pptr, a1, b1, c1, d1, e1, f1, g1);
		} else
		    put7(pptr, a0, b0, c0, d0, e0, f0, g0);
		pptr += PIXEL_SIZE;
		if ((bit >>= 1) == 0)
		    bit = 0x80, sbyte = *sptr++;
	    }
	    while (--count > 0);
	    line += sraster;
	    inc_ptr(dest, draster);
	}
    } else if (one != gx_no_color_index) {	/* Loop for character and pattern masks. */
	/* This is used heavily. */
	declare_unpack_color(a1, b1, c1, d1, e1, f1, g1, one);
	int first_mask = first_bit << 1;
	int first_count, first_skip;

	if (sbit + w > 8)
	    first_mask -= 1,
		first_count = 8 - sbit;
	else
	    first_mask -= first_mask >> w,
		first_count = w;
	first_skip = first_count * PIXEL_SIZE;
	while (h-- > 0) {
	    register byte *pptr = dest;
	    const byte *sptr = line;
	    register int sbyte = *sptr++ & first_mask;
	    int count = w - first_count;

	    if (sbyte) {
		register int bit = first_bit;

		do {
		    if (sbyte & bit)
			put7(pptr, a1, b1, c1, d1, e1, f1, g1);
		    pptr += PIXEL_SIZE;
		}
		while ((bit >>= 1) & first_mask);
	    } else
		pptr += first_skip;
	    while (count >= 8) {
		sbyte = *sptr++;
		if (sbyte & 0xf0) {
		    if (sbyte & 0x80)
			put7(pptr, a1, b1, c1, d1, e1, f1, g1);
		    if (sbyte & 0x40)
			put7(pptr + 5, a1, b1, c1, d1, e1, f1, g1);
		    if (sbyte & 0x20)
			put7(pptr + 10, a1, b1, c1, d1, e1, f1, g1);
		    if (sbyte & 0x10)
			put7(pptr + 15, a1, b1, c1, d1, e1, f1, g1);
		}
		if (sbyte & 0xf) {
		    if (sbyte & 8)
			put7(pptr + 20, a1, b1, c1, d1, e1, f1, g1);
		    if (sbyte & 4)
			put7(pptr + 25, a1, b1, c1, d1, e1, f1, g1);
		    if (sbyte & 2)
			put7(pptr + 30, a1, b1, c1, d1, e1, f1, g1);
		    if (sbyte & 1)
			put7(pptr + 35, a1, b1, c1, d1, e1, f1, g1);
		}
		pptr += 8 * PIXEL_SIZE;
		count -= 8;
	    }
	    if (count > 0) {
		register int bit = 0x80;

		sbyte = *sptr++;
		do {
		    if (sbyte & bit)
			put7(pptr, a1, b1, c1, d1, e1, f1, g1);
		    pptr += PIXEL_SIZE;
		    bit >>= 1;
		}
		while (--count > 0);
	    }
	    line += sraster;
	    inc_ptr(dest, draster);
	}
    }
    return 0;
}

/* Copy a color bitmap. */
private int
mem_true56_copy_color(gx_device * dev,
	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
		      int x, int y, int w, int h)
{
    gx_device_memory * const mdev = (gx_device_memory *)dev;

    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
    mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
    return 0;
}

/* Copy an alpha map. */
private int
mem_true56_copy_alpha(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 color, int depth)
{
    /*
     * I do not know what to do about alpha.
     */
    return 0;
}

/* ================ "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(mem56_word_copy_mono, mem56_word_copy_color, mem56_word_fill_rectangle);

/* Here is the device descriptor. */
const gx_device_memory mem_true56_word_device =
mem_full_device("image56w", 56, 0, mem_open,
		gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
     mem56_word_copy_mono, mem56_word_copy_color, mem56_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. */
private int
mem56_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 * 56, w * 56, h, true);
    mem_true56_fill_rectangle(dev, x, y, w, h, color);
    mem_swap_byte_rect(base, raster, x * 56, w * 56, h, false);
    return 0;
}

/* Copy a bitmap. */
private int
mem56_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 * 56, w * 56, h, store);
    mem_true56_copy_mono(dev, base, sourcex, sraster, id,
			 x, y, w, h, zero, one);
    mem_swap_byte_rect(row, raster, x * 56, w * 56, h, false);
    return 0;
}

/* Copy a color bitmap. */
private int
mem56_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)
{
    gx_device_memory * const mdev = (gx_device_memory *)dev;
    byte *row;
    uint raster;

    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
    row = scan_line_base(mdev, y);
    raster = mdev->raster;
    mem_swap_byte_rect(row, raster, x * 56, w * 56, h, true);
    bytes_copy_rectangle(row + x * PIXEL_SIZE, raster, base + sourcex * PIXEL_SIZE,
    				sraster, w * PIXEL_SIZE, h);
    mem_swap_byte_rect(row, raster, x * 56, w * 56, h, false);
    return 0;
}

#endif /* !arch_is_big_endian */

--- NEW FILE: gdevm64.c ---
/* Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises, 2001 Artifex Software.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/

/*$Id: gdevm64.c,v 1.1 2002/08/22 07:12:28 henrys Exp $ */
/* 64-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 */

/* Define debugging statistics. */
#ifdef DEBUG
struct stats_mem64_s {
    long
	fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
	fprevc[257];
    double ftotal;
} stats_mem64;
static int prev_count;
static gx_color_index prev_colors[256];
# define INCR(v) (++(stats_mem64.v))
#else
# define INCR(v) DO_NOTHING
#endif


/* ================ Standard (byte-oriented) device ================ */

#undef chunk
#define chunk byte
#define PIXEL_SIZE 2

/* Procedures */
declare_mem_procs(mem_true64_copy_mono, mem_true64_copy_color, mem_true64_fill_rectangle);
private dev_proc_copy_alpha(mem_true64_copy_alpha);

/* The device descriptor. */
const gx_device_memory mem_true64_device =
mem_full_alpha_device("image64", 64, 0, mem_open,
		 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
     mem_true64_copy_mono, mem_true64_copy_color, mem_true64_fill_rectangle,
		      gx_default_map_cmyk_color, mem_true64_copy_alpha,
		 gx_default_strip_tile_rectangle, mem_default_strip_copy_rop,
		      mem_get_bits_rectangle);

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

/* Put a 64-bit color into the bitmap. */
#define put8(ptr, abcd, efgh)\
	(ptr)[0] = abcd, (ptr)[1] = efgh
/* Free variables: [m]dev, abcd, degh. */
#if arch_is_big_endian
/* Unpack a color into 32 bit chunks. */
#  define declare_unpack_color(abcd, efgh, color)\
	bits32 abcd = (color) >> 32;\
	bits32 efgh = (color)
#else
/* Unpack a color into 32 bit chunks. */
#  define declare_unpack_color(abcd, efgh, color)\
	bits32 abcd = (0x000000ff & ((color) >> 56)) |\
		      (0x0000ff00 & ((color) >> 40)) |\
		      (0x00ff0000 & ((color) >> 24)) |\
		      (0xff000000 & ((color) >> 8));\
	bits32 efgh = (0x000000ff & ((color) >> 24)) |\
		      (0x0000ff00 & ((color) >> 8)) |\
		      (0x00ff0000 & ((color) << 8)) |\
		      (0xff000000 & ((color) << 24))
#endif
#define dest32 ((bits32 *)dest)

/* Fill a rectangle with a color. */
private int
mem_true64_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;
    declare_scan_ptr(dest);
    declare_unpack_color(abcd, efgh, color);

    /*
     * In order to avoid testing w > 0 and h > 0 twice, we defer
     * executing setup_rect, and use fit_fill_xywh instead of
     * fit_fill.
     */
    fit_fill_xywh(dev, x, y, w, h);
    INCR(fill);
#ifdef DEBUG
    stats_mem64.ftotal += w;
#endif
    if (h <= 0)
	return 0;
    if (w >= 5) {
	INCR(fwide);
	setup_rect(dest);
#ifdef DEBUG
	{
	    int ci;
	    for (ci = 0; ci < prev_count; ++ci)
		if (prev_colors[ci] == color)
	    	    break;
	    INCR(fprevc[ci]);
	    if (ci == prev_count) {
		if (ci < countof(prev_colors))
	    	    ++prev_count;
		else
	    	    --ci;
	    }
	    if (ci) {
		memmove(&prev_colors[1], &prev_colors[0],
			ci * sizeof(prev_colors[0]));
		prev_colors[0] = color;
	    }
	}
#endif
	INCR(fcolor[min(w, 100)]);
	while (h-- > 0) {
	    register bits32 *pptr = dest32;
	    int w1 = w;

	    while (w1 >= 4) {
		put8(pptr, abcd, efgh);
		put8(pptr + 2, abcd, efgh);
		put8(pptr + 4, abcd, efgh);
		put8(pptr + 6, abcd, efgh);
		pptr += 4 * PIXEL_SIZE;
		w1 -= 4;
	    }
	    switch (w1) {
		case 1:
		    put8(pptr, abcd, efgh);
		    break;
		case 2:
		    put8(pptr, abcd, efgh);
		    put8(pptr + 2, abcd, efgh);
		    break;
		case 3:
		    put8(pptr, abcd, efgh);
		    put8(pptr + 2, abcd, efgh);
		    put8(pptr + 4, abcd, efgh);
		    break;
		case 0:
		    ;
	    }
	    inc_ptr(dest, draster);
	}
    } else {		/* w < 5 */
	INCR(fnarrow[max(w, 0)]);
	setup_rect(dest);
	switch (w) {
	    case 4:
		do {
		    put8(dest32, abcd, efgh);
		    put8(dest32 + 2, abcd, efgh);
		    put8(dest32 + 4, abcd, efgh);
		    put8(dest32 + 6, abcd, efgh);
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 3:
		do {
		    put8(dest32, abcd, efgh);
		    put8(dest32 + 2, abcd, efgh);
		    put8(dest32 + 4, abcd, efgh);
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 2:
		do {
		    put8(dest32, abcd, efgh);
		    put8(dest32 + 2, abcd, efgh);
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 1:
		do {
		    put8(dest32, abcd, efgh);
		    inc_ptr(dest, draster);
		}
		while (--h);
		break;
	    case 0:
	    default:
		;
	}
    }
    return 0;
}

/* Copy a monochrome bitmap. */
private int
mem_true64_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;
    int sbit;
    int first_bit;

    declare_scan_ptr(dest);

    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
    setup_rect(dest);
    line = base + (sourcex >> 3);
    sbit = sourcex & 7;
    first_bit = 0x80 >> sbit;
    if (zero != gx_no_color_index) {	/* Loop for halftones or inverted masks */
	/* (never used). */
	declare_unpack_color(abcd0, efgh0, zero);
	declare_unpack_color(abcd1, efgh1, one);
	while (h-- > 0) {
	    register bits32 *pptr = dest32;
	    const 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)
			put8(pptr, abcd1, efgh1);
		} else
		    put8(pptr, abcd0, efgh0);
		pptr += PIXEL_SIZE;
		if ((bit >>= 1) == 0)
		    bit = 0x80, sbyte = *sptr++;
	    }
	    while (--count > 0);
	    line += sraster;
	    inc_ptr(dest, draster);
	}
    } else if (one != gx_no_color_index) {	/* Loop for character and pattern masks. */
	/* This is used heavily. */
	declare_unpack_color(abcd1, efgh1, one);
	int first_mask = first_bit << 1;
	int first_count, first_skip;

	if (sbit + w > 8)
	    first_mask -= 1,
		first_count = 8 - sbit;
	else
	    first_mask -= first_mask >> w,
		first_count = w;
	first_skip = first_count * PIXEL_SIZE;
	while (h-- > 0) {
	    register bits32 *pptr = dest32;
	    const byte *sptr = line;
	    register int sbyte = *sptr++ & first_mask;
	    int count = w - first_count;

	    if (sbyte) {
		register int bit = first_bit;

		do {
		    if (sbyte & bit)
			put8(pptr, abcd1, efgh1);
		    pptr += PIXEL_SIZE;
		}
		while ((bit >>= 1) & first_mask);
	    } else
		pptr += first_skip;
	    while (count >= 8) {
		sbyte = *sptr++;
		if (sbyte & 0xf0) {
		    if (sbyte & 0x80)
			put8(pptr, abcd1, efgh1);
		    if (sbyte & 0x40)
			put8(pptr + 2, abcd1, efgh1);
		    if (sbyte & 0x20)
			put8(pptr + 4, abcd1, efgh1);
		    if (sbyte & 0x10)
			put8(pptr + 6, abcd1, efgh1);
		}
		if (sbyte & 0xf) {
		    if (sbyte & 8)
			put8(pptr + 8, abcd1, efgh1);
		    if (sbyte & 4)
			put8(pptr + 10, abcd1, efgh1);
		    if (sbyte & 2)
			put8(pptr + 12, abcd1, efgh1);
		    if (sbyte & 1)
			put8(pptr + 14, abcd1, efgh1);
		}
		pptr += 8 * PIXEL_SIZE;
		count -= 8;
	    }
	    if (count > 0) {
		register int bit = 0x80;

		sbyte = *sptr++;
		do {
		    if (sbyte & bit)
			put8(pptr, abcd1, efgh1);
		    pptr += PIXEL_SIZE;
		    bit >>= 1;
		}
		while (--count > 0);
	    }
	    line += sraster;
	    inc_ptr(dest, draster);
	}
    }
    return 0;
}

/* Copy a color bitmap. */
private int
mem_true64_copy_color(gx_device * dev,
	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
		      int x, int y, int w, int h)
{
    gx_device_memory * const mdev = (gx_device_memory *)dev;

    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
    mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
    return 0;
}

/* Copy an alpha map. */
private int
mem_true64_copy_alpha(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 color, int depth)
{
    /*
     * I do not know what to do about alpha.
     */
    return 0;
}

/* ================ "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(mem64_word_copy_mono, mem64_word_copy_color, mem64_word_fill_rectangle);

/* Here is the device descriptor. */
const gx_device_memory mem_true64_word_device =
mem_full_device("image64w", 64, 0, mem_open,
		gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
     mem64_word_copy_mono, mem64_word_copy_color, mem64_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. */
private int
mem64_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 * 64, w * 64, h, true);
    mem_true64_fill_rectangle(dev, x, y, w, h, color);
    mem_swap_byte_rect(base, raster, x * 64, w * 64, h, false);
    return 0;
}

/* Copy a bitmap. */
private int
mem64_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 * 64, w * 64, h, store);
    mem_true64_copy_mono(dev, base, sourcex, sraster, id,
			 x, y, w, h, zero, one);
    mem_swap_byte_rect(row, raster, x * 64, w * 64, h, false);
    return 0;
}

/* Copy a color bitmap. */
private int
mem64_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)
{
    gx_device_memory * const mdev = (gx_device_memory *)dev;
    byte *row;
    uint raster;

    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
    row = scan_line_base(mdev, y);
    raster = mdev->raster;
    mem_swap_byte_rect(row, raster, x * 64, w * 64, h, true);
    bytes_copy_rectangle(row + x * PIXEL_SIZE, raster, base + sourcex * PIXEL_SIZE,
    				sraster, w * PIXEL_SIZE, h);
    mem_swap_byte_rect(row, raster, x * 64, w * 64, h, false);
    return 0;
}

#endif /* !arch_is_big_endian */

--- NEW FILE: gdevxcf.c ---
/* Copyright (C) 2002 artofcode LLC.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/

/*$Id: gdevxcf.c,v 1.1 2002/08/22 07:12:28 henrys Exp $ */
/* Gimp (XCF) export device, supporting DeviceN color models. */

[...1386 lines suppressed...]
	
    }
    return code;
}

static int
xcf_print_page(gx_device_printer *pdev, FILE *file)
{
    xcf_write_ctx xc;

    xc.f = file;
    xc.offset = 0;

    xcf_setup_tiles(&xc, (xcf_device *)pdev);
    xcf_write_header(&xc, (xcf_device *)pdev);
    xcf_write_image_data(&xc, pdev);
    xcf_write_footer(&xc, (xcf_device *)pdev);

    return 0;
}


--- NEW FILE: gsovrc.c ---
/* Copyright (C) 2002 Aladdin Enterprises.  All rights reserved.
  
  This file is part of AFPL Ghostscript.
  
  AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  distributor accepts any responsibility for the consequences of using it, or
  for whether it serves any particular purpose or works at all, unless he or
  she says so in writing.  Refer to the Aladdin Free Public License (the
  "License") for full details.
  
  Every copy of AFPL Ghostscript must include a copy of the License, normally
  in a plain ASCII text file named PUBLIC.  The License grants you the right
  to copy, modify and redistribute AFPL Ghostscript, but only under certain
  conditions described in the License.  Among other things, the License
  requires that the copyright notice and this notice be preserved on all
  copies.
*/

/* $Id: gsovrc.c,v 1.1 2002/08/22 07:12:29 henrys Exp $ */
[...1132 lines suppressed...]
    }

    /* build the overprint device */
    opdev = gs_alloc_struct_immovable( mem,
                                       overprint_device_t,
                                       &st_overprint_device_t,
                                       "create overprint compositor" );
    if ((*popdev = (gx_device *)opdev) == 0)
        return_error(gs_error_VMerror);
    gx_device_init( (gx_device *)opdev, 
                    (const gx_device *)&gs_overprint_device,
                    mem,
                    true );
    gx_device_copy_params((gx_device *)opdev, tdev);
    gx_device_set_target((gx_device_forward *)opdev, tdev);

    /* set up the overprint parameters */
    return update_overprint_params( opdev,
                                    &((const gs_overprint_t *)pct)->params );
}

--- NEW FILE: gsovrc.h ---
/* Copyright (C) 2002 Aladdin Enterprises.  All rights reserved.
  
  This file is part of AFPL Ghostscript.
  
  AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  distributor accepts any responsibility for the consequences of using it, or
  for whether it serves any particular purpose or works at all, unless he or
  she says so in writing.  Refer to the Aladdin Free Public License (the
  "License") for full details.
  
  Every copy of AFPL Ghostscript must include a copy of the License, normally
  in a plain ASCII text file named PUBLIC.  The License grants you the right
  to copy, modify and redistribute AFPL Ghostscript, but only under certain
  conditions described in the License.  Among other things, the License
  requires that the copyright notice and this notice be preserved on all
  copies.
*/

/* $Id: gsovrc.h,v 1.1 2002/08/22 07:12:29 henrys Exp $ */
/* overprint/overprint mode compositor interface */

#ifndef gsovrc_INCLUDED
#  define gsovrc_INCLUDED

#include "gsstype.h"
#include "gscompt.h"

/*
 * Overprint compositor.
 *
 * The overprint and overprint mode capability allow drawing operations
 * to affect a subset of the set of color model components, rather than
 * all components. The overprint feature allows the set of affected
 * components to be determined by the color space, but independently of
 * the drawing color. Overprint mode allows both the color space and
 * drawing color to determine which components are affected.
 *
 * The significance of the overprint feature for a device is dependent on
 * the extent of rendering that is to be performed for that device:
 *
 *  1. High level devices, such as the PDFWrite and PSWrite devices,
 *     do not, in principle, require the graphic library to convert
 *     between color spaces and color models. These devices can accept
 *     color space descriptions, so conversion to a color model can be
 *     left to whatever application uses the generated file.
 *
 *     For these devices, overprint and overprint mode are just
 *     additional state parameters that are incorporated into the output
 *     file. These may or may not be supported. For example, overprint
 *     mode cannot be supported in the PSWrite device.
 *
 *     Note that the current implementation of PDFWrite and PSWrite
 *     do require the graphic library to convert between color spaces
 *     and a color model, for all objects except images. To implement
 *     the overprint feature under this design, the devices would
 *     have to support the get_bits_rectangle method, which means they
 *     would need to function as low-level devices. Since that defeats
 *     the purpose of having a high-level device, for the time being
 *     overprint and overprint mode are not supported for the PDFWrite
 *     and PSWrite devices.
 *
 *  2. Low level devices require the graphic library to convert between
 *     color spaces and color models, and perform actual rendering. For
 *     these devices both overprint and overprint mode require a form
 *     of mixing of the drawing color with any existing output. This
 *     mixing is mechanically similar to that required for transparency
 *     or raster op support, but differs from these because it affects 
 *     different color components differently (transparency and raster
 *     operations are applied uniformly to all color components).
 *
 * Because the implementation of overprint for high level devices is
 * either trivial or essentially impossible (short of dealing with them
 * as low level devices), the discussion below is restricted to the
 * implementation for low level devices.
 * 
 * In principle, the effects of overprint and overprint mode are
 * modified by changes to the current color, the current color space,
 * and the process color model. Changes in the latter are only
 * significant, however, if they change the number or identification of
 * color model components. This can only be done in a sensible way by
 * discarding any existing graphic output. So, for the preparation of a
 * single page of output, we need only be concerned about changes to the
 * current color or current color space.
 *
 * For typical graphic operations such as line drawing or area filling,
 * both the current color and the current color space remain constant.
 * Overprint and overprint mode are significant for these operations
 * only if the output page contained data prior to the operation. If
 * this is not the case, overprint is irrelevant, as the initial state
 * of any retained color components, and the state of these components
 * in the drawing color, will be the same.
 *
 * Aside from the devices that generate output, Ghostscript makes use
 * of two additional types of the devices for rendering. Forwarding
 * devices do not generate output of their own; they merely forward
 * rendering commands to a target device. Accumulating devices render
 * output to a special buffer (often part of clipping or a caching 
 * operation), which is subsequently sent to the primary output device 
 * in a lower-level form.
 *
 * It is conceivable that a forwarding device could be dependent on the
 * overprint feature (e.g.: an "inking" filter to determine how much
 * of each colorant is required in each area of the output), but this
 * is unlikely and, in practice, never seems to arise (in practice,
 * inking filters scan the fully generated output). Hence, we ignore
 * this possibility, and need not be concerned with overprint when
 * installing or removing forwarding devices.
 *
 * Overprint mode is of interest to accumulating devices only if these
 * devices either begin operation with a non-empty output buffer, or if
 * the current color or color space can change during the lifetime of
 * an instantiation of the device. Most instantiations of accumulating
 * devices live only for the rendering of a single graphic object, for
 * which neither the color or color space can change. There are a few
 * exceptions:
 *
 *  - Though images and shaded fills are single graphic objects, they
 *    involve (potentially) many colors. Conveniently, overprint mode
 *    does not apply to either images or shaded fills, so these cause
 *    no difficulty. For the same reason PatternType 2 patterns do
 *    not cause difficulty, though it is necessary to create/update
 *    the overprint compositor to reflect the colorspace included
 *    in the shading dictionary.
 *
 *  - The gs_pdf14_device, which implements the PDF 1.4 transparency
 *    facilities, is an accumulating device that supports only
 *    the high-level rendering methods (fill_path, etc.). Actual
 *    rendering is done with a separate marking device, an instance
 *    of which is created for each graphic object rendered. The
 *    marking device renders into the output buffer of the 
 *    gs_pdf14_device, which contains the results of prior rendering
 *    operations. Thus, overprint is significant to the marking
 *    device. The interaction of transparency and overprint are,
 *    however, more complex than can be captured by a simple
 *    compositor. The gs_pdf14_device and the corresponding device
 *    (will) implement overprint and overprint mode directly. These
 *    devices discard attempts to build an overprint compositor.
 *
 *  - The most essential exception involves colored tiling patterns.
 *    Both the color and color space may change multiple times
 *    during the rendering of a colored pattern. If a colored
 *    pattern is cached, an accurate implementation would require
 *    the cache to included compositor creation instructions.
 *    This is not possible in the current Ghostscript pattern
 *    cache (which has other problems independent of overprint).
 *    The best that can be done is to keep the overprint compositor
 *    current during the caching operation itself. For single level
 *    patterns, this will allow the tile instance to be rendered
 *    accurately, even if the tile does not properly overprint
 *    the output raster.
 *
 * Based on this reasoning, we can limit application of the overprint
 * compositor to a small numer of situations:
 *
 *  1. When the overprint or overprint mode parameter of the current
 *     graphic state is changed (the overprint mode parameter is
 *     ignored if overprint is set to false).
 *
 *  2. When the current color space changes, if overprint is set to true
 *     (the colorspace cannot be relevant if the overprint is false).
 *     There are a few exceptions to this rule for uncolored caches
 *     (user paths, FontType 3 fonts) and the anti-alias super-sampling.
 *
 *  3. If the device in the graphic state is changed, or if this device is
 *     reopened after having been closed (e.g.: due to the action of
 *     put_params), if the overprint parameter is set to true.
 *
 *  4. During grestore or setgstate (because the overprint/overprint
 *     mode parameters might change without the current device changing).
 *
 *  5. When creating the pattern accumulator device, if overprint is
 *     set to true.
 *
 * Unlike the other compositors used by Ghostscript (the alpha-channel
 * compositor and the implemented but not used raster operation
 * compositor), once created, the overprint compositor is made part of the
 * current graphic state, and assumes the lifetime and open/close
 * status of the device to which it is applied. In effect, the device to
 * which the compositor is applied will, for purposes of the graphic
 * state, cease to exist as as independent item. The only way to discard
 * the compositor is to change the current device.
 *
 * Subsequent invocations of create_compositor will not create a new
 * compositor. Rather, it changes the parameters of the existing
 * compositor device. The compositor functions with only a small
 * performance penalty if overprint is disabled, so there is no reason
 * to discard the compositor if oveprint is turned off.
 *
 * The compositor device will emulate the open/close state of the device
 * to which it is applied. This is accomplished by forwarding all open
 * and close requests. In addition, the compositor device will check the
 * status of the device to which it is applied after each put_params call,
 * and will change its own status to reflect this status. The underlying
 * device is required to close itself if an invocation of put_params
 * changes in the process color model.
 *
 * NB: It is not possible, without an excessive performance delay, for
 *     the compositor to detect all cases in which the device to which
 *     it is applied may close itself due to an error condition. We
 *     believe this will never cause difficulty in practice, as the
 *     closing of a device is not itself used as an error indication.
 *
 */

#ifndef gs_overprint_params_t_DEFINED
#  define gs_overprint_params_t_DEFINED
typedef struct gs_overprint_params_s    gs_overprint_params_t;
#endif

struct gs_overprint_params_s {

    /*
     * Are any component values to be retained?
     *
     * If this is false (overprint off), all other fields in the compositor
     * are ignored, and the compositor does nothing with respect to rendering
     * (it doesn't even impose a performance penalty).
     *
     * If this field is true, the retain_spot_comps, retain_zeroed_comps,
     * and potentially the retained_comps fields should be initialized.
     *
     * Note that this field may be false even if overprint is true. This
     * would be the case if the current color space was a Separation color
     * space with the component "All".
     */
    bool            retain_any_comps;

    /*
     * Are spot (non-process) color component values retained?
     *
     * If overprint is true, this field will be true for all color spaces
     * other than Separation/DeviceN color spaces.
     *
     * The overprint compositor will itself determine what constitutes a
     * process color. This is done by using the color space mapping
     * routines for the target device for all three standard device
     * color spaces (DeviceGray, DeviceRGB, and DeviceCMYK) and the
     * set of all possible colors with individual components either 0
     * or 1. Any color model component which is mapped to 0 for all of
     * these cases is considered a spot color.
     *
     * If this field is true, the drawn_comps field (see below) is ignored.
     */
    bool            retain_spot_comps;

    /*
     * Are component values retained when the drawing component value is 0?
     * This is the case if overprint and overprint mode are both true (this
     * is a PDF rather than a PostScript feature), and both the color space
     * and color model are DeviceCMYK. If this flag is set, drawing color
     * components that have 0 intensity will not affect the output.
     *
     * If this field is true, the drawn_comps field (see below) is ignored.
     */
    bool            retain_zeroed_comps;

    /*
     * The list of color model compoents to be retained (i.e.: that are
     * not affected by drawing operations). The field is bit-encoded;
     * the bit corresponding to component i is (1 << i).  This bit will be
     * 1 if the corresponding component is set from the drawing color, 0 if
     * it is to be left unaffected.
     */
    gx_color_index  drawn_comps;
};

/* some elementary macros for manipulating drawn_comps */
#define gs_overprint_set_drawn_comp(pparam, i)      \
    ((pparam)->drawn_comps |= 1 << (i))

#define gs_overprint_clear_drawn_comp(pparam, i)    \
    ((pparam)->drawn_comps &= ~(1 << 1))

#define gs_overprint_clear_all_drawn_comps(pparam)  \
    ((pparam)->drawn_comps = 0)

#define gs_overprint_get_drawn_comp(pparam, i)      \
    (((pparam)->drawn_comps & (1 << (i))) != 0)


/*
 * In the unlikely event that the overprint parameters will ever be
 * allocated on the heap, we provide GC structure descriptors for
 * them.
 */
extern_st(st_overprint_params);

#define public_st_overprint_params_t    /* in gsovrc.c */   \
    gs_public_st_simple( st_overprint_params,               \
                         gs_overprint_params_t,             \
                         "gs_overprint_params_t" )


/* create an overprint composition object */
extern  int    gs_create_overprint(
    gs_composite_t **               ppct,
    const gs_overprint_params_t *   pparams,
    gs_memory_t *                   mem );

/* verify that a compositor is the overprint compositor */
extern bool    gs_is_overprint_compositor(const gs_composite_t * pct);

#endif  /* gsovrc_INCLUDED */

--- NEW FILE: gsserial.c ---
/* Copyright (C) 2002 artofcode LLC.  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.

  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/
/* $Id: gsserial.c,v 1.1 2002/08/22 07:12:29 henrys Exp $ */
/* some utilities useful for converting objects to serial form */

#include "stdpre.h"
#include "gstypes.h"
#include "gsserial.h"


/*
 * Procedures for converint between integers and a variable-length,
 * little-endian string representation thereof. This scheme uses a
 * base-128 format with the high-order bit of each byte used as a
 * continuation flag ((b & 0x80) == 0 ==> this is the last byte of the
 * current number). See gsserial.h for complete information.
 */

/*
 * Determine the size of the string representation of an unsigned or
 * signed integer.
 */
int
enc_u_size_uint(uint uval)
{
    int     i = 1;

    while ((uval >>= enc_u_shift) > 0)
        ++i;
    return i;
}

int
enc_s_size_int(int ival)
{
    /* MIN_INT must be handled specially */
    if (ival < 0) {
        if (ival == enc_s_min_int)
            return enc_s_sizew_max;
        ival = -ival;
    }
    return enc_u_sizew((uint)ival << 1);
}

/*
 * Encode a signed or unsigned integer. The array pointed to by ptr is
 * assumed to be large enough. The returned pointer immediately follows
 * the encoded number.
 */
byte *
enc_u_put_uint(uint uval, byte * ptr)
{
    int     tmp_v;

    for (;;) {
        tmp_v = uval & (enc_u_lim_1b - 1);
        if ((uval >>= enc_u_shift) == 0)
            break;
        *ptr++ = tmp_v | enc_u_lim_1b;
    }
    *ptr++ = tmp_v;
    return ptr;
}

byte *
enc_s_put_int(int ival, byte * ptr)
{
    uint    uval, tmp_v;

    /* MIN_INT must be handled specially */
    if (ival < 0 && ival != enc_s_min_int)
        uval = (uint)-ival;
    else
        uval = (uint)ival;

    tmp_v = (uval & enc_s_max_1b) | (ival < 0 ? enc_s_max_1b + 1 : 0);
    if (uval > enc_s_max_1b) {
        *ptr++ = tmp_v | enc_u_lim_1b;
        return enc_u_put_uint(uval >> enc_s_shift0, ptr);
    } else {
        *ptr++ = tmp_v;
        return ptr;
    }
}


/*
 * Decode an integer string for a signed or unsigned integer. Note that
 * two forms of this procedure are provide, to allow both const and non-
 * const byte pointers to be handled (the former is far more common).
 */
const byte *
enc_u_get_uint(uint * pval, const byte * ptr)
{
    uint    uval = 0, tmp_val;
    int     shift = 0;

    while (((tmp_val = *ptr++) & enc_u_lim_1b) != 0) {
        uval |= (tmp_val & (enc_u_lim_1b - 1)) << shift;
        shift += enc_u_shift;
    }
    *pval = uval | (tmp_val << shift);
    
    return ptr;
}

byte *
enc_u_get_uint_nc(uint * pval, byte * ptr)
{
    const byte *    tmp_ptr = ptr;

    tmp_ptr = enc_u_get_uint(pval, tmp_ptr);
    return ptr += tmp_ptr - ptr;
}

const byte *
enc_s_get_int(int * pval, const byte * ptr)
{
    int     ival = *ptr++;
    bool    neg = false;

    if ((ival & (enc_s_max_1b + 1)) != 0) {
        ival ^= enc_s_max_1b + 1;
        neg = true;
    }
    if ((ival & enc_u_lim_1b) != 0) {
        uint     tmp_val;

        ival ^= enc_u_lim_1b;
        ptr = enc_u_get_uint(&tmp_val, ptr);
        ival |= tmp_val << enc_s_shift0;
    }
    if (neg && ival >= 0)    /* >= check required for enc_s_min_int */
        ival = -ival;

    *pval = ival;
    return ptr;
}

byte *
enc_s_get_int_nc(int * pval, byte * ptr)
{
    const byte *    tmp_ptr = ptr;

    tmp_ptr = enc_s_get_int(pval, tmp_ptr);
    return ptr += tmp_ptr - ptr;
}

#ifdef UNIT_TEST

#include <stdio.h>
#include <string.h>


/*
 * Encoding and decoding of integers is verified using a round-trip process,
 * integer ==> string ==> integer. The string size is separately checked to
 * verify that it is not too large (it can't be too small if the round-trip
 * check works). If an integer x is represented by nbytes, then it must be
 * that x >= 1U << (7 * (n - 1)) (unsigned; 1U << (7 * (n - 2) + 6) for
 * signed integers; there is no need to check 1-byte encodings).
 *
 * It is possible to check every value, but this is not necessary. Any
 * failures that arise will do so in the vicinty of powers of 2.
 */

/* check the length of an encoded string */
void
check_u_sizew(uint uval, int len)
{
    if (len != enc_u_sizew(uval))
        fprintf( stderr,
                 "Size calculation error for (usigned) %u (%d != %d)\n",
                 uval,
                 len,
                 enc_u_sizew(uval) );
    if ( len > 1                                                           &&
         (len > enc_u_sizew_max  || uval < 1U << (enc_u_shift * (len - 1)))  )
        fprintf( stderr, "unsigned encoding too large for %u (%d bytes)\n",
                 uval,
                 len );
}

void
check_s_sizew(int ival, int len)
{
    uint    uval;

    if (len != enc_s_sizew(ival))
        fprintf( stderr,
                 "Size calculation error for (signed) %d (%d != %d)\n",
                 ival,
                 len,
                 enc_s_sizew(ival) );
    if (len <= 1)
        return;
    if (ival < 0 && ival != enc_s_min_int)
        uval = (uint)-ival;
    else
        uval = (uint)ival;
    if ( len > enc_s_sizew_max                                 ||
         uval < 1U << (enc_s_shift1 * (len - 2) + enc_s_shift0)  )
        fprintf( stderr,
                 "signed encoding too large for %d (%d bytes)\n",
                 ival,
                 len );
}

/* check the encode and decode procedures on a value */
void
check_u(uint uval)
{
    byte            buff[32];   /* generous size */
    byte *          cp0 = buff;
    const byte *    cp1 = buff;
    byte *          cp2 = buff;
    uint            res_val;

    memset(buff, 0, sizeof(buff));
    enc_u_putw(uval, cp0);
    check_u_sizew(uval, cp0 - buff);
    memset(cp0, (uval == 0 ? 0x7f : 0), sizeof(buff) - (cp0 - buff));

    enc_u_getw(res_val, cp1);
    if (cp1 != cp0)
        fprintf( stderr,
                 "encoded length disparity (const) for "
                 "(unsigned) %u (%d != %d)\n",
                 uval,
                 cp0 - buff,
                 cp1 - buff );
    if (res_val != uval)
        fprintf( stderr,
                 "decode error (const) for (unsigned) %u (!= %u)\n",
                 uval,
                 res_val );

    enc_u_getw_nc(res_val, cp2);
    if (cp2 != cp0)
        fprintf( stderr,
                 "encoded length disparity (non-const) for "
                 "(unsigned) %u (%d != %d)\n",
                 uval,
                 cp0 - buff,
                 cp1 - buff );
    if (res_val != uval)
        fprintf( stderr,
                 "decode error (non-const) for (unsigned) %u (!= %u)\n",
                 uval,
                 res_val );
}

void
check_s(int ival)
{
    byte            buff[32];   /* generous size */
    byte *          cp0 = buff;
    const byte *    cp1 = buff;
    byte *          cp2 = buff;
    int             res_val;

    memset(buff, 0, sizeof(buff));
    enc_s_putw(ival, cp0);
    check_s_sizew(ival, cp0 - buff);
    memset(cp0, (ival == 0 ? 0x7f : 0), sizeof(buff) - (cp0 - buff));

    enc_s_getw(res_val, cp1);
    if (cp1 != cp0)
        fprintf( stderr,
                 "encoded length disparity (const) for "
                 "(signed) %d (%d != %d)\n",
                 ival,
                 cp0 - buff,
                 cp1 - buff );
    if (res_val != ival)
        fprintf( stderr,
                 "decode error (const) for (signed) %d (!= %d)\n",
                 ival,
                 res_val );

    enc_s_getw_nc(res_val, cp2);
    if (cp1 != cp0)
        fprintf( stderr,
                 "encoded length disparity (non-const) for "
                 "(signed) %d (%d != %d)\n",
                 ival,
                 cp0 - buff,
                 cp1 - buff );
    if (res_val != ival)
        fprintf( stderr,
                 "decode error (non-const) for (unsigned) %d (!= %d)\n",
                 ival,
                 res_val );
}

/* test the provided value and some surrounding values */
void
check_u_vals(uint uval)
{
    uint    diff = 1;

    check_u(uval);
    do {
        check_u(uval - diff);
        check_u(uval + diff);
    } while ((diff <<= 1) < uval);
}

void
check_s_vals(int ival)
{
    int     diff = 1;

    check_s(ival);
    if (ival == enc_s_min_int) {
        do {
            check_s(ival - diff);
            check_s(ival + diff);
        } while ((diff <<= 1) != enc_s_min_int);
    } else {
        int     abs_val = (ival < 0 ? -ival : ival);

        do {
            check_s(ival - diff);
            check_s(ival + diff);
        } while ((diff <<= 1) < abs_val);
    }
}


int
main(void)
{
    uint     uval;
    int      ival;

    check_u_vals(0);
    for (uval = 1; uval != 0; uval <<= 1)
        check_u_vals(uval);

    check_s_vals(0);
    for (ival = 1; ival != 0; ival <<= 1) {
        check_s_vals(ival);
        if (ival != enc_s_min_int)
            check_s_vals(-ival);
    }

    fprintf(stderr, "all done\n");
    return 0;
}

#endif  /* UNIT_TEST */

--- NEW FILE: gsserial.h ---
/* Copyright (C) 2002 artofcode LLC.  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.

  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/
/* $Id: gsserial.h,v 1.1 2002/08/22 07:12:29 henrys Exp $ */
/* some general structures useful for converting objects to serial form */

#ifndef gsserial_INCLUDED
#  define gsserial_INCLUDED

/*
 * A variable-length, little-endian format for encoding (unsigned)
 * integers.
 *
 * This format represents integers is a base-128 form that is quite
 * compact for parameters whose values are typically small.
 *
 * A number x is represented by the string of bytes s[0], ... s[n],
 * where:
 *
 *    s[i] & 0x80 == 0x80 for i = 0, ..., n - 1,
 *    s[n] & 0x80 == 0x00 
 *
 * and
 *
 *    x == s[0] + (s[1] << 7) + (s[2] << 14) + ... (s[n] << (n * 7))
 *
 * In words, the high-order bit is used as a continue bit; it is off
 * only for the last byte of the string. The low-order 7 bits of each
 * byte for the base-128 digit, with the low-order digits preceding
 * the high-order digits.
 *
 * The encoding considers all numbers as unsigned. It may be used with
 * signed quantities (just change the interpretation), though obviously
 * it is inefficient with negative numbers.
 *
 * This code was originally part of the command list device module.
 * Though the names used here differ from those used from those used in
 * that module, they follow the same pattern, which accounts for certain
 * peculiarities.
 */
#define enc_u_shift     7
#define enc_u_lim_1b    (1U << enc_u_shift)
#define enc_u_lim_2b    (1U << (2 * enc_u_shift))

/* determine the encoded size of an (unsigned) integer */
extern  int     enc_u_size_uint(uint);

#define enc_u_sizew(w)                                      \
    ( (uint)(w) < enc_u_lim_1b                              \
        ? 1                                                 \
        : (uint)(w) < enc_u_lim_2b ? 2 : enc_u_size_uint(w) ) 

/* similarly, for a pair of values (frequently used for points) */
#define enc_u_size2w(w1, w2)                        \
    ( ((uint)(w1) | (uint)(w2)) < enc_u_lim_1b      \
        ? 2                                         \
        : enc_u_size_uint(w1) + enc_u_size_uint(w2) )

#define enc_u_sizexy(xy)    enc_u_size2w((xy).x, (xy).y)

/* the maximum size of an encoded uint */
#define enc_u_sizew_max ((8 * sizeof(uint) + enc_u_shift - 1) / enc_u_shift)

/* encode and decode an unsigned integer; note special handling of const */
extern  byte *          enc_u_put_uint(uint, byte *);
extern  const byte *    enc_u_get_uint(uint *, const byte *);
extern  byte *          enc_u_get_uint_nc(uint *, byte *);

#define enc_u_putw(w, p)                                        \
    BEGIN                                                       \
        if ((uint)(w) < enc_u_lim_1b)                           \
            *(p)++ = (byte)(w);                                 \
        else if ((uint)(w) < enc_u_lim_2b) {                    \
            *(p)++ = enc_u_lim_1b | ((w) & (enc_u_lim_1b - 1)); \
            *(p)++ = (w) >> enc_u_shift;                        \
        } else                                                  \
            (p) = enc_u_put_uint((w), (p));                     \
    END

/* encode a pair of integers; this is often used with points */
#define enc_u_put2w(w1, w2, p)                          \
    BEGIN                                               \
        if (((uint)(w1) | (uint)(w2)) < enc_u_lim_1b) { \
            *(p)++ = (w1);                              \
            *(p)++ = (w2);                              \
        } else {                                        \
            (p) = enc_u_put_uint((w1), (p));            \
            (p) = enc_u_put_uint((w2), (p));            \
        }                                               \
    END

#define enc_u_putxy(xy, p)    enc_u_put2w((xy).x, (xy).y, (p))


/* decode an unsigned integer */
#define enc_u_getw(w, p)                        \
    BEGIN                                       \
        if (((w) = *(p)) >= enc_u_lim_1b) {     \
            uint    tmp_w;                      \
                                                \
            (p) = enc_u_get_uint(&tmp_w, (p));  \
            (w) = tmp_w;                        \
        } else                                  \
            ++(p);                              \
    END

#define enc_u_getw_nc(w, p)                         \
    BEGIN                                           \
        if (((w) = *(p)) >= enc_u_lim_1b) {         \
            uint    tmp_w;                          \
                                                    \
            (p) = enc_u_get_uint_nc(&tmp_w, (p));   \
            (w) = tmp_w;                            \
        } else                                      \
            ++(p);                                  \
    END

/* decode a pair of unsigned integers; this is often used for points */
#define enc_u_get2w(w1, w2, p)  \
    BEGIN                       \
        enc_u_getw((w1), (p));  \
        enc_u_getw((w2), (p));  \
    END

#define enc_u_get2w_nc(w1, w2, p)   \
    BEGIN                           \
        enc_u_getw_nc((w1), (p));   \
        enc_u_getw_nc((w2), (p));   \
    END

#define enc_u_getxy(xy, p)      enc_u_get2w((xy).x, (xy).y, (p))
#define enc_u_getxy_nc(xy, p)   enc_u_get2w_nc((xy).x, (xy).y, (p))


/*
 * An encoding mechanism similar to that above for signed integers. This
 * makes use of the next-to-highest order bit of the first byte to encode
 * the sign of the number. Thus, the number x is represented by the bytes
 * s[0], ... s[n], where:
 *
 *    s[i] & 0x80 == 0x80 for i = 0, ..., n - 1,
 *    s[n] & 0x80 == 0x00,
 *
 *    s[0] & 0x40 == 0x40 if x < 0,
 *    s[0] & 0x40 == 0x00 if x >- 0,
 *
 * and
 *
 *    abs(x) = s[0] + (s[1] << 6) + (s[2] << 13) + ... (s[n] * (n * 7 - 1))
 *
 * This encoding is less efficient than the unsigned encoding for non-
 * negative numbers but is much more efficient for numbers that might be
 * negative.
 *
 * There are no special 2-value versions of these macros, as it is not
 * possible to test both values against the limit simultaneously. We do,
 * however, provide point encoding macros.
 */
#define enc_s_shift0    6
#define enc_s_shift1    (enc_s_shift0 + 1)
#define enc_s_max_1b    ((1U << enc_s_shift0) - 1)
#define enc_s_min_1b    (-(int)enc_s_max_1b)
#define enc_s_max_2b    ((1U << (enc_s_shift0 + enc_s_shift1) - 1))
#define enc_s_min_2b    (-enc_s_max_2b)
#define enc_s_min_int   ((int)(1U << (8 * sizeof(int) - 1)))

/* determine the encoded size of a signed integer */
extern  int     enc_s_size_int(int);

/* the maximum size of encoded integer */
#define enc_s_sizew_max   ((8 * sizeof(int)) / enc_s_shift1 + 1)

#define enc_s_sizew(v)                                                  \
    ( (v) >= 0 ? enc_u_sizew((uint)(v) << 1)                            \
               : (v) != enc_s_min_int ? enc_u_sizew((uint)-(v) << 1)    \
                                      : enc_s_sizew_max )

#define enc_s_sizexy(xy)    (enc_s_sizew((xy).x) + enc_s_sizew((xy).y))


/* encode and decode a signed integfer; note special handling of const */
extern  byte *          enc_s_put_int(int, byte *);
extern  const byte *    enc_s_get_int(int *, const byte *);
extern  byte *          enc_s_get_int_nc(int *, byte *);

#define enc_s_putw(v, p)                                            \
    BEGIN                                                           \
        if ((int)(v) <= enc_s_max_1b && (int)(v) >= enc_s_min_1b)   \
            *(p)++ =  ((v) & enc_s_max_1b)                          \
                    | ((v) < 0 ? (enc_s_max_1b + 1) : 0);           \
        else                                                        \
            (p) = enc_s_put_int((v), (p));                          \
    END

#define enc_s_putxy(xy, p)          \
    BEGIN                           \
        enc_s_putw((xy).x, (p));    \
        enc_s_putw((xy).y, (p));    \
    END

#define enc_s_getw(v, p)                                \
    BEGIN                                               \
        if (((v = *p) & (1U << enc_s_shift1)) != 0) {   \
            int     tmp_v;                              \
                                                        \
            (p) = enc_s_get_int(&tmp_v, (p));           \
            (v) = tmp_v;                                \
        } else {                                        \
            if (((v) & (1U << enc_s_shift0)) != 0)      \
                (v) = -((v) & enc_s_max_1b);            \
            ++(p);                                      \
        }                                               \
    END

#define enc_s_getw_nc(v, p)                             \
    BEGIN                                               \
        if (((v = *p) & (1U << enc_s_shift1)) != 0) {   \
            int     tmp_v;                              \
                                                        \
            (p) = enc_s_get_int_nc(&tmp_v, (p));        \
            (v) = tmp_v;                                \
        } else {                                        \
            if (((v) & (1U << enc_s_shift0)) != 0)      \
                (v) = -((v) & enc_s_max_1b);            \
            ++(p);                                      \
        }                                               \
    END

#define enc_s_getxy(xy, p)          \
    BEGIN                           \
        enc_s_getw((xy).x, (p));    \
        enc_s_getw((xy).y, (p));    \
    END

#define enc_s_getxy_nc(xy, p)       \
    BEGIN                           \
        enc_s_getw_nc((xy).x, (p)); \
        enc_s_getw_nc((xy).y, (p)); \
    END

#endif  /* gsserial_INCLUDED */

--- NEW FILE: gswts.c ---
/* Copyright (C) 2002 artofcode LLC.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/
/*$Id: gswts.c,v 1.1 2002/08/22 07:12:29 henrys Exp $ */
/* Screen generation for Well Tempered Screening. */
#include "stdpre.h"
#include <stdlib.h> /* for malloc */
[...1111 lines suppressed...]

    mat.xx = xres / 72.0;
    mat.xy = 0;
    mat.yx = 0;
    mat.yy = yres / 72.0;

    h.frequency = 175;
    h.angle = 30;

    wcp = wts_pick_cell_size(&h, &mat);
    dlprintf2("cell size = %d x %d\n", wcp->width, wcp->height);
    wse = gs_wts_screen_enum_new(wcp);
    wts_run_enum_squaredot(wse);
    wts_sort_blue(wse);
    ws = wts_screen_from_enum(wse);

    dump_thresh(ws, 512, 512);
    return 0;
}
#endif

--- NEW FILE: gswts.h ---
/* Copyright (C) 2002 artofcode LLC.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/
/*$Id: gswts.h,v 1.1 2002/08/22 07:12:29 henrys Exp $ */
#ifndef gswts_INCLUDED
#  define gswts_INCLUDED

#ifndef gs_wts_screen_enum_t_DEFINED
#  define gs_wts_screen_enum_t_DEFINED
typedef struct gs_wts_screen_enum_s gs_wts_screen_enum_t;
#endif

typedef struct gx_wts_cell_params_s gx_wts_cell_params_t;

typedef enum {
    WTS_SCREEN_J,
    WTS_SCREEN_H
    /* very plausibly, rational should be another type. */
} wts_screen_type;

/* Note: this corresponds roughly to the SP structure in the WTS code. */
struct gx_wts_cell_params_s {
    wts_screen_type t;
    int width;
    int height;
    double ufast;
    double vfast;
    double uslow;
    double vslow;
};

gx_wts_cell_params_t *
wts_pick_cell_size(gs_screen_halftone *ph, const gs_matrix *pmat);

gs_wts_screen_enum_t *
gs_wts_screen_enum_new(gx_wts_cell_params_t *wcp);

int
gs_wts_screen_enum_currentpoint(gs_wts_screen_enum_t *wse, gs_point *ppt);

int
gs_wts_screen_enum_next(gs_wts_screen_enum_t *wse, floatp value);

int
wts_sort_blue(gs_wts_screen_enum_t *wse);

int
wts_sort_cell(gs_wts_screen_enum_t *wse);

wts_screen_t *
wts_screen_from_enum(const gs_wts_screen_enum_t *wse);

void
gs_wts_free_enum(gs_wts_screen_enum_t *wse);

void
gs_wts_free_screen(wts_screen_t *wts);

#endif




--- NEW FILE: gxdevndi.c ---
/* Copyright (C) 1989, 1995, 1996, 1998, 1999 Aladdin Enterprises.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/

/*$Id: gxdevndi.c,v 1.1 2002/08/22 07:12:29 henrys Exp $ */
#include "gx.h"
#include "gsstruct.h"
#include "gsdcolor.h"
#include "gxdevice.h"
#include "gxlum.h"
#include "gxcmap.h"
#include "gxdither.h"
#include "gzht.h"
#include "gxfrac.h"
#include "gxwts.h"

/*
 * Binary halftoning algorithms.
 *
 * The procedures in this file use halftoning (if necessary)
 * to implement a given device color that has already gone through
 * the transfer function.  There are two major cases: gray and color.
 * Gray halftoning always uses a binary screen.  Color halftoning
 * uses either a fast algorithm with a binary screen that produces
 * relatively poor approximations, or a very slow algorithm with a
 * general colored screen (or screens) that faithfully implements
 * the Adobe specifications.
 */

/* Tables for fast computation of fractional color levels. */
/* We have to put the table before any uses of it because of a bug */
/* in the VAX C compiler. */
/* We have to split up the definition of the table itself because of a bug */
/*  in the IBM AIX 3.2 C compiler. */
private const gx_color_value q0[] = {
    0
};
private const gx_color_value q1[] = {
    0, frac_color_(1, 1)
};
private const gx_color_value q2[] = {
    0, frac_color_(1, 2), frac_color_(2, 2)
};
private const gx_color_value q3[] = {
    0, frac_color_(1, 3), frac_color_(2, 3), frac_color_(3, 3)
};
private const gx_color_value q4[] = {
    0, frac_color_(1, 4), frac_color_(2, 4), frac_color_(3, 4),
    frac_color_(4, 4)
};
private const gx_color_value q5[] = {
    0, frac_color_(1, 5), frac_color_(2, 5), frac_color_(3, 5),
    frac_color_(4, 5), frac_color_(5, 5)
};
private const gx_color_value q6[] = {
    0, frac_color_(1, 6), frac_color_(2, 6), frac_color_(3, 6),
    frac_color_(4, 6), frac_color_(5, 6), frac_color_(6, 6)
};
private const gx_color_value q7[] = {
    0, frac_color_(1, 7), frac_color_(2, 7), frac_color_(3, 7),
    frac_color_(4, 7), frac_color_(5, 7), frac_color_(6, 7), frac_color_(7, 7)
};

/* We export fc_color_quo for the fractional_color macro in gzht.h. */
const gx_color_value *const fc_color_quo[8] = {
    q0, q1, q2, q3, q4, q5, q6, q7
};

/* Begin code for setting up WTS device color. This should probably
   move into its own module. */

/**
 * gx_render_device_DevN_wts: Render DeviceN color by halftoning with WTS.
 *
 * This routine is the primary constructor for WTS device colors.
 * Note that, in the WTS code path, we sample the plane_vector array
 * during device color construction, while in the legacy code path,
 * it is sampled in the set_ht_colors procedure, invoked from
 * fill_rectangle. Does it affect correctness? I don't think so, but
 * it needs to be tested.
 **/
private int
gx_render_device_DeviceN_wts(frac * pcolor,
			     gx_device_color * pdevc, gx_device * dev,
			     gx_device_halftone * pdht,
			     const gs_int_point * ht_phase)
{
    int i;
    gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
    int num_comp = pdht->num_comp;

    for (i = 0; i < num_comp; i++) {
	cv[i] = 0;
    }

    pdevc->type = gx_dc_type_wts;
    pdevc->colors.wts.w_ht = pdht;

    if (dev->color_info.separable_and_linear != GX_CINFO_SEP_LIN) {
	/* Monochrome case may be inverted. */
	pdevc->colors.wts.plane_vector[1] =
	    dev_proc(dev, encode_color)(dev, cv);
    }
    for (i = 0; i < num_comp; i++) {
	pdevc->colors.wts.levels[i] = pcolor[i];
	cv[i] = gx_max_color_value;
	pdevc->colors.wts.plane_vector[i] =
	    dev_proc(dev, encode_color)(dev, cv);
	cv[i] = 0;
    }
    pdevc->colors.wts.num_components = num_comp;
    return 0;
}

/*
 * Render DeviceN possibly by halftoning.
 *  pcolors = pointer to an array color values (as fracs)
 *  pdevc - pointer to device color structure
 *  dev = pointer to device data structure
 *  pht = pointer to halftone data structure
 *  ht_phase  = halftone phase
 *  gray_colorspace = true -> current color space is DeviceGray.
 *  This is part of a kludge to minimize differences in the
 *  regression testing.
 */
int
gx_render_device_DeviceN(frac * pcolor,
	gx_device_color * pdevc, gx_device * dev,
	gx_device_halftone * pdht, const gs_int_point * ht_phase,
	bool gray_colorspace)
{
    uint max_value = (dev->color_info.max_components == 1) ?
	dev->color_info.dither_grays - 1 :
	dev->color_info.dither_colors - 1;
    frac rem_color[GS_CLIENT_COLOR_MAX_COMPONENTS];
    frac dither_check = 0;
    uint int_color[GS_CLIENT_COLOR_MAX_COMPONENTS];
    gx_color_value vcolor[GS_CLIENT_COLOR_MAX_COMPONENTS];
    int i;
    int num_colors = dev->color_info.num_components;
    uint l_color[GS_CLIENT_COLOR_MAX_COMPONENTS];

    if (pdht && pdht->components && pdht->components[0].corder.wts)
	return gx_render_device_DeviceN_wts(pcolor, pdevc, dev, pdht,
					    ht_phase);

    /* TO_DO_DEVICEN - kludge to minimize DeviceN regressions */
    if (gray_colorspace || num_colors == 1)
	for (i = 0; i < num_colors; i++) {
	    unsigned long hsize = pdht ?
		    (unsigned) pdht->components[i].corder.num_levels
	    	    : 1;
	    unsigned long nshades = hsize * max_value + 1;
	    long shade = nshades * pcolor[i] / (frac_1_long + 1);
	    int_color[i] = shade / hsize;
	    l_color[i] = shade % hsize;
	    dither_check |= l_color[i];
	}
    else {

        /* Compute the quotient and remainder of each color component */
        /* with the actual number of available colors. */
        switch (max_value) {
	    case 1:		/* 8 or 16 colors */
	        for (i = 0; i < num_colors; i++) {
	            if (pcolor[i] == frac_1) {
		        rem_color[i] = 0;
		        int_color[i] = 1;
		    }
		    else {
		        rem_color[i] = pcolor[i];
		        dither_check |= rem_color[i];
		        int_color[i] = 0;
		    }
	        }
	        break;
	    default:
	        {
		    ulong want_x;

	            for (i = 0; i < num_colors; i++) {
		        want_x = (ulong) max_value * pcolor[i];
		        int_color[i] = frac_1_quo(want_x);
		        rem_color[i] = frac_1_rem(want_x, int_color[i]);
		        dither_check |= rem_color[i];
	            }
	        }
        }

	for (i = 0; i < num_colors; i++)
	    l_color[i] = rem_color[i] * pdht->components[i].corder.num_levels
				/ frac_1;
    }

    /* Check for no dithering required */
    if (!dither_check) {
	for (i = 0; i < num_colors; i++)
	    vcolor[i] = fractional_color(int_color[i], max_value);
	color_set_pure(pdevc, dev_proc(dev, encode_color)(dev, vcolor));
	return 0;
    }


#ifdef DEBUG
    if (gs_debug_c('c')) {
	dlprintf1("[c]ncomp=%d ", num_colors);
	for (i = 0; i < num_colors; i++)
	    dlprintf1("0x%x, ", pcolor[i]);
	dlprintf("-->\n   ");
	for (i = 0; i < num_colors; i++)
	    dlprintf2("%x+0x%x, ", int_color[i], rem_color[i]);
	dlprintf("-->\n");
    }
#endif

    /* Use the slow, general colored halftone algorithm. */

    for (i = 0; i < num_colors; i++)
        _color_set_c(pdevc, i, int_color[i], l_color[i]);
    gx_complete_halftone(pdevc, num_colors, pdht);

    color_set_phase_mod(pdevc, ht_phase->x, ht_phase->y,
			    pdht->lcm_width, pdht->lcm_height);

    /* Determine if we are using only one component */
    if (!(pdevc->colors.colored.plane_mask &
	 (pdevc->colors.colored.plane_mask - 1))) {
	/* We can reduce this color to a binary halftone or pure color. */
	return gx_devn_reduce_colored_halftone(pdevc, dev);
    }

    return 1;
}

/* Reduce a colored halftone to a binary halftone or pure color. */
/* This routine is called when only one component is being halftoned. */
int
gx_devn_reduce_colored_halftone(gx_device_color *pdevc, gx_device *dev)
{
    int planes = pdevc->colors.colored.plane_mask;
    int gray_index = dev->color_info.gray_index;
    int num_colors = dev->color_info.num_components;
    gx_color_value max_color = (num_colors == 1 && gray_index == 0) ?
	dev->color_info.dither_grays - 1 :
	dev->color_info.dither_colors - 1;
    uint b[GX_DEVICE_COLOR_MAX_COMPONENTS];
    gx_color_value v[GX_DEVICE_COLOR_MAX_COMPONENTS];
    gx_color_index c0, c1;
    int i;

    for (i = 0; i < num_colors; i++) {
        b[i] = pdevc->colors.colored.c_base[i];
        v[i] = fractional_color(b[i], max_color);
    }
    c0 = dev_proc(dev, encode_color)(dev, v);

    if (planes == 0) {
	/*
	 * Use a pure color.  This case is unlikely, but it can occur if
	 * (and only if) the difference of each component from the nearest
	 * device color is less than one halftone level.
	 */
	color_set_pure(pdevc, c0);
	return 0;
    } else {
	/* Use a binary color. */
	int i = 0;
	uint bi;
	const gx_device_halftone *pdht = pdevc->colors.colored.c_ht;
	/*
	 * NB: the halftone orders are all set up for an additive color
	 *     space.  To use these work with a subtractive color space, it is
	 *     necessary to invert both the color level and the color
	 *     pair. Note that if the original color was provided an
	 *     additive space, this will reverse (in an approximate sense)
	 *     the color conversion performed to express the color in
	 *     subtractive space.
	 */
	bool invert = dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE;
	uint level;

	/* Convert plane mask bit position to component number */
	/* Determine i = log2(planes);  This works for powers of two */
	while (planes > 7) {
	    i += 3;
	    planes >>= 3;
	}
	i += planes >> 1;  /* log2 for 1,2,4 */

	bi = b[i] + 1;
	v[i] = fractional_color(bi, max_color);
	level = pdevc->colors.colored.c_level[i];
        c1 = dev_proc(dev, encode_color)(dev, v);
	if (invert) {
	    level = pdht->components[i].corder.num_levels - level;
	    color_set_binary_halftone_component(pdevc, pdht, i, c1, c0, level);
	} else
	    color_set_binary_halftone_component(pdevc, pdht, i, c0, c1, level);
					    
	return 1;
    }
}

--- NEW FILE: gxdevndi.h ---
/* Copyright (C) 1994, 1995, 1996, 1997, 1998 Aladdin Enterprises.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/

/*$Id: gxdevndi.h,v 1.1 2002/08/22 07:12:29 henrys Exp $ */
/* Interface to gxdevndi.c */

/* This is the halfoning handlers for DeviceN colors */

#ifndef gxdevndi_INCLUDED
#  define gxdevndi_INCLUDED

#include "gxfrac.h"

#ifndef gx_device_halftone_DEFINED
#  define gx_device_halftone_DEFINED
typedef struct gx_device_halftone_s gx_device_halftone;
#endif

/* Render a color, possibly by halftoning. */
/* Return as for gx_render_[device_]gray. */
int gx_render_device_color_devn(P10(frac red, frac green, frac blue, frac white,
			       bool cmyk, gx_color_value alpha,
			       gx_device_color * pdevc, gx_device * dev,
			       gx_device_halftone * pdht,
			       const gs_int_point * ht_phase));


#endif /* gxdevndi_INCLUDED */

--- NEW FILE: gxdhtserial.c ---
/* Copyright (C) 2002 artofcode LLC.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/

/* $Id: */
/* Serialization and de-serialization for (traditional) halftones */

#include "memory_.h"
#include <assert.h>
#include "gx.h"
#include "gscdefs.h"
#include "gserrors.h"
#include "gsstruct.h"
#include "gsutil.h"             /* for gs_next_ids */
#include "gzstate.h"
#include "gxdevice.h"           /* for gzht.h */
#include "gzht.h"
#include "gswts.h"
#include "gxdhtres.h"
#include "gsserial.h"
#include "gxdhtserial.h"


/*
 * Declare the set of procedures that return resident halftones. This
 * declares both the array of procedures and their type. It is used
 * only to check if a transmitted halftone order matches one in ROM.
 */
extern_gx_device_halftone_list();


/*
 * An enumeration of halftone transfer functions. These must distinguish
 * between cases in which no transfer function is present, and when one
 * is present but provides the identity transformation (an empty
 * PostScript array).
 */
typedef enum {
    gx_ht_tf_none = 0,
    gx_ht_tf_identity,
    gx_ht_tf_complete
} gx_ht_tf_type_t;

/* enumeration to distinguish well-tempered screening orders from others */
typedef enum {
    gx_ht_traditional,
    gx_ht_wts
} gx_ht_order_type_t;


/*
 * Serialize a transfer function. These will occupy one byte if they are
 * not present or provide an identity mapping,
 * 1 + transfer_map_size * sizeof(frac) otherwise.
 *
 * Returns:
 *
 *    0, with *psize set the the amount of space required, if successful
 *
 *    gs_error_rangecheck, with *psize set to the size required, if the
 *        original *psize was not large enough
 */
private int
gx_ht_write_tf(
    const gx_transfer_map * pmap,
    byte *                  data,    
    uint *                  psize )
{
    int                     req_size = 1;   /* minimum of one byte */

    /* check for sufficient space */
    if ( pmap != 0 && pmap->proc != gs_identity_transfer)
        req_size += sizeof(pmap->values);
    if (req_size > *psize) {
        *psize = req_size;
        return gs_error_rangecheck;
    }

    if (req_size == 1)
        *data = (byte)(pmap == 0 ? gx_ht_tf_none : gx_ht_tf_identity);
    else {
        *data++ = (byte)gx_ht_tf_complete;
        memcpy(data, pmap->values, sizeof(pmap->values));
    }

    *psize = req_size;
    return 0;
}

/*
 * Reconstruct a transfer function from its serial representation. The
 * buffer provided is expected to be large enough to hold the entire
 * transfer function.
 *
 * Returns the number of bytes read, or < 0 in the event of an error.
 */
private int
gx_ht_read_tf(
    gx_transfer_map **  ppmap,
    const byte *        data,
    uint                size,
    gs_memory_t *       mem )
{
    gx_ht_tf_type_t     tf_type;
    gx_transfer_map *   pmap;

    /* read the type byte */
    if (--size < 0)
        return_error(gs_error_rangecheck);
    tf_type = (gx_ht_tf_type_t)*data++;

    /* if no transfer function, exit now */
    if (tf_type == gx_ht_tf_none) {
        *ppmap = 0;
        return 1;
    }

    /* allocate a transfer map */
    pmap = gs_alloc_struct( mem,
                            gx_transfer_map,
                            &st_transfer_map,
                            "gx_ht_read_tf" );
    if (pmap == 0)
        return_error(gs_error_VMerror);

    pmap->id = gs_next_ids(1);
    pmap->closure.proc = 0;
    pmap->closure.data = 0;
    if (tf_type == gx_ht_tf_identity) {
        gx_set_identity_transfer(pmap);
        return 1;
    } else if (tf_type == gx_ht_tf_complete && size >= sizeof(pmap->values)) {
        memcpy(pmap->values, data, sizeof(pmap->values));
        pmap->proc = gs_mapped_transfer;
        return 1 + sizeof(pmap->values);
    } else {
        gs_free_object(mem, pmap, "gx_ht_read_tf");
        return_error(gs_error_rangecheck);
    }
}


/*
 * Serialize a halftone component. The only part that is serialized is the
 * halftone order; the other two components are only required during
 * halftone construction.
 *
 * Returns:
 *
 *    0, with *psize set the the amount of space required, if successful
 *
 *    gs_error_rangecheck, with *psize set to the size required, if the
 *        original *psize was not large enough
 *
 *    some other error code, with *psize unchange, in the event of an
 *        error other than lack of space
 */
private int
gx_ht_write_component(
    const gx_ht_order_component *   pcomp,
    byte *                          data,
    uint *                          psize )
{
    const gx_ht_order *             porder = &pcomp->corder;
    byte *                          data0 = data;
    int                             code, levels_size, bits_size, tmp_size = 0;
    int                             req_size;

    /*
     * There is no need to transmit the comp_number field, as this must be
     * the same as the index in the component array (see gx_ht_write).
     *
     * There is also no reason to transmit the colorant name (cname), as
     * this is only used by some high-level devices that would not be targets
     * of the command list device (and even those devices should be able to
     * get the information from their color models).
     *
     * This leaves the order itself.
     *
     * Check if we are a well-tempered-screening order. Serialization of these
     * is not yet implemented.
     */
    if (porder->wts != 0)
       return_error(gs_error_unknownerror);     /* not yet supported */

    /*
     * The following order fields are not transmitted:
     *
     *  params          Only required during halftone cell construction
     *
     *  wse, wts        Only used for well-tempered screens (see above)
     *
     *  raster          Can be re-calculated by the renderer from the width
     *
     *  orig_height,    The only potential use for these parameters is in
     *  orig_shift      this routine; they are not useful to the renderer.
     *
     *  full_height     Can be re-calculated by the renderer from the
     *                  height, width, and shift values.
     *
     *  data_memory     Must be provided by the renderer.
     *
     *  cache           Must be provided by the renderer.
     *
     *  screen_params   Ony required during halftone cell construction
     *
     * In addition, the procs parameter is passed as an index into the
     * ht_order_procs_table, as the renderer may not be in the same address
     * space as the writer.
     *
     * Calculate the size required.
     */
    levels_size = porder->num_levels * sizeof(porder->levels[0]); 
    bits_size = porder->num_bits * porder->procs->bit_data_elt_size;
    req_size =   1          /* gx_ht_type_t */
               + enc_u_sizew(porder->width)
               + enc_u_sizew(porder->height)
               + enc_u_sizew(porder->shift)
               + enc_u_sizew(porder->num_levels)
               + enc_u_sizew(porder->num_bits)
               + 1          /* order procs, as index into table */
               + levels_size
               + bits_size;
    code = gx_ht_write_tf(porder->transfer, data, &tmp_size);
    if (code < 0 && code != gs_error_rangecheck)
        return code;
    req_size += tmp_size;
    if (req_size > *psize) {
        *psize = req_size;
        return gs_error_rangecheck;
    }

    /* identify this as a traditional halftone */
    *data++ = (byte)gx_ht_traditional;

    /* write out the dimensional data */
    enc_u_putw(porder->width, data);
    enc_u_putw(porder->height, data);
    enc_u_putw(porder->shift, data);
    enc_u_putw(porder->num_levels, data);
    enc_u_putw(porder->num_bits, data);

    /* white out the procs index */
    *data++ = porder->procs - ht_order_procs_table;

    /* copy the levels array and whitening order array */
    memcpy(data, porder->levels, levels_size);
    data += levels_size;
    memcpy(data, porder->bit_data, bits_size);
    data += bits_size;

    /* write out the transfer function */
    tmp_size = *psize - (data - data0);
    if ((code = gx_ht_write_tf(porder->transfer, data, &tmp_size)) == 0)
        *psize = tmp_size + (data - data0);
    return code;
}

/*
 * Reconstruct a halftone component from its serial representation. The
 * buffer provided is expected to be large enough to hold the entire
 * halftone component.
 *
 * Because halftone components are allocated in arrays (an unfortunate
 * arrangement, as it prevents component sharing), a pointer to an
 * already allocated component structure is passed as an operand, as
 * opposed to the more normal mechanism that would have a read routine
 * allocate the component. The memory pointer is still passed, however,
 * as the levels and bit_data arrays must be allocated.
 *
 * Returns the number of bytes read, or < 0 in the event of an error.
 */
private int
gx_ht_read_component(
    gx_ht_order_component * pcomp,
    const byte *            data,
    uint                    size,
    gs_memory_t *           mem )
{
    gx_ht_order             new_order;
    const byte *            data0 = data;
    const byte *            data_lim = data + size;
    gx_ht_order_type_t      order_type;
    int                     i, code, levels_size, bits_size;
    const gx_dht_proc *     phtrp = gx_device_halftone_list;

    /* check the order type */
    if (--size < 0)
        return_error(gs_error_rangecheck);
    order_type = (gx_ht_order_type_t)*data++;

    /* currently only the traditional halftone order are supported */
    if (order_type != gx_ht_traditional)
       return_error(gs_error_unknownerror);

    /*
     * For performance reasons, the number encoding macros do not
     * support full buffer size verification. The code below verifies
     * that a minimum number of bytes is available, then converts
     * blindly and does not check again until the various integers are
     * read. Obviously this can be hazardous, but should not be a
     * problem in practice, as the calling code should have verified
     * that the data provided holds the entire halftone.
     */
    if (size < 7)
        return_error(gs_error_rangecheck);
    enc_u_getw(new_order.width, data);
    enc_u_getw(new_order.height, data);
    enc_u_getw(new_order.shift, data);
    enc_u_getw(new_order.num_levels, data);
    enc_u_getw(new_order.num_bits, data);
    if (data >= data_lim)
        return_error(gs_error_rangecheck);
    new_order.procs = &ht_order_procs_table[*data++];

    /* calculate the space required for levels and bit data */
    levels_size = new_order.num_levels * sizeof(new_order.levels[0]);
    bits_size = new_order.num_bits * new_order.procs->bit_data_elt_size;

    /* + 1 below is for the minimal transfer function */
    if (data + bits_size + levels_size + 1 > data_lim)
        return_error(gs_error_rangecheck);

    /*
     * Allocate the levels and bit data structures. The gx_ht_alloc_ht_order
     * has a name that is both strange and misleading. The routine does
     * not allocate a halftone order. Rather, it initializes the order,
     * and allocates the levels and bit data arrays. In particular, it
     * sets all of the following fields:
     *
     *    wse = 0,
     *    wts = 0,
     *    width = operand width
     *    height = operand height
     *    raster = bitmap_raster(operand width)
     *    shift = operand shift
     *    orig_height = operand height
     *    orig_shift = operand strip_shift
     *    num_levels = operand num_levels
     *    num_bits = operand num_bits
     *    procs = operand procs
     *    levels = newly allocated array
     *    bit_data = new allocated array
     *    cache = 0
     *    transfer = 0
     *
     * Since several of the list fields are already set, this call
     * effectively sets them to the values they already have. This is a
     * bit peculiar but not otherwise harmful.
     *
     * For reasons that are not known and are probably historical, the
     * procedure does not initialize the params or screen_params fields.
     * In the unlikely event that these fields are ever contain pointers,
     * we initialize them explicitly here. Wse, params, and scrren_params
     * probably should not occur in the device halftone at all; they are
     * themselves historical artifacts.
     */
    code = gx_ht_alloc_ht_order( &new_order,
                                 new_order.width,
                                 new_order.height,
                                 new_order.num_levels,
                                 new_order.num_bits,
                                 new_order.shift,
                                 new_order.procs,
                                 mem );
    if (code < 0)
        return code;
    memset(&new_order.params, 0, sizeof(new_order.params));
    memset(&new_order.screen_params, 0, sizeof(new_order.screen_params));

    /* fill in the levels and bit_data arrays */
    memcpy(new_order.levels, data, levels_size);
    data += levels_size;
    memcpy(new_order.bit_data, data, bits_size);
    data += bits_size;

    /* process the transfer function */
    code = gx_ht_read_tf(&new_order.transfer, data, data_lim - data, mem);
    if (code < 0) {
        gx_ht_order_release(&new_order, mem, false);
        return code;
    }
    data += code;

    /*
     * Check to see if the order is in ROM. Since it is possible (if not
     * particularly likely) that the command list writer and renderer do
     * not have the same set of ROM-based halftones, the full halftone
     * order is transmitted and compared against the set ROM set provided
     * by the renderer. If there is a match, the transmitted version is
     * discarded and the ROM version used.
     *
     * It is not clear which, if any or the currently used devices
     * provide a ROM-based halftone order set.
     */
    for (i = 0; phtrp[i] != 0; i++) {
        const gx_device_halftone_resource_t *const *    pphtr = phtrp[i]();
        const gx_device_halftone_resource_t *           phtr;

        while ((phtr = *pphtr++) != 0) {
            /*
             * This test does not check for strict equality of the order,
             * nor is strict equality necessary. The ROM data will replace
             * just the levels and bit_data arrays of the transmitted
             * order, so only these must be the same. We don't even care
             * if the ROM's levels and bit_data arrays are larger; we
             * will never check values beyond the range required by the
             * current order.
             */
            if ( memcmp(phtr->levels, new_order.levels, levels_size) == 0  &&
                 memcmp(phtr->bit_data, new_order.bit_data, bits_size) == 0  ) {
                /* the casts below are required to discard const qualifiers */
                gs_free_object(mem, new_order.bit_data, "gx_ht_read_component");
                new_order.bit_data = (void *)phtr->bit_data;
                gs_free_object(mem, new_order.levels, "gx_ht_read_component");
                new_order.levels = (uint *)phtr->levels;
                goto done;
            }
        }
    }

  done:
    /* everything OK, save the order and return the # of bytes read */
    pcomp->corder = new_order;
    pcomp->cname = 0;
    return data - data0;
}


/*
 * Serialize a halftone. The essential step is the serialization of the
 * halftone orders; beyond this only the halftone type must be
 * transmitted.
 *
 * Returns:
 *
 *    0, with *psize set the the amount of space required, if successful
 *
 *    gs_error_rangecheck, with *psize set to the size required, if the
 *        original *psize was not large enough
 *
 *    some other error code, with *psize unchange, in the event of an
 *        error other than lack of space
 */
int
gx_ht_write(
    const gx_device_halftone *  pdht,
    const gx_device *           dev,
    byte *                      data,
    uint *                      psize )
{
    int                         num_comps = dev->color_info.num_components;
    int                         i, code;
    uint                        req_size = 1, used_size = 1;
                                /* 1 for halftone type */

    /*
     * With the introduction of color models, there should never be a
     * halftone that includes just one component. Enforce this
     * restriction, even though it is not present in much of the rest
     * of the code.
     *
     * NB: the pdht->order field is ignored by this code.
     */
    assert(pdht != 0 && pdht->components != 0);

    /*
     * The following fields do not need to be transmitted:
     *
     *  order       Ignored by this code (see above).
     *
     *  rc, id      Recreated by the allocation code on the renderer.
     *
     *  num_comp    Must be the same as dev->color_info.num_components,
     *              which must be the same on both the writer and the
     *              rendered. Indeed, the entire color model must be the
     *              same for writer and renderer.
     *
     *  lcm_width,  Can be recreated by the de-serialization code on the
     *  lcm_height  the renderer. Since halftones are transmitted
     *              infrequently (for normal jobs), the time required
     *              for re-calculation is not significant.
     *
     * Hence, the only fields that must be serialized are the type and
     * the components.
     *
     * Several halftone components may be identical, but there is
     * currently no simple way to determine this. Halftones are normally
     * transmitted only once per page, so it is not clear that use of
     * such information would significantly reduce command list size.
     */
    assert(pdht->num_comp == num_comps);

    /* calculate the required data space */
    for ( i = 0, code = gs_error_rangecheck;
          i < num_comps && code == gs_error_rangecheck;
          i++) {
        uint     tmp_size = 0;

        /* sanity check */
        assert(i == pdht->components[i].comp_number);

        code = gx_ht_write_component( &pdht->components[i],
                                      data,
                                      &tmp_size );
        req_size += tmp_size;
    }
    if (code < 0 && code != gs_error_rangecheck)
        return code;
    else if (*psize < req_size) {
        *psize = req_size;
        return 0;
    }
    req_size = *psize;

    /* the halftone type is known to fit in a byte */
    *data++ = (byte)pdht->type;

    /* serialize the halftone components */
    for (i = 0, code = 0; i < num_comps && code == 0; i++) {
        uint    tmp_size = req_size - used_size;

        code = gx_ht_write_component( &pdht->components[i],
                                      data,
                                      &tmp_size );
        used_size += tmp_size;
        data += tmp_size;
    }

    if (code < 0) {
        if (code == gs_error_rangecheck)
            code = gs_error_unknownerror;
        return code;
    }

    *psize = used_size;
    return 0;
}

/*
 * Reconstruct a halftone from its serial representation, and install it
 * as the current halftone. The buffer provided is expected to be large
 * enough to hold the entire halftone.
 *
 * The reading and installation phases are combined in this routine so as
 * to avoid unnecessarily allocating a device halftone and its component
 * array, just to release them immediately after installation is complete.
 * There is also not much reason to reconstuct a halftone except to make
 * it the current halftone.
 *
 * Returns the number of bytes read, or <0 in the event of an error.
 */
int
gx_ht_read_and_install(
    gs_imager_state *       pis,
    const gx_device *       dev,
    const byte *            data,
    uint                    size,
    gs_memory_t *           mem )
{
    gx_ht_order_component   components[GX_DEVICE_COLOR_MAX_COMPONENTS];
    const byte *            data0 = data;
    gx_device_halftone      dht;
    int                     num_comps = dev->color_info.num_components;
    int                     i, code;

    /* fill in some fixed fields */
    memset(&dht.order, 0, sizeof(dht.order));
    memset(&dht.rc, 0, sizeof(dht.rc));
    dht.id = gs_no_id;      /* updated during installation */
    dht.components = components;
    dht.num_comp = num_comps;
    dht.lcm_width = 1;      /* recalculated during installation */
    dht.lcm_height = 1;

    /* clear pointers in the components array in case we need to abort */
    memset(components, 0, sizeof(components));

    /* get the halftone type */
    if (size-- < 1)
        return_error(gs_error_rangecheck);
    dht.type = (gs_halftone_type)(*data++);

    /* process the component orders */
    for (i = 0, code = 0; i < num_comps && code >= 0; i++) {
        code = gx_ht_read_component(&components[i], data, size, mem);
        if (code >= 0) {
            size -= code;
            data += code;
        }
    }

    /* if everything is OK, install the halftone */
    if (code >= 0)
        code = gx_imager_dev_ht_install(pis, &dht, dht.type, dev);

    /*
     * Regardless of the success of installation, discard the allocated
     * elements now. The gx_device_halftone_release procedure can't be
     * used, as the components array is on the stack rather than in the
     * heap. We must also pay special attention to the transfer functions,
     * if any, as there reference counts are not incremented until the
     * halftone is stored in the imager state. Hence, we only want to
     * release them if their reference counts are still 0.
     */
    for (i = 0; i < num_comps; i++) {
        if (components[i].corder.transfer->rc.ref_count != 0)
            components[i].corder.transfer = 0;
        gx_ht_order_release(&components[i].corder, mem, false);
    }

    return code < 0 ? code : data - data0;
}

--- NEW FILE: gxdhtserial.h ---
/* Copyright (C) 2002 artofcode LLC.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/

/* $Id: */
/* Interface to [de-]serialization for (traditional) halftones */

#ifndef gxdhtserial_INCLUDED
#  define gxdhtserial_INCLUDED

#ifndef gs_memory_DEFINED
#  define gs_memory_DEFINED
typedef struct gs_memory_s  gs_memory_t;
#endif

#ifndef gx_device_DEFINED
#  define gx_device_DEFINED
typedef struct gx_device_s  gx_device;
#endif

#ifndef gx_device_halftone_DEFINED
#  define gx_device_halftone_DEFINED
typedef struct gx_device_halftone_s gx_device_halftone;
#endif

#ifndef gs_imager_state_DEFINED
#  define gs_imager_state_DEFINED
typedef struct gs_imager_state_s    gs_imager_state;
#endif


/*
 * Serialize a halftone.
 *
 * Returns:
 *
 *    0, with *psize set the the amount of space required, if successful
 *
 *    gs_error_rangecheck, with *psize set to the size required, if the
 *        original *psize was not large enough
 *
 *    some other error code, with *psize unchange, in the event of an
 *        error other than lack of space
 */
extern  int     gx_ht_write( const gx_device_halftone * pdht,
                             const gx_device *          dev,
                             byte *                     data,
                             uint *                     psize );

/*
 * Reconstruct a halftone from its serial representation, and install it
 * as the current halftone. The buffer provided is expected to be large
 * enough to hold the entire halftone.
 *
 * The reading and installation phases are combined in this routine so as
 * to avoid unnecessarily allocating a device halftone and its component
 * array, just to release them immediately after installation is complete.
 * There is also not much reason to reconstuct a halftone except to make
 * it the current halftone.
 *
 * Returns the number of bytes read, or < 0 in the event of an error.
 */
extern  int     gx_ht_read_and_install( gs_imager_state *   pis,
                                        const gx_device *   dev,
                                        const byte *        data,
                                        uint                size,
                                        gs_memory_t *       mem );

#endif  /* gxdhtserail_INCLUDED */

--- NEW FILE: gxoprect.c ---
/* Copyright (C) 2002 Aladdin Enterprises.  All rights reserved.
  
  This file is part of AFPL Ghostscript.
  
  AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  distributor accepts any responsibility for the consequences of using it, or
  for whether it serves any particular purpose or works at all, unless he or
  she says so in writing.  Refer to the Aladdin Free Public License (the
  "License") for full details.
  
  Every copy of AFPL Ghostscript must include a copy of the License, normally
  in a plain ASCII text file named PUBLIC.  The License grants you the right
  to copy, modify and redistribute AFPL Ghostscript, but only under certain
  conditions described in the License.  Among other things, the License
  requires that the copyright notice and this notice be preserved on all
  copies.
*/

/* $Id: gxoprect.c,v 1.1 2002/08/22 07:12:29 henrys Exp $ */
/* generic (very slow) overprint fill rectangle implementation */

#include "memory_.h"
#include "gx.h"
#include "gserrors.h"
#include "gsutil.h"             /* for gs_next_ids */
#include "gxdevice.h"
#include "gsdevice.h"
#include "gxgetbit.h"
#include "gxoprect.h"
#include "gsbitops.h"


/*
 * Unpack a scanline for a depth < 8. In this case we know the depth is
 * divisor of 8 and thus a power of 2, which implies that 8 / depth is
 * also a power of 2.
 */
private void
unpack_scanline_lt8(
    gx_color_index *    destp,
    const byte *        srcp,
    int                 src_offset,
    int                 width,
    int                 depth )
{
    byte                buff = 0;
    int                 i = 0, shift = 8 - depth, p_per_byte = 8 / depth;

    /* exit early if nothing to do */
    if (width == 0)
        return;

    /* skip over src_offset */
    if (src_offset >= p_per_byte) {
        srcp += src_offset / p_per_byte;
        src_offset &= (p_per_byte - 1);
    }
    if (src_offset > 0) {
        buff = *srcp++ << (src_offset * depth);
        i = src_offset;
        width += src_offset;
    }

    /* process the interesting part of the scanline */
    for (; i < width; i++, buff <<= depth) {
        if ((i & (p_per_byte - 1)) == 0)
            buff = *srcp++;
        *destp++ = buff >> shift;
    }
}

/*
 * Pack a scanline for a depth of < 8. Note that data prior to dest_offset
 * and any data beyond the width must be left undisturbed.
 */
private void
pack_scanline_lt8(
    const gx_color_index *  srcp,
    byte *                  destp,
    int                     dest_offset,
    int                     width,
    int                     depth )
{
    byte                    buff = 0;
    int                     i = 0, p_per_byte = 8 / depth;

    /* exit early if nothing to do */
    if (width == 0)
        return;

    /* skip over dest_offset */
    if (dest_offset >= p_per_byte) {
        destp += dest_offset / p_per_byte;
        dest_offset &= (p_per_byte - 1);
    }
    if (dest_offset > 0) {
        buff = *destp++ >> (8 - dest_offset * depth);
        i = dest_offset;
        width += dest_offset;
    }

    /* process the interesting part of the scanline */
    for (; i < width; i++) {
        buff = (buff << depth) | *srcp++;
        if ((i & (p_per_byte - 1)) == p_per_byte - 1)
            *destp++ = buff;
    }
    if ((i &= (p_per_byte - 1)) != 0) {
        int     shift = depth * (p_per_byte - i);
        int     mask = (1 << shift) - 1;

        *destp = (*destp & mask) | (buff << shift);
    }
}

/*
 * Unpack a scanline for a depth >= 8. In this case, the depth must be
 * a multiple of 8.
 */
private void
unpack_scanline_ge8(
    gx_color_index *    destp,
    const byte *        srcp,
    int                 src_offset,
    int                 width,
    int                 depth )
{
    gx_color_index      buff = 0;
    int                 i, j, bytes_per_p = depth >> 3;

    /* skip over src_offset */
    srcp += src_offset * bytes_per_p;

    /* process the interesting part of the scanline */
    width *= bytes_per_p;
    for (i = 0, j = 0; i < width; i++) {
        buff = (buff << 8) | *srcp++;
        if (++j == bytes_per_p) {
            *destp++ = buff;
            buff = 0;
            j = 0;
        }
    }
}

/*
 * Pack a scanline for depth >= 8.
 */
private void
pack_scanline_ge8(
    const gx_color_index *  srcp,
    byte *                  destp,
    int                     dest_offset,
    int                     width,
    int                     depth )
{
    gx_color_index          buff = 0;
    int                     i, j, bytes_per_p = depth >> 3;
    int                     shift = depth - 8;

    /* skip over dest_offset */
    destp += dest_offset;

    /* process the interesting part of the scanline */
    width *= bytes_per_p;
    for (i = 0, j = bytes_per_p - 1; i < width; i++, buff <<= 8) {
        if (++j == bytes_per_p) {
            buff = *srcp++;
            j = 0;
        }
        *destp++ = buff >> shift;
    }
}


/*
 * Perform the fill rectangle operation for a non-separable color encoding
 * that requires overprint support. This situation requires that colors be
 * decoded, modified, and re-encoded. These steps must be performed per
 * output pixel, so there is no hope of achieving good performance.
 * Consequently, only minimal performance optimizations are applied below.
 *
 * The overprint device structure is known only in gsovr.c, and thus is not
 * available here. The required information from the overprint device is,
 * therefore, provided via explicit operands.  The device operand points to
 * the target of the overprint compositor device, not the compositor device
 * itself. The drawn_comps bit array and the memory descriptor pointer are
 * also provided explicitly as operands.
 *
 * Returns 0 on success, < 0 in the event of an error.
 */
int
gx_overprint_generic_fill_rectangle(
    gx_device *             tdev,
    gx_color_index          drawn_comps,
    int                     x,
    int                     y,
    int                     w,
    int                     h,
    gx_color_index          color,
    gs_memory_t *           mem )
{
    gx_color_value          src_cvals[GX_DEVICE_COLOR_MAX_COMPONENTS];
    gx_color_index *        pcolor_buff = 0;
    byte *                  gb_buff = 0;
    gs_get_bits_params_t    gb_params;
    gs_int_rect             gb_rect;
    int                     depth = tdev->color_info.depth;
    int                     bit_x, start_x, end_x, raster, code;
    void                    (*unpack_proc)( gx_color_index *,
                                            const byte *,
                                            int, int, int );
    void                    (*pack_proc)( const gx_color_index *,
                                          byte *,
                                          int, int, int );

    fit_fill(tdev, x, y, w, h);
    bit_x = x * depth;
    start_x = bit_x & ~(8 * align_bitmap_mod - 1);
    end_x = bit_x + w * depth;

    /* select the appropriate pack/unpack routines */
    if (depth >= 8) {
        unpack_proc = unpack_scanline_ge8;
        pack_proc = pack_scanline_ge8;
    } else {
        unpack_proc = unpack_scanline_lt8;
        pack_proc = pack_scanline_lt8;
    }

    /* decode the source color */
    if ((code = dev_proc(tdev, decode_color)(tdev, color, src_cvals)) < 0)
        return code;

    /* allocate space for a scanline of color indices */
    pcolor_buff = (gx_color_index *)
                      gs_alloc_bytes( mem,
                                      w * sizeof(gx_color_index),
                                      "overprint generic fill rectangle" );
    if (pcolor_buff == 0)
        return gs_note_error(gs_error_VMerror);

    /* allocate a buffer for the returned data */
    raster = bitmap_raster(end_x - start_x);
    gb_buff = gs_alloc_bytes(mem, raster, "overprint generic fill rectangle");
    if (gb_buff == 0) {
        gs_free_object( mem,
                        pcolor_buff,
                        "overprint generic fill rectangle" );
        return gs_note_error(gs_error_VMerror);
    }

    /*
     * Initialize the get_bits parameters. The selection of options is
     * based on the following logic:
     *
     *  - Overprint is only defined with respect to components of the
     *    process color model, so the retrieved information must be kept
     *    in that color model. The gx_bitmap_format_t bitfield regards
     *    this as the native color space.
     *
     *  - Overprinting and alpha compositing don't mix, so there is no
     *    reason to retrieve the alpha information.
     *
     *  - Data should be returned in the depth of the process color
     *    model. Though this depth could be specified explicitly, there
     *    is little reason to do so. 
     *
     *  - Though overprint is much more easily implemented with planar
     *    data, there is no planar version of the copy_color method to
     *    send the modified data back to device. Hence, we must retrieve
     *    data in chunky form.
     *
     *  - It is not possible to modify the raster data "in place", as
     *    doing so would bypass any other forwarding devices currently
     *    in the device "stack" (e.g.: a bounding box device). Hence,
     *    we must work with a copy of the data, which is passed to the
     *    copy_color method at the end of fill_rectangle operation.
     *
     *  - Though we only require data for those planes that will not be
     *    modified, there is no benefit to returning less than the full
     *    data for each pixel if the color encoding is not separable.
     *    Since this routine will be used only for encodings that are
     *    not separable, we might as well ask for full information.
     *
     *  - Though no particular alignment and offset are required, it is
     *    useful to make the copy operation as fast as possible. Ideally
     *    we would calculate an offset so that the data achieves optimal
     *    alignment. Alas, some of the devices work much more slowly if
     *    anything but GB_OFFSET_0 is specified, so that is what we use.
     */
    gb_params.options =  GB_COLORS_NATIVE
                       | GB_ALPHA_NONE
                       | GB_DEPTH_ALL
                       | GB_PACKING_CHUNKY
                       | GB_RETURN_COPY
                       | GB_ALIGN_STANDARD
                       | GB_OFFSET_0
                       | GB_RASTER_STANDARD;
    gb_params.x_offset = 0;     /* for consistency */
    gb_params.data[0] = gb_buff;
    gb_params.raster = raster;

    gb_rect.p.x = x;
    gb_rect.q.x = x + w;

    /* process each scanline separately */
    while (h-- > 0 && code >= 0) {
        gx_color_index *    cp = pcolor_buff;
        int                 i;

        gb_rect.p.y = y++;
        gb_rect.q.y = y;
        code = dev_proc(tdev, get_bits_rectangle)( tdev,
                                                   &gb_rect,
                                                   &gb_params,
                                                   0 );
        if (code < 0)
            break;
        unpack_proc(pcolor_buff, gb_buff, 0, w, depth);
        for (i = 0; i < w; i++, cp++) {
            gx_color_index  comps;
            int             j;
            gx_color_value  dest_cvals[GX_DEVICE_COLOR_MAX_COMPONENTS];
        
            if ((code = dev_proc(tdev, decode_color)(tdev, *cp, dest_cvals)) < 0)
                break;
            for (j = 0, comps = drawn_comps; comps != 0; ++j, comps >>= 1) {
                if ((comps & 0x1) != 0)
                    dest_cvals[j] = src_cvals[j];
            }
            *cp = dev_proc(tdev, encode_color)(tdev, dest_cvals);
        }
        pack_proc(pcolor_buff, gb_buff, 0, w, depth);
        code = dev_proc(tdev, copy_color)( tdev,
                                           gb_buff,
                                           0,
                                           raster,
                                           gs_no_bitmap_id,
                                           x, y - 1, w, 1 );
    }

    gs_free_object( mem,
                    gb_buff,
                    "overprint generic fill rectangle" );
    gs_free_object( mem,
                    pcolor_buff,
                    "overprint generic fill rectangle" );

    return code;
}



/*
 * Replication of 2 and 4 bit patterns to fill a mem_mono_chunk.
 */
private mono_fill_chunk fill_pat_2[4] = {
    mono_fill_make_pattern(0x00), mono_fill_make_pattern(0x55),
    mono_fill_make_pattern(0xaa), mono_fill_make_pattern(0xff)
};

private mono_fill_chunk fill_pat_4[16] = {
    mono_fill_make_pattern(0x00), mono_fill_make_pattern(0x11),
    mono_fill_make_pattern(0x22), mono_fill_make_pattern(0x33),
    mono_fill_make_pattern(0x44), mono_fill_make_pattern(0x55),
    mono_fill_make_pattern(0x66), mono_fill_make_pattern(0x77),
    mono_fill_make_pattern(0x88), mono_fill_make_pattern(0x99),
    mono_fill_make_pattern(0xaa), mono_fill_make_pattern(0xbb),
    mono_fill_make_pattern(0xcc), mono_fill_make_pattern(0xdd),
    mono_fill_make_pattern(0xee), mono_fill_make_pattern(0xff)
};

/*
 * Replicate a color or mask as required to fill a mem_mono_fill_chunk.
 * This is possible if (8 * sizeof(mono_fill_chunk)) % depth == 0.
 * Since sizeof(mono_fill_chunk) is a power of 2, this will be the case
 * if depth is a power of 2 and depth <= 8 * sizeof(mono_fill_chunk).
 */
private mono_fill_chunk
replicate_color(int depth, mono_fill_chunk color)
{
    switch (depth) {

      case 1:
        color = -color;

      case 2:
        color = fill_pat_2[color];

      case 4:
        color = fill_pat_4[color];

      case 8:
        color= mono_fill_make_pattern(color);

#if mono_fill_chunk_bytes > 2
      case 16:
        color = (color << 16) | color;
        /* fall through */
#endif
#if mono_fill_chunk_bytes > 4
      case 32:
        color = (color << 32) | color;
        break;
#endif
    }

    return color;
}


/*
 * Perform the fill rectangle operation for a separable color encoding
 * that requires overprint support.
 *
 * This is handled via two separate cases. If
 *
 *    (8 * sizeof(mono_fill_chunk)) % tdev->color_info.depth = 0,
 *
 * then is possible to work via the masked analog of the bits_fill_rectangle
 * procedure, bits_fill_rectangle_masked. This requires that both the
 * color and component mask be replicated sufficiently to fill the
 * mono_fill_chunk. The somewhat elaborate set-up aside, the resulting
 * algorithm is about as efficient as can be achieved when using
 * get_bits_rectangle. More efficient algorithms require overprint to be
 * implemented in the target device itself.
 *
 * If the condition is not satisfied, a simple byte-wise algorithm is
 * used. This requires minimal setup but is not efficient, as it works in
 * units that are too small. More efficient methods are possible in this
 * case, but the required setup for a general depth is excessive (even
 * with the restriction that depth % 8 = 0). Hence, efficiency for these
 * cases is better addressed by direct implementation of overprint for
 * memory devices.
 *
 * For both cases, the color and retain_mask values passed to this
 * procedure are expected to be already swapped as required for a byte-
 * oriented bitmap. This consideration affects only little-endian
 * machines. For those machines, if depth > 9 the color passed to these
 * two procedures will not be the same as that passed to
 * gx_overprint_generic_fill_rectangle.
 *
 * Returns 0 on success, < 0 in the event of an error.
 */
int
gx_overprint_sep_fill_rectangle_1(
    gx_device *             tdev,
    gx_color_index          retain_mask,    /* already swapped */
    int                     x,
    int                     y,
    int                     w,
    int                     h,
    gx_color_index          color,          /* already swapped */
    gs_memory_t *           mem )
{
    byte *                  gb_buff = 0;
    gs_get_bits_params_t    gb_params;
    gs_int_rect             gb_rect;
    int                     code, bit_w, depth = tdev->color_info.depth;
    int                     raster;
    mono_fill_chunk         rep_color, rep_mask;

    fit_fill(tdev, x, y, w, h);
    bit_w = w * depth;

    /* set up replicated color and retain mask */
    if (depth < 8 * sizeof(mono_fill_chunk)) {
        rep_color = replicate_color(depth, (mono_fill_chunk)color);
        rep_mask = replicate_color(depth, (mono_fill_chunk)retain_mask);
    } else {
        rep_color = (mono_fill_chunk)color;
        rep_mask = (mono_fill_chunk)retain_mask;
    }

    /* allocate a buffer for the returned data */
    raster = bitmap_raster(w * depth);
    gb_buff = gs_alloc_bytes(mem, raster, "overprint sep fill rectangle 1");
    if (gb_buff == 0)
        return gs_note_error(gs_error_VMerror);

    /*
     * Initialize the get_bits parameters. The selection of options is
     * the same as that for gx_overprint_generic_fill_rectangle (above).
     */
    gb_params.options =  GB_COLORS_NATIVE
                       | GB_ALPHA_NONE
                       | GB_DEPTH_ALL
                       | GB_PACKING_CHUNKY
                       | GB_RETURN_COPY
                       | GB_ALIGN_STANDARD
                       | GB_OFFSET_0
                       | GB_RASTER_STANDARD;
    gb_params.x_offset = 0;     /* for consistency */
    gb_params.data[0] = gb_buff;
    gb_params.raster = raster;

    gb_rect.p.x = x;
    gb_rect.q.x = x + w;

    /* process each scanline separately */
    while (h-- > 0 && code >= 0) {
        gb_rect.p.y = y++;
        gb_rect.q.y = y;
        code = dev_proc(tdev, get_bits_rectangle)( tdev,
                                                   &gb_rect,
                                                   &gb_params,
                                                   0 );
        if (code < 0)
            break;
        bits_fill_rectangle_masked( gb_buff,
                                    0,
                                    raster,
                                    rep_color,
                                    rep_mask,
                                    bit_w,
                                    1 );
        code = dev_proc(tdev, copy_color)( tdev,
                                           gb_buff,
                                           0,
                                           raster,
                                           gs_no_bitmap_id,
                                           x, y - 1, w, 1 );
    }

    gs_free_object( mem,
                    gb_buff,
                    "overprint generic fill rectangle" );

    return code;
}


int
gx_overprint_sep_fill_rectangle_2(
    gx_device *             tdev,
    gx_color_index          retain_mask,    /* already swapped */
    int                     x,
    int                     y,
    int                     w,
    int                     h,
    gx_color_index          color,          /* already swapped */
    gs_memory_t *           mem )
{
    byte *                  gb_buff = 0;
    gs_get_bits_params_t    gb_params;
    gs_int_rect             gb_rect;
    int                     code, byte_w, raster;
    int                     byte_depth = tdev->color_info.depth >> 3;
    byte *                  pcolor;
    byte *                  pmask;

    fit_fill(tdev, x, y, w, h);
    byte_w = w * byte_depth;

    /* set up color and retain mask pointers */
    pcolor = (byte *)&color;
    pmask = (byte *)&retain_mask;
#if arch_is_big_endian
    pcolor += sizeof(gx_color_index) - byte_depth;
    pmask += sizeof(gx_color_index) - byte_depth;
#endif

    /* allocate a buffer for the returned data */
    raster = bitmap_raster(w * (byte_depth << 3));
    gb_buff = gs_alloc_bytes(mem, raster, "overprint sep fill rectangle 1");
    if (gb_buff == 0)
        return gs_note_error(gs_error_VMerror);

    /*
     * Initialize the get_bits parameters. The selection of options is
     * the same as that for gx_overprint_generic_fill_rectangle (above).
     */
    gb_params.options =  GB_COLORS_NATIVE
                       | GB_ALPHA_NONE
                       | GB_DEPTH_ALL
                       | GB_PACKING_CHUNKY
                       | GB_RETURN_COPY
                       | GB_ALIGN_STANDARD
                       | GB_OFFSET_0
                       | GB_RASTER_STANDARD;
    gb_params.x_offset = 0;     /* for consistency */
    gb_params.data[0] = gb_buff;
    gb_params.raster = raster;

    gb_rect.p.x = x;
    gb_rect.q.x = x + w;

    /* process each scanline separately */
    while (h-- > 0 && code >= 0) {
        int     i, j;
        byte *  cp = gb_buff;

        gb_rect.p.y = y++;
        gb_rect.q.y = y;
        code = dev_proc(tdev, get_bits_rectangle)( tdev,
                                                   &gb_rect,
                                                   &gb_params,
                                                   0 );
        if (code < 0)
            break;
        for (i = 0, j = 0; i < byte_w; i++, cp++) {
            *cp = (*cp & pmask[j]) | pcolor[j];
            if (++j == byte_depth)
                j = 0;
        }
        code = dev_proc(tdev, copy_color)( tdev,
                                           gb_buff,
                                           0,
                                           raster,
                                           gs_no_bitmap_id,
                                           x, y - 1, w, 1 );
    }

    gs_free_object( mem,
                    gb_buff,
                    "overprint generic fill rectangle" );

    return code;
}


--- NEW FILE: gxoprect.h ---
/* Copyright (C) 2002 Aladdin Enterprises.  All rights reserved.
  
  This file is part of AFPL Ghostscript.
  
  AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  distributor accepts any responsibility for the consequences of using it, or
  for whether it serves any particular purpose or works at all, unless he or
  she says so in writing.  Refer to the Aladdin Free Public License (the
  "License") for full details.
  
  Every copy of AFPL Ghostscript must include a copy of the License, normally
  in a plain ASCII text file named PUBLIC.  The License grants you the right
  to copy, modify and redistribute AFPL Ghostscript, but only under certain
  conditions described in the License.  Among other things, the License
  requires that the copyright notice and this notice be preserved on all
  copies.
*/

/* $Id: gxoprect.h,v 1.1 2002/08/22 07:12:29 henrys Exp $ */
/* geneic overprint fill rectangle interface */

#ifndef gxoprect_INCLUDED
#define gxoprect_INCLUDED

/*
 * Perform the fill rectangle operation for a non-separable color encoding
 * that requires overprint support.
 *
 * Returns 0 on success, < 0 in the event of an error.
 */
extern  int     gx_overprint_generic_fill_rectangle(
    gx_device *             tdev,
    gx_color_index          drawn_comps,
    int                     x,
    int                     y,
    int                     w,
    int                     h,
    gx_color_index          color,
    gs_memory_t *           mem );

/*
 * Perform the fill rectangle operation of a separable color encoding.
 * There are two versions of this routine: ..._1 for cases in which the
 * color depth is a divisor of 8 * sizeof(mono_fill_chunk), and ..._2 if
 * this is not the case (most typically if the depth == 24).
 *
 * For both cases, the color and retain_mask values passed to this
 * procedure are expected to be already swapped as required for a byte-
 * oriented bitmap. This consideration affects only little-endian
 * machines. For those machines, if depth > 9 the color passed to these
 * two procedures will not be the same as that passed to
 * gx_overprint_generic_fill_rectangle.
 *
 * Returns 0 on success, < 0 in the event of an error.
 */
extern  int     gx_overprint_sep_fill_rectangle_1(
    gx_device *             tdev,
    gx_color_index          retain_mask,    /* already swapped */
    int                     x,
    int                     y,
    int                     w,
    int                     h,
    gx_color_index          color,          /* already swapped */
    gs_memory_t *           mem );

extern  int     gx_overprint_sep_fill_rectangle_2(
    gx_device *             tdev,
    gx_color_index          retain_mask,    /* already swapped */
    int                     x,
    int                     y,
    int                     w,
    int                     h,
    gx_color_index          color,          /* already swapped */
    gs_memory_t *           mem );

#endif  /* gxoprect_INCLUDED */

--- NEW FILE: gxwts.c ---
/* Copyright (C) 2002 artofcode LLC.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/
/*$Id: gxwts.c,v 1.1 2002/08/22 07:12:29 henrys Exp $ */
/* Rendering using Well Tempered Screening. */
#include "stdpre.h"
#include "memory_.h" /* for memcmp */
#include <stdlib.h> /* for malloc */
#include "gx.h"
#include "gxstate.h"
#include "gsht.h"
#include "math_.h"
#include "gserrors.h"
#include "gxdcolor.h"
#include "gxdevcli.h"
#include "gxdht.h"
#include "gxwts.h"

#define GXWTS_USE_DOUBLE

#ifndef UNIT_TEST
/* device color type for wts. */

/* todo: trace and relocate pointers */
gs_private_st_simple(st_dc_wts, gx_device_color, "dc_wts");
private dev_color_proc_save_dc(gx_dc_wts_save_dc);
private dev_color_proc_get_dev_halftone(gx_dc_wts_get_dev_halftone);
private dev_color_proc_load(gx_dc_wts_load);
private dev_color_proc_fill_rectangle(gx_dc_wts_fill_rectangle);
private dev_color_proc_equal(gx_dc_wts_equal);
private dev_color_proc_write(gx_dc_wts_write);
private dev_color_proc_read(gx_dc_wts_read);
private dev_color_proc_get_nonzero_comps(gx_dc_wts_get_nonzero_comps);
const gx_device_color_type_t gx_dc_type_data_wts = {
    &st_dc_wts,
    gx_dc_wts_save_dc, gx_dc_wts_get_dev_halftone,
    gx_dc_wts_load, gx_dc_wts_fill_rectangle,
    gx_dc_default_fill_masked, gx_dc_wts_equal,
    gx_dc_wts_write, gx_dc_wts_read,
    gx_dc_wts_get_nonzero_comps
};
#undef gx_dc_type_wts
const gx_device_color_type_t *const gx_dc_type_wts =
&gx_dc_type_data_wts;
#endif

/* Low-level implementation follows. */

/**
 * mul_shr_16: Multiply and shift right 16.
 * @a: 32-bit signed number.
 * @b: 32-bit signed number.
 *
 * Multiply @a and @b, then shift right 16 bits. Allow intermediate value
 * to overflow 32 bits.
 *
 * Return value: result.
 **/
#ifdef GXWTS_USE_DOUBLE
private int
mul_shr_16 (int a, int b)
{
  return floor(((double) a) * ((double) b) * (1.0 / (1 << 16)));
}
#else
#error todo: supply mul_shr_16 based on 64 bit integer type
#endif

/* Implementation of wts_get_samples for rational cells. */
#if 0
private int
wts_get_samples_rat(const wts_screen_t *ws, int x, int y,
		    wts_screen_sample_t **samples, int *p_nsamples)
{
    int d = y / ws->cell_height;
    int r = y % ws->cell_height;
    int x_ix = ((d * ws->cell_shift) + x) % ws->cell_width;
    *p_nsamples = ws->cell_width - x_ix;
    *samples = ws->samples + x_ix + r * ws->cell_width;
    return 0;
}
#endif

/* Implementation of wts_get_samples for Screen J. */
private int
wts_get_samples_j(const wts_screen_t *ws, int x, int y,
		  wts_screen_sample_t **samples, int *p_nsamples)
{
   const wts_screen_j_t *wsj = (const wts_screen_j_t *)ws;
    /* int d = y / ws->cell_height; */
    int y_ix = y;
    int x_ix = x;
    double pad = (wsj->pa) * (1.0 / (1 << 16));
    double pbd = (wsj->pb) * (1.0 / (1 << 16));
    double afrac = x * pad;
    double bfrac = x * pbd;
    int acount = floor(afrac);
    int bcount = floor(bfrac);
    int ccount = mul_shr_16(y, wsj->pc);
    int dcount = mul_shr_16(y, wsj->pd);
    int nsamples;

    x_ix += acount * wsj->XA + bcount * wsj->XB +
	ccount * wsj->XC + dcount * wsj->XD;
    y_ix += acount * wsj->YA + bcount * wsj->YB +
	ccount * wsj->YC + dcount * wsj->YD;

    x_ix += (y_ix / ws->cell_height) * ws->cell_shift;
    x_ix %= ws->cell_width;
    y_ix %= ws->cell_height;

    nsamples = ws->cell_width - x_ix;
    if (floor (afrac + (nsamples - 1) * pad) > acount)
	nsamples = ceil((acount + 1 - afrac) / pad);

    if (floor (bfrac + (nsamples - 1) * pbd) > bcount)
	nsamples = ceil((bcount + 1 - bfrac) / pbd);
#if 0
    printf("get_samples: (%d, %d) -> (%d, %d) %d (cc=%d)\n",
	   x, y, x_ix, y_ix, nsamples, ccount);
#endif
    *p_nsamples = nsamples;
    *samples = ws->samples + x_ix + y_ix * ws->cell_width;
    return 0;
}

/**
 * wts_get_samples: Get samples from Well Tempered Screening cell.
 * @ws: Well Tempered Screening cell.
 * @x: X coordinate of starting point.
 * @y: Y coordinate of starting point.
 * @samples: Where to store pointer to samples.
 * @p_nsamples: Where to store number of valid samples.
 *
 * Finds samples from the cell for use in halftoning. On success,
 * @p_nsamples is set to the number of valid samples, ie for 0 <= i <
 * nsamples, samples[i] is a valid sample for coordinate (x + i, y).
 * p_nsamples is guaranteed to at least 1. The samples in @samples
 * are valid for the lifetime of the cell, or until the next garbage
 * collection, whichever comes first.
 *
 * Todo: describe meaning of wts_screen_sample_t (particularly edge
 * cases).
 *
 * Note: may want to add a "cursor" to the api as an optimization. It
 * can wait, though.
 *
 * Return value: 0 on success.
 **/
int
wts_get_samples(const wts_screen_t *ws, int x, int y,
		wts_screen_sample_t **samples, int *p_nsamples)
{
    return wts_get_samples_j(ws, x, y, samples, p_nsamples);
}

/* Device color methods follow. */

private void
gx_dc_wts_save_dc(const gx_device_color * pdevc, gx_device_color_saved * psdc)
{
    psdc->type = pdevc->type;
    memcpy( psdc->colors.wts.levels,
            pdevc->colors.wts.levels,
            sizeof(psdc->colors.wts.levels) );
    psdc->phase = pdevc->phase;
}

private const gx_device_halftone *
gx_dc_wts_get_dev_halftone(const gx_device_color * pdevc)
{
    return pdevc->colors.wts.w_ht;
}

private int
gx_dc_wts_load(gx_device_color *pdevc, const gs_imager_state * pis,
	       gx_device *ignore_dev, gs_color_select_t select)
{
    return 0;
}

/**
 * wts_draw: Draw a halftoned shade into a 1 bit deep buffer.
 * @ws: WTS screen.
 * @shade: Gray shade to draw.
 * @data: Destination buffer.
 * @data_raster: Rowstride for destination buffer.
 * @x, @y, @w, @h: coordinates of rectangle to draw.
 *
 * This is close to an implementation of the "draw" method for the
 * gx_ht_order class. Currently, only WTS screens implement this
 * method, and only WTS device colors invoke it. However, implementing
 * this for legacy order objects is probably a good idea, to improve
 * halftoning performance as the cell size scales up.
 *
 * However, it's not exactly an implementation of the "draw" method
 * for the gx_ht_order class because the "self" type would need to be
 * gx_ht_order. Currently, however, device colors don't hold a pointer
 * to the order object. Some amount of refactoring seems to be in
 * order.
 *
 * Return value: 0 on success.
 **/
private int
wts_draw(wts_screen_t *ws, wts_screen_sample_t shade,
	 byte *data, int data_raster,
	 int x, int y, int w, int h)
{
    int xo, yo;
    unsigned char *line_start = data;

    for (yo = 0; yo < h; yo++) {
	unsigned char *line_ptr = line_start;
	int mask = 0x80;
	unsigned char b = 0;
	int imax;

	for (xo = 0; xo < w; xo += imax) {
	    wts_screen_sample_t *samples;
	    int n_samples, i;

	    wts_get_samples(ws, x + xo, y + yo, &samples, &n_samples);
	    imax = min(w - xo, n_samples);
	    for (i = 0; i < imax; i++) {
		if (shade > samples[i])
		    b |= mask;
		mask >>= 1;
		if (mask == 0) {
		    *line_ptr++ = b;
		    b = 0;
		    mask = 0x80;
		}
	    }
	}
	if (mask != 0x80)
	    *line_ptr = b;
	line_start += data_raster;
    }
    return 0;
}

/**
 * Special case implementation for one component. When we do plane_mask,
 * we'll want to generalize this to handle any single-bit plane_mask.
 **/
private int
gx_dc_wts_fill_rectangle_1(const gx_device_color *pdevc,
			   int x, int y, int w, int h,
			   gx_device *dev, gs_logical_operation_t lop,
			   const gx_rop_source_t *source)
{
    /* gx_rop_source_t no_source; */
    int tile_raster = ((w + 31) & -32) >> 3;
    int tile_size = tile_raster * h;
    unsigned char *tile_data;
    int code = 0;
    gx_ht_order_component *components = pdevc->colors.wts.w_ht->components;
    wts_screen_t *ws = components[0].corder.wts;
    wts_screen_sample_t shade = pdevc->colors.wts.levels[0];
    gx_color_index color0, color1;

    color0 = dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN ? 0 :
	pdevc->colors.wts.plane_vector[1];
    color1 = pdevc->colors.wts.plane_vector[0];

    tile_data = malloc(tile_size);

    wts_draw(ws, shade, tile_data, tile_raster, x, y, w, h);
 
    /* See gx_dc_ht_binary_fill_rectangle() for explanation. */
    if (dev->color_info.depth > 1)
	lop &= ~lop_T_transparent;

    /* Interesting question: should data_x be (x & 7), rather than 0,
       to improve alignment? */
    if (source == NULL && lop_no_S_is_T(lop))
	code = (*dev_proc(dev, copy_mono))
	    (dev, tile_data, 0, tile_raster, gx_no_bitmap_id,
	     x, y, w, h, color0, color1);

    free(tile_data);
    return code;
}

private int
gx_dc_wts_write(
    const gx_device_color *         pdevc,
    const gx_device_color_saved *   psdc,
    const gx_device *               dev,
    byte *                          pdata,
    uint *                          psize )
{
    /* not yet implemented */
    return_error(gs_error_unknownerror);
}

private int
gx_dc_wts_read(
    gx_device_color *       pdevc,
    const gs_imager_state * pis,
    const gx_device_color * prior_devc,
    const gx_device *       dev,
    const byte *            pdata,
    uint                    size,
    gs_memory_t *           mem )
{
    /* not yet implemented */
    return_error(gs_error_unknownerror);
}


/**
 * wts_repack_tile_4: Repack four 1-bit tiles into chunky nibbles.
 * Note: argument list will change. plane_mask and base_color will
 * probably get added as an optimization.
 *
 * Note: we round w up to an even value. We're counting on the
 * subsequent copy_color to ignore any extra bits.
 **/
private void
wts_repack_tile_4(unsigned char *ctile_data, int ctile_raster,
		  const unsigned char **tile_data, int tile_raster,
		  const gx_color_index *plane_vector, bool invert,
		  int w, int h)
{
    int y;
    int tile_idx_start = 0;
    char *ctile_start = ctile_data;
    byte inv_byte = invert ? 0xff : 0;

    for (y = 0; y < h; y++) {
	int x;
	int tile_idx = tile_idx_start;

	for (x = 0; x < w; x += 2) {
	    byte b = 0;
	    byte m0 = 0x80 >> (x & 6);
	    byte m1 = m0 >> 1;
	    byte td;

	    td = tile_data[0][tile_idx] ^ inv_byte;
	    if (td & m0) b |= plane_vector[0] << 4;
	    if (td & m1) b |= plane_vector[0];

	    td = tile_data[1][tile_idx] ^ inv_byte;
	    if (td & m0) b |= plane_vector[1] << 4;
	    if (td & m1) b |= plane_vector[1];

	    td = tile_data[2][tile_idx] ^ inv_byte;
	    if (td & m0) b |= plane_vector[2] << 4;
	    if (td & m1) b |= plane_vector[2];

	    td = tile_data[3][tile_idx] ^ inv_byte;
	    if (td & m0) b |= plane_vector[3] << 4;
	    if (td & m1) b |= plane_vector[3];

	    if ((x & 6) == 6)
		tile_idx++;
	    ctile_start[x >> 1] = b;
	}
	tile_idx_start += tile_raster;
	ctile_start += ctile_raster;
    }
}

/* Special case implementation for four components. Intermediate color
 * to the order objecttile (for copy_color) is packed 2 to a byte.
 *
 * Looking at this code, it should generalize to more than four
 * components. Probably the repack code should get factored out.
 */
private int
gx_dc_wts_fill_rectangle_4(const gx_device_color *pdevc,
			   int x, int y, int w, int h,
			   gx_device *dev, gs_logical_operation_t lop,
			   const gx_rop_source_t *source)
{
    int num_comp = pdevc->colors.wts.num_components;
    /* gx_rop_source_t no_source; */

    int tile_raster = ((w + 31) & -32) >> 3;
    int tile_size = tile_raster * h;
    unsigned char *tile_data[4];

    int ctile_raster = ((w + 7) & -8) >> 1;
    int ctile_size = ctile_raster * h;
    unsigned char *ctile_data;

    int code = 0;
    bool invert = 0 && dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE;
    int i;

    for (i = 0; i < num_comp; i++) {
	wts_screen_sample_t shade = pdevc->colors.wts.levels[i];
	gx_ht_order_component *components = pdevc->colors.wts.w_ht->components;
	wts_screen_t *ws = components[i].corder.wts;

	tile_data[i] = malloc(tile_size);
	wts_draw(ws, shade, tile_data[i], tile_raster, x, y, w, h);
    }

    ctile_data = malloc(ctile_size);
    wts_repack_tile_4(ctile_data, ctile_raster, tile_data, tile_raster,
		      pdevc->colors.wts.plane_vector, invert, w, h);
 
    /* See gx_dc_ht_binary_fill_rectangle() for explanation. */
    if (dev->color_info.depth > 1)
	lop &= ~lop_T_transparent;

    if (source == NULL && lop_no_S_is_T(lop))
	code = (*dev_proc(dev, copy_color))
	    (dev, ctile_data, 0, ctile_raster, gx_no_bitmap_id,
	     x, y, w, h);

    free(ctile_data);
    for (i = 0; i < num_comp; i++) {
	free(tile_data[i]);
    }

    return code;
}

private int
gx_dc_wts_fill_rectangle(const gx_device_color *pdevc,
			 int x, int y, int w, int h,
			 gx_device *dev, gs_logical_operation_t lop,
			 const gx_rop_source_t *source)
{
    int num_comp = pdevc->colors.wts.num_components;

    if (num_comp == 1)
	return gx_dc_wts_fill_rectangle_1(pdevc, x, y, w, h, dev, lop, source);
    else if (num_comp <= 4)
	return gx_dc_wts_fill_rectangle_4(pdevc, x, y, w, h, dev, lop, source);
    else
	return -1;
}

/* Compare two wts colors for equality. */
private int
gx_dc_wts_equal(const gx_device_color *pdevc1,
		const gx_device_color *pdevc2)
{
    uint num_comp = pdevc1->colors.wts.num_components;

    if (pdevc2->type != pdevc1->type ||
	pdevc1->phase.x != pdevc2->phase.x ||
	pdevc1->phase.y != pdevc2->phase.y ||
	num_comp != pdevc2->colors.wts.num_components
	)
	return false;
    return
	!memcmp(pdevc1->colors.wts.levels,
		pdevc2->colors.wts.levels,
		num_comp * sizeof(pdevc1->colors.wts.levels[0]));
}

/*
 * Get the nonzero components of a wts halftone. This is used to
 * distinguish components that are given zero intensity due to halftoning
 * from those for which the original color intensity was in fact zero.
 */
int
gx_dc_wts_get_nonzero_comps(
    const gx_device_color * pdevc,
    const gx_device *       dev_ignored,
    gx_color_index *        pcomp_bits )
{
    int                     i, ncomps =  pdevc->colors.wts.num_components;
    gx_color_index comp_bits = 0; /* todo: plane_mask */

    for (i = 0; i < ncomps; i++) {
        if (pdevc->colors.wts.levels[i] != 0)
            comp_bits |= ((gx_color_index)1) << i;
    }
    *pcomp_bits = comp_bits;

    return 0;
}

--- NEW FILE: gxwts.h ---
/* Copyright (C) 2002 artofcode LLC.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/
/*$Id: gxwts.h,v 1.1 2002/08/22 07:12:29 henrys Exp $ */
#ifndef gxwts_INCLUDED
#  define gxwts_INCLUDED

typedef bits16 wts_screen_sample_t;

#ifndef wts_screen_t_DEFINED
#  define wts_screen_t_DEFINED
typedef struct wts_screen_s wts_screen_t;
#endif

struct wts_screen_s {
    /* methods */
    int cell_width;
    int cell_height;
    int cell_shift;
    wts_screen_sample_t *samples;
};

typedef struct {
    wts_screen_t base;

    /* Probabilities of "jumps". A and B jumps can happen when moving
       one pixel to the right. C and D can happen when moving one pixel
       down. */
    int pa; /* change to double? */
    int pb;
    int pc;
    int pd;

    int XA;
    int YA;
    int XB;
    int YB;
    int XC;
    int YC;
    int XD;
    int YD;
} wts_screen_j_t;

typedef struct {
    wts_screen_t base;

    /* This is the exact value that x1 and (width-x1) approximates. */
    double px;
    /* Ditto y1 and (height-y1). */
    double py;

    int x1;
    int y1;
} wts_screen_h_t;

int
wts_get_samples(const wts_screen_t *ws, int x, int y,
		wts_screen_sample_t **samples, int *p_nsamples);

#endif

--- NEW FILE: zcolor3.c ---
/* Copyright (C) 2002 Aladdin Enterprises.  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.
  
  For more information about licensing, please refer to
  http://www.ghostscript.com/licensing/. For information on
  commercial licensing, go to http://www.artifex.com/licensing/ or
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
*/

/*$Id:*/
/* Level 3 color operators */
#include "ghost.h"
#include "oper.h"
#include "igstate.h"


/*
 *  <bool>   .setuseciecolor  -
 *
 * Set the use_cie_color parameter for the interpreter state, which
 * corresponds to the UseCIEColor page device parameter. This parameter
 * may be read at all language levels, but it may be set only for
 * language level 3. The parameter is handled separately from the page
 * device dictionary primarily for performance reasons (it may need to
 * be checked frequently), but also to ensure proper language level
 * specific behavior.
 *
 * This operator is accessible only during initialization and is called
 * only under controlled conditions. Hence, it does not do any operand
 * checking.
 */
private int
zsetuseciecolor(i_ctx_t * i_ctx_p)
{
    os_ptr  op = osp;

    istate->use_cie_color = *op;
    pop(1);
    return 0;
}


/*
 * Initialization procedure
 */

const op_def    zcolor3_l3_op_defs[] = {
    op_def_begin_ll3(),
    { "0.setuseciecolor", zsetuseciecolor },
    op_def_end(0)
};

Index: devs.mak
===================================================================
RCS file: /cvs/ghostscript/gs/src/devs.mak,v
retrieving revision 1.69
retrieving revision 1.70
diff -u -d -r1.69 -r1.70
--- devs.mak	26 Jul 2002 07:27:19 -0000	1.69
+++ devs.mak	22 Aug 2002 07:12:28 -0000	1.70
@@ -383,7 +383,7 @@
 	$(SETDEV) $(DD)display $(display_)
 
 $(GLOBJ)gdevdsp.$(OBJ) : $(GLSRC)gdevdsp.c $(string__h)\
- $(gp_h) $(gpcheck_h) $(gdevpccm_h) $(gsparam_h)\
+ $(gp_h) $(gpcheck_h) $(gdevpccm_h) $(gsparam_h) $(gsdevice_h)\
  $(GDEVH) $(gxdevmem_h) $(gdevdsp_h) $(gdevdsp2_h)
 	$(GLCC) $(GLO_)gdevdsp.$(OBJ) $(C_) $(GLSRC)gdevdsp.c
 
@@ -692,7 +692,7 @@
 $(GLOBJ)gdevpsdu.$(OBJ) : $(GLSRC)gdevpsdu.c $(GXERR)\
  $(jpeglib__h) $(memory__h) $(stdio__h)\
  $(sa85x_h) $(scfx_h) $(sdct_h) $(sjpeg_h) $(sstring_h) $(strimpl_h)\
- $(gdevpsdf_h) $(spprint_h)
+ $(gdevpsdf_h) $(spprint_h) $(gsovrc_h)
 	$(GLJCC) $(GLO_)gdevpsdu.$(OBJ) $(C_) $(GLSRC)gdevpsdu.c
 
 # PostScript and EPS writers
@@ -1183,6 +1183,38 @@
 
 $(DD)cgm24.dev : $(DEVS_MAK) $(cgm_)
 	$(SETDEV) $(DD)cgm24 $(cgm_)
+
+### ------------------------ The DeviceN device ------------------------ ###
+
+devn_=$(GLOBJ)gdevdevn.$(OBJ)
+
+$(DD)spotrgb.dev : $(DEVS_MAK) $(devn_) $(GLD)page.dev
+	$(SETDEV) $(DD)spotrgb $(devn_)
+
+$(DD)spotcmyk.dev : $(DEVS_MAK) $(devn_) $(GLD)page.dev
+	$(SETDEV) $(DD)spotcmyk $(devn_)
+
+$(DD)devicen.dev : $(DEVS_MAK) $(devn_) $(GLD)page.dev
+	$(SETDEV) $(DD)devicen $(devn_)
+
+$(GLOBJ)gdevdevn.$(OBJ) : $(GLSRC)gdevdevn.c $(PDEVH) $(math__h)\
+ $(gdevprn_h) $(gsparam_h) $(gscrd_h) $(gscrdp_h) $(gxlum_h) $(gdevdcrd_h)\
+ $(gstypes_h) $(gxdcconv_h)
+	$(GLCC) $(GLO_)gdevdevn.$(OBJ) $(C_) $(GLSRC)gdevdevn.c
+
+### --------------------------- The XCF device ------------------------- ###
+
+xcf_=$(GLOBJ)gdevxcf.$(OBJ)
+
+$(DD)xcf.dev : $(DEVS_MAK) $(xcf_) $(GLD)page.dev
+	$(SETDEV) $(DD)xcf $(xcf_)
+
+$(DD)xcfcmyk.dev : $(DEVS_MAK) $(xcf_) $(GLD)page.dev
+	$(SETDEV) $(DD)xcfcmyk $(xcf_)
+
+$(GLOBJ)gdevxcf.$(OBJ) : $(GLSRC)gdevxcf.c $(PDEVH) $(math__h)\
+ $(gdevdcrd_h) $(gscrd_h) $(gscrdp_h) $(gsparam_h) $(gxlum_h) $(icc_h)
+	$(GLICCCC) $(GLO_)gdevxcf.$(OBJ) $(C_) $(GLSRC)gdevxcf.c
 
 ### ------------------------- JPEG file format ------------------------- ###
 

Index: gconf.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gconf.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gconf.c	21 Feb 2002 22:24:51 -0000	1.5
+++ gconf.c	22 Aug 2002 07:12:28 -0000	1.6
@@ -25,6 +25,7 @@
 #include "gxiclass.h"
 #include "gxiodev.h"
 #include "gxiparam.h"
+#include "gxcomp.h"
 
 /*
  * The makefile generates the file gconfig.h, which consists of
@@ -62,6 +63,7 @@
 /* ---------------- Resources (devices, inits, IODevices) ---------------- */
 
 /* Declare devices, image types, init procedures, and IODevices as extern. */
+#define compositor_(comp_type) extern gs_composite_type_t comp_type;
 #define device_(dev) extern gx_device dev;
 #define device2_(dev) extern const gx_device dev;
 #define halftone_(dht) extern DEVICE_HALFTONE_RESOURCE_PROC(dht);
@@ -77,6 +79,15 @@
 #undef halftone_
 #undef device2_
 #undef device_
+#undef compositor_
+
+/* Set up compositor type table. */
+#define compositor_(comp_type) &comp_type,
+private const gs_composite_type_t *const gx_compositor_list[] = {
+#include "gconf.h"
+    0
+};
+#undef compositor_
 
 /* Set up the device table. */
 #define device_(dev) (const gx_device *)&dev,
@@ -141,6 +152,19 @@
 #undef io_device_
 /* We must use unsigned here, not uint.  See gscdefs.h. */
 const unsigned gx_io_device_table_count = countof(gx_io_device_table) - 1;
+
+/* Find a compositor by name. */
+extern_gs_find_compositor();
+const gs_composite_type_t *
+gs_find_compositor(int comp_id)
+{
+    const gs_composite_type_t *const * ppcomp = gx_compositor_list;
+    const gs_composite_type_t *  pcomp;
+
+    while ((pcomp = *ppcomp++) != 0 && pcomp->comp_id != comp_id)
+        ;
+    return pcomp;
+}
 
 /* Return the list of device prototypes, a NULL list of their structure */
 /* descriptors (no longer used), and (as the value) the length of the lists. */

Index: gdev4693.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdev4693.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gdev4693.c	21 Feb 2002 22:24:51 -0000	1.5
+++ gdev4693.c	22 Aug 2002 07:12:28 -0000	1.6
@@ -38,11 +38,13 @@
 const gx_device_printer gs_t4693d8_device = t4693d_prn_device("t4693d8",24, 255);
 
 private gx_color_index
-gdev_t4693d_map_rgb_color(gx_device *dev,
-	gx_color_value r, gx_color_value g, gx_color_value b)
+gdev_t4693d_map_rgb_color(gx_device *dev, const gx_color_value cv[])
 {
 	ushort bitspercolor = prn_dev->color_info.depth / 3;
 	ulong max_value = (1 << bitspercolor) - 1;
+
+        gx_color_value r, g, b;
+        r = cv[0]; g = cv[1]; b = cv[2];
 
 	if (bitspercolor == 5) {
 		bitspercolor--;

Index: gdevabuf.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevabuf.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gdevabuf.c	21 Feb 2002 22:24:51 -0000	1.5
+++ gdevabuf.c	22 Aug 2002 07:12:28 -0000	1.6
@@ -58,11 +58,10 @@
 
 /* Reimplement color mapping. */
 private gx_color_index
-mem_alpha_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
-			gx_color_value b)
+mem_alpha_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
     gx_device_memory * const mdev = (gx_device_memory *)dev;
-    gx_color_index color = gx_forward_map_rgb_color(dev, r, g, b);
+    gx_color_index color = gx_forward_map_rgb_color(dev, cv);
 
     return (color == 0 || color == gx_no_color_index ? color :
 	    (gx_color_index) ((1 << mdev->log2_alpha_bits) - 1));
@@ -81,7 +80,11 @@
 		   gx_color_value g, gx_color_value b, gx_color_value alpha)
 {
     gx_device_memory * const mdev = (gx_device_memory *)dev;
-    gx_color_index color = gx_forward_map_rgb_color(dev, r, g, b);
+    gx_color_index color;
+    gx_color_value cv[3];
+
+    cv[0] = r; cv[1] = g; cv[2] = b;
+    gx_forward_map_rgb_color(dev, cv);
 
     return (color == 0 || color == gx_no_color_index ? color :
 	    (gx_color_index) (alpha >> (gx_color_value_bits -

Index: gdevbbox.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevbbox.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gdevbbox.c	22 Feb 2002 08:37:19 -0000	1.7
+++ gdevbbox.c	22 Aug 2002 07:12:28 -0000	1.8
@@ -129,7 +129,16 @@
      bbox_create_compositor,
      NULL,			/* get_hardware_params */
      bbox_text_begin,
-     NULL			/* finish_copydevice */
+     NULL,			/* finish_copydevice */
+     NULL,			/* begin_transparency_group */
+     NULL,			/* end_transparency_group */
+     NULL,			/* begin_transparency_mask */
+     NULL,			/* end_transparency_mask */
+     NULL,			/* discard_transparency_layer */
+     NULL,			/* get_color_mapping_procs */
+     NULL,			/* get_color_comp_index */
+     NULL,			/* encode_color */
+     NULL			/* decode_color */
     },
     0,				/* target */
     1,				/*true *//* free_standing */
@@ -257,7 +266,10 @@
 	set_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb);
 	set_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color);
 	set_dev_proc(dev, map_rgb_alpha_color, gx_forward_map_rgb_alpha_color);
-	set_dev_proc(dev, map_color_rgb_alpha, gx_forward_map_color_rgb_alpha);
+	set_dev_proc(dev, get_color_mapping_procs, gx_forward_get_color_mapping_procs);
+	set_dev_proc(dev, get_color_comp_index, gx_forward_get_color_comp_index);
+	set_dev_proc(dev, encode_color, gx_forward_encode_color);
+	set_dev_proc(dev, decode_color, gx_forward_decode_color);
 	gx_device_set_target((gx_device_forward *)dev, target);
     }
     dev->box_procs = box_procs_default;

Index: gdevbit.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevbit.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gdevbit.c	21 Feb 2002 22:24:51 -0000	1.4
+++ gdevbit.c	22 Aug 2002 07:12:28 -0000	1.5
@@ -108,15 +108,14 @@
 /* Map gray to color. */
 /* Note that 1-bit monochrome is a special case. */
 private gx_color_index
-bit_mono_map_rgb_color(gx_device * dev, gx_color_value red,
-		       gx_color_value green, gx_color_value blue)
+bit_mono_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
     int bpc = dev->color_info.depth;
     int drop = sizeof(gx_color_value) * 8 - bpc;
     gx_color_value gray =
-    (red * (unsigned long)lum_red_weight +
-     green * (unsigned long)lum_green_weight +
-     blue * (unsigned long)lum_blue_weight +
+    (cv[0] * (unsigned long)lum_red_weight +
+     cv[1] * (unsigned long)lum_green_weight +
+     cv[2] * (unsigned long)lum_blue_weight +
      (lum_all_weights / 2))
     / lum_all_weights;
 
@@ -126,14 +125,14 @@
 /* Map RGB to gray shade. */
 /* Only used in CMYK mode when put_params has set ForceMono=1 */
 private gx_color_index
-bit_forcemono_map_rgb_color(gx_device * dev, gx_color_value red,
-		  gx_color_value green, gx_color_value blue)
+bit_forcemono_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
     gx_color_value color;
     int bpc = dev->color_info.depth / 4;	/* This function is used in CMYK mode */
     int drop = sizeof(gx_color_value) * 8 - bpc;
-    gx_color_value gray = red;
-
+    gx_color_value gray, red, green, blue;
+    red = cv[0]; green = cv[1]; blue = cv[2];
+    gray = red;
     if ((red != green) || (green != blue))
 	gray = (red * (unsigned long)lum_red_weight +
 	     green * (unsigned long)lum_green_weight +
@@ -198,16 +197,15 @@
 
 /* Map CMYK to color. */
 private gx_color_index
-bit_map_cmyk_color(gx_device * dev, gx_color_value cyan,
-	gx_color_value magenta, gx_color_value yellow, gx_color_value black)
+bit_map_cmyk_color(gx_device * dev, const gx_color_value cv[])
 {
     int bpc = dev->color_info.depth / 4;
     int drop = sizeof(gx_color_value) * 8 - bpc;
     gx_color_index color =
-    ((((((cyan >> drop) << bpc) +
-	(magenta >> drop)) << bpc) +
-      (yellow >> drop)) << bpc) +
-    (black >> drop);
+    ((((((cv[0] >> drop) << bpc) +
+	(cv[1] >> drop)) << bpc) +
+      (cv[2] >> drop)) << bpc) +
+    (cv[3] >> drop);
 
     return (color == gx_no_color_index ? color ^ 1 : color);
 }

Index: gdevbmpc.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevbmpc.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gdevbmpc.c	18 Jul 2002 11:01:44 -0000	1.5
+++ gdevbmpc.c	22 Aug 2002 07:12:28 -0000	1.6
@@ -212,9 +212,11 @@
 
 /* Map a r-g-b color to a color index. */
 gx_color_index
-bmp_map_16m_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
-		  gx_color_value b)
+bmp_map_16m_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
+
+    gx_color_value r, g, b;
+    r = cv[0]; g = cv[1]; b = cv[2];
     return gx_color_value_to_byte(r) +
 	((uint) gx_color_value_to_byte(g) << 8) +
 	((ulong) gx_color_value_to_byte(b) << 16);

Index: gdevcdj.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevcdj.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- gdevcdj.c	16 Jun 2002 05:48:54 -0000	1.10
+++ gdevcdj.c	22 Aug 2002 07:12:28 -0000	1.11
@@ -2684,12 +2684,11 @@
     (y) = gx_bits_to_color_value((v) & ((1 << (b)) - 1), (b))
 
 private gx_color_index
-gdev_cmyk_map_cmyk_color(gx_device* pdev,
-    gx_color_value cyan, gx_color_value magenta, gx_color_value yellow,
-    gx_color_value black) {
-
+gdev_cmyk_map_cmyk_color(gx_device* pdev, const gx_color_value cv[])
+{
+    gx_color_value cyan, magenta, yellow, black;
     gx_color_index color;
-
+    cyan = cv[0]; magenta = cv[1]; yellow = cv[2]; black = cv[3];
     switch (pdev->color_info.depth) {
 	case 1:
 	   color = (cyan | magenta | yellow | black) > gx_max_color_value / 2 ?
@@ -2724,34 +2723,35 @@
 /* Mapping of RGB colors to gray values. */
 
 private gx_color_index
-gdev_cmyk_map_rgb_color(gx_device *pdev, gx_color_value r, gx_color_value g, gx_color_value b)
+gdev_cmyk_map_rgb_color(gx_device *pdev, const gx_color_value cv[])
 {
+    gx_color_value r, g, b;
+    r = cv[0]; g = cv[1]; b = cv[2];
+    if (gx_color_value_to_byte(r & g & b) == 0xff) {
+        return (gx_color_index) 0;	/* White */
+    } else {
+        gx_color_value c = gx_max_color_value - r;
+        gx_color_value m = gx_max_color_value - g;
+        gx_color_value y = gx_max_color_value - b;
 
-  if (gx_color_value_to_byte(r & g & b) == 0xff) {
-      return (gx_color_index) 0;	/* White */
-  } else {
-      gx_color_value c = gx_max_color_value - r;
-      gx_color_value m = gx_max_color_value - g;
-      gx_color_value y = gx_max_color_value - b;
-
-      switch (pdev->color_info.depth) {
-	  case 1:
-	      return (c | m | y) > gx_max_color_value / 2 ?
-	          (gx_color_index) 1 : (gx_color_index) 0;
-	      /*NOTREACHED*/
-	      break;
+        switch (pdev->color_info.depth) {
+        case 1:
+            return (c | m | y) > gx_max_color_value / 2 ?
+                (gx_color_index) 1 : (gx_color_index) 0;
+            /*NOTREACHED*/
+            break;
 
-	  case 8:
-	      return ((ulong) c * lum_red_weight * 10
-	          + (ulong) m * lum_green_weight * 10
-	          + (ulong) y * lum_blue_weight * 10)
-		  >> (gx_color_value_bits + 2);
-	      /*NOTREACHED*/
-	      break;
-      }
-  }
+        case 8:
+            return ((ulong) c * lum_red_weight * 10
+                    + (ulong) m * lum_green_weight * 10
+                    + (ulong) y * lum_blue_weight * 10)
+                        >> (gx_color_value_bits + 2);
+            /*NOTREACHED*/
+            break;
+        }
+    }
 
-   return (gx_color_index) 0;	/* This should never happen. */
+    return (gx_color_index) 0;	/* This should never happen. */
 }
 
 /* Mapping of CMYK colors. */
@@ -2835,9 +2835,10 @@
    } while (0)
 
 private gx_color_index
-gdev_pcl_map_rgb_color(gx_device *pdev, gx_color_value r,
-				 gx_color_value g, gx_color_value b)
+gdev_pcl_map_rgb_color(gx_device *pdev, const gx_color_value cv[])
 {
+  gx_color_value r, g, b;
+  r = cv[0]; g = cv[1]; b = cv[2];
   if (gx_color_value_to_byte(r & g & b) == 0xff)
     return (gx_color_index)0;         /* white */
   else {

Index: gdevcmap.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevcmap.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gdevcmap.c	21 Feb 2002 22:24:51 -0000	1.4
+++ gdevcmap.c	22 Aug 2002 07:12:28 -0000	1.5
@@ -33,40 +33,47 @@
 public_st_device_cmap();
 
 /* Device procedures */
-private dev_proc_map_rgb_color(cmap_map_rgb_color);
-private dev_proc_map_rgb_alpha_color(cmap_map_rgb_alpha_color);
-private dev_proc_map_cmyk_color(cmap_map_cmyk_color);
 private dev_proc_get_params(cmap_get_params);
 private dev_proc_put_params(cmap_put_params);
 private dev_proc_begin_typed_image(cmap_begin_typed_image);
+private dev_proc_get_color_mapping_procs(cmap_get_color_mapping_procs);
+
+/*
+ * NB: all of the device color model information will be replaced by
+ * the target's color model information. Only the
+ * get_color_mapping_procs method is modified (aside from
+ * get_params/put_params).
+ *
+ * The begin_typed_image method is used only to force use of the default
+ * image rendering routines if a special mapping_method (anything other
+ * than device_cmap_identity) is requested.
+ */
 
 private const gx_device_cmap gs_cmap_device = {
     std_device_dci_body(gx_device_cmap, 0, "special color mapper",
-			0, 0, 1, 1,
-			3, 24, 255, 255, 256, 256),
+                        0, 0, 1, 1,
+                        3, 24, 255, 255, 256, 256),
     {
-	0, 0, 0, 0, 0,
-	cmap_map_rgb_color,
-	0,			/* map_color_rgb */
-	gx_forward_fill_rectangle,
-	gx_forward_tile_rectangle,
-	gx_forward_copy_mono,
-	gx_forward_copy_color,
-	0, 0,
-	cmap_get_params,
-	cmap_put_params,
-	cmap_map_cmyk_color,
-	0, 0,
-	cmap_map_rgb_alpha_color,
-	0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0,
-	gx_default_begin_image,
-	0, 0, 0, 0, 0,
-	cmap_begin_typed_image,
-	0,
-	0			/* map_color_rgb_alpha */
+        0, 0, 0, 0, 0, 0, 0,
+        gx_forward_fill_rectangle,
+        gx_forward_tile_rectangle,
+        gx_forward_copy_mono,
+        gx_forward_copy_color,
+        0, 0,
+        cmap_get_params,
+        cmap_put_params,
+        0, 0, 0, 0,
+        0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0,
+        gx_default_begin_image,
+        0, 0, 0, 0, 0,
+        cmap_begin_typed_image,
+        0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0,
+        cmap_get_color_mapping_procs,
+        0, 0, 0
     },
-    0,				/* target */
+    0,                          /* target */
     device_cmap_identity
 };
 
@@ -94,15 +101,22 @@
 	    set_dev_proc(cmdev, map_cmyk_color, gx_forward_map_cmyk_color);
 	    cmdev->color_info.max_gray = target->color_info.max_gray;
 	    cmdev->color_info.max_color = target->color_info.max_color;
+	    cmdev->color_info.max_components =
+	        target->color_info.max_components;
 	    cmdev->color_info.num_components =
 		target->color_info.num_components;
+	    cmdev->color_info.polarity = target->color_info.polarity;
+	    cmdev->color_info.gray_index = target->color_info.gray_index;
+	    cmdev->color_info.cm_name = target->color_info.cm_name;
 	    gx_device_copy_color_procs((gx_device *)cmdev, target);
 	    break;
 
 	case device_cmap_monochrome:
 	    cmdev->color_info.max_gray = target->color_info.max_gray;
 	    cmdev->color_info.max_color = target->color_info.max_color;
-	    cmdev->color_info.num_components = 1;
+	    cmdev->color_info.max_components = 
+	        cmdev->color_info.num_components = 1;
+	    cmdev->color_info.cm_name = "DeviceGray";
 	    break;
 
 	case device_cmap_snap_to_primaries:
@@ -112,7 +126,9 @@
 	     * We have to be an RGB device, otherwise "primaries" doesn't
 	     * have the proper meaning.
 	     */
-	    cmdev->color_info.num_components = 3;
+	    cmdev->color_info.max_components = 
+	        cmdev->color_info.num_components = 3;
+	    cmdev->color_info.cm_name = "DeviceRGB";
 	    break;
 
 	default:
@@ -140,107 +156,6 @@
     return 0;
 }
 
-/* Map RGB colors, and convert to the target's native color model. */
-/* Return true if the target is an RGB device, false if CMYK. */
-private bool
-cmap_convert_rgb_color(const gx_device_cmap * cmdev, gx_color_value red,
-		       gx_color_value green, gx_color_value blue,
-		       gx_color_value cv[4])
-{
-    gx_color_value red_out, green_out, blue_out;
-
-    switch (cmdev->mapping_method) {
-
-	case device_cmap_snap_to_primaries:
-	    /* Snap each RGB primary component to 0 or 1 individually. */
-	    red_out =
-		(red <= gx_max_color_value / 2 ? 0 : gx_max_color_value);
-	    green_out =
-		(green <= gx_max_color_value / 2 ? 0 : gx_max_color_value);
-	    blue_out =
-		(blue <= gx_max_color_value / 2 ? 0 : gx_max_color_value);
-	    break;
-
-	case device_cmap_color_to_black_over_white:
-	    /* Snap black to white, other colors to black. */
-	    red_out = green_out = blue_out =
-		((red | green | blue) == 0 ? gx_max_color_value : 0);
-	    break;
-
-	case device_cmap_identity:
-	case device_cmap_monochrome:
-	default:
-	    red_out = red, green_out = green, blue_out = blue;
-	    break;
-
-    }
-
-    /* Check for a CMYK device. */
-    if (cmdev->target->color_info.num_components <= 3) {
-	cv[0] = red_out, cv[1] = green_out, cv[2] = blue_out;
-	return true;
-    }
-
-    /*
-     * Convert RGB to CMYK using default (null) black generation and
-     * undercolor removal.  This isn't right, but we don't have access to an
-     * imager state to provide the correct procedures.
-     */
-    cv[0] = gx_max_color_value - red_out;
-    cv[1] = gx_max_color_value - green_out;
-    cv[2] = gx_max_color_value - blue_out;
-    cv[3] = 0;
-    return false;
-}
-
-private gx_color_index
-cmap_map_rgb_color(gx_device * dev, gx_color_value red,
-		   gx_color_value green, gx_color_value blue)
-{
-    const gx_device_cmap *const cmdev = (const gx_device_cmap *)dev;
-    gx_device *target = cmdev->target;
-    gx_color_value cv[4];
-    bool is_rgb = cmap_convert_rgb_color(cmdev, red, green, blue, cv);
-
-    return
-	(is_rgb ? target->procs.map_rgb_color(target, cv[0], cv[1], cv[2]) :
-	 target->procs.map_cmyk_color(target, cv[0], cv[1], cv[2], cv[3]));
-}
-
-private gx_color_index
-cmap_map_rgb_alpha_color(gx_device * dev, gx_color_value red,
-			 gx_color_value green, gx_color_value blue,
-			 gx_color_value alpha)
-{
-    const gx_device_cmap *const cmdev = (const gx_device_cmap *)dev;
-    gx_device *target = cmdev->target;
-    gx_color_value cv[4];
-    bool is_rgb = cmap_convert_rgb_color(cmdev, red, green, blue, cv);
-
-    return
-	(is_rgb ? target->procs.map_rgb_alpha_color(target, cv[0], cv[1],
-						    cv[2], alpha) :
-	 /****** CMYK DISREGARDS ALPHA ******/
-	 target->procs.map_cmyk_color(target, cv[0], cv[1], cv[2], cv[3]));
-}
-
-private gx_color_index
-cmap_map_cmyk_color(gx_device * dev, gx_color_value c,
-		    gx_color_value m, gx_color_value y, gx_color_value k)
-{
-    const gx_device_cmap *const cmdev = (const gx_device_cmap *)dev;
-    gx_device *target = cmdev->target;
-    frac frac_rgb[3];
-
-    if (cmdev->mapping_method == device_cmap_identity)
-	return target->procs.map_cmyk_color(target, c, m, y, k);
-    color_cmyk_to_rgb(cv2frac(c), cv2frac(m), cv2frac(y), cv2frac(k),
-		      NULL, frac_rgb);
-    return cmap_map_rgb_color(dev, frac2cv(frac_rgb[0]),
-			      frac2cv(frac_rgb[1]),
-			      frac2cv(frac_rgb[2]));
-}
-
 /* Get parameters. */
 private int
 cmap_get_params(gx_device * dev, gs_param_list * plist)
@@ -309,3 +224,101 @@
     return gx_default_begin_typed_image(dev, pis, pmat, pic, prect,
 					pdcolor, pcpath, memory, pinfo);
 }
+
+private void
+cmap_gray_cs_to_cm(gx_device * dev, frac gray, frac out[])
+{
+    gx_device_cmap *    cmdev = (gx_device_cmap *)dev;
+    frac gx_max_color_frac   = cv2frac(gx_max_color_value);
+    switch (cmdev->mapping_method) {
+    case device_cmap_snap_to_primaries:
+        gray = (gray <= gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
+        break;
+
+    case device_cmap_color_to_black_over_white:
+        gray = (gray == 0 ? gx_max_color_frac : 0);
+        break;
+    }
+    {
+        gx_device *target = cmdev->target ? cmdev->target : dev;
+        gx_cm_color_map_procs *cm_procs =  (dev_proc( target, get_color_mapping_procs)(target));
+        cm_procs->map_gray(target, gray, out );
+    }
+}
+
+private void
+cmap_rgb_cs_to_cm(gx_device * dev, const gs_imager_state * pis, frac r, frac g, frac b, frac out[])
+{
+    
+    gx_device_cmap *    cmdev = (gx_device_cmap *)dev;
+    frac gx_max_color_frac   = cv2frac(gx_max_color_value);
+    switch (cmdev->mapping_method) {
+        
+    case device_cmap_snap_to_primaries:
+        r = (r <= gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
+        g = (g <= gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
+        b = (b <= gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
+        break;
+
+    case device_cmap_color_to_black_over_white:
+        if (r == 0 && g == 0 && b == 0)
+            r = g = b = gx_max_color_frac;
+        else
+            r = g = b = 0;
+        break;
+
+    case device_cmap_monochrome:
+        r = g = b = color_rgb_to_gray(r, g, b, NULL);
+        break;
+    }
+    {
+        gx_device *target = cmdev->target ? cmdev->target : dev;
+        gx_cm_color_map_procs *cm_procs =  (dev_proc( target, get_color_mapping_procs)(target));
+        cm_procs->map_rgb(target, pis, r, g, b, out );
+    }
+}
+
+private void
+cmap_cmyk_cs_to_cm(gx_device * dev, frac c, frac m, frac y, frac k, frac out[])
+{
+    gx_device_cmap *    cmdev = (gx_device_cmap *)dev;
+    frac gx_max_color_frac   = cv2frac(gx_max_color_value);
+    /* We aren't sure what to do with k so we leave it alone.  NB this
+       routine is untested and does not appear to be called.  More
+       testing needed. */
+    switch (cmdev->mapping_method) {
+    case device_cmap_snap_to_primaries:
+        c = (c > gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
+        m = (m > gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
+        y = (y > gx_max_color_frac / 2 ? 0 : gx_max_color_frac);
+        break;
+
+    case device_cmap_color_to_black_over_white:
+        if (c == gx_max_color_frac && m == gx_max_color_frac && y == gx_max_color_frac)
+            c = m = y = 0;
+        else
+            c = m = y = gx_max_color_frac;
+        break;
+
+    case device_cmap_monochrome:
+        c = m = y = color_cmyk_to_gray(c, m, y, k, NULL);
+        break;
+    }
+    {
+        gx_device *target = cmdev->target ? cmdev->target : dev;
+        gx_cm_color_map_procs *cm_procs =  (dev_proc( target, get_color_mapping_procs)(target));
+        cm_procs->map_cmyk(target, c, m, y, k, out );
+    }
+}
+
+private const gx_cm_color_map_procs cmap_cm_procs = {
+    cmap_gray_cs_to_cm, cmap_rgb_cs_to_cm, cmap_cmyk_cs_to_cm
+};
+
+
+private const gx_cm_color_map_procs *
+cmap_get_color_mapping_procs(const gx_device * dev)
+{
+    return &cmap_cm_procs;
+}
+

Index: gdevdbit.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevdbit.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gdevdbit.c	21 Jun 2002 22:05:33 -0000	1.5
+++ gdevdbit.c	22 Aug 2002 07:12:28 -0000	1.6
@@ -168,12 +168,13 @@
 	const byte *row;
 	gs_memory_t *mem = dev->memory;
 	int bpp = dev->color_info.depth;
+	int ncomps = dev->color_info.num_components;
 	uint in_size = gx_device_raster(dev, false);
 	byte *lin;
 	uint out_size;
 	byte *lout;
 	int code = 0;
-	gx_color_value color_rgb[3];
+	gx_color_value color_cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
 	int ry;
 
 	fit_copy(dev, data, data_x, raster, id, x, y, width, height);
@@ -185,7 +186,7 @@
 	    code = gs_note_error(gs_error_VMerror);
 	    goto out;
 	}
-	(*dev_proc(dev, map_color_rgb)) (dev, color, color_rgb);
+	(*dev_proc(dev, decode_color)) (dev, color, color_cv);
 	for (ry = y; ry < y + height; row += raster, ++ry) {
 	    byte *line;
 	    int sx, rx;
@@ -221,6 +222,14 @@
 
 			    previous = 0;
 			    switch (bpp >> 3) {
+				case 8:
+				    previous += (gx_color_index) * src++ << 56;
+				case 7:
+				    previous += (gx_color_index) * src++ << 48;
+				case 6:
+				    previous += (gx_color_index) * src++ << 40;
+				case 5:
+				    previous += (gx_color_index) * src++ << 32;
 				case 4:
 				    previous += (gx_color_index) * src++ << 24;
 				case 3:
@@ -234,10 +243,11 @@
 		    }
 		    if (alpha == 0) {	/* Just write the old color. */
 			composite = previous;
-		    } else {	/* Blend RGB values. */
-			gx_color_value rgb[3];
+		    } else {	/* Blend values. */
+			gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
+			int i;
 
-			(*dev_proc(dev, map_color_rgb)) (dev, previous, rgb);
+			(*dev_proc(dev, decode_color)) (dev, previous, cv);
 #if arch_ints_are_short
 #  define b_int long
 #else
@@ -245,14 +255,12 @@
 #endif
 #define make_shade(old, clr, alpha, amax) \
   (old) + (((b_int)(clr) - (b_int)(old)) * (alpha) / (amax))
-			rgb[0] = make_shade(rgb[0], color_rgb[0], alpha, 15);
-			rgb[1] = make_shade(rgb[1], color_rgb[1], alpha, 15);
-			rgb[2] = make_shade(rgb[2], color_rgb[2], alpha, 15);
+			for (i=0; i<ncomps; i++)
+			    cv[i] = make_shade(cv[i], color_cv[i], alpha, 15);
 #undef b_int
 #undef make_shade
 			composite =
-			    (*dev_proc(dev, map_rgb_color)) (dev, rgb[0],
-							     rgb[1], rgb[2]);
+			    (*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 == 7)	/* move 1/2 towards 1 */

Index: gdevdflt.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevdflt.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gdevdflt.c	21 Feb 2002 22:24:51 -0000	1.5
+++ gdevdflt.c	22 Aug 2002 07:12:28 -0000	1.6
@@ -16,6 +16,7 @@
 
 /* $Id$ */
 /* Default device implementation */
+#include "math_.h"
 #include "gx.h"
 #include "gserrors.h"
 #include "gsropt.h"
@@ -24,6 +25,308 @@
 
 /* ---------------- Default device procedures ---------------- */
 
+/*
+ * Set a color model polarity to be additive or subtractive. In either
+ * case, indicate an error (and don't modify the polarity) if the current
+ * setting differs from the desired and is not GX_CINFO_POLARITY_UNKNOWN.
+ */
+static void
+set_cinfo_polarity(gx_device * dev, gx_color_polarity_t new_polarity)
+{
+#ifdef DEBUG
+    /* sanity check */
+    if (new_polarity == GX_CINFO_POLARITY_UNKNOWN) {
+        dprintf("set_cinfo_polarity: illegal operand");
+        return;
+    }
+#endif
+
+    if (dev->color_info.polarity == GX_CINFO_POLARITY_UNKNOWN)
+        dev->color_info.polarity = new_polarity;
+    else if (dev->color_info.polarity != new_polarity)
+        dprintf("set_cinfo_polarity: different polarity already set");
+}
+
+
+private gx_color_index
+(*get_encode_color(gx_device *dev))(gx_device *, const gx_color_value *)
+{
+    dev_proc_encode_color(*encode_proc);
+
+    /* use encode_color if it has been provided */
+    if ((encode_proc = dev_proc(dev, encode_color)) == 0) {
+        if ( (dev->color_info.num_components == 1 ||
+              dev->color_info.num_components == 3    )              &&
+             (encode_proc = dev_proc(dev, map_rgb_color)) != 0  )
+            set_cinfo_polarity(dev, GX_CINFO_POLARITY_ADDITIVE);
+        else if ( dev->color_info.num_components == 4                    &&
+                 (encode_proc = dev_proc(dev, map_cmyk_color)) != 0   )
+            set_cinfo_polarity(dev, GX_CINFO_POLARITY_SUBTRACTIVE);
+    }
+
+    /*
+     * If no encode_color procedure at this point, the color model had
+     * better be monochrome (though not necessarily bi-level). In this
+     * case, it is assumed to be additive, as that is consistent with
+     * the pre-DeviceN code.
+     *
+     * If this is not the case, then the color model had better be known
+     * to be separable and linear, for there is no other way to derive
+     * an encoding. This is the case even for weakly linear and separable
+     * color models with a known polarity.
+     */
+    if (encode_proc == 0) {
+        if (dev->color_info.num_components == 1 && dev->color_info.depth != 0) {
+            set_cinfo_polarity(dev, GX_CINFO_POLARITY_ADDITIVE);
+            if (dev->color_info.max_gray == (1 << dev->color_info.depth) - 1)
+                encode_proc = gx_default_gray_fast_encode;
+            else
+                encode_proc = gx_default_gray_encode;
+            dev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
+        } else if (dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN) {
+            gx_color_value  max_gray = dev->color_info.max_gray;
+            gx_color_value  max_color = dev->color_info.max_color;
+
+            if ( (max_gray & (max_gray + 1)) == 0  &&
+                 (max_color & (max_color + 1)) == 0  )
+                /* NB should be gx_default_fast_encode_color */
+                encode_proc = gx_default_encode_color;
+            else
+                encode_proc = gx_default_encode_color;
+        } else
+            dprintf("get_encode_color: no color encoding information");
+    }
+
+    return encode_proc;
+}
+
+/*
+ * Determine if a color model has the properties of a DeviceRGB
+ * color model. This procedure is, in all likelihood, high-grade
+ * overkill, but since this is not a performance sensitive area
+ * no harm is done.
+ *
+ * Since there is little benefit to checking the values 0, 1, or
+ * 1/2, we use the values 1/4, 1/3, and 3/4 in their place. We
+ * compare the results to see if the intensities match to within
+ * a tolerance of .01, which is arbitrarily selected.
+ */
+
+private bool
+is_like_DeviceRGB(gx_device * dev)
+{
+    const gx_cm_color_map_procs *   cm_procs;
+    frac                            cm_comp_fracs[3];
+    int                             i;
+
+    if ( dev->color_info.num_components != 3                   ||
+         dev->color_info.polarity != GX_CINFO_POLARITY_ADDITIVE  )
+        return false;
+    cm_procs = dev_proc(dev, get_color_mapping_procs)(dev);
+    if (cm_procs == 0 || cm_procs->map_rgb == 0)
+        return false;
+
+    /* check the values 1/4, 1/3, and 3/4 */
+    cm_procs->map_rgb( dev,
+                       0,
+                       frac_1 / 4,
+                       frac_1 / 3,
+                       3 * frac_1 / 4,
+                       cm_comp_fracs );
+
+    /* verify results to .01 */
+    cm_comp_fracs[0] -= frac_1 / 4;
+    cm_comp_fracs[1] -= frac_1 / 3;
+    cm_comp_fracs[2] -= 3 * frac_1 / 4;
+    for ( i = 0;
+           i < 3                            &&
+           -frac_1 / 100 < cm_comp_fracs[i] &&
+           cm_comp_fracs[i] < frac_1 / 100;
+          i++ )
+        ;
+    return i == 3;
+}
+
+/*
+ * Similar to is_like_DeviceRGB, but for DeviceCMYK.
+ */
+private bool
+is_like_DeviceCMYK(gx_device * dev)
+{
+    const gx_cm_color_map_procs *   cm_procs;
+    frac                            cm_comp_fracs[4];
+    int                             i;
+
+    if ( dev->color_info.num_components != 4                      ||
+         dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE  )
+        return false;
+    cm_procs = dev_proc(dev, get_color_mapping_procs)(dev);
+    if (cm_procs == 0 || cm_procs->map_cmyk == 0)
+        return false;
+
+    /* check the values 1/4, 1/3, 3/4, and 1/8 */
+    cm_procs->map_cmyk( dev,
+                        frac_1 / 4,
+                        frac_1 / 3,
+                        3 * frac_1 / 4,
+                        frac_1 / 8,
+                        cm_comp_fracs );
+
+    /* verify results to .01 */
+    cm_comp_fracs[0] -= frac_1 / 4;
+    cm_comp_fracs[1] -= frac_1 / 3;
+    cm_comp_fracs[2] -= 3 * frac_1 / 4;
+    cm_comp_fracs[3] -= frac_1 / 8;
+    for ( i = 0;
+           i < 4                            &&
+           -frac_1 / 100 < cm_comp_fracs[i] &&
+           cm_comp_fracs[i] < frac_1 / 100;
+          i++ )
+        ;
+    return i == 4;
+}
+
+/*
+ * Two default decode_color procedures to use for monochrome devices.
+ * These will make use of the map_color_rgb routine, and use the first
+ * component of the returned value or its inverse.
+ */
+private int
+gx_default_1_add_decode_color(
+    gx_device *     dev,
+    gx_color_index  color,
+    gx_color_value  cv[1] )
+{
+    gx_color_value  rgb[3];
+    int             code = dev_proc(dev, map_color_rgb)(dev, color, rgb);
+
+    cv[0] = rgb[0];
+    return code;
+}
+
+private int
+gx_default_1_sub_decode_color(
+    gx_device *     dev,
+    gx_color_index  color,
+    gx_color_value  cv[1] )
+{
+    gx_color_value  rgb[3];
+    int             code = dev_proc(dev, map_color_rgb)(dev, color, rgb);
+
+    cv[0] = gx_max_color_value - rgb[0];
+    return code;
+}
+
+/*
+ * A default decode_color procedure for DeviceCMYK color models.
+ *
+ * There is no generally accurate way of decode a DeviceCMYK color using
+ * the map_color_rgb method. Unfortunately, there are many older devices
+ * employ the DeviceCMYK color model but don't provide a decode_color
+ * method. The code below works on the assumption of full undercolor
+ * removal and black generation. This may not be accurate, but is the
+ * best that can be done in the absence of other information.
+ */
+private int
+gx_default_cmyk_decode_color(
+    gx_device *     dev,
+    gx_color_index  color,
+    gx_color_value  cv[4] )
+{
+    int             i, code = dev_proc(dev, map_color_rgb)(dev, color, cv);
+    gx_color_value  min_val = gx_max_color_value;
+
+    for (i = 0; i < 3; i++) {
+        if ((cv[i] = gx_max_color_value - cv[i]) < min_val)
+            min_val = cv[i];
+    }
+    for (i = 0; i < 3; i++)
+        cv[i] -= min_val;
+    cv[3] = min_val;
+
+    return code;
+}
+
+
+private int
+(*get_decode_color(gx_device * dev))(gx_device *, gx_color_index, gx_color_value *)
+{
+    /* if a method has already been provided, use it */
+    if (dev_proc(dev, decode_color) != 0)
+        return dev_proc(dev, decode_color);
+
+    /*
+     * If a map_color_rgb method has been provided, we may be able to use it.
+     * Currently this will always be the case, as a default value will be
+     * provided this method. While this default may not be correct, we are not
+     * introducing any new errors by using it.
+     */
+    if (dev_proc(dev, map_color_rgb) != 0) {
+
+        /* if the device has a DeviceRGB color model, use map_color_rgb */
+        if (is_like_DeviceRGB(dev))
+            return dev_proc(dev, map_color_rgb);
+
+        /* gray devices can be handled based on their polarity */
+        if ( dev->color_info.num_components == 1 &&
+             dev->color_info.gray_index == 0       )
+            return dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE
+                       ? gx_default_1_add_decode_color
+                       : gx_default_1_sub_decode_color;
+
+        /*
+         * There is no accurate way to decode colors for cmyk devices
+         * using the map_color_rgb procedure. Unfortunately, this cases
+         * arises with some frequency, so it is useful not to generate an
+         * error in this case. The mechanism below assumes full undercolor
+         * removal and black generation, which may not be accurate but are
+         * the  best that can be done in the absence of other information.
+         */
+        if (is_like_DeviceCMYK(dev))
+            return gx_default_cmyk_decode_color;
+    }
+
+    /*
+     * The separable and linear case will already have been handled by
+     * code in gx_device_fill_in_procs, so at this point we can only hope
+     * the device doesn't use the decode_color method.
+     */
+     return gx_error_decode_color;
+}
+
+/*
+ * If a device has a linear and separable encode color function then
+ * set up the comp_bits, comp_mask, and comp_shift fields.
+ */
+void
+set_linear_color_bits_mask_shift(gx_device * dev)
+{
+    int i;
+    byte gray_index = dev->color_info.gray_index;
+    gx_color_value max_gray = dev->color_info.max_gray;
+    gx_color_value max_color = dev->color_info.max_color;
+    int num_components = dev->color_info.num_components;
+
+#define comp_bits (dev->color_info.comp_bits)
+#define comp_mask (dev->color_info.comp_mask)
+#define comp_shift (dev->color_info.comp_shift)
+    comp_shift[num_components - 1] = 0;
+    for ( i = num_components - 1 - 1; i >= 0; i-- ) {
+        comp_shift[i] = comp_shift[i + 1] + 
+            ( i == gray_index ? ilog2(max_gray + 1) : ilog2(max_color + 1) );
+    }
+    for ( i = 0; i < num_components; i++ ) {
+        comp_bits[i] = ( i == gray_index ?
+                         ilog2(max_gray + 1) :
+                         ilog2(max_color + 1) );
+        comp_mask[i] = (((gx_color_index)1 << comp_bits[i]) - 1)
+                                               << comp_shift[i];
+    }
+#undef comp_bits
+#undef comp_mask
+#undef comp_shift
+}
+
 /* Fill in NULL procedures in a device procedure record. */
 void
 gx_device_fill_in_procs(register gx_device * dev)
@@ -34,7 +337,7 @@
     fill_dev_proc(dev, sync_output, gx_default_sync_output);
     fill_dev_proc(dev, output_page, gx_default_output_page);
     fill_dev_proc(dev, close_device, gx_default_close_device);
-    fill_dev_proc(dev, map_rgb_color, gx_default_map_rgb_color);
+    /* see below for map_rgb_color */
     fill_dev_proc(dev, map_color_rgb, gx_default_map_color_rgb);
     /* NOT fill_rectangle */
     fill_dev_proc(dev, tile_rectangle, gx_default_tile_rectangle);
@@ -44,7 +347,7 @@
     fill_dev_proc(dev, get_bits, gx_default_get_bits);
     fill_dev_proc(dev, get_params, gx_default_get_params);
     fill_dev_proc(dev, put_params, gx_default_put_params);
-    fill_dev_proc(dev, map_cmyk_color, gx_default_map_cmyk_color);
+    /* see below for map_cmyk_color */
     fill_dev_proc(dev, get_xfont_procs, gx_default_get_xfont_procs);
     fill_dev_proc(dev, get_xfont_device, gx_default_get_xfont_device);
     fill_dev_proc(dev, map_rgb_alpha_color, gx_default_map_rgb_alpha_color);
@@ -95,6 +398,100 @@
     fill_dev_proc(dev, get_hardware_params, gx_default_get_hardware_params);
     fill_dev_proc(dev, text_begin, gx_default_text_begin);
     fill_dev_proc(dev, finish_copydevice, gx_default_finish_copydevice);
+
+    set_dev_proc(dev, encode_color, get_encode_color(dev));
+    set_dev_proc(dev, map_cmyk_color, dev_proc(dev, encode_color));
+    set_dev_proc(dev, map_rgb_color, dev_proc(dev, encode_color));
+
+
+    if ( dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN ) {
+        fill_dev_proc(dev, encode_color, gx_default_encode_color);
+        fill_dev_proc(dev, map_cmyk_color, gx_default_encode_color);
+        fill_dev_proc(dev, map_rgb_color, gx_default_encode_color);
+    } else {
+        /* if it isn't set now punt */
+        fill_dev_proc(dev, encode_color, gx_error_encode_color);
+        fill_dev_proc(dev, map_cmyk_color, gx_error_encode_color);
+        fill_dev_proc(dev, map_rgb_color, gx_error_encode_color);
+    }
+
+    /*
+     * Fill in the color mapping procedures and the component index
+     * assignment procedure if they have not been provided by the client.
+     *
+     * Because it is difficult to provide default encoding procedures
+     * that handle level inversion, this code needs to check both
+     * the number of components and the polarity of color model.
+     */
+    switch (dev->color_info.num_components) {
+    case 1:     /* DeviceGray or DeviceInvertGray */
+        if (dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE) {
+            fill_dev_proc( dev,
+                           get_color_mapping_procs,
+                           gx_default_DevGray_get_color_mapping_procs );
+        } else {
+            dprintf( "Subtractive gray mapping not implemented");
+#if 0
+            fill_dev_proc( dev,
+                           get_color_mapping_procs,
+                           gx_default_InvertDevGray_get_color_mapping_procs );
+#endif
+        }
+        fill_dev_proc( dev,
+                       get_color_comp_index,
+                       gx_default_DevGray_get_color_comp_index );
+        break;
+
+    case 3:
+        if (dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE) {
+            fill_dev_proc( dev,
+                           get_color_mapping_procs,
+                           gx_default_DevRGB_get_color_mapping_procs );
+            fill_dev_proc( dev,
+                           get_color_comp_index,
+                           gx_default_DevRGB_get_color_comp_index );
+        } else {
+            dprintf ( "DeviceCMY mapping procs not supported\n" );
+#if 0
+            fill_dev_proc( dev,
+                           get_color_mapping_procs,
+                           gx_default_DevCMY_get_color_mapping_procs );
+            fill_dev_proc( dev,
+                           get_color_comp_index,
+                           gx_default_DevCMY_get_color_comp_index );
+#endif
+        }
+        break;
+
+    case 4:
+        fill_dev_proc(dev, get_color_mapping_procs, gx_default_DevCMYK_get_color_mapping_procs);
+        fill_dev_proc(dev, get_color_comp_index, gx_default_DevCMYK_get_color_comp_index);
+        break;
+    default:		/* Unknown color model - set error handlers */
+        fill_dev_proc(dev, get_color_mapping_procs, gx_error_get_color_mapping_procs);
+        fill_dev_proc(dev, get_color_comp_index, gx_error_get_color_comp_index);
+    }
+
+    if ( dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN ) {
+        fill_dev_proc(dev, decode_color, gx_default_decode_color);
+	if ((dev_proc(dev, map_color_rgb) != 0) !=
+	    (dev_proc(dev, decode_color) != 0)) {
+	    if (is_like_DeviceRGB(dev)) {
+		if (dev_proc(dev, map_color_rgb) != 0)
+		    set_dev_proc(dev, decode_color, dev_proc(dev, map_color_rgb));
+		else if (dev_proc(dev, decode_color) != 0)
+		    set_dev_proc(dev, map_color_rgb, dev_proc(dev, decode_color));
+	    }
+        }
+    }
+    fill_dev_proc(dev, map_color_rgb, gx_default_map_color_rgb);
+
+    set_dev_proc(dev, decode_color, get_decode_color(dev));
+
+    /* initialiazation -- NB this chould be moved */
+    if ( dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN ) {
+	set_linear_color_bits_mask_shift(dev);
+    }
 }
 
 int

Index: gdevdgbr.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevdgbr.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gdevdgbr.c	16 Jun 2002 05:48:54 -0000	1.5
+++ gdevdgbr.c	22 Aug 2002 07:12:28 -0000	1.6
@@ -324,6 +324,7 @@
 	     */
 	    gx_device_memory tdev;
 	    byte *line_ptr = data;
+	    int bit_w = w * depth;
 
 	    tdev.line_ptrs = &tdev.base;
 	    for (; h > 0; line_ptr += raster, src += dev_raster, --h) {
@@ -331,9 +332,12 @@
 		int align = ALIGNMENT_MOD(line_ptr, align_bitmap_mod);
 
 		tdev.base = line_ptr - align;
+		/* set up parameters required by copy_mono's fit_copy */
+		tdev.width = dest_bit_x + (align << 3) + bit_w;
+		tdev.height = 1;
 		(*dev_proc(&mem_mono_device, copy_mono))
 		    ((gx_device *) & tdev, src, bit_x, dev_raster, gx_no_bitmap_id,
-		     dest_bit_x + (align << 3), 0, w, 1,
+		     dest_bit_x + (align << 3), 0, bit_w, 1,
 		     (gx_color_index) 0, (gx_color_index) 1);
 	    }
 	} else if (options & ~stored_options & GB_COLORS_NATIVE) {
@@ -428,44 +432,67 @@
 	sample_store_declare_setup(dest, dbit, dbyte, dest_line,
 				   dest_bit_offset & 7, depth);
 
-	for (i = 0; i < w; ++i) {
-	    int j;
-	    gx_color_value v[4], va = alpha_default;
-	    gx_color_index pixel;
+#define v2frac(value) ((long)(value) * frac_1 / src_max)
 
-	    /* Fetch the source data. */
-	    if (stored->options & GB_ALPHA_FIRST) {
-		sample_load_next16(va, src, sbit, src_depth);
-		va = v2cv(va);
-	    }
-	    for (j = 0; j < ncolors; ++j) {
-		gx_color_value vj;
+        for (i = 0; i < w; ++i) {
+            int j;
+            frac sc[4], dc[GX_DEVICE_COLOR_MAX_COMPONENTS];
+            gx_color_value v[GX_DEVICE_COLOR_MAX_COMPONENTS], va = alpha_default;
+            gx_color_index pixel;
+            bool do_alpha = false;
+            gx_cm_color_map_procs * map_procs;
 
-		sample_load_next16(vj, src, sbit, src_depth);
-		v[j] = v2cv(vj);
-	    }
-	    if (stored->options & GB_ALPHA_LAST) {
-		sample_load_next16(va, src, sbit, src_depth);
-		va = v2cv(va);
-	    }
-	    /* Convert and store the pixel value. */
-	    switch (ncolors) {
-	    case 1:
-		v[2] = v[1] = v[0];
-	    case 3:
-		pixel = (*dev_proc(dev, map_rgb_alpha_color))
-		    (dev, v[0], v[1], v[2], va);
-		break;
-	    case 4:
-		/****** NO ALPHA FOR CMYK ******/
-		pixel = (*dev_proc(dev, map_cmyk_color))
-		    (dev, v[0], v[1], v[2], v[3]);
-		break;
-	    default:
-		return_error(gs_error_rangecheck);
-	    }
-	    sample_store_next32(pixel, dest, dbit, depth, dbyte);
-	}
+            map_procs = dev_proc(dev, get_color_mapping_procs)(dev);
+
+            /* Fetch the source data. */
+            if (stored->options & GB_ALPHA_FIRST) {
+                sample_load_next16(va, src, sbit, src_depth);
+                va = v2cv(va);
+                do_alpha = true;
+            }
+            for (j = 0; j < ncolors; ++j) {
+                gx_color_value vj;
+
+                sample_load_next16(vj, src, sbit, src_depth);
+                sc[j] = v2frac(vj);
+            }
+            if (stored->options & GB_ALPHA_LAST) {
+                sample_load_next16(va, src, sbit, src_depth);
+                va = v2cv(va);
+                do_alpha = true;
+            }
+
+            /* Convert and store the pixel value. */
+            if (do_alpha) {
+                for (j = 0; j < ncolors; j++)
+                    v[j] = frac2cv(sc[j]);
+                if (ncolors == 1)
+                    v[2] = v[1] = v[0];
+                pixel = dev_proc(dev, map_rgb_alpha_color)
+                    (dev, v[0], v[1], v[2], va);
+            } else {
+
+                switch (ncolors) {
+                case 1:
+                    map_procs->map_gray(dev, sc[0], dc);
+                    break;
+                case 3:
+                    map_procs->map_rgb(dev, 0, sc[0], sc[1], sc[2], dc);
+                    break;
+                case 4:
+                    map_procs->map_cmyk(dev, sc[0], sc[1], sc[2], sc[3], dc);
+                    break;
+                default:
+                    return_error(gs_error_rangecheck);
+                }
+
+                for (j = 0; j < dev->color_info.num_components; j++)
+                    v[j] = frac2cv(dc[j]);
+
+                pixel = dev_proc(dev, encode_color)(dev, v);
+            }
+            sample_store_next32(pixel, dest, dbit, depth, dbyte);
+        }
 	sample_store_flush(dest, dbit, depth, dbyte);
     }
     return 0;

Index: gdevdrop.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevdrop.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gdevdrop.c	16 Jun 2002 05:48:55 -0000	1.6
+++ gdevdrop.c	22 Aug 2002 07:12:28 -0000	1.7
@@ -255,15 +255,20 @@
 }
 
 private gx_color_index
-map_rgb_to_color_via_cmyk(gx_device * dev, gx_color_value r,
-			  gx_color_value g, gx_color_value b)
+map_rgb_to_color_via_cmyk(gx_device * dev, const gx_color_value rgbcv[])
 {
-    gx_color_value c = gx_max_color_value - r;
-    gx_color_value m = gx_max_color_value - g;
-    gx_color_value y = gx_max_color_value - b;
-    gx_color_value k = (c < m ? min(c, y) : min(m, y));
+    gx_color_value cmykcv[4];
+    
+    cmykcv[0] = gx_max_color_value - rgbcv[0];
+    cmykcv[1] = gx_max_color_value - rgbcv[1];
+    cmykcv[2] = gx_max_color_value - rgbcv[2];
+    cmykcv[3] = (cmykcv[0] < cmykcv[1] ? min(cmykcv[0], cmykcv[2]) : min(cmykcv[1], cmykcv[2]));
 
-    return (*dev_proc(dev, map_cmyk_color)) (dev, c - k, m - k, y - k, k);
+    cmykcv[0] -= cmykcv[3];
+    cmykcv[1] -= cmykcv[3];
+    cmykcv[2] -= cmykcv[3];
+
+    return (*dev_proc(dev, map_cmyk_color)) (dev, cmykcv);
 }
 private void
 pack_from_standard(gx_device * dev, byte * dest, int destx, const byte * src,
@@ -281,7 +286,6 @@
 
     for (x = width; --x >= 0;) {
 	byte vr, vg, vb;
-	gx_color_value r, g, b;
 	gx_color_index pixel;
 	byte chop = 0x1;
 
@@ -296,10 +300,11 @@
 	 * isn't accurate.
 	 */
 	for (;;) {
-	    r = gx_color_value_from_byte(vr);
-	    g = gx_color_value_from_byte(vg);
-	    b = gx_color_value_from_byte(vb);
-	    pixel = (*map) (dev, r, g, b);
+            gx_color_value cv[3];
+	    cv[0] = gx_color_value_from_byte(vr);
+	    cv[1] = gx_color_value_from_byte(vg);
+	    cv[2] = gx_color_value_from_byte(vb);
+	    pixel = (*map) (dev, cv);
 	    if (pixel != gx_no_color_index)
 		break;
 	    /* Reduce the color accuracy and try again. */

Index: gdevdsp.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevdsp.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- gdevdsp.c	21 Jun 2002 22:30:09 -0000	1.11
+++ gdevdsp.c	22 Aug 2002 07:12:28 -0000	1.12
@@ -41,6 +41,7 @@
 #include "string_.h"
 #include "gx.h"
 #include "gserrors.h"
+#include "gsdevice.h"		/* for gs_copydevice */
 #include "gxdevice.h"
 
 #include "gp.h"
@@ -76,8 +77,6 @@
 private dev_proc_map_color_rgb(display_map_color_rgb_rgb);
 private dev_proc_map_rgb_color(display_map_rgb_color_bgr24);
 private dev_proc_map_color_rgb(display_map_color_rgb_bgr24);
[...685 lines suppressed...]
+	    if ((nFormat & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_1)
+	    	set_cmyk_color_procs(pdev, cmyk_1bit_map_cmyk_color,
+						cmyk_1bit_map_color_cmyk);
+	    else if ((nFormat & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8)
+	    	set_cmyk_color_procs(pdev, cmyk_8bit_map_cmyk_color,
+						cmyk_8bit_map_color_cmyk);
 	    else
 		return_error(gs_error_rangecheck);
 	    break;
@@ -1142,8 +1216,9 @@
 
     /* restore old anti_alias info */
     dci.anti_alias = ddev->color_info.anti_alias;
-
     ddev->color_info = dci;
+    /* Set the mask bits, etc. even though we are setting linear: unkown */
+    set_linear_color_bits_mask_shift(pdev);
     ddev->nFormat = nFormat;
 
     return 0;

Index: gdevepsc.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevepsc.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gdevepsc.c	16 Jun 2002 05:48:55 -0000	1.6
+++ gdevepsc.c	22 Aug 2002 07:12:28 -0000	1.7
@@ -75,18 +75,18 @@
 /* Map an RGB color to a printer color. */
 #define cv_shift (sizeof(gx_color_value) * 8 - 1)
 private gx_color_index
-epson_map_rgb_color(gx_device *dev,
-  gx_color_value r, gx_color_value g, gx_color_value b)
+epson_map_rgb_color(gx_device *dev, const gx_color_value cv[])
 {
-if (gx_device_has_color(dev))
-	{
+
+    gx_color_value r = cv[0];
+    gx_color_value g = cv[1];
+    gx_color_value b = cv[2];
+    
+    if (gx_device_has_color(dev))
 /* use ^7 so WHITE is 0 for internal calculations */
-	return (gx_color_index)rgb_color[r >> cv_shift][g >> cv_shift][b >> cv_shift] ^ 7;	
-	}
-else
-	{
-	return gx_default_map_rgb_color(dev, r, g, b);
-	}
+        return (gx_color_index)rgb_color[r >> cv_shift][g >> cv_shift][b >> cv_shift] ^ 7;	
+    else
+	return gx_default_map_rgb_color(dev, cv);
 }
 
 /* Map the printer color back to RGB. */

Index: gdevm1.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevm1.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gdevm1.c	21 Feb 2002 22:24:51 -0000	1.4
+++ gdevm1.c	22 Aug 2002 07:12:28 -0000	1.5
@@ -50,23 +50,19 @@
 
 /* Map color to/from RGB.  This may be inverted. */
 private gx_color_index
-mem_mono_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
-		       gx_color_value b)
+mem_mono_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
     gx_device_memory * const mdev = (gx_device_memory *)dev;
-
-    return (gx_default_w_b_map_rgb_color(dev, r, g, b) ^
-	    mdev->palette.data[0]) & 1;
+    return (gx_default_w_b_map_rgb_color(dev, cv) ^ mdev->palette.data[0]) & 1;
 }
+
 private int
 mem_mono_map_color_rgb(gx_device * dev, gx_color_index color,
 		       gx_color_value prgb[3])
 {
     gx_device_memory * const mdev = (gx_device_memory *)dev;
-
-    return gx_default_w_b_map_color_rgb(dev,
-					(color ^ mdev->palette.data[0]) & 1,
-					prgb);
+    /* NB code doesn't make sense... map_color_rgb procedures return an error code */
+    return (gx_default_w_b_map_color_rgb(dev, color, prgb) ^ mdev->palette.data[0]) & 1;
 }
 
 /* Fill a rectangle with a color. */

Index: gdevm16.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevm16.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gdevm16.c	21 Feb 2002 22:24:51 -0000	1.4
+++ gdevm16.c	22 Aug 2002 07:12:28 -0000	1.5
@@ -41,12 +41,11 @@
 
 /* Map a r-g-b color to a color index. */
 private gx_color_index
-mem_true16_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
-			 gx_color_value b)
+mem_true16_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
-    return ((r >> (gx_color_value_bits - 5)) << 11) +
-	((g >> (gx_color_value_bits - 6)) << 5) +
-	(b >> (gx_color_value_bits - 5));
+    return ((cv[0] >> (gx_color_value_bits - 5)) << 11) +
+	((cv[1] >> (gx_color_value_bits - 6)) << 5) +
+	(cv[2] >> (gx_color_value_bits - 5));
 }
 
 /* Map a color index to a r-g-b color. */

Index: gdevmem.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevmem.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gdevmem.c	21 Feb 2002 22:24:51 -0000	1.4
+++ gdevmem.c	22 Aug 2002 07:12:28 -0000	1.5
@@ -80,31 +80,39 @@
 
 /* Return the appropriate memory device for a given */
 /* number of bits per pixel (0 if none suitable). */
-private const gx_device_memory *const mem_devices[33] = {
+private const gx_device_memory *const mem_devices[65] = {
     0, &mem_mono_device, &mem_mapped2_device, 0, &mem_mapped4_device,
     0, 0, 0, &mem_mapped8_device,
     0, 0, 0, 0, 0, 0, 0, &mem_true16_device,
     0, 0, 0, 0, 0, 0, 0, &mem_true24_device,
-    0, 0, 0, 0, 0, 0, 0, &mem_true32_device
+    0, 0, 0, 0, 0, 0, 0, &mem_true32_device,
+    0, 0, 0, 0, 0, 0, 0, &mem_true40_device,
+    0, 0, 0, 0, 0, 0, 0, &mem_true48_device,
+    0, 0, 0, 0, 0, 0, 0, &mem_true56_device,
+    0, 0, 0, 0, 0, 0, 0, &mem_true64_device
 };
 const gx_device_memory *
 gdev_mem_device_for_bits(int bits_per_pixel)
 {
-    return ((uint)bits_per_pixel > 32 ? (const gx_device_memory *)0 :
+    return ((uint)bits_per_pixel > 64 ? (const gx_device_memory *)0 :
 	    mem_devices[bits_per_pixel]);
 }
 /* Do the same for a word-oriented device. */
-private const gx_device_memory *const mem_word_devices[33] = {
+private const gx_device_memory *const mem_word_devices[65] = {
     0, &mem_mono_device, &mem_mapped2_word_device, 0, &mem_mapped4_word_device,
     0, 0, 0, &mem_mapped8_word_device,
     0, 0, 0, 0, 0, 0, 0, 0 /*no 16-bit word device*/,
     0, 0, 0, 0, 0, 0, 0, &mem_true24_word_device,
-    0, 0, 0, 0, 0, 0, 0, &mem_true32_word_device
+    0, 0, 0, 0, 0, 0, 0, &mem_true32_word_device,
+    0, 0, 0, 0, 0, 0, 0, &mem_true40_word_device,
+    0, 0, 0, 0, 0, 0, 0, &mem_true48_word_device,
+    0, 0, 0, 0, 0, 0, 0, &mem_true56_word_device,
+    0, 0, 0, 0, 0, 0, 0, &mem_true64_word_device
 };
 const gx_device_memory *
 gdev_mem_word_device_for_bits(int bits_per_pixel)
 {
-    return ((uint)bits_per_pixel > 32 ? (const gx_device_memory *)0 :
+    return ((uint)bits_per_pixel > 64 ? (const gx_device_memory *)0 :
 	    mem_word_devices[bits_per_pixel]);
 }
 
@@ -119,7 +127,7 @@
     int bits_per_pixel = dev->color_info.depth;
     const gx_device_memory *mdproto;
 
-    if ((uint)bits_per_pixel > 32)
+    if ((uint)bits_per_pixel > 64)
 	return false;
     mdproto = mem_devices[bits_per_pixel];
     if (mdproto != 0 && dev_proc(dev, draw_thin_line) == dev_proc(mdproto, draw_thin_line))
@@ -162,12 +170,12 @@
 	gx_device_copy_color_procs((gx_device *)dev, target);
 	dev->cached_colors = target->cached_colors;
     }
-    if (dev->color_info.depth == 1)
+    if (dev->color_info.depth == 1) {
 	gdev_mem_mono_set_inverted(dev,
-				   (target == 0 ||
-				    (*dev_proc(target, map_rgb_color))
-			    (target, (gx_color_value) 0, (gx_color_value) 0,
-			     (gx_color_value) 0) != 0));
+				   (target == 0 || 
+                                    dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE));
+    }
+    gx_device_fill_in_procs(dev);
 }
 /* Make a monobit memory device.  This is never a page device. */
 /* Note that white=0, black=1. */
@@ -180,6 +188,7 @@
     set_dev_proc(dev, get_page_device, gx_default_get_page_device);
     gx_device_set_target((gx_device_forward *)dev, target);
     gdev_mem_mono_set_inverted(dev, true);
+    gx_device_fill_in_procs(dev);
 }
 
 /* Define whether a monobit memory device is inverted (black=1). */
@@ -516,13 +525,12 @@
 /* (2, 4, or 8 bits per pixel.) */
 /* This requires searching the palette. */
 gx_color_index
-mem_mapped_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
-			 gx_color_value b)
+mem_mapped_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
     gx_device_memory * const mdev = (gx_device_memory *)dev;
-    byte br = gx_color_value_to_byte(r);
-    byte bg = gx_color_value_to_byte(g);
-    byte bb = gx_color_value_to_byte(b);
+    byte br = gx_color_value_to_byte(cv[0]);
+    byte bg = gx_color_value_to_byte(cv[1]);
+    byte bb = gx_color_value_to_byte(cv[2]);
     register const byte *pptr = mdev->palette.data;
     int cnt = mdev->palette.size;
     const byte *which = 0;	/* initialized only to pacify gcc */

Index: gdevmem.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevmem.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gdevmem.h	16 Jun 2002 07:25:26 -0000	1.6
+++ gdevmem.h	22 Aug 2002 07:12:28 -0000	1.7
@@ -209,6 +209,10 @@
 extern const gx_device_memory mem_true16_device;
 extern const gx_device_memory mem_true24_device;
 extern const gx_device_memory mem_true32_device;
+extern const gx_device_memory mem_true40_device;
+extern const gx_device_memory mem_true48_device;
+extern const gx_device_memory mem_true56_device;
+extern const gx_device_memory mem_true64_device;
 extern const gx_device_memory mem_planar_device;
 /*
  * We declare the RasterOp implementation procedures here because they are
@@ -225,6 +229,10 @@
 #  define mem_mapped8_word_device mem_mapped8_device
 #  define mem_true24_word_device mem_true24_device
 #  define mem_true32_word_device mem_true32_device
+#  define mem_true40_word_device mem_true40_device
+#  define mem_true48_word_device mem_true48_device
+#  define mem_true56_word_device mem_true56_device
+#  define mem_true64_word_device mem_true64_device
 #else
 extern const gx_device_memory mem_mono_word_device;
 extern const gx_device_memory mem_mapped2_word_device;
@@ -232,6 +240,10 @@
 extern const gx_device_memory mem_mapped8_word_device;
 extern const gx_device_memory mem_true24_word_device;
 extern const gx_device_memory mem_true32_word_device;
+extern const gx_device_memory mem_true40_word_device;
+extern const gx_device_memory mem_true48_word_device;
+extern const gx_device_memory mem_true56_word_device;
+extern const gx_device_memory mem_true64_word_device;
 
 #endif
 /* Provide standard palettes for 1-bit devices. */

Index: gdevmr1.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevmr1.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gdevmr1.c	21 Feb 2002 22:24:51 -0000	1.4
+++ gdevmr1.c	22 Aug 2002 07:12:28 -0000	1.5
@@ -57,12 +57,13 @@
 
     /* If map_rgb_color isn't the default one for monobit memory */
     /* devices, palette might not be set; set it now if needed. */
-    if (mdev->palette.data == 0)
+    if (mdev->palette.data == 0) {
+        gx_color_value cv[3];
+        cv[0] = cv[1] = cv[2] = 0;
 	gdev_mem_mono_set_inverted(mdev,
 				   (*dev_proc(dev, map_rgb_color))
-				   (dev, (gx_color_value) 0,
-				    (gx_color_value) 0, (gx_color_value) 0)
-				   != 0);
+				   (dev, cv) != 0);
+    }
     invert = mdev->palette.data[0] != 0;
 
 #ifdef DEBUG

Index: gdevnfwd.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevnfwd.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gdevnfwd.c	21 Feb 2002 22:24:51 -0000	1.5
+++ gdevnfwd.c	22 Aug 2002 07:12:28 -0000	1.6
@@ -19,6 +19,8 @@
 #include "gx.h"
 #include "gserrors.h"
 #include "gxdevice.h"
+#include "gxcmap.h"
+#include "memory_.h"
 
 /* ---------------- Forwarding procedures ---------------- */
 
@@ -95,6 +97,10 @@
     fill_dev_proc(dev, create_compositor, gx_no_create_compositor);
     fill_dev_proc(dev, get_hardware_params, gx_forward_get_hardware_params);
     fill_dev_proc(dev, text_begin, gx_forward_text_begin);
+    fill_dev_proc(dev, get_color_mapping_procs, gx_forward_get_color_mapping_procs);
+    fill_dev_proc(dev, get_color_comp_index, gx_forward_get_color_comp_index);
+    fill_dev_proc(dev, encode_color, gx_forward_encode_color);
+    fill_dev_proc(dev, decode_color, gx_forward_decode_color);
     gx_device_fill_in_procs((gx_device *) dev);
 }
 
@@ -106,7 +112,10 @@
     set_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb);
     set_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color);
     set_dev_proc(dev, map_rgb_alpha_color, gx_forward_map_rgb_alpha_color);
-    set_dev_proc(dev, map_color_rgb_alpha, gx_forward_map_color_rgb_alpha);
+    set_dev_proc(dev, get_color_mapping_procs, gx_forward_get_color_mapping_procs);
+    set_dev_proc(dev, get_color_comp_index, gx_forward_get_color_comp_index);
+    set_dev_proc(dev, encode_color, gx_forward_encode_color);
+    set_dev_proc(dev, decode_color, gx_forward_decode_color);
 }
 
 void
@@ -146,14 +155,13 @@
 }
 
 gx_color_index
-gx_forward_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
-			 gx_color_value b)
+gx_forward_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
     gx_device_forward * const fdev = (gx_device_forward *)dev;
     gx_device *tdev = fdev->target;
 
-    return (tdev == 0 ? gx_default_map_rgb_color(dev, r, g, b) :
-	    dev_proc(tdev, map_rgb_color)(tdev, r, g, b));
+    return (tdev == 0 ? gx_error_encode_color(dev, cv) :
+	    dev_proc(tdev, map_rgb_color)(tdev, cv));
 }
 
 int
@@ -258,14 +266,13 @@
 }
 
 gx_color_index
-gx_forward_map_cmyk_color(gx_device * dev, gx_color_value c, gx_color_value m,
-			  gx_color_value y, gx_color_value k)
+gx_forward_map_cmyk_color(gx_device * dev, const gx_color_value cv[])
 {
     gx_device_forward * const fdev = (gx_device_forward *)dev;
     gx_device *tdev = fdev->target;
 
-    return (tdev == 0 ? gx_default_map_cmyk_color(dev, c, m, y, k) :
-	    dev_proc(tdev, map_cmyk_color)(tdev, c, m, y, k));
+    return (tdev == 0 ? gx_default_map_cmyk_color(dev, cv) :
+	    dev_proc(tdev, map_cmyk_color)(tdev, cv));
 }
 
 const gx_xfont_procs *
@@ -586,6 +593,126 @@
 		memory, ppenum);
 }
 
+/* Forwarding device color mapping procs. */
+
+/*
+ * We need to forward the color mapping to the target device.
+ */
+static void
+fwd_map_gray_cs(gx_device * dev, frac gray, frac out[])
+{
+    gx_device_forward * const fdev = (gx_device_forward *)dev;
+    gx_device * const tdev = fdev->target;
+    const gx_cm_color_map_procs * pprocs;
+
+    /* Verify that all of the pointers and procs are set */
+    /* If not then use a default routine.  This case should be an error */
+    if (tdev == 0 || dev_proc(tdev, get_color_mapping_procs) == 0 ||
+          (pprocs = dev_proc(tdev, get_color_mapping_procs(tdev))) == 0 ||
+          pprocs->map_gray == 0)
+        gray_cs_to_gray_cm(tdev, gray, out);   /* if all else fails */
+    else
+        pprocs->map_gray(tdev, gray, out);
+}
+
+/*
+ * We need to forward the color mapping to the target device.
+ */
+static void
+fwd_map_rgb_cs(gx_device * dev, const gs_imager_state *pis,
+				   frac r, frac g, frac b, frac out[])
+{
+    gx_device_forward * const fdev = (gx_device_forward *)dev;
+    gx_device * const tdev = fdev->target;
+    const gx_cm_color_map_procs * pprocs;
+
+    /* Verify that all of the pointers and procs are set */
+    /* If not then use a default routine.  This case should be an error */
+    if (tdev == 0 || dev_proc(tdev, get_color_mapping_procs) == 0 ||
+          (pprocs = dev_proc(tdev, get_color_mapping_procs(tdev))) == 0 ||
+          pprocs->map_rgb == 0)
+        rgb_cs_to_rgb_cm(tdev, pis, r, g, b, out);   /* if all else fails */
+    else
+        pprocs->map_rgb(tdev, pis, r, g, b, out);
+}
+
+/*
+ * We need to forward the color mapping to the target device.
+ */
+static void
+fwd_map_cmyk_cs(gx_device * dev, frac c, frac m, frac y, frac k, frac out[])
+{
+    gx_device_forward * const fdev = (gx_device_forward *)dev;
+    gx_device * const tdev = fdev->target;
+    const gx_cm_color_map_procs * pprocs;
+
+    /* Verify that all of the pointers and procs are set */
+    /* If not then use a default routine.  This case should be an error */
+    if (tdev == 0 || dev_proc(tdev, get_color_mapping_procs) == 0 ||
+          (pprocs = dev_proc(tdev, get_color_mapping_procs(tdev))) == 0 ||
+          pprocs->map_cmyk == 0)
+        cmyk_cs_to_cmyk_cm(tdev, c, m, y, k, out);   /* if all else fails */
+    else
+        pprocs->map_cmyk(tdev, c, m, y, k, out);
+};
+
+static const gx_cm_color_map_procs FwdDevice_cm_map_procs = {
+    fwd_map_gray_cs, fwd_map_rgb_cs, fwd_map_cmyk_cs
+};
+/*
+ * Instead of returning the target device's mapping procs, we need
+ * to return a list of forwarding wrapper procs for the color mapping
+ * procs.  This is required because the target device mapping procs
+ * may also need the target device pointer (instead of the forwarding
+ * device pointer).
+ */
+const gx_cm_color_map_procs *
+gx_forward_get_color_mapping_procs(const gx_device * dev)
+{
+    gx_device_forward * const fdev = (gx_device_forward *)dev;
+    gx_device * const tdev = fdev->target;
+
+    return (tdev == 0 || dev_proc(tdev, get_color_mapping_procs) == 0
+	? gx_default_DevGray_get_color_mapping_procs(dev)
+	: &FwdDevice_cm_map_procs);
+}
+
+int
+gx_forward_get_color_comp_index(const gx_device * dev, const char * pname,
+						int name_size, int src_index)
+{
+    gx_device_forward * const fdev = (gx_device_forward *)dev;
+    gx_device *tdev = fdev->target;
+
+    return (tdev == 0 
+	? gx_error_get_color_comp_index(dev, pname, name_size, src_index)
+	: dev_proc(tdev, get_color_comp_index)(tdev, pname, name_size, src_index));
+}
+
+gx_color_index
+gx_forward_encode_color(gx_device * dev, const gx_color_value colors[])
+{
+    gx_device_forward * const fdev = (gx_device_forward *)dev;
+    gx_device *tdev = fdev->target;
+
+    return (tdev == 0 ? gx_error_encode_color(dev, colors)
+		      : dev_proc(tdev, encode_color)(tdev, colors));
+}
+
+int
+gx_forward_decode_color(gx_device * dev, gx_color_index cindex, gx_color_value colors[])
+{
+    gx_device_forward * const fdev = (gx_device_forward *)dev;
+    gx_device *tdev = fdev->target;
+
+    if (tdev == 0)	/* If no device - just clear the color values */
+	memset(colors, 0, sizeof(gx_color_value[GX_DEVICE_COLOR_MAX_COMPONENTS]));
+    else
+	dev_proc(tdev, decode_color)(tdev, cindex, colors);
+    return 0;
+}
+
+
 /* ---------------- The null device(s) ---------------- */
 
 private dev_proc_fill_rectangle(null_fill_rectangle);
@@ -649,7 +776,16 @@
 	gx_non_imaging_create_compositor,\
 	gx_forward_get_hardware_params,\
 	gx_default_text_begin,\
-	gx_default_finish_copydevice\
+	gx_default_finish_copydevice,\
+	NULL,				/* begin_transparency_group */\
+	NULL,				/* end_transparency_group */\
+	NULL,				/* begin_transparency_mask */\
+	NULL,				/* end_transparency_mask */\
+	NULL,				/* discard_transparency_layer */\
+	gx_forward_get_color_mapping_procs,	/* get_color_mapping_procs */\
+	gx_forward_get_color_comp_index,/* get_color_comp_index */\
+	gx_forward_encode_color,	/* encode_color */\
+	gx_forward_decode_color		/* decode_color */\
 }
 
 const gx_device_null gs_null_device = {

Index: gdevp14.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevp14.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- gdevp14.c	6 Jun 2002 06:57:12 -0000	1.12
+++ gdevp14.c	22 Aug 2002 07:12:28 -0000	1.13
@@ -37,6 +37,7 @@
 #include "gsimage.h"
 #include "gzstate.h"
 #include "gdevp14.h"
+#include "gsovrc.h"
 
 # define INCR(v) DO_NOTHING
 
@@ -119,6 +120,7 @@
 private dev_proc_stroke_path(pdf14_stroke_path);
 private dev_proc_begin_typed_image(pdf14_begin_typed_image);
 private dev_proc_text_begin(pdf14_text_begin);
+private dev_proc_create_compositor(pdf14_create_compositor);
 private dev_proc_begin_transparency_group(pdf14_begin_transparency_group);
 private dev_proc_end_transparency_group(pdf14_end_transparency_group);
 
@@ -173,7 +175,7 @@
 	pdf14_begin_typed_image,	/* begin_typed_image */
 	NULL,	/* get_bits_rectangle */
 	NULL,	/* map_color_rgb_alpha */
-	NULL,	/* create_compositor */
+	pdf14_create_compositor,	/* create_compositor */
 	NULL,	/* get_hardware_params */
 	pdf14_text_begin,	/* text_begin */
 	NULL,	/* finish_copydevice */
@@ -187,6 +189,8 @@
     pdf14_ctx *ctx;
     gx_device *target;
 
+    const gx_color_map_procs *(*save_get_cmap_procs)(const gs_imager_state *,
+						     const gx_device *);
 } pdf14_device;
 
 gs_private_st_composite_use_final(st_pdf14_device, pdf14_device, "pdf14_device",
@@ -291,6 +295,9 @@
     { 0 }
 };
 
+private const gx_color_map_procs *
+    pdf14_get_cmap_procs(const gs_imager_state *, const gx_device *);
+
 /* ------ Private definitions ------ */
 
 /**
@@ -629,17 +636,21 @@
     int planestride = buf->planestride;
     byte *buf_ptr = buf->data;
     byte *linebuf;
+    gs_color_space cs;
 
+#if 0
     /* Set graphics state device to target, so that image can set up
        the color mapping properly. */
     rc_increment(pdev);
     gs_setdevice_no_init(pgs, target);
+#endif
 
     /* Set color space to RGB, in preparation for sending an RGB image. */
     gs_setrgbcolor(pgs, 0, 0, 0);
 
-    gs_image_t_init_adjust(&image, pis->shared->device_color_spaces.named.RGB,
-			   false);
+    gs_cspace_init_DeviceRGB(&cs);
+    gx_set_dev_color(pgs);
+    gs_image_t_init_adjust(&image, &cs, false);
     image.ImageMatrix.xx = width;
     image.ImageMatrix.yy = height;
     image.Width = width;
@@ -716,9 +727,11 @@
 
     info->procs->end_image(info, true);
 
+#if 0
     /* Restore device in graphics state.*/
     gs_setdevice_no_init(pgs, (gx_device*) pdev);
     rc_decrement_only(pdev, "pdf_14_put_image");
+#endif
 
     return code;
 }
@@ -892,6 +905,27 @@
     return code;
 }
 
+/*
+ * The overprint compositor can be handled directly, so just set *pcdev = dev
+ * and return. Since the gs_pdf14_device only supports the high-level routines
+ * of the interface, don't bother trying to handle any other compositor.
+ */
+private int
+pdf14_create_compositor(
+    gx_device *             dev,
+    gx_device **            pcdev,
+    const gs_composite_t *  pct,
+    const gs_imager_state * pis,
+    gs_memory_t *           mem )
+{
+    if (gs_is_overprint_compositor(pct)) {
+        *pcdev = dev;
+        return 0;
+    } else
+        return gx_no_create_compositor(dev, pcdev, pct, pis, mem);
+}
+
+private int
 pdf14_text_begin(gx_device * dev, gs_imager_state * pis,
 		 const gs_text_params_t * text, gs_font * font,
 		 gx_path * path, const gx_device_color * pdcolor,
@@ -1061,9 +1095,227 @@
     return 0;
 }
 
+
+/**
+ * Here we have logic to override the cmap_procs with versions that
+ * do not apply the transfer function. These copies should track the
+ * versions in gxcmap.c.
+ **/
+
+private cmap_proc_gray(pdf14_cmap_gray_direct);
+private cmap_proc_rgb(pdf14_cmap_rgb_direct);
+private cmap_proc_cmyk(pdf14_cmap_cmyk_direct);
+private cmap_proc_rgb_alpha(pdf14_cmap_rgb_alpha_direct);
+private cmap_proc_separation(pdf14_cmap_separation_direct);
+private cmap_proc_devicen(pdf14_cmap_devicen_direct);
+
+private const gx_color_map_procs pdf14_cmap_many = {
+     pdf14_cmap_gray_direct,
+     pdf14_cmap_rgb_direct,
+     pdf14_cmap_cmyk_direct,
+     pdf14_cmap_rgb_alpha_direct,
+     pdf14_cmap_separation_direct,
+     pdf14_cmap_devicen_direct
+    };
+
+/**
+ * Note: copied from gxcmap.c because it's inlined.
+ **/
+private inline void
+map_components_to_colorants(const frac * pcc,
+	const gs_devicen_color_map * pcolor_component_map, frac * plist)
+{
+    int i = pcolor_component_map->num_colorants - 1;
+    int pos;
+
+    /* Clear all output colorants first */
+    for (; i >= 0; i--) {
+	plist[i] = frac_0;
+    }
+
+    /* Map color components into output list */
+    for (i = pcolor_component_map->num_components - 1; i >= 0; i--) {
+	pos = pcolor_component_map->color_map[i];
+	if (pos >= 0)
+	    plist[pos] = pcc[i];
+    }
+}
+
+private void
+pdf14_cmap_gray_direct(frac gray, gx_device_color * pdc, const gs_imager_state * pis,
+		 gx_device * dev, gs_color_select_t select)
+{
+    int i, ncomps = dev->color_info.num_components;
+    frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    gx_color_index color;
+
+    /* map to the color model */
+    dev_proc(dev, get_color_mapping_procs)(dev)->map_gray(dev, gray, cm_comps);
+
+    for (i = 0; i < ncomps; i++)
+        cv[i] = frac2cv(cm_comps[i]);
+
+    /* encode as a color index */
+    color = dev_proc(dev, encode_color)(dev, cv);
+
+    /* check if the encoding was successful; we presume failure is rare */
+    if (color != gx_no_color_index)
+        color_set_pure(pdc, color);
+}
+
+
+private void
+pdf14_cmap_rgb_direct(frac r, frac g, frac b, gx_device_color * pdc,
+     const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+    int i, ncomps = dev->color_info.num_components;
+    frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    gx_color_index color;
+
+    /* map to the color model */
+    dev_proc(dev, get_color_mapping_procs)(dev)->map_rgb(dev, pis, r, g, b, cm_comps);
+
+    for (i = 0; i < ncomps; i++)
+        cv[i] = frac2cv(cm_comps[i]);
+
+    /* encode as a color index */
+    color = dev_proc(dev, encode_color)(dev, cv);
+
+    /* check if the encoding was successful; we presume failure is rare */
+    if (color != gx_no_color_index)
+        color_set_pure(pdc, color);
+}
+
+private void
+pdf14_cmap_cmyk_direct(frac c, frac m, frac y, frac k, gx_device_color * pdc,
+     const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+    int i, ncomps = dev->color_info.num_components;
+    frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    gx_color_index color;
+
+    /* map to the color model */
+    dev_proc(dev, get_color_mapping_procs)(dev)->map_cmyk(dev, c, m, y, k, cm_comps);
+
+    for (i = 0; i < ncomps; i++)
+        cv[i] = frac2cv(cm_comps[i]);
+
+    color = dev_proc(dev, encode_color)(dev, cv);
+    if (color != gx_no_color_index) 
+	color_set_pure(pdc, color);
+}
+
+private void
+pdf14_cmap_rgb_alpha_direct(frac r, frac g, frac b, frac alpha, gx_device_color * pdc,
+     const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+    int i, ncomps = dev->color_info.num_components;
+    frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    gx_color_value cv_alpha, cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    gx_color_index color;
+
+    /* map to the color model */
+    dev_proc(dev, get_color_mapping_procs)(dev)->map_rgb(dev, pis, r, g, b, cm_comps);
+
+    /* pre-multiply to account for the alpha weighting */
+    if (alpha != frac_1) {
+#ifdef PREMULTIPLY_TOWARDS_WHITE
+        frac alpha_bias = frac_1 - alpha;
+#else
+	frac alpha_bias = 0;
+#endif
+
+        for (i = 0; i < ncomps; i++)
+            cm_comps[i] = (frac)((long)cm_comps[i] * alpha) / frac_1 + alpha_bias;
+    }
+
+    for (i = 0; i < ncomps; i++)
+        cv[i] = frac2cv(cm_comps[i]);
+
+    /* encode as a color index */
+    if (dev_proc(dev, map_rgb_alpha_color) != gx_default_map_rgb_alpha_color &&
+         (cv_alpha = frac2cv(alpha)) != gx_max_color_value)
+        color = dev_proc(dev, map_rgb_alpha_color)(dev, cv[0], cv[1], cv[2], cv_alpha);
+    else
+        color = dev_proc(dev, encode_color)(dev, cv);
+
+    /* check if the encoding was successful; we presume failure is rare */
+    if (color != gx_no_color_index)
+        color_set_pure(pdc, color);
+}
+
+
+private void
+pdf14_cmap_separation_direct(frac all, gx_device_color * pdc, const gs_imager_state * pis,
+		 gx_device * dev, gs_color_select_t select)
+{
+    int i;
+    bool additive = dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE;
+    frac comp_value = all;
+    frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    gx_color_index color;
+
+    if (pis->color_component_map.sep_type == SEP_ALL) {
+	/*
+	 * Invert the photometric interpretation for additive
+	 * color spaces because separations are always subtractive.
+	 */
+	if (additive)
+	    comp_value = frac_1 - comp_value;
+
+        /* Use the "all" value for all components */
+        i = pis->color_component_map.num_colorants - 1;
+        for (; i >= 0; i--)
+            cm_comps[i] = comp_value;
+    }
+    else {
+        /* map to the color model */
+        map_components_to_colorants(&comp_value, &(pis->color_component_map), cm_comps);
+    }
+
+    /* encode as a color index */
+    color = dev_proc(dev, encode_color)(dev, cv);
+
+    /* check if the encoding was successful; we presume failure is rare */
+    if (color != gx_no_color_index)
+        color_set_pure(pdc, color);
+}
+
+
+private void
+pdf14_cmap_devicen_direct(const frac * pcc, 
+    gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+    gs_color_select_t select)
+{
+    frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    gx_color_index color;
+
+    /* map to the color model */
+    map_components_to_colorants(pcc, &(pis->color_component_map), cm_comps);;
+
+    /* encode as a color index */
+    color = dev_proc(dev, encode_color)(dev, cv);
+
+    /* check if the encoding was successful; we presume failure is rare */
+    if (color != gx_no_color_index)
+        color_set_pure(pdc, color);
+}
+
+private const gx_color_map_procs *
+pdf14_get_cmap_procs(const gs_imager_state *pis, const gx_device * dev)
+{
+    /* The pdf14 marking device itself is always continuous tone. */
+    return &pdf14_cmap_many;
+}
+
 private int
 gs_pdf14_device_filter_push(gs_device_filter_t *self, gs_memory_t *mem,
-			   gx_device **pdev, gx_device *target)
+			    gx_device **pdev, gs_state *pgs, gx_device *target)
 {
     pdf14_device *p14dev;
     int code;
@@ -1080,19 +1332,33 @@
 
     rc_assign(p14dev->target, target, "gs_pdf14_device_filter_push");
 
+    p14dev->save_get_cmap_procs = pgs->get_cmap_procs;
+    pgs->get_cmap_procs = pdf14_get_cmap_procs;
+
     code = dev_proc((gx_device *) p14dev, open_device) ((gx_device *) p14dev);
     *pdev = (gx_device *) p14dev;
     return code;
 }
 
 private int
-gs_pdf14_device_filter_pop(gs_device_filter_t *self, gs_memory_t *mem,
+gs_pdf14_device_filter_prepop(gs_device_filter_t *self, gs_memory_t *mem,
 			   gs_state *pgs, gx_device *dev)
 {
-    gx_device *target = ((pdf14_device *)dev)->target;
+    pdf14_device *p14dev = (pdf14_device *)dev;
+
+    pgs->get_cmap_procs = p14dev->save_get_cmap_procs;
+    return 0;
+}
+
+private int
+gs_pdf14_device_filter_postpop(gs_device_filter_t *self, gs_memory_t *mem,
+			   gs_state *pgs, gx_device *dev)
+{
+    pdf14_device *p14dev = (pdf14_device *)dev;
+    gx_device *target = pgs->device;
     int code;
 
-    code = pdf14_put_image((pdf14_device *)dev, pgs, target);
+    code = pdf14_put_image(p14dev, pgs, target);
     if (code < 0)
 	return code;
 
@@ -1100,8 +1366,7 @@
     if (code < 0)
 	return code;
 
-    ((pdf14_device *)dev)->target = 0;
-    rc_decrement_only(target, "gs_pdf14_device_filter_pop");
+    rc_decrement(p14dev->target, "gs_pdf14_device_filter_pop");
 
     gs_free_object(mem, self, "gs_pdf14_device_filter_pop");
     return 0;
@@ -1117,7 +1382,8 @@
     if (df == 0)
 	return_error(gs_error_VMerror);
     df->push = gs_pdf14_device_filter_push;
-    df->pop = gs_pdf14_device_filter_pop;
+    df->prepop = gs_pdf14_device_filter_prepop;
+    df->postpop = gs_pdf14_device_filter_postpop;
     *pdf = df;
     return 0;
 }

Index: gdevpbm.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpbm.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gdevpbm.c	22 Jun 2002 03:44:40 -0000	1.7
+++ gdevpbm.c	22 Aug 2002 07:12:28 -0000	1.8
@@ -284,15 +284,22 @@
 /* Map an RGB color to a PGM gray value. */
 /* Keep track of whether the image is black-and-white or gray. */
 private gx_color_index
-pgm_map_rgb_color(gx_device * pdev, gx_color_value r, gx_color_value g,
-		  gx_color_value b)
+pgm_map_rgb_color(gx_device * pdev, const gx_color_value cv[])
 {				/* We round the value rather than truncating it. */
-    gx_color_value gray =
-    ((r * (ulong) lum_red_weight) +
+    gx_color_value gray;
+    /* TO_DO_DEVICEN  - Kludge to emulate pre DeviceN math errors */
+#if 1
+    gx_color_value r, g, b;
+
+    r = cv[0]; g = cv[0]; b = cv[0];
+    gray = ((r * (ulong) lum_red_weight) +
      (g * (ulong) lum_green_weight) +
      (b * (ulong) lum_blue_weight) +
      (lum_all_weights / 2)) / lum_all_weights
     * pdev->color_info.max_gray / gx_max_color_value;
+#else	    /* Should be ... */
+    gray = cv[0] * pdev->color_info.max_gray / gx_max_color_value;
+#endif
 
     if (!(gray == 0 || gray == pdev->color_info.max_gray)) {
 	gx_device_pbm * const bdev = (gx_device_pbm *)pdev;
@@ -319,15 +326,13 @@
 /* Map an RGB color to a PPM color tuple. */
 /* Keep track of whether the image is black-and-white, gray, or colored. */
 private gx_color_index
-ppm_map_rgb_color(gx_device * pdev, gx_color_value r, gx_color_value g,
-		  gx_color_value b)
+ppm_map_rgb_color(gx_device * pdev, const gx_color_value cv[])
 {
     gx_device_pbm * const bdev = (gx_device_pbm *)pdev;
-    gx_color_index color = gx_default_rgb_map_rgb_color(pdev, r, g, b);
+    gx_color_index color = gx_default_encode_color(pdev, cv);
     int bpc = pdev->color_info.depth / 3;
     gx_color_index mask =
 	((gx_color_index)1 << (pdev->color_info.depth - bpc)) - 1;
-
     if (!(((color >> bpc) ^ color) & mask)) { /* gray shade */
 	if (color != 0 && (~color & mask))
 	    bdev->uses_color |= 1;
@@ -356,15 +361,14 @@
 
 /* Map a CMYK color to a pixel value. */
 private gx_color_index
-pkm_map_cmyk_color(gx_device * pdev, gx_color_value c, gx_color_value m,
-		   gx_color_value y, gx_color_value k)
+pkm_map_cmyk_color(gx_device * pdev, const gx_color_value cv[])
 {
     uint bpc = pdev->color_info.depth >> 2;
     uint max_value = pdev->color_info.max_color;
-    uint cc = c * max_value / gx_max_color_value;
-    uint mc = m * max_value / gx_max_color_value;
-    uint yc = y * max_value / gx_max_color_value;
-    uint kc = k * max_value / gx_max_color_value;
+    uint cc = cv[0] * max_value / gx_max_color_value;
+    uint mc = cv[1] * max_value / gx_max_color_value;
+    uint yc = cv[2] * max_value / gx_max_color_value;
+    uint kc = cv[3] * max_value / gx_max_color_value;
     gx_color_index color =
 	(((((cc << bpc) + mc) << bpc) + yc) << bpc) + kc;
 
@@ -634,7 +638,7 @@
      * If we're writing planes for a CMYK device, we have 0 = white,
      * mask = black, which is the opposite of the pgm convention.
      */
-    uint invert = (pdev->color_info.num_components == 4 ? mask : 0);
+    uint invert = (pdev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE);
     byte *bp;
     uint x;
     int shift;

Index: gdevpccm.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpccm.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gdevpccm.c	21 Feb 2002 22:24:51 -0000	1.4
+++ gdevpccm.c	22 Aug 2002 07:12:28 -0000	1.5
@@ -45,8 +45,7 @@
 /* ------ EGA/VGA (4-bit) color mapping ------ */
 
 gx_color_index
-pc_4bit_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
-		      gx_color_value b)
+pc_4bit_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
 #define Nb gx_color_value_bits
     static const byte grays[4] =
@@ -69,6 +68,8 @@
 
 #undef tab3
 #define q4mask (-1 << (Nb - 2))
+    gx_color_value r, g, b;
+    r = cv[0]; g = cv[1]; b = cv[2];
     if (!((r ^ g) & q4mask) && !((g ^ b) & q4mask))	/* gray */
 #undef q4mask
 	return (gx_color_index) grays[r >> (Nb - 2)];
@@ -114,11 +115,13 @@
  */
 
 gx_color_index
-pc_8bit_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
-		      gx_color_value b)
+pc_8bit_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
-    uint rv = r / (gx_max_color_value / 7 + 1);
-    uint gv = g / (gx_max_color_value / 7 + 1);
+    gx_color_value r, g, b;
+    uint rv, gv;
+    r = cv[0]; g = cv[1]; b = cv[2];
+    rv = r / (gx_max_color_value / 7 + 1);
+    gv = g / (gx_max_color_value / 7 + 1);
 
     return (gx_color_index)
 	(rv == gv && gv == b / (gx_max_color_value / 7 + 1) ?

Index: gdevpcl.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpcl.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gdevpcl.c	21 Feb 2002 22:24:51 -0000	1.7
+++ gdevpcl.c	22 Aug 2002 07:12:28 -0000	1.8
@@ -98,9 +98,10 @@
 
 /* Map an RGB color to a printer color. */
 gx_color_index
-gdev_pcl_3bit_map_rgb_color(gx_device * dev,
-		       gx_color_value r, gx_color_value g, gx_color_value b)
+gdev_pcl_3bit_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
+    gx_color_value r, g, b;
+    r = cv[0]; g = cv[1]; b = cv[2];
     return (((b >> cv_shift) << 2) + ((g >> cv_shift) << 1) + (r >> cv_shift)) ^ 7;
 }
 

Index: gdevpdf.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpdf.c,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -d -r1.50 -r1.51
--- gdevpdf.c	28 Jun 2002 14:36:04 -0000	1.50
+++ gdevpdf.c	22 Aug 2002 07:12:28 -0000	1.51
@@ -131,7 +131,7 @@
   gdev_pdf_copy_mono,
   gdev_pdf_copy_color,
   NULL,				/* draw_line */
-  NULL,				/* get_bits */
+  psdf_get_bits,		/* get_bits */
   gdev_pdf_get_params,
   gdev_pdf_put_params,
   NULL,				/* map_cmyk_color */
@@ -157,9 +157,9 @@
   NULL,				/* strip_copy_rop */
   NULL,				/* get_clipping_box */
   gdev_pdf_begin_typed_image,
-  NULL,				/* get_bits_rectangle */
+  psdf_get_bits_rectangle,	/* get_bits_rectangle */
   NULL,				/* map_color_rgb_alpha */
-  NULL,				/* create_compositor */
+  psdf_create_compositor,	/* create_compositor */
   NULL,				/* get_hardware_params */
   gdev_pdf_text_begin
  },
@@ -409,9 +409,12 @@
 	set_dev_proc(pdev, map_color_rgb, cmyk_8bit_map_color_rgb);
        /* possible problems with aliassing on next statement */
 	set_dev_proc(pdev, map_cmyk_color, cmyk_8bit_map_cmyk_color);
-        color = gx_map_cmyk_color((gx_device *)pdev,
-		      frac2cv(frac_0), frac2cv(frac_0),
-		      frac2cv(frac_0), frac2cv(frac_1));
+        {
+            gx_color_value cv[4];
+            cv[0] = cv[1] = cv[2] = frac2cv(frac_0);
+            cv[3] = frac2cv(frac_1);
+            color = dev_proc(pdev, map_cmyk_color)(pdev, cv);
+        }
 	break;
     default:			/* can't happen */
 	DO_NOTHING;

Index: gdevpdfc.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpdfc.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- gdevpdfc.c	7 May 2002 19:56:46 -0000	1.26
+++ gdevpdfc.c	22 Aug 2002 07:12:28 -0000	1.27
@@ -730,7 +730,7 @@
 	if (pfn == 0)
 	    return_error(gs_error_rangecheck);
 	if ((code = pdf_separation_name(pdev, &v,
-					pcs->params.separation.sname)) < 0 ||
+					pcs->params.separation.sep_name)) < 0 ||
 	    (code = pdf_separation_color_space(pdev, pca, "/Separation", &v,
 					       (const gs_color_space *)
 					&pcs->params.separation.alt_space,

Index: gdevpdfg.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpdfg.c,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -d -r1.22 -r1.23
--- gdevpdfg.c	16 Jun 2002 05:48:55 -0000	1.22
+++ gdevpdfg.c	22 Aug 2002 07:12:28 -0000	1.23
@@ -42,9 +42,10 @@
 {
     gx_color_index color = 0; /* black on DeviceGray and DeviceRGB */
     if(pdev->color_info.num_components == 4) {
-        color = gx_map_cmyk_color((gx_device *)pdev,
-		      frac2cv(frac_0), frac2cv(frac_0),
-		      frac2cv(frac_0), frac2cv(frac_1));
+        gx_color_value cv[4];
+        cv[0] = cv[1] = cv[2] = frac2cv(frac_0);
+        cv[3] = frac2cv(frac_1);
+        color = dev_proc(pdev, map_cmyk_color)(pdev, cv);
     }
     color_set_pure(&pdev->fill_color, color);
     color_set_pure(&pdev->stroke_color, color);
@@ -128,10 +129,11 @@
 pdf_separation_name(gx_device_pdf *pdev, cos_value_t *pvalue,
 		    gs_separation_name sname)
 {
+#ifdef TO_DO_DEVICEN
     static const char *const snames[] = {
 	gs_ht_separation_name_strings
     };
-    char buf[sizeof(ulong) * 8 / 3 + 2];	/****** BOGUS ******/
+    static char buf[sizeof(ulong) * 8 / 3 + 2];	/****** BOGUS ******/
     const char *str;
     uint len;
     byte *chars;
@@ -149,6 +151,7 @@
     chars[0] = '/';
     memcpy(chars + 1, str, len);
     cos_string_value(pvalue, chars, len + 1);
+#endif
     return 0;
 }
 
@@ -689,7 +692,9 @@
 	const gs_halftone_component *const phtc = &pmht->components[i];
 	cos_value_t value;
 
+#ifdef TO_DO_DEVICEN
 	code = pdf_separation_name(pdev, &value, phtc->cname);
+#endif
 	if (code < 0)
 	    return code;
 	cos_value_write(&value, pdev);
@@ -719,7 +724,7 @@
     switch (pht->type) {
     case ht_type_screen:
 	code = pdf_write_screen_halftone(pdev, &pht->params.screen,
-					 &pdht->order, &id);
+					 &pdht->components[0].corder, &id);
 	break;
     case ht_type_colorscreen:
 	code = pdf_write_colorscreen_halftone(pdev, &pht->params.colorscreen,
@@ -727,15 +732,15 @@
 	break;
     case ht_type_spot:
 	code = pdf_write_spot_halftone(pdev, &pht->params.spot,
-				       &pdht->order, &id);
+				       &pdht->components[0].corder, &id);
 	break;
     case ht_type_threshold:
 	code = pdf_write_threshold_halftone(pdev, &pht->params.threshold,
-					    &pdht->order, &id);
+					    &pdht->components[0].corder, &id);
 	break;
     case ht_type_threshold2:
 	code = pdf_write_threshold2_halftone(pdev, &pht->params.threshold2,
-					     &pdht->order, &id);
+					     &pdht->components[0].corder, &id);
 	break;
     case ht_type_multiple:
     case ht_type_multiple_colorscreen:
@@ -796,6 +801,8 @@
     gs_id transfer_ids[4];
     int code = 0;
 
+    dprintf( "pdf_update_transfer() unimplemented\n");
+#ifdef TO_DO_DEVICEN
     for (i = 0; i < 4; ++i) {
 	transfer_ids[i] = pis->set_transfer.indexed[i]->id;
 	if (pdev->transfer_ids[i] != transfer_ids[i])
@@ -828,6 +835,7 @@
 	memcpy(pdev->transfer_ids, transfer_ids, sizeof(pdev->transfer_ids));
 	pdev->transfer_not_identity = mask;
     }
+#endif
     return code;
 }
 

Index: gdevplnx.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevplnx.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gdevplnx.c	21 Feb 2002 22:24:51 -0000	1.4
+++ gdevplnx.c	22 Aug 2002 07:12:28 -0000	1.5
@@ -188,13 +188,13 @@
 	    }
 	ppdc->colors.colored.plane_mask &= 1 << plane;
 	if (ppdc->colors.colored.c_level[plane] == 0) {
-	    gx_reduce_colored_halftone(ppdc, (gx_device *)edev, true);
+	    gx_devn_reduce_colored_halftone(ppdc, (gx_device *)edev);
 	    ppdc->colors.pure = COLOR_PIXEL(edev, ppdc->colors.pure);
 	    reduced = REDUCE_PURE(edev, gx_dc_pure_color(ppdc));
 	} else if (ppdc->colors.colored.alpha != gx_max_color_value)
 	    return REDUCE_FAILED; /* can't reduce */
 	else {
-	    gx_reduce_colored_halftone(ppdc, (gx_device *)edev, true);
+	    gx_devn_reduce_colored_halftone(ppdc, (gx_device *)edev);
 	    ppdc->colors.binary.color[0] =
 		COLOR_PIXEL(edev, ppdc->colors.binary.color[0]);
 	    ppdc->colors.binary.color[1] =

Index: gdevprn.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevprn.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- gdevprn.c	16 Jun 2002 05:48:55 -0000	1.10
+++ gdevprn.c	22 Aug 2002 07:12:28 -0000	1.11
@@ -385,6 +385,10 @@
 	COPY_PROC(get_clipping_box);
 	COPY_PROC(map_color_rgb_alpha);
 	COPY_PROC(get_hardware_params);
+	COPY_PROC(get_color_mapping_procs);
+	COPY_PROC(get_color_comp_index);
+	COPY_PROC(encode_color);
+	COPY_PROC(decode_color);
 #undef COPY_PROC
 	/* If using a command list, already opened the device. */
 	if (is_command_list)

Index: gdevprn.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevprn.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- gdevprn.h	18 Jul 2002 11:01:44 -0000	1.11
+++ gdevprn.h	22 Aug 2002 07:12:28 -0000	1.12
@@ -407,6 +407,22 @@
   prn_device_margins_body(dtype, procs, dname, w10, h10, xdpi, ydpi,\
     lm, tm, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_page)
 
+#define prn_device_margins_body_extended(dtype, procs, dname, w10, h10, xdpi, ydpi, lo, to, lm, bm, rm, tm, mcomp, ncomp, pol, depth, gi, mg, mc, dg, dc, ef, cn, print_page)\
+	std_device_full_body_type_extended(dtype, &procs, dname, &st_device_printer,\
+	  (int)((long)(w10) * (xdpi) / 10),\
+	  (int)((long)(h10) * (ydpi) / 10),\
+	  xdpi, ydpi,\
+	  mcomp, ncomp, pol, depth, gi, mg, mc, dg, dc, ef, cn,\
+	  -(lo) * (xdpi), -(to) * (ydpi),\
+	  (lm) * 72.0, (bm) * 72.0,\
+	  (rm) * 72.0, (tm) * 72.0\
+	),\
+	prn_device_body_rest_(print_page)
+
+#define prn_device_body_extended(dtype, procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, mcomp, ncomp, pol, depth, gi, mg, mc, dg, dc, ef, cn, print_page)\
+  prn_device_margins_body_extended(dtype, procs, dname, w10, h10, xdpi, ydpi,\
+    lm, tm, lm, bm, rm, tm, mcomp, ncomp, pol, depth, gi, mg, mc, dg, dc, ef, cn, print_page)
+
 #define prn_device_std_margins_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lo, to, lm, bm, rm, tm, color_bits, print_page)\
 	std_device_std_color_full_body_type(dtype, &procs, dname, &st_device_printer,\
 	  (int)((float)(w10) * (xdpi) / 10 + 0.5),\

Index: gdevps.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevps.c,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- gdevps.c	16 Jun 2002 05:48:55 -0000	1.27
+++ gdevps.c	22 Aug 2002 07:12:28 -0000	1.28
@@ -116,7 +116,7 @@
 		psw_copy_mono,\
 		psw_copy_color,\
 		NULL,			/* draw_line */\
-		NULL,			/* get_bits */\
+		psdf_get_bits,\
 		psw_get_params,\
 		psw_put_params,\
 		NULL,			/* map_cmyk_color */\
@@ -139,7 +139,12 @@
 		NULL,			/* image_data */\
 		NULL,			/* end_image */\
 		NULL,			/* strip_tile_rectangle */\
-		NULL/******psw_strip_copy_rop******/\
+		NULL,/******psw_strip_copy_rop******/\
+		NULL,			/* get_clipping_box */\
+		NULL,			/* begin_typed_image */\
+		psdf_get_bits_rectangle,\
+		NULL,			/* map_color_rgb_alpha */\
+		psdf_create_compositor\
 	}
 
 const gx_device_pswrite gs_pswrite_device = {

Index: gdevpsdf.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpsdf.h,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- gdevpsdf.h	27 Jun 2002 04:03:03 -0000	1.17
+++ gdevpsdf.h	22 Aug 2002 07:12:28 -0000	1.18
@@ -390,4 +390,11 @@
 int psdf_set_color(gx_device_vector *vdev, const gx_drawing_color *pdc,
 		   const psdf_set_color_commands_t *ppscc);
 
+/* stubs to disable get_bits, get_bits_rectangle */
+dev_proc_get_bits(psdf_get_bits);
+dev_proc_get_bits_rectangle(psdf_get_bits_rectangle);
+
+/* intercept and ignore overprint compositor creation */
+dev_proc_create_compositor(psdf_create_compositor);
+
 #endif /* gdevpsdf_INCLUDED */

Index: gdevpsdi.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpsdi.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- gdevpsdi.c	14 Jun 2002 06:03:08 -0000	1.21
+++ gdevpsdi.c	22 Aug 2002 07:12:28 -0000	1.22
@@ -357,9 +357,12 @@
 	    pis != 0 &&
 	    gs_color_space_get_index(pim->ColorSpace) ==
 	    gs_color_space_index_DeviceCMYK;
+	gs_color_space rgb_cs;
 
-	if (cmyk_to_rgb)
-	    pim->ColorSpace = gs_cspace_DeviceRGB(pis);
+	if (cmyk_to_rgb) {
+	    gs_cspace_init_DeviceRGB(&rgb_cs);  /* idempotent initialization */
+	    pim->ColorSpace = &rgb_cs;
+	}
 	if (params.Depth == -1)
 	    params.Depth = (cmyk_to_rgb ? 8 : bpc_out);
 	if (do_downsample(&params, pim, resolution)) {
@@ -436,4 +439,3 @@
 		    width, height, depth, bits_per_sample);
     return code;
 }
-

Index: gdevpsdu.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpsdu.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- gdevpsdu.c	21 May 2002 20:07:11 -0000	1.16
+++ gdevpsdu.c	22 Aug 2002 07:12:28 -0000	1.17
@@ -29,6 +29,7 @@
 #include "sjpeg.h"
 #include "spprint.h"
 #include "sstring.h"
+#include "gsovrc.h"
 
 /* Structure descriptors */
 public_st_device_psdf();
@@ -406,4 +407,48 @@
     int status = s_close_filters(&pbw->strm, pbw->target);
 
     return (status >= 0 ? 0 : gs_note_error(gs_error_ioerror));
+}
+
+/* ---------------- Overprint, Get Bits ---------------- */
+
+/*
+ * High level devices cannot perform get_bits or get_bits_rectangle
+ * operations, for obvious reasons.
+ */
+int
+psdf_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data)
+{
+    return_error(gs_error_unregistered);
+}
+
+int
+psdf_get_bits_rectangle(
+    gx_device *             dev,
+    const gs_int_rect *     prect,
+    gs_get_bits_params_t *  params,
+    gs_int_rect **          unread )
+{
+    return_error(gs_error_unregistered);
+}
+
+/*
+ * Create compositor procedure for PostScript/PDF writer. Since these
+ * devices directly support overprint (and have access to the imager
+ * state), no compositor is required for overprint support. Hence, this
+ * routine just recognizes and discards invocations of the overprint
+ * compositor.
+ */
+int
+psdf_create_compositor(
+    gx_device *             dev,
+    gx_device **            pcdev,
+    const gs_composite_t *  pct,
+    const gs_imager_state * pis,
+    gs_memory_t *           mem )
+{
+    if (gs_is_overprint_compositor(pct)) {
+        *pcdev = dev;
+        return 0;
+    } else
+        return gx_default_create_compositor(dev, pcdev, pct, pis, mem);
 }

Index: gdevrops.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevrops.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gdevrops.c	21 Feb 2002 22:24:52 -0000	1.5
+++ gdevrops.c	22 Aug 2002 07:12:28 -0000	1.6
@@ -92,7 +92,16 @@
      NULL,				/* create_compositor */
      gx_forward_get_hardware_params,
      NULL,				/* text_begin */
-     NULL				/* finish_copydevice */
+     NULL,				/* finish_copydevice */
+     NULL,				/* begin_transparency_group */
+     NULL,				/* end_transparency_group */
+     NULL,				/* begin_transparency_mask */
+     NULL,				/* end_transparency_mask */
+     NULL,				/* discard_transparency_layer */
+     gx_forward_get_color_mapping_procs,
+     gx_forward_get_color_comp_index,
+     gx_forward_encode_color,
+     gx_forward_decode_color
     },
     0,				/* target */
     lop_default			/* log_op */

Index: gdevstc.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevstc.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gdevstc.c	16 Jun 2002 05:48:55 -0000	1.5
+++ gdevstc.c	22 Aug 2002 07:12:28 -0000	1.6
@@ -1785,7 +1785,7 @@
   }                                                    /* comp */
 
   if(code == 0) {
-
+      gx_color_value cv[4];
       sd->stc.flags |= STCOK4GO;
 
 /*
@@ -1798,26 +1798,28 @@
          set_dev_proc(sd,map_rgb_color, stc_map_gray_color);
          set_dev_proc(sd,map_cmyk_color,gx_default_map_cmyk_color);
          set_dev_proc(sd,map_color_rgb, stc_map_color_gray);
-         white = stc_map_gray_color((gx_device *) sd,
-                    gx_max_color_value,gx_max_color_value,gx_max_color_value);
+         cv[0] = cv[1] = cv[2] = gx_max_color_value;
+         white = stc_map_gray_color((gx_device *) sd, cv);
          break;
       case 3:
          set_dev_proc(sd,map_rgb_color, stc_map_rgb_color);
          set_dev_proc(sd,map_cmyk_color,gx_default_map_cmyk_color);
          set_dev_proc(sd,map_color_rgb, stc_map_color_rgb);
-         white = stc_map_rgb_color((gx_device *) sd,
-                    gx_max_color_value,gx_max_color_value,gx_max_color_value);
+         cv[0] = cv[1] = cv[2] = gx_max_color_value;
+         white = stc_map_rgb_color((gx_device *) sd, cv);
          break;
       default:
          set_dev_proc(sd,map_rgb_color, gx_default_map_rgb_color);
          if(sd->stc.flags & STCCMYK10) {
             set_dev_proc(sd,map_cmyk_color,stc_map_cmyk10_color);
             set_dev_proc(sd,map_color_rgb, stc_map_color_cmyk10);
-            white = stc_map_cmyk10_color((gx_device *) sd,0,0,0,0);
+            cv[0] = cv[1] = cv[2] = cv[3] = 0;
+            white = stc_map_cmyk10_color((gx_device *) sd, cv);
          } else {
             set_dev_proc(sd,map_cmyk_color,stc_map_cmyk_color);
             set_dev_proc(sd,map_color_rgb, stc_map_color_cmyk);
-            white = stc_map_cmyk_color((gx_device *) sd,0,0,0,0);
+            cv[0] = cv[1] = cv[2] = cv[3] = 0;
+            white = stc_map_cmyk_color((gx_device *) sd,cv);
          }
          break;                               /* Establish color-procs */
       }
@@ -1996,12 +1998,14 @@
  *** color-mapping of gray-scales
  ***/
 private gx_color_index 
-stc_map_gray_color(gx_device *pdev,
-        gx_color_value r, gx_color_value g, gx_color_value b)
+stc_map_gray_color(gx_device *pdev, const gx_color_value cv[])
 {
 
    stcolor_device *sd = (stcolor_device *) pdev;
    gx_color_index rv;
+   gx_color_value r = cv[0];
+   gx_color_value g = cv[1];
+   gx_color_value b = cv[2];
 
    if((r == g) && (g == b)) {
 
@@ -2055,14 +2059,15 @@
  *** color-mapping of rgb-values
  ***/
 private gx_color_index 
-stc_map_rgb_color(gx_device *pdev,
-                  gx_color_value r, gx_color_value g, gx_color_value b)
+stc_map_rgb_color(gx_device *pdev, const gx_color_value cv[])
 {
 
    stcolor_device *sd = (stcolor_device *) pdev;
    int          shift = sd->color_info.depth == 24 ? 8 : sd->stc.bits;
    gx_color_index  rv = 0;
-
+   gx_color_value r = cv[0];
+   gx_color_value g = cv[1];
+   gx_color_value b = cv[2];
    if((sd->stc.am != NULL) && ((r != g) || (g != b))) {
       float *m,fr,fg,fb,fv;
 
@@ -2122,13 +2127,16 @@
  *** color-mapping of cmyk-values
  ***/
 private gx_color_index 
-stc_map_cmyk_color(gx_device *pdev,
-        gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k)
+stc_map_cmyk_color(gx_device *pdev, const gx_color_value cv[])
 {
 
    stcolor_device *sd = (stcolor_device *) pdev;
    int          shift = sd->color_info.depth == 32 ? 8 : sd->stc.bits;
    gx_color_index rv = 0;
+   gx_color_value c = cv[0];
+   gx_color_value m = cv[1];
+   gx_color_value y = cv[2];
+   gx_color_value k = cv[3];
 
    if((c == m) && (m == y)) {
 
@@ -2241,13 +2249,17 @@
  *** color-mapping of cmyk10-values
  ***/
 private gx_color_index 
-stc_map_cmyk10_color(gx_device *pdev,
-        gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k)
+stc_map_cmyk10_color(gx_device *pdev, const gx_color_value cv[])
 {
 
    stcolor_device *sd = (stcolor_device *) pdev;
    int             mode;
    gx_color_index rv  = 0;
+
+   gx_color_value c = cv[0];
+   gx_color_value m = cv[1];
+   gx_color_value y = cv[2];
+   gx_color_value k = cv[3];
 
    if((c == m) && (m == y)) {
 

Index: gdevtknk.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevtknk.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gdevtknk.c	21 Feb 2002 22:24:52 -0000	1.5
+++ gdevtknk.c	22 Aug 2002 07:12:28 -0000	1.6
@@ -91,8 +91,12 @@
 
 /* Map an RGB color to a printer color. */
 private gx_color_index
-tekink_map_rgb_color(gx_device *dev, ushort r, ushort g, ushort b)
+tekink_map_rgb_color(gx_device *dev, const gx_color_value cv[])
 {
+    gx_color_value r = cv[0];
+    gx_color_value g = cv[1];
+    gx_color_value b = cv[2];
+    
     return(rgb_to_index[(((b>32767) << 2) + ((g>32767) << 1) + 
 			(r>32767)) & 7]);
 }

Index: gdevupd.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevupd.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- gdevupd.c	16 Jun 2002 05:48:55 -0000	1.8
+++ gdevupd.c	22 Aug 2002 07:12:28 -0000	1.9
@@ -2146,11 +2146,12 @@
 */
 
 private gx_color_index
-upd_cmyk_icolor(gx_device *pdev,
-   gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k)
+upd_cmyk_icolor(gx_device *pdev, const gx_color_value cv[])
 {
    const upd_p     upd = ((upd_device *)pdev)->upd;
    gx_color_index  rv;
+   gx_color_value c, m, y, k;
+   c = cv[0]; m = cv[1]; y = cv[2]; k = cv[3];
 
 /**
 All 4-Component-Modi have to deal with the Problem, that a value
@@ -2260,11 +2261,12 @@
 /* ------------------------------------------------------------------- */
 
 private gx_color_index
-upd_rgb_1color(gx_device *pdev,
-   gx_color_value r, gx_color_value g, gx_color_value b)
+upd_rgb_1color(gx_device *pdev, const gx_color_value cv[])
 {
    const upd_p     upd = ((upd_device *)pdev)->upd;
    gx_color_index  rv;
+   gx_color_value r, g, b;
+   r = cv[0]; g = cv[1]; b = cv[2];
 
    rv = upd_truncate(upd,0,r);
 
@@ -2315,11 +2317,12 @@
 /* ------------------------------------------------------------------- */
 
 private gx_color_index
-upd_rgb_3color(gx_device *pdev,
-   gx_color_value r, gx_color_value g, gx_color_value b)
+upd_rgb_3color(gx_device *pdev, const gx_color_value cv[])
 {
    const upd_p     upd = ((upd_device *)pdev)->upd;
    gx_color_index  rv;
+   gx_color_value r, g, b;
+   r = cv[0]; g = cv[1]; b = cv[2];
 
    rv = upd_truncate(upd,0,r) | upd_truncate(upd,1,g) | upd_truncate(upd,2,b);
    if(rv == gx_no_color_index) rv ^= 1;
@@ -2379,11 +2382,13 @@
 /* ------------------------------------------------------------------- */
 
 private gx_color_index
-upd_rgb_4color(gx_device *pdev,
-   gx_color_value r, gx_color_value g, gx_color_value b)
+upd_rgb_4color(gx_device *pdev, const gx_color_value cv[])
 {
    const upd_p     upd = ((upd_device *)pdev)->upd;
    gx_color_index  rv;
+   gx_color_value r, g, b;
+
+   r = cv[0]; g = cv[1]; b = cv[2];
 
    if((r == g) && (g == b)) {
 
@@ -2467,13 +2472,15 @@
 /* ------------------------------------------------------------------- */
 
 private gx_color_index
-upd_cmyk_kcolor(gx_device *pdev,
-   gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k)
+upd_cmyk_kcolor(gx_device *pdev, const gx_color_value cv[])
 {
    const upd_p     upd = ((upd_device *)pdev)->upd;
    gx_color_index  rv;
    gx_color_value  black;
 
+   gx_color_value c, m, y, k;
+   c = cv[0]; m = cv[1]; y = cv[2]; k = cv[3];
+
    if((c == m) && (m == y)) {
 
       black = c > k ? c : k;
@@ -2578,13 +2585,13 @@
 /* ------------------------------------------------------------------- */
 
 private gx_color_index
-upd_rgb_ovcolor(gx_device *pdev,
-   gx_color_value r, gx_color_value g, gx_color_value b)
+upd_rgb_ovcolor(gx_device *pdev, const gx_color_value cv[])
 {
    const upd_p     upd = ((upd_device *)pdev)->upd;
    gx_color_index  rv;
    gx_color_value  c,m,y,black;
-
+   gx_color_value r, g, b;
+   r = cv[0]; g = cv[1]; b = cv[2];
    if((r == g) && (g == b)) {
 
       black  = gx_max_color_value - r;
@@ -2659,12 +2666,13 @@
 /* ------------------------------------------------------------------- */
 
 private gx_color_index
-upd_rgb_novcolor(gx_device *pdev,
-   gx_color_value r, gx_color_value g, gx_color_value b)
+upd_rgb_novcolor(gx_device *pdev, const gx_color_value cv[])
 {
    const upd_p     upd = ((upd_device *)pdev)->upd;
    gx_color_index  rv;
    gx_color_value  c,m,y,black;
+   gx_color_value r, g, b;
+   r = cv[0]; g = cv[1]; b = cv[2];
 
    if((r == g) && (g == b)) {
 

Index: gdevvec.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevvec.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- gdevvec.c	21 Feb 2002 22:24:52 -0000	1.15
+++ gdevvec.c	22 Aug 2002 07:12:28 -0000	1.16
@@ -992,7 +992,6 @@
 						 vdev->open_options);
 	}
     }
-    gdev_vector_load_cache(vdev);	/* in case color mapping changed */
     return 0;
 }
 

Index: gdevx.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevx.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- gdevx.c	16 Jun 2002 05:48:55 -0000	1.13
+++ gdevx.c	22 Aug 2002 07:12:28 -0000	1.14
@@ -579,6 +579,10 @@
 	XPutImage(xdev->dpy, xdev->dest, xdev->gc, &xdev->image,
 		  sourcex, 0, x, y, w, h);
 	xdev->image.depth = xdev->image.bits_per_pixel = 1;
+
+	/* give up on optimization */
+	xdev->colors_or = (x_pixel)(-1);
+	xdev->colors_and = 0;
     }
     return 0;
 }

Index: gdevxalt.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevxalt.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gdevxalt.c	16 Jun 2002 05:48:55 -0000	1.7
+++ gdevxalt.c	22 Aug 2002 07:12:28 -0000	1.8
@@ -323,8 +323,7 @@
 	    (*dev_proc(tdev, map_color_rgb))(tdev, pixel, rgb);
 	    pixel_in = pixel;
 	    if (dev->color_info.num_components <= 3)
-		pixel_out = (*dev_proc(dev, map_rgb_color))
-		    (dev, rgb[0], rgb[1], rgb[2]);
+		pixel_out = (*dev_proc(dev, map_rgb_color))(dev, rgb);
 	    else {
 		/* Convert RGB to CMYK. */
 		gx_color_value c = gx_max_color_value - rgb[0];
@@ -332,8 +331,9 @@
 		gx_color_value y = gx_max_color_value - rgb[2];
 		gx_color_value k = (c < m ? min(c, y) : min(m, y));
 
-		pixel_out = (*dev_proc(dev, map_cmyk_color))
-		    (dev, c - k, m - k, y - k, k);
+                gx_color_value cmyk[4];
+                cmyk[0] = c - k; cmyk[1] = m - k; cmyk[2] = y - k; cmyk[3] = k;
+		pixel_out = (*dev_proc(dev, map_cmyk_color))(dev, cmyk);
 	    }
 	}
 	LINE_ACCUM(pixel_out, depth);
@@ -478,7 +478,7 @@
     if (result >= 0)
 	cindex = result;
     else
-	cindex = dev_proc(tdev, map_rgb_color)(tdev, rgb[0], rgb[1], rgb[2]);
+	cindex = dev_proc(tdev, map_rgb_color)(tdev, rgb);
     if (color < 16)
 	((gx_device_X_wrapper *) dev)->color_cache[color] = cindex;
     return cindex;
@@ -607,13 +607,12 @@
 }
 
 private gx_color_index
-x_cmyk_map_cmyk_color(gx_device * dev,
-		      gx_color_value c, gx_color_value m, gx_color_value y,
-		      gx_color_value k)
+x_cmyk_map_cmyk_color(gx_device * dev, const gx_color_value cv[])
 {
     int shift = dev->color_info.depth >> 2;
-    gx_color_index pixel = c >> (gx_color_value_bits - shift);
-
+    gx_color_index pixel = cv[0] >> (gx_color_value_bits - shift);
+    gx_color_value c, m, y, k;
+    c = cv[0]; m = cv[1]; y = cv[2]; k = cv[3];
     pixel = (pixel << shift) | (m >> (gx_color_value_bits - shift));
     pixel = (pixel << shift) | (y >> (gx_color_value_bits - shift));
     return (pixel << shift) | (k >> (gx_color_value_bits - shift));
@@ -797,9 +796,11 @@
 x_alpha_map_rgb_alpha_color(gx_device * dev,
  gx_color_value r, gx_color_value g, gx_color_value b, gx_color_value alpha)
 {
-    gx_color_index color = gx_forward_map_rgb_color(dev, r, g, b);
+    gx_color_index color;
+    gx_color_value cv[3];
     byte abyte = alpha >> (gx_color_value_bits - 8);
-
+    cv[0] = r; cv[1] = g; cv[2] = b;
+    color = gx_forward_map_rgb_color(dev, cv);
     return (abyte == 0 ? (gx_color_index)0xff << 24 :
 	    ((gx_color_index) (abyte ^ 0xff) << 24) + color);
 }
@@ -851,12 +852,13 @@
 #define make_shade(v, alpha)\
   (gx_max_color_value -\
    ((gx_max_color_value - (v)) * (alpha) / 15))
-		    gx_color_value r = make_shade(rgb[0], alpha);
-		    gx_color_value g = make_shade(rgb[1], alpha);
-		    gx_color_value b = make_shade(rgb[2], alpha);
+                    gx_color_value cv[3];
+		    cv[0] = make_shade(rgb[0], alpha);
+		    cv[1] = make_shade(rgb[1], alpha);
+		    cv[2] = make_shade(rgb[2], alpha);
 
 #undef make_shade
-		    a_color = (*dev_proc(tdev, map_rgb_color)) (tdev, r, g, b);
+		    a_color = (*dev_proc(tdev, map_rgb_color)) (tdev, cv);
 		    if (a_color != gx_no_color_index) {
 			shades[alpha] = a_color;
 			break;
@@ -943,19 +945,21 @@
 
 /* Map RGB to a fake color. */
 private gx_color_index
-x_rg16x_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
-		      gx_color_value b)
+x_rg16x_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
     /* Permute the colors to G5/B5/R6. */
+    gx_color_value r, g, b;
+    r = cv[0]; g = cv[1]; b = cv[2];
     return (r >> (gx_color_value_bits - 6)) +
 	((g >> (gx_color_value_bits - 5)) << 11) +
 	((b >> (gx_color_value_bits - 5)) << 6);
 }
 private gx_color_index
-x_rg32x_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
-		      gx_color_value b)
+x_rg32x_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
     /* Permute the colors to G11/B10/R11. */
+    gx_color_value r, g, b;
+    r = cv[0]; g = cv[1]; b = cv[2];
     return (r >> (gx_color_value_bits - 11)) +
 	((gx_color_index)(g >> (gx_color_value_bits - 11)) << 21) +
 	((gx_color_index)(b >> (gx_color_value_bits - 10)) << 11);

Index: gdevxcmp.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevxcmp.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gdevxcmp.c	19 Apr 2002 00:04:52 -0000	1.7
+++ gdevxcmp.c	22 Aug 2002 07:12:28 -0000	1.8
@@ -559,10 +559,12 @@
 
 /* Map RGB values to a pixel value. */
 gx_color_index
-gdev_x_map_rgb_color(gx_device * dev,
-		     gx_color_value r, gx_color_value g, gx_color_value b)
+gdev_x_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
     gx_device_X *const xdev = (gx_device_X *) dev;
+    gx_color_value r = cv[0];
+    gx_color_value g = cv[1];
+    gx_color_value b = cv[2];
 
     /* X and ghostscript both use shorts for color values. */
     /* Set drgb to the nearest color that the device can represent. */

Index: genconf.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/genconf.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- genconf.c	16 Jun 2002 05:48:55 -0000	1.8
+++ genconf.c	22 Aug 2002 07:12:28 -0000	1.9
@@ -41,6 +41,12 @@
  * See the next section on command line switches for the meaning of
  * <name_prefix>.
  *
+ *    -comp <name>
+ *
+ *	Adds compositor_(<name_prefix>_composite_<name>_type) to <gconfig.h>.
+ *	Used for gs_composite_type_t structures, whose identity may need to
+ *	passed through the command list.
+ *
  *    -dev <device>
  *
  *	Adds device_(<name_prefix><device>_device) to <gconfig.h>.
@@ -276,13 +282,14 @@
 	    string_list_t sorted_resources;
 	    string_list_t resources;
 	    string_list_t devs;	/* also includes devs2 */
+	    string_list_t compositors;
 	    string_list_t fonts;
 	    string_list_t libs;
 	    string_list_t libpaths;
 	    string_list_t links;
 	    string_list_t objs;
 	} named;
-#define NUM_RESOURCE_LISTS 8
+#define NUM_RESOURCE_LISTS 9
 	string_list_t indexed[NUM_RESOURCE_LISTS];
     } lists;
     string_pattern_t lib_p;
@@ -305,6 +312,7 @@
 static const string_list_t init_config_lists[] = {
     {"resource", 100, uniq_first},
     {"sorted_resource", 20, uniq_first},
+    {"-comp", 10, uniq_first},
     {"-dev", 100, uniq_first},
     {"-font", 50, uniq_first},
     {"-lib", 20, uniq_last},
@@ -477,6 +485,7 @@
 	    case 'h':
 		process_replaces(&conf);
 		fputs("/* This file was generated automatically by genconf.c. */\n", out);
+		write_list(out, &conf.lists.named.compositors, "%s\n");
 		write_list(out, &conf.lists.named.devs, "%s\n");
 		sort_uniq(&conf.lists.named.resources, true);
 		write_list(out, &conf.lists.named.resources, "%s\n");
@@ -749,6 +758,12 @@
 	/* Handle a few resources specially; just queue the rest. */
 	switch (category[0]) {
 #define IS_CAT(str) !strcmp(category, str)
+	    case 'c':
+		if (!IS_CAT("comp"))
+		    goto err;
+		pat = "compositor_(%scomposite_%%s_type)";
+		list = &pconf->lists.named.compositors;
+		goto pre;
 	    case 'd':
 		if (IS_CAT("dev"))
 		    pat = "device_(%s%%s_device)";

Index: gs.mak
===================================================================
RCS file: /cvs/ghostscript/gs/src/gs.mak,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- gs.mak	22 Jun 2002 03:33:12 -0000	1.14
+++ gs.mak	22 Aug 2002 07:12:28 -0000	1.15
@@ -58,7 +58,7 @@
 #	    always icclib (compiled in statically)
 #	DEVICE_DEVS - the devices to include in the executable.
 #	    See devs.mak for details.
-#	DEVICE_DEVS1...DEVICE_DEVS20 - additional devices, if the definition
+#	DEVICE_DEVS1...DEVICE_DEVS21 - additional devices, if the definition
 #	    of DEVICE_DEVS doesn't fit on one line.  See devs.mak for details.
 #	FEATURE_DEVS - what features to include in the executable.
 #	    Normally this is one of:
@@ -297,6 +297,8 @@
 SETPDEV2=$(EXP)$(ECHOGS_XE) -e .dev -w- -l-dev2 -b -s -l-include -l$(GLGENDIR)$(D)page -l-obj
 SETMOD=$(EXP)$(ECHOGS_XE) -e .dev -w- -l-obj
 ADDMOD=$(EXP)$(ECHOGS_XE) -e .dev -a- $(NULL)
+SETCOMP=$(EXP)$(ECHOGS_XE) -e .dev -w- -l-comp
+ADDCOMP=$(EXP)$(ECHOGS_XE) -e .dev -a- -l-comp
 
 # Define the search lists and compilation switches for the third-party
 # libraries, and the compilation switches for their clients.
@@ -368,7 +370,8 @@
  $(DEVICE_DEVS6) $(DEVICE_DEVS7) $(DEVICE_DEVS8) $(DEVICE_DEVS9) \
  $(DEVICE_DEVS10) $(DEVICE_DEVS11) $(DEVICE_DEVS12) $(DEVICE_DEVS13) \
  $(DEVICE_DEVS14) $(DEVICE_DEVS15) $(DEVICE_DEVS16) $(DEVICE_DEVS17) \
- $(DEVICE_DEVS18) $(DEVICE_DEVS19) $(DEVICE_DEVS20) $(DEVICE_DEVS_EXTRA)
+ $(DEVICE_DEVS18) $(DEVICE_DEVS19) $(DEVICE_DEVS20) $(DEVICE_DEVS21) \
+ $(DEVICE_DEVS_EXTRA)
 
 devs_tr=$(GLGENDIR)$(D)devs.tr
 $(devs_tr) : $(GS_MAK) $(TOP_MAKEFILES) $(ECHOGS_XE)
@@ -396,6 +399,7 @@
 	$(EXP)$(ECHOGS_XE) -a $(devs_tr) -+ $(DEVICE_DEVS18)
 	$(EXP)$(ECHOGS_XE) -a $(devs_tr) -+ $(DEVICE_DEVS19)
 	$(EXP)$(ECHOGS_XE) -a $(devs_tr) -+ $(DEVICE_DEVS20)
+	$(EXP)$(ECHOGS_XE) -a $(devs_tr) -+ $(DEVICE_DEVS21)
 	$(EXP)$(ECHOGS_XE) -a $(devs_tr) -+ $(DEVICE_DEVS_EXTRA)
 	$(EXP)$(ECHOGS_XE) -a $(devs_tr) - $(GLGENDIR)$(D)libcore
 

Index: gsalphac.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsalphac.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gsalphac.c	16 Jun 2002 05:48:55 -0000	1.5
+++ gsalphac.c	22 Aug 2002 07:12:28 -0000	1.6
@@ -95,8 +95,9 @@
 private composite_equal_proc(c_alpha_equal);
 private composite_write_proc(c_alpha_write);
 private composite_read_proc(c_alpha_read);
-private const gs_composite_type_t gs_composite_alpha_type =
+const gs_composite_type_t gs_composite_alpha_type =
 {
+    GX_COMPOSITOR_ALPHA,
     {
 	c_alpha_create_default_compositor,
 	c_alpha_equal,
@@ -174,19 +175,19 @@
 	     gs_memory_t * mem)
 {
     gs_composite_alpha_params_t params;
+    int code, nbytes = 1;
 
     if (size < 1 || *data > composite_op_last)
 	return_error(gs_error_rangecheck);
     params.op = *data;
     if (params.op == composite_Dissolve) {
-	if (size != 1 + sizeof(params.delta))
+	if (size < 1 + sizeof(params.delta))
 	    return_error(gs_error_rangecheck);
 	memcpy(&params.delta, data + 1, sizeof(params.delta));
-    } else {
-	if (size != 1)
-	    return_error(gs_error_rangecheck);
+	nbytes += sizeof(params.delta);
     }
-    return gs_create_composite_alpha(ppcte, &params, mem);
+    code = gs_create_composite_alpha(ppcte, &params, mem);
+    return code < 0 ? code : nbytes;
 }
 
 /* ---------------- Alpha-compositing device ---------------- */
@@ -316,10 +317,9 @@
 /* ------ (RGB) color mapping ------ */
 
 private gx_color_index
-dca_map_rgb_color(gx_device * dev,
-		  gx_color_value r, gx_color_value g, gx_color_value b)
+dca_map_rgb_color(gx_device * dev, const gx_color_value cv[])
 {
-    return dca_map_rgb_alpha_color(dev, r, g, b, gx_max_color_value);
+    return dca_map_rgb_alpha_color(dev, cv[0], cv[1], cv[2], gx_max_color_value);
 }
 private gx_color_index
 dca_map_rgb_alpha_color(gx_device * dev,
@@ -451,7 +451,7 @@
     }
     rect.p.x = x, rect.q.x = x + w;
     std_params.options =
-	gb_colors_for_device(dev) |
+	GB_COLORS_NATIVE |
 	(GB_ALPHA_LAST | GB_DEPTH_8 | GB_PACKING_CHUNKY |
 	 GB_RETURN_COPY | GB_RETURN_POINTER | GB_ALIGN_ANY |
 	 GB_OFFSET_0 | GB_OFFSET_ANY | GB_RASTER_STANDARD |

Index: gsbitops.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsbitops.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gsbitops.c	21 Feb 2002 22:24:52 -0000	1.5
+++ gsbitops.c	22 Aug 2002 07:12:28 -0000	1.6
@@ -77,97 +77,156 @@
 
     if (last_bit < 0) {		/* <=1 chunk */
 	set_mono_thin_mask(right_mask, width_bits, bit);
-	switch ((byte) pattern) {
-	    case 0:
-		FOR_EACH_LINE(*ptr &= ~right_mask;
-		    );
+	if (pattern == 0)
+	    FOR_EACH_LINE(*ptr &= ~right_mask;);
+	else if (pattern == (mono_fill_chunk)(-1))
+	    FOR_EACH_LINE(*ptr |= right_mask;);
+	else
+	    FOR_EACH_LINE(
+		*ptr = (*ptr & ~right_mask) | (pattern & right_mask); );
+    } else {
+	chunk mask;
+	int last = last_bit >> chunk_log2_bits;
+
+	set_mono_left_mask(mask, bit);
+	set_mono_right_mask(right_mask, (last_bit & chunk_bit_mask) + 1);
+	switch (last) {
+	    case 0:		/* 2 chunks */
+		if (pattern == 0)
+		    FOR_EACH_LINE(*ptr &= ~mask; ptr[1] &= ~right_mask;);
+		else if (pattern == (mono_fill_chunk)(-1))
+		    FOR_EACH_LINE(*ptr |= mask; ptr[1] |= right_mask;);
+		else
+		    FOR_EACH_LINE(
+		        *ptr = (*ptr & ~mask) | (pattern & mask);
+			ptr[1] = (ptr[1] & ~right_mask) | (pattern & right_mask); );
 		break;
-	    case 0xff:
-		FOR_EACH_LINE(*ptr |= right_mask;
-		    );
+	    case 1:		/* 3 chunks */
+		if (pattern == 0)
+		    FOR_EACH_LINE( *ptr &= ~mask;
+				   ptr[1] = 0;
+				   ptr[2] &= ~right_mask; );
+		else if (pattern == (mono_fill_chunk)(-1))
+		    FOR_EACH_LINE( *ptr |= mask;
+				   ptr[1] = ~(chunk) 0;
+				   ptr[2] |= right_mask; );
+		else
+		    FOR_EACH_LINE( *ptr = (*ptr & ~mask) | (pattern & mask);
+				    ptr[1] = pattern;
+				    ptr[2] = (ptr[2] & ~right_mask) | (pattern & right_mask); );
 		break;
-	    default:
-		FOR_EACH_LINE(
-		       *ptr = (*ptr & ~right_mask) | (pattern & right_mask);
-		    );
+	    default:{		/* >3 chunks */
+		    uint byte_count = (last_bit >> 3) & -chunk_bytes;
+
+		    if (pattern == 0)
+			FOR_EACH_LINE( *ptr &= ~mask;
+				       memset(ptr + 1, 0, byte_count);
+				       ptr[last + 1] &= ~right_mask; );
+		    else if (pattern == (mono_fill_chunk)(-1))
+			FOR_EACH_LINE( *ptr |= mask;
+				       memset(ptr + 1, 0xff, byte_count);
+				       ptr[last + 1] |= right_mask; );
+		    else
+			FOR_EACH_LINE(
+				*ptr = (*ptr & ~mask) | (pattern & mask);
+				memset(ptr + 1, (byte) pattern, byte_count);
+				ptr[last + 1] = (ptr[last + 1] & ~right_mask) |
+					        (pattern & right_mask); 	);
+		}
 	}
+    }
+#undef FOR_EACH_LINE
+}
+
+/*
+ * Similar to bits_fill_rectangle, but with an additional source mask.
+ * The src_mask variable is 1 for those bits of the original that are
+ * to be retained. The mask argument must consist of the requisite value
+ * in every byte, in the same manner as the pattern.
+ */
+void
+bits_fill_rectangle_masked(byte * dest, int dest_bit, uint draster,
+		    mono_fill_chunk pattern, mono_fill_chunk src_mask,
+		    int width_bits, int height)
+{
+    uint bit;
+    chunk right_mask;
+    int line_count = height;
+    chunk *ptr;
+    int last_bit;
+
+#define FOR_EACH_LINE(stat)\
+	do { stat } while ( inc_ptr(ptr, draster), --line_count )
+
+    dest += (dest_bit >> 3) & -chunk_align_bytes;
+    ptr = (chunk *) dest;
+    bit = dest_bit & chunk_align_bit_mask;
+    last_bit = width_bits + bit - (chunk_bits + 1);
+
+    if (last_bit < 0) {		/* <=1 chunk */
+	set_mono_thin_mask(right_mask, width_bits, bit);
+	right_mask &= ~src_mask;
+	if (pattern == 0)
+	    FOR_EACH_LINE(*ptr &= ~right_mask;);
+	else if (pattern == (mono_fill_chunk)(-1))
+	    FOR_EACH_LINE(*ptr |= right_mask;);
+	else
+	    FOR_EACH_LINE(
+		*ptr = (*ptr & ~right_mask) | (pattern & right_mask); );
     } else {
 	chunk mask;
 	int last = last_bit >> chunk_log2_bits;
 
 	set_mono_left_mask(mask, bit);
 	set_mono_right_mask(right_mask, (last_bit & chunk_bit_mask) + 1);
+	mask &= ~src_mask;
+	right_mask &= ~src_mask;
 	switch (last) {
 	    case 0:		/* 2 chunks */
-		switch ((byte) pattern) {
-		    case 0:
-			FOR_EACH_LINE(*ptr &= ~mask;
-				      ptr[1] &= ~right_mask;
-			    );
-			break;
-		    case 0xff:
-			FOR_EACH_LINE(*ptr |= mask;
-				      ptr[1] |= right_mask;
-			    );
-			break;
-		    default:
-			FOR_EACH_LINE(
-				   *ptr = (*ptr & ~mask) | (pattern & mask);
-					 ptr[1] = (ptr[1] & ~right_mask) | (pattern & right_mask);
-			    );
-		}
+		if (pattern == 0)
+		    FOR_EACH_LINE(*ptr &= ~mask; ptr[1] &= ~right_mask;);
+		else if (pattern == (mono_fill_chunk)(-1))
+		    FOR_EACH_LINE(*ptr |= mask; ptr[1] |= right_mask;);
+		else
+		    FOR_EACH_LINE(
+		        *ptr = (*ptr & ~mask) | (pattern & mask);
+			ptr[1] = (ptr[1] & ~right_mask) | (pattern & right_mask); );
 		break;
 	    case 1:		/* 3 chunks */
-		switch ((byte) pattern) {
-		    case 0:
-			FOR_EACH_LINE(
-					 *ptr &= ~mask;
-					 ptr[1] = 0;
-					 ptr[2] &= ~right_mask;
-			    );
-			break;
-		    case 0xff:
-			FOR_EACH_LINE(
-					 *ptr |= mask;
-					 ptr[1] = ~(chunk) 0;
-					 ptr[2] |= right_mask;
-			    );
-			break;
-		    default:
-			FOR_EACH_LINE(
-				   *ptr = (*ptr & ~mask) | (pattern & mask);
-					 ptr[1] = pattern;
-					 ptr[2] = (ptr[2] & ~right_mask) | (pattern & right_mask);
-			    );
-		}
+		if (pattern == 0)
+		    FOR_EACH_LINE( *ptr &= ~mask;
+				   ptr[1] &= src_mask;
+				   ptr[2] &= ~right_mask; );
+		else if (pattern == (mono_fill_chunk)(-1))
+		    FOR_EACH_LINE( *ptr |= mask;
+				   ptr[1] |= ~src_mask;
+				   ptr[2] |= right_mask; );
+		else
+		    FOR_EACH_LINE( *ptr = (*ptr & ~mask) | (pattern & mask);
+				    ptr[1] =(ptr[1] & src_mask) | pattern;
+				    ptr[2] = (ptr[2] & ~right_mask) | (pattern & right_mask); );
 		break;
 	    default:{		/* >3 chunks */
-		    uint byte_count = (last_bit >> 3) & -chunk_bytes;
+                    int     i;
 
-		    switch ((byte) pattern) {
-			case 0:
-			    FOR_EACH_LINE(
-					     *ptr &= ~mask;
-					     memset(ptr + 1, 0, byte_count);
-					     ptr[last + 1] &= ~right_mask;
-				);
-			    break;
-			case 0xff:
-			    FOR_EACH_LINE(
-					     *ptr |= mask;
-					  memset(ptr + 1, 0xff, byte_count);
-					     ptr[last + 1] |= right_mask;
-				);
-			    break;
-			default:
-			    FOR_EACH_LINE(
-				   *ptr = (*ptr & ~mask) | (pattern & mask);
-				memset(ptr + 1, (byte) pattern, byte_count);
-					     ptr[last + 1] =
-					     (ptr[last + 1] & ~right_mask) |
-					     (pattern & right_mask);
-				);
-		    }
+		    if (pattern == 0)
+			FOR_EACH_LINE( *ptr++ &= ~mask;
+				       for (i = 0; i < last; i++)
+					   *ptr++ &= src_mask;
+				       *ptr &= ~right_mask; );
+		    else if (pattern == (mono_fill_chunk)(-1))
+			FOR_EACH_LINE( *ptr++ |= mask;
+				       for (i = 0; i < last; i++)
+					   *ptr++ |= ~src_mask;
+					*ptr |= right_mask; );
+		    else
+			FOR_EACH_LINE(
+			    /* note: we know (pattern & ~src_mask) == pattern */
+			    *ptr = (*ptr & ~mask) | (pattern & mask);
+			    ++ptr;
+			    for (i = 0; i < last; i++, ptr++)
+                                *ptr = (*ptr & src_mask) | pattern;
+				*ptr = (*ptr & ~right_mask) | (pattern & right_mask); );
 		}
 	}
     }

Index: gsbitops.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsbitops.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gsbitops.h	16 Jun 2002 08:45:42 -0000	1.5
+++ gsbitops.h	22 Aug 2002 07:12:28 -0000	1.6
@@ -122,12 +122,12 @@
   switch ( (dbpv) >> 2 ) {\
   case 0:\
     if ( (dbit += (dbpv)) == 8 )\
-       *(dptr)++ = dbbyte | (value), dbbyte = 0, dbit = 0;\
-    else dbbyte |= (value) << (8 - dbit);\
+       *(dptr)++ = dbbyte | (byte)(value), dbbyte = 0, dbit = 0;\
+    else dbbyte |= (byte)((value) << (8 - dbit));\
     break;\
   case 1:\
     if ( dbit ^= 4 ) dbbyte = (byte)((value) << 4);\
-    else *(dptr)++ = dbbyte | (value);\
+    else *(dptr)++ = dbbyte | ((byte)(value));\
     break;\
   /* case 2 is deliberately omitted */
 #define sample_store_next8(value, dptr, dbit, dbpv, dbbyte)\
@@ -135,9 +135,9 @@
   case 2: *(dptr)++ = (byte)(value); break;\
   sample_end_
 #define sample_store_next_12_(value, dptr, dbit, dbbyte)\
-    if ( dbit ^= 4 ) *(dptr)++ = (value) >> 4, dbbyte = (byte)((value) << 4);\
+    if ( dbit ^= 4 ) *(dptr)++ = (byte)((value) >> 4), dbbyte = (byte)((value) << 4);\
     else\
-      *(dptr) = dbbyte | ((value) >> 8), (dptr)[1] = (byte)(value), dptr += 2;
+      *(dptr) = dbbyte | (byte)((value) >> 8), (dptr)[1] = (byte)(value), dptr += 2;
 #define sample_store_next_12(value, dptr, dbit, dbbyte)\
   BEGIN sample_store_next_12_(value, dptr, dbit, dbbyte) END
 #define sample_store_next12_(value, dptr, dbit, dbpv, dbbyte)\
@@ -160,6 +160,17 @@
   case 4: *(dptr)++ = (byte)((value) >> 8);\
   case 2: *(dptr)++ = (byte)(value); break;\
   sample_end_
+#define sample_store_next64(value, dptr, dbit, dbpv, dbbyte)\
+  sample_store_next12_(value, dptr, dbit, dbpv, dbbyte)\
+  case 16: *(dptr)++ = (byte)((value) >> 56);\
+  case 14: *(dptr)++ = (byte)((value) >> 48);\
+  case 12: *(dptr)++ = (byte)((value) >> 40);\
+  case 10: *(dptr)++ = (byte)((value) >> 32);\
+  case 8: *(dptr)++ = (byte)((value) >> 24);\
+  case 6: *(dptr)++ = (byte)((value) >> 16);\
+  case 4: *(dptr)++ = (byte)((value) >> 8);\
+  case 2: *(dptr)++ = (byte)(value); break;\
+  sample_end_
 
 /* Skip over storing one sample.  This may or may not store into the */
 /* skipped region. */
@@ -199,7 +210,10 @@
 #  define mono_fill_make_pattern(byt) (uint)((uint)(byt) * 0x01010101)
 #endif
 void bits_fill_rectangle(byte * dest, int dest_bit, uint raster,
-    mono_fill_chunk pattern, int width_bits, int height);
+		      mono_fill_chunk pattern, int width_bits, int height);
+void bits_fill_rectangle_masked(byte * dest, int dest_bit, uint raster,
+		      mono_fill_chunk pattern, mono_fill_chunk src_mask,
+		      int width_bits, int height);
 
 /* Replicate a bitmap horizontally in place. */
 void bits_replicate_horizontally(byte * data, uint width, uint height,

Index: gsccolor.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsccolor.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gsccolor.h	21 Feb 2002 22:24:52 -0000	1.4
+++ gsccolor.h	22 Aug 2002 07:12:28 -0000	1.5
@@ -33,7 +33,7 @@
  * This must be at least 4, and should be at least 6 to accommodate
  * hexachrome DeviceN color spaces.
  */
-#define GS_CLIENT_COLOR_MAX_COMPONENTS 6
+#define GS_CLIENT_COLOR_MAX_COMPONENTS 16
 
 /* Paint (non-Pattern) colors */
 typedef struct gs_paint_color_s {

Index: gscdevn.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gscdevn.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- gscdevn.c	16 Jun 2002 05:48:55 -0000	1.9
+++ gscdevn.c	22 Aug 2002 07:12:28 -0000	1.10
@@ -26,6 +26,13 @@
 #include "gsstruct.h"
 #include "gxcspace.h"
 #include "gxcdevn.h"
+#include "gxfarith.h"
+#include "gxfrac.h"
+#include "gxcmap.h"
+#include "gxistate.h"
+#include "gscoord.h"
+#include "gzstate.h"
+#include "gxdevcli.h"
 
 /* ---------------- Color space ---------------- */
 
@@ -37,7 +44,6 @@
 /* Define the DeviceN color space type. */
 private cs_proc_num_components(gx_num_components_DeviceN);
 private cs_proc_base_space(gx_alt_space_DeviceN);
-private cs_proc_equal(gx_equal_DeviceN);
 private cs_proc_init_color(gx_init_DeviceN);
 private cs_proc_restrict_color(gx_restrict_DeviceN);
 private cs_proc_concrete_space(gx_concrete_space_DeviceN);
@@ -48,11 +54,12 @@
 const gs_color_space_type gs_color_space_type_DeviceN = {
     gs_color_space_index_DeviceN, true, false,
     &st_color_space_DeviceN, gx_num_components_DeviceN,
-    gx_alt_space_DeviceN, gx_equal_DeviceN,
+    gx_alt_space_DeviceN,
     gx_init_DeviceN, gx_restrict_DeviceN,
     gx_concrete_space_DeviceN,
     gx_concretize_DeviceN, gx_remap_concrete_DeviceN,
     gx_default_remap_color, gx_install_DeviceN,
+    gx_comp_map_set_overprint,
     gx_adjust_cspace_DeviceN, gx_no_adjust_color_count
 };
 
@@ -81,7 +88,45 @@
 /* ------ Public procedures ------ */
 
 /*
- * Build a DeviceN color space.
+ * Build a DeviceN color space.  Not including allocation and
+ * initialization of the color space.
+ */
+int
+gs_build_DeviceN(
+		gs_color_space *pcspace,
+		uint num_components,
+		const gs_color_space *palt_cspace,
+		gs_memory_t *pmem
+		)
+{
+    gs_device_n_params *pcsdevn = pcsdevn = &pcspace->params.device_n;
+    gs_separation_name *pnames = 0;
+    int code;
+
+    if (palt_cspace == 0 || !palt_cspace->type->can_be_alt_space)
+	return_error(gs_error_rangecheck);
+
+    /* Allocate space for color names list. */
+    code = alloc_device_n_map(&pcsdevn->map, pmem, "gs_cspace_build_DeviceN");
+    if (code < 0) {
+	return code;
+    }
+    /* Allocate space for color names list. */
+    pnames = (gs_separation_name *)
+	gs_alloc_byte_array(pmem, num_components, sizeof(gs_separation_name),
+			  ".gs_cspace_build_DeviceN(names)");
+    if (pnames == 0) {
+	gs_free_object(pmem, pcsdevn->map, ".gs_cspace_build_DeviceN(map)");
+	return_error(gs_error_VMerror);
+    }
+    pcsdevn->names = pnames;
+    pcsdevn->num_components = num_components;
+    return 0;
+}
+
+/*
+ * Build a DeviceN color space.  Including allocation and initialization
+ * of the color space.
  */
 int
 gs_cspace_build_DeviceN(
@@ -96,20 +141,15 @@
     gs_device_n_params *pcsdevn = 0; /* bogus initialization */
     int code;
 
-    if (palt_cspace == 0 || !palt_cspace->type->can_be_alt_space)
-	return_error(gs_error_rangecheck);
-
     code = gs_cspace_alloc(&pcspace, &gs_color_space_type_DeviceN, pmem);
     if (code < 0)
 	return code;
-    pcsdevn = &pcspace->params.device_n;
-    code = alloc_device_n_map(&pcsdevn->map, pmem, "gs_cspace_build_DeviceN");
+
+    code = gs_build_DeviceN(pcspace, num_components, palt_cspace, pmem);
     if (code < 0) {
 	gs_free_object(pmem, pcspace, "gs_cspace_build_DeviceN");
 	return code;
     }
-    pcsdevn->names = psnames;
-    pcsdevn->num_components = num_components;
     gs_cspace_init_from((gs_color_space *)&pcsdevn->alt_space, palt_cspace);
     *ppcspace = pcspace;
     return 0;
@@ -136,11 +176,10 @@
  */
 int
 gs_cspace_set_devn_proc(gs_color_space * pcspace,
-			int (*proc)(const gs_device_n_params *,
-				    const float *,
-				    float *,
-				    const gs_imager_state *,
-				    void *
+			int (*proc)(const float *,
+                                    float *,
+                                    const gs_imager_state *,
+                                    void *
 				    ),
 			void *proc_data
 			)
@@ -156,10 +195,18 @@
     return 0;
 }
 
+/*
+ * Check if we are using the alternate color space.
+ */
+bool
+using_alt_color_space(const gs_state * pgs)
+{
+    return (pgs->color_component_map.use_alt_cspace);
+}
+
 /* Map a DeviceN color using a Function. */
-private int
-map_devn_using_function(const gs_device_n_params *pcsdevn,
-			const float *in, float *out,
+int
+map_devn_using_function(const float *in, float *out,
 			const gs_imager_state *pis, void *data)
 
 {
@@ -217,31 +264,16 @@
 private const gs_color_space *
 gx_alt_space_DeviceN(const gs_color_space * pcs)
 {
-    return (const gs_color_space *)&(pcs->params.device_n.alt_space);
-}
-
-/* Test whether one DeviceN color space equals another. */
-private bool
-gx_equal_DeviceN(const gs_color_space *pcs1, const gs_color_space *pcs2)
-{
-    return (gs_color_space_equal(gx_alt_space_DeviceN(pcs1),
-				 gx_alt_space_DeviceN(pcs2)) &&
-	    pcs1->params.device_n.num_components ==
-	      pcs2->params.device_n.num_components &&
-	    !memcmp(pcs1->params.device_n.names, pcs2->params.device_n.names,
-		    pcs1->params.device_n.num_components *
-		      sizeof(pcs1->params.device_n.names[0])) &&
-	    pcs1->params.device_n.map->tint_transform ==
-	      pcs2->params.device_n.map->tint_transform &&
-	    pcs1->params.device_n.map->tint_transform_data ==
-	      pcs2->params.device_n.map->tint_transform_data);
+    return pcs->params.device_n.use_alt_cspace
+	   ? (const gs_color_space *)&(pcs->params.device_n.alt_space)
+    	   : NULL;
 }
 
 /* Initialize a DeviceN color. */
 private void
 gx_init_DeviceN(gs_client_color * pcc, const gs_color_space * pcs)
 {
-    int i;
+    uint i;
 
     for (i = 0; i < pcs->params.device_n.num_components; ++i)
 	pcc->paint.values[i] = 1.0;
@@ -251,7 +283,7 @@
 private void
 gx_restrict_DeviceN(gs_client_color * pcc, const gs_color_space * pcs)
 {
-    int i;
+    uint i;
 
     for (i = 0; i < pcs->params.device_n.num_components; ++i) {
 	floatp value = pcc->paint.values[i];
@@ -265,89 +297,210 @@
 gx_concrete_space_DeviceN(const gs_color_space * pcs,
 			  const gs_imager_state * pis)
 {
-    /* We don't support concrete DeviceN spaces yet. */
-    const gs_color_space *pacs =
-	(const gs_color_space *)&pcs->params.device_n.alt_space;
+#ifdef DEBUG
+    /* 
+     * Check that we are using the current color space, even though
+     * this is not required for this routine.
+     */
+    if (pcs->id != pis->cspace_id)
+	dprintf("gx_concrete_space_DeviceN: color space id mismatch");
+#endif
 
-    return cs_concrete_space(pacs, pis);
+    /*
+     * Check if we are using the alternate color space.
+     */
+    if (pis->color_component_map.use_alt_cspace) {
+        const gs_color_space *pacs =
+	    (const gs_color_space *)&pcs->params.device_n.alt_space;
+
+        return cs_concrete_space(pacs, pis);
+    }
+    /*
+     * DeviceN color spaces are concrete (when not using alt. color space).
+     */
+    return pcs;
 }
 
+
 private int
 gx_concretize_DeviceN(const gs_client_color * pc, const gs_color_space * pcs,
 		      frac * pconc, const gs_imager_state * pis)
 {
-    int code, tcode;
+    int code, tcode = 0;
     gs_client_color cc;
     const gs_color_space *pacs =
 	(const gs_color_space *)&pcs->params.device_n.alt_space;
     gs_device_n_map *map = pcs->params.device_n.map;
 
-    /* Check the 1-element cache first. */
-    if (map->cache_valid) {
-	int i;
+#ifdef DEBUG
+    /* 
+     * Check that we are using the current color space, even though
+     * this is not required for this routine.
+     */
+    if (pcs->id != pis->cspace_id)
+	dprintf("gx_concrete_space_DeviceN: color space id mismatch");
+#endif
 
-	for (i = pcs->params.device_n.num_components; --i >= 0;) {
-	    if (map->tint[i] != pc->paint.values[i])
-		break;
-	}
-	if (i < 0) {
-	    int num_out = gs_color_space_num_components(pacs);
+    /*
+     * Check if we need to map into the alternate color space.
+     * We must preserve tcode for implementing a semi-hack in the interpreter.
+     */
+    if (pis->color_component_map.use_alt_cspace) {
+	    /* Check the 1-element cache first. */
+	if (map->cache_valid) {
+	    int i;
 
-	    for (i = 0; i < num_out; ++i)
-		pconc[i] = map->conc[i];
-	    return 0;
+	    for (i = pcs->params.device_n.num_components; --i >= 0;) {
+		if (map->tint[i] != pc->paint.values[i])
+		    break;
+	    }
+	    if (i < 0) {
+		int num_out = gs_color_space_num_components(pacs);
+
+		for (i = 0; i < num_out; ++i)
+		    pconc[i] = map->conc[i];
+		return 0;
+	    }
 	}
+        tcode = (*pcs->params.device_n.map->tint_transform)
+	     (pc->paint.values, &cc.paint.values[0],
+	     pis, pcs->params.device_n.map->tint_transform_data);
+        if (tcode < 0)
+	    return tcode;
+	code = cs_concretize_color(&cc, pacs, pconc, pis);
+    }
+    else {
+	float ftemp;
+	int i;
+
+	for (i = pcs->params.device_n.num_components; --i >= 0;)
+	    pconc[i] = unit_frac(pc->paint.values[i], ftemp);
+	return 0;
     }
-    /*
-     * We always map into the alternate color space.  We must preserve
-     * tcode for implementing a semi-hack in the interpreter.
-     */
-    tcode = (*pcs->params.device_n.map->tint_transform)
-	(&pcs->params.device_n, pc->paint.values, &cc.paint.values[0],
-	 pis, pcs->params.device_n.map->tint_transform_data);
-    if (tcode < 0)
-	return tcode;
-    code = (*pacs->type->concretize_color) (&cc, pacs, pconc, pis);
     return (code < 0 || tcode == 0 ? code : tcode);
 }
 
 private int
-gx_remap_concrete_DeviceN(const frac * pconc,
+gx_remap_concrete_DeviceN(const frac * pconc, const gs_color_space * pcs,
 	gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
 			  gs_color_select_t select)
 {
-    /* We don't support concrete DeviceN colors yet. */
-    return_error(gs_error_rangecheck);
+#ifdef DEBUG
+    /* 
+     * Check that we are using the current color space, even though
+     * this is not required for this routine.
+     */
+    if (pcs->id != pis->cspace_id)
+	dprintf("gx_remap_concrete_DeviceN: color space id mismatch");
+#endif
+
+    if (pis->color_component_map.use_alt_cspace) {
+        const gs_color_space *pacs =
+	    (const gs_color_space *)&pcs->params.device_n.alt_space;
+
+	return (*pacs->type->remap_concrete_color)
+				(pconc, pacs, pdc, pis, dev, select);
+    }
+    else {
+	gx_remap_concrete_devicen(pconc, pdc, pis, dev, select);
+	return 0;
+    }
 }
 
-/* Install a DeviceN color space. */
+/*
+ * Check that the color component names for a DeviceN color space
+ * match the device colorant names.  Also build a gs_devicen_color_map
+ * structure.
+ */
 private int
-gx_install_DeviceN(const gs_color_space * pcs, gs_state * pgs)
+check_DeviceN_component_names(const gs_color_space * pcs, gs_state * pgs)
 {
     const gs_separation_name *names = pcs->params.device_n.names;
-    uint i, j;
+    int num_comp = pcs->params.device_n.num_components;
+    int i, j;
+    int colorant_number;
+    byte * pname;
+    uint name_size;
+    gs_devicen_color_map * pcolor_component_map
+	= &pgs->color_component_map;
+    const gx_device * dev = pgs->device;
     const char none_str[] = "None";
-    const int none_size = strlen(none_str);
+    const uint none_size = strlen(none_str);
+    bool non_match = false;
+
+    pcolor_component_map->num_components = num_comp;
+    pcolor_component_map->num_colorants = dev->color_info.num_components;
+    pcolor_component_map->sep_type = SEP_OTHER;
     /*
-     * Postscript does not accept /None as a color component but it is
-     * allowed in PDF so we accept it.  Except for /None, no components
-     * are allowed to have duplicated names.
+     * Always use the alternate color space if the current device is
+     * using an additive color model.
      */
-    for (i = 1; i < pcs->params.device_n.num_components; ++i) {
-	byte *pname;
-	uint name_size;
-
-    	pcs->params.device_n.get_colorname_string(names[i], &pname, &name_size);
-	if (name_size != none_size ||
-	        (strncmp(none_str, (const char *) pname, name_size)!=0)) {
-	    for (j = 0; j < i; ++j) {
+    if (dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE) {
+	pcolor_component_map->use_alt_cspace = true;
+	return 0;
+    }
+    /*
+     * Now check the names of the color components.
+     */
+    for(i = 0; i < num_comp; i++ ) {
+        non_match = false;
+	/*
+	 * Get the character string and length for the component name.
+	 */
+	pgs->client_procs.get_colorname_string(names[i], &pname, &name_size);
+	/*
+         * Postscript does not accept /None as a color component but it is
+         * allowed in PDF so we accept it.  It is also accepted as a
+	 * separation name.
+         */
+	if (name_size == none_size &&
+	        (strncmp(none_str, (const char *)pname, name_size) == 0)) {
+	    pcolor_component_map->color_map[i] = -1;
+	}
+	else {
+ 	    /*
+	     * Check for duplicated names.  Except for /None, no components
+	     * are allowed to have duplicated names.
+	     */
+	    for (j = 0; j < i; j++) {
 	        if (names[i] == names[j])
 		    return_error(gs_error_rangecheck);
             }
-        }
+	    /*
+	     * Compare the colorant name to the device's.  If the device's
+	     * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
+	     * colorant is in the SeparationNames list but not in the
+	     * SeparationOrder list.
+	     */
+	    colorant_number = (*dev_proc(dev, get_color_comp_index))
+				    (dev, (const char *)pname, name_size, i);
+	    if (colorant_number >= 0) {		/* If valid colorant name */
+		pcolor_component_map->color_map[i] =
+		    (colorant_number == GX_DEVICE_COLOR_MAX_COMPONENTS) ? -1
+		    					   : colorant_number;
+	    }
+	    else
+		non_match = true;
+        }	
     }
-    return (*pcs->params.device_n.alt_space.type->install_cspace)
+    pcolor_component_map->use_alt_cspace = non_match;
+    return 0;
+}
+
+/* Install a DeviceN color space. */
+private int
+gx_install_DeviceN(const gs_color_space * pcs, gs_state * pgs)
+{
+    int code = check_DeviceN_component_names(pcs, pgs);
+
+    if (code < 0)
+       return code;
+    pgs->color_space->params.device_n.use_alt_cspace =
+	using_alt_color_space(pgs);
+    if (pgs->color_space->params.device_n.use_alt_cspace)
+        return (*pcs->params.device_n.alt_space.type->install_cspace)
 	((const gs_color_space *) & pcs->params.device_n.alt_space, pgs);
+    return 0;
 }
 
 /* Adjust the reference count of a DeviceN color space. */

Index: gscdevn.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gscdevn.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gscdevn.h	16 Jun 2002 08:45:42 -0000	1.6
+++ gscdevn.h	22 Aug 2002 07:12:28 -0000	1.7
@@ -23,31 +23,42 @@
 #include "gscspace.h"
 
 /*
+ * Fill in a DeviceN color space.  Does not include allocation
+ * and initialization of the color space.
+ * Note that the client is responsible for memory management of the
+ * tint transform Function.
+ */
+int gs_build_DeviceN(
+			gs_color_space *pcspace,
+			uint num_components,
+			const gs_color_space *palt_cspace,
+			gs_memory_t *pmem
+			);
+/*
  * Allocate and fill in a DeviceN color space.
  * Note that the client is responsible for memory management of the
- * name array and (if used) the tint transform Function.
+ * tint transform Function.
  */
 int gs_cspace_build_DeviceN(
-			    gs_color_space **ppcspace,
-			    gs_separation_name *psnames,
-			    uint num_components,
-			    const gs_color_space *palt_cspace,
-			    gs_memory_t *pmem
-			    );
+			       gs_color_space **ppcspace,
+			       gs_separation_name *psnames,
+			       uint num_components,
+			       const gs_color_space *palt_cspace,
+			       gs_memory_t *pmem
+			       );
 
 /* Set the tint transformation procedure for a DeviceN color space. */
 /* VMS limits procedure names to 31 characters, and some systems only */
 /* compare the first 23 characters. */
 extern int gs_cspace_set_devn_proc(
-				   gs_color_space * pcspace,
-				   int (*proc)(const gs_device_n_params *,
-					       const float *,
-					       float *,
-					       const gs_imager_state *,
-					       void *
-					       ),
-				   void *proc_data
-				   );
+				      gs_color_space * pcspace,
+			int (*proc)(const float *,
+				       float *,
+				       const gs_imager_state *,
+				       void *
+				      ),
+				      void *proc_data
+				      );
 
 /* Set the DeviceN tint transformation procedure to a Function. */
 #ifndef gs_function_DEFINED
@@ -55,12 +66,16 @@
 #  define gs_function_DEFINED
 #endif
 int gs_cspace_set_devn_function(gs_color_space *pcspace,
-				gs_function_t *pfn);
+				   gs_function_t *pfn);
 
 /*
  * If the DeviceN tint transformation procedure is a Function,
  * return the function object, otherwise return 0.
  */
 gs_function_t *gs_cspace_get_devn_function(const gs_color_space *pcspace);
+
+/* Map a DeviceN color using a Function. */
+int map_devn_using_function(const float *in, float *out,
+			const gs_imager_state *pis, void *data);
 
 #endif /* gscdevn_INCLUDED */

Index: gscolor.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gscolor.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- gscolor.c	16 Jun 2002 05:48:55 -0000	1.8
+++ gscolor.c	22 Aug 2002 07:12:28 -0000	1.9
@@ -21,11 +21,11 @@
 #include "gsstruct.h"
 #include "gsutil.h"		/* for gs_next_ids */
 #include "gsccolor.h"
-#include "gscssub.h"
 #include "gxcspace.h"
 #include "gxdcconv.h"
 #include "gxdevice.h"		/* for gx_color_index */
 #include "gxcmap.h"
+#include "gscolor2.h"
 #include "gzstate.h"
 
 /* Imported from gsht.c */
@@ -106,158 +106,43 @@
 int
 gs_setgray(gs_state * pgs, floatp gray)
 {
-    gs_client_color *pcc = pgs->ccolor;
-
-    if (pgs->in_cachedevice)
-	return_error(gs_error_undefined);
-    cs_adjust_color_count(pgs, -1);
-    gs_cspace_assign(pgs->color_space, gs_current_DeviceGray_space(pgs));
-    pgs->orig_cspace_index = pgs->orig_base_cspace_index =
-	gs_color_space_index_DeviceGray;
-    pcc->paint.values[0] = FORCE_UNIT(gray);
-    pcc->pattern = 0;		/* for GC */
-    gx_unset_dev_color(pgs);
-    return 0;
-}
-
-/* currentgray */
-int
-gs_currentgray(const gs_state * pgs, float *pg)
-{
-    const gs_client_color *pcc = pgs->ccolor;
-    const gs_imager_state *const pis = (const gs_imager_state *)pgs;
+    gs_color_space      cs;
+    int                 code;
 
-    switch (pgs->orig_cspace_index) {
-	case gs_color_space_index_DeviceGray:
-	    *pg = pcc->paint.values[0];
-	    break;
-	case gs_color_space_index_DeviceRGB:
-	    *pg = frac2float(color_rgb_to_gray(
-					float2frac(pcc->paint.values[0]),
-					float2frac(pcc->paint.values[1]),
-					float2frac(pcc->paint.values[2]),
-					pis));
-	    break;
-	case gs_color_space_index_DeviceCMYK:
-	    *pg = frac2float(color_cmyk_to_gray(
-					float2frac(pcc->paint.values[0]),
-					float2frac(pcc->paint.values[1]),
-					float2frac(pcc->paint.values[2]),
-					float2frac(pcc->paint.values[3]),
-					pis));
-	    break;
-	default:
-	    /*
-	     * Might be another convertible color space, but this is rare,
-	     * so we don't care about speed or (to some extent) accuracy.
-	     */
-	    {
-		float rgb[3];
-		int code = gs_currentrgbcolor(pgs, rgb);
+    gs_cspace_init_DeviceGray(&cs);
+    if ((code = gs_setcolorspace(pgs, &cs)) >= 0) {
+        gs_client_color *   pcc = pgs->ccolor;
 
-		if (code < 0)
-		    return code;
-		*pg = frac2float(color_rgb_to_gray(
-						   float2frac(rgb[0]),
-						   float2frac(rgb[1]),
-						   float2frac(rgb[2]),
-						   pis));
-	    }
+        cs_adjust_color_count(pgs, -1); /* not strictly necessary */
+        pcc->paint.values[0] = FORCE_UNIT(gray);
+        pcc->pattern = 0;		/* for GC */
+        gx_unset_dev_color(pgs);
     }
-    return 0;
+    return code;
 }
 
 /* setrgbcolor */
 int
 gs_setrgbcolor(gs_state * pgs, floatp r, floatp g, floatp b)
 {
-    gs_client_color *pcc = pgs->ccolor;
-
-    if (pgs->in_cachedevice)
-	return_error(gs_error_undefined);
-    cs_adjust_color_count(pgs, -1);
-    gs_cspace_assign(pgs->color_space, gs_current_DeviceRGB_space(pgs));
-    pgs->orig_cspace_index = pgs->orig_base_cspace_index =
-	gs_color_space_index_DeviceRGB;
-    pcc->paint.values[0] = FORCE_UNIT(r);
-    pcc->paint.values[1] = FORCE_UNIT(g);
-    pcc->paint.values[2] = FORCE_UNIT(b);
-    pcc->pattern = 0;		/* for GC */
-    gx_unset_dev_color(pgs);
-    return 0;
-}
+    gs_color_space      cs;
+    int                 code;
 
-/* currentrgbcolor */
-int
-gs_currentrgbcolor(const gs_state * pgs, float pr3[3])
-{
-    const gs_client_color *pcc = pgs->ccolor;
-    const gs_color_space *pcs = pgs->color_space;
-    const gs_color_space *pbcs = pcs;
-    const gs_imager_state *const pis = (const gs_imager_state *)pgs;
-    gs_color_space_index csi = pgs->orig_cspace_index;
-    frac fcc[4];
-    gs_client_color cc;
-    int code;
+    gs_cspace_init_DeviceRGB(&cs);
+    if ((code = gs_setcolorspace(pgs, &cs)) >= 0) {
+       gs_client_color *    pcc = pgs->ccolor;
 
-  sw:switch (csi) {
-	case gs_color_space_index_DeviceGray:
-	    pr3[0] = pr3[1] = pr3[2] = pcc->paint.values[0];
-	    return 0;
-	case gs_color_space_index_DeviceRGB:
-	    pr3[0] = pcc->paint.values[0];
-	    pr3[1] = pcc->paint.values[1];
-	    pr3[2] = pcc->paint.values[2];
-	    return 0;
-	case gs_color_space_index_DeviceCMYK:
-	    color_cmyk_to_rgb(
-				 float2frac(pcc->paint.values[0]),
-				 float2frac(pcc->paint.values[1]),
-				 float2frac(pcc->paint.values[2]),
-				 float2frac(pcc->paint.values[3]),
-				 pis, fcc);
-	    pr3[0] = frac2float(fcc[0]);
-	    pr3[1] = frac2float(fcc[1]);
-	    pr3[2] = frac2float(fcc[2]);
-	    return 0;
-        case gs_color_space_index_CIEICC:
-         icc_cs:if (gs_cspace_base_space(pbcs) != NULL)
-                  goto bcs;
-                break;
-	case gs_color_space_index_DeviceN:
-	case gs_color_space_index_Separation:
-	  ds:if (cs_concrete_space(pbcs, pis) == pbcs)
-		break;		/* not using alternative space */
-	    /* (falls through) */
-	case gs_color_space_index_Indexed:
-	  bcs:pbcs = gs_cspace_base_space(pbcs);
-	    switch (pbcs->type->index) {
-		case gs_color_space_index_DeviceN:
-		case gs_color_space_index_Separation:
-		    goto ds;
-                case gs_color_space_index_CIEICC:
-                    goto icc_cs;
-		default:	/* outer switch will catch undefined cases */
-		    break;
-	    }
-	    code = cs_concretize_color(pcc, pcs, fcc, pis);
-	    if (code < 0)
-		return code;
-	    cc.paint.values[0] = frac2float(fcc[0]);
-	    cc.paint.values[1] = frac2float(fcc[1]);
-	    cc.paint.values[2] = frac2float(fcc[2]);
-	    cc.paint.values[3] = frac2float(fcc[3]);
-	    pcc = &cc;
-	    pcs = pbcs;
-	    csi = pgs->orig_base_cspace_index;
-	    goto sw;
-	default:
-	    break;
+        cs_adjust_color_count(pgs, -1); /* not strictly necessary */
+        pcc->paint.values[0] = FORCE_UNIT(r);
+        pcc->paint.values[1] = FORCE_UNIT(g);
+        pcc->paint.values[2] = FORCE_UNIT(b);
+        pcc->pattern = 0;		/* for GC */
+        gx_unset_dev_color(pgs);
     }
-    pr3[0] = pr3[1] = pr3[2] = 0.0;
-    return 0;
+    return code;
 }
 
+
 /* setnullcolor */
 int
 gs_setnullcolor(gs_state * pgs)
@@ -279,11 +164,11 @@
 int
 gs_settransfer_remap(gs_state * pgs, gs_mapping_proc tproc, bool remap)
 {
-    gx_transfer_colored *ptran = &pgs->set_transfer.colored;
+    gx_transfer *ptran = &pgs->set_transfer;
 
     /*
      * We can safely decrement the reference counts
-     * of the non-gray transfer maps, because
+     * of the non-default transfer maps, because
      * if any of them get freed, the rc_unshare can't fail.
      */
     rc_decrement(ptran->red, "gs_settransfer");
@@ -293,10 +178,9 @@
 		      pgs->memory, goto fail, "gs_settransfer");
     ptran->gray->proc = tproc;
     ptran->gray->id = gs_next_ids(1);
-    ptran->red = ptran->gray;
-    ptran->green = ptran->gray;
-    ptran->blue = ptran->gray;
-    ptran->gray->rc.ref_count += 3;
+    ptran->red = 0;
+    ptran->green = 0;
+    ptran->blue = 0;
     if (remap) {
 	load_transfer_map(pgs, ptran->gray, 0.0);
 	gx_set_effective_transfer(pgs);
@@ -307,6 +191,7 @@
     rc_increment(ptran->red);
     rc_increment(ptran->green);
     rc_increment(ptran->blue);
+    rc_increment(ptran->gray);
     return_error(gs_error_VMerror);
 }
 
@@ -314,7 +199,7 @@
 gs_mapping_proc
 gs_currenttransfer(const gs_state * pgs)
 {
-    return pgs->set_transfer.colored.gray->proc;
+    return pgs->set_transfer.gray->proc;
 }
 
 /* ------ Non-operator routines ------ */
@@ -323,18 +208,14 @@
 void
 gx_set_device_color_1(gs_state * pgs)
 {
-    gx_device_color *pdc = pgs->dev_color;
-    gs_client_color *pcc = pgs->ccolor;
+    gs_color_space  cs;
 
-    cs_adjust_color_count(pgs, -1);
-    pcc->paint.values[0] = 0.0;
-    pcc->pattern = 0;		/* for GC */
-    color_set_pure(pdc, 1);
+    gs_setoverprint(pgs, false);
+    gs_setoverprintmode(pgs, 0);
+    gs_cspace_init_DeviceGray(&cs);
+    gs_setcolorspace(pgs, &cs);
+    color_set_pure(pgs->dev_color, 1);
     pgs->log_op = lop_default;
-    gs_cspace_assign(pgs->color_space,
-		     gs_cspace_DeviceGray((const gs_imager_state *)pgs));
-    pgs->orig_cspace_index = pgs->orig_base_cspace_index =
-	gs_color_space_index_DeviceGray;
 }
 
 /* ------ Internal routines ------ */

Index: gscolor1.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gscolor1.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gscolor1.c	16 Jun 2002 05:48:55 -0000	1.7
+++ gscolor1.c	22 Aug 2002 07:12:28 -0000	1.8
@@ -21,13 +21,15 @@
 #include "gsstruct.h"
 #include "gsutil.h"		/* for gs_next_ids */
 #include "gsccolor.h"
-#include "gscssub.h"
 #include "gxcspace.h"
 #include "gxdcconv.h"
 #include "gxdevice.h"		/* for gx_color_index */
 #include "gxcmap.h"
 #include "gzstate.h"
 #include "gscolor1.h"
+#include "gscolor2.h"
+#include "gxhttype.h"
+#include "gzht.h"
 
 /* Imports from gscolor.c */
 void load_transfer_map(gs_state *, gx_transfer_map *, floatp);
@@ -42,96 +44,25 @@
 int
 gs_setcmykcolor(gs_state * pgs, floatp c, floatp m, floatp y, floatp k)
 {
-    gs_client_color *pcc = pgs->ccolor;
-
-    if (pgs->in_cachedevice)
-	return_error(gs_error_undefined);
-    cs_adjust_color_count(pgs, -1);
-    gs_cspace_assign(pgs->color_space, gs_current_DeviceCMYK_space(pgs));
-    pgs->orig_cspace_index = pgs->orig_base_cspace_index =
-	gs_color_space_index_DeviceCMYK;
-    pcc->paint.values[0] = FORCE_UNIT(c);
-    pcc->paint.values[1] = FORCE_UNIT(m);
-    pcc->paint.values[2] = FORCE_UNIT(y);
-    pcc->paint.values[3] = FORCE_UNIT(k);
-    pcc->pattern = 0;		/* for GC */
-    gx_unset_dev_color(pgs);
-    return 0;
-}
+    gs_color_space      cs;
+    int                 code;
 
-/* currentcmykcolor */
-int
-gs_currentcmykcolor(const gs_state * pgs, float pr4[4])
-{
-    const gs_client_color *pcc = pgs->ccolor;
-    const gs_color_space *pcs = pgs->color_space;
-    const gs_color_space *pbcs = pcs;
-    const gs_imager_state *const pis = (const gs_imager_state *)pgs;
-    gs_color_space_index csi = pgs->orig_cspace_index;
-    frac fcc[4];
-    gs_client_color cc;
-    int code;
+    gs_cspace_init_DeviceCMYK(&cs);
+    if ((code = gs_setcolorspace(pgs, &cs)) >= 0) {
+       gs_client_color *    pcc = pgs->ccolor;
 
-  sw:switch (csi) {
-	case gs_color_space_index_DeviceGray:
-	    pr4[0] = pr4[1] = pr4[2] = 0.0;
-	    pr4[3] = 1.0 - pcc->paint.values[0];
-	    return 0;
-	case gs_color_space_index_DeviceRGB:
-	    color_rgb_to_cmyk(float2frac(pcc->paint.values[0]),
-			      float2frac(pcc->paint.values[1]),
-			      float2frac(pcc->paint.values[2]),
-			      pis, fcc);
-	    pr4[0] = frac2float(fcc[0]);
-	    pr4[1] = frac2float(fcc[1]);
-	    pr4[2] = frac2float(fcc[2]);
-	    pr4[3] = frac2float(fcc[3]);
-	    return 0;
-	case gs_color_space_index_DeviceCMYK:
-	    pr4[0] = pcc->paint.values[0];
-	    pr4[1] = pcc->paint.values[1];
-	    pr4[2] = pcc->paint.values[2];
-	    pr4[3] = pcc->paint.values[3];
-	    return 0;
-        case gs_color_space_index_CIEICC:
-         icc_cs:if (gs_cspace_base_space(pbcs) != NULL)
-                  goto bcs;
-                break;
-	case gs_color_space_index_DeviceN:
-	case gs_color_space_index_Separation:
-	  ds:if (cs_concrete_space(pbcs, pis) == pbcs)
-		break;		/* not using alternative space */
-	    /* (falls through) */
-	case gs_color_space_index_Indexed:
-	  bcs:pbcs = gs_cspace_base_space(pbcs);
-	    switch (pbcs->type->index) {
-		case gs_color_space_index_DeviceN:
-		case gs_color_space_index_Separation:
-		    goto ds;
-                case gs_color_space_index_CIEICC:
-                    goto icc_cs;
-		default:	/* outer switch will catch undefined cases */
-		    break;
-	    }
-	    code = cs_concretize_color(pcc, pcs, fcc, pis);
-	    if (code < 0)
-		return code;
-	    cc.paint.values[0] = frac2float(fcc[0]);
-	    cc.paint.values[1] = frac2float(fcc[1]);
-	    cc.paint.values[2] = frac2float(fcc[2]);
-	    cc.paint.values[3] = frac2float(fcc[3]);
-	    pcc = &cc;
-	    pcs = pbcs;
-	    csi = pgs->orig_base_cspace_index;
-	    goto sw;
-	default:
-	    break;
+        cs_adjust_color_count(pgs, -1); /* not strictly necessary */
+        pcc->paint.values[0] = FORCE_UNIT(c);
+        pcc->paint.values[1] = FORCE_UNIT(m);
+        pcc->paint.values[2] = FORCE_UNIT(y);
+        pcc->paint.values[3] = FORCE_UNIT(k);
+        pcc->pattern = 0;		/* for GC */
+        gx_unset_dev_color(pgs);
     }
-    pr4[0] = pr4[1] = pr4[2] = 0.0;
-    pr4[3] = 1.0;
-    return 0;
+    return code;
 }
 
+
 /* setblackgeneration */
 /* Remap=0 is used by the interpreter. */
 int
@@ -200,9 +131,10 @@
 			  gs_mapping_proc blue_proc,
 			  gs_mapping_proc gray_proc, bool remap)
 {
-    gx_transfer_colored *ptran = &pgs->set_transfer.colored;
-    gx_transfer_colored old;
+    gx_transfer *ptran = &pgs->set_transfer;
+    gx_transfer old;
     gs_id new_ids = gs_next_ids(4);
+    gx_device * dev = pgs->device;
 
     old = *ptran;
     rc_unshare_struct(ptran->gray, gx_transfer_map, &st_transfer_map,
@@ -221,6 +153,14 @@
     ptran->green->id = new_ids + 2;
     ptran->blue->proc = blue_proc;
     ptran->blue->id = new_ids + 3;
+    ptran->red_component_num = 
+        gs_color_name_component_number(dev, "Red", 3, ht_type_colorscreen);
+    ptran->green_component_num = 
+        gs_color_name_component_number(dev, "Green", 5, ht_type_colorscreen);
+    ptran->blue_component_num = 
+        gs_color_name_component_number(dev, "Blue", 4, ht_type_colorscreen);
+    ptran->gray_component_num = 
+        gs_color_name_component_number(dev, "Gray", 4, ht_type_colorscreen);
     if (remap) {
 	load_transfer_map(pgs, ptran->red, 0.0);
 	load_transfer_map(pgs, ptran->green, 0.0);
@@ -252,7 +192,7 @@
 void
 gs_currentcolortransfer(const gs_state * pgs, gs_mapping_proc procs[4])
 {
-    const gx_transfer_colored *ptran = &pgs->set_transfer.colored;
+    const gx_transfer *ptran = &pgs->set_transfer;
 
     procs[0] = ptran->red->proc;
     procs[1] = ptran->green->proc;

Index: gscolor2.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gscolor2.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- gscolor2.c	16 Jun 2002 05:48:55 -0000	1.9
+++ gscolor2.c	22 Aug 2002 07:12:28 -0000	1.10
@@ -32,39 +32,32 @@
 int
 gs_setcolorspace(gs_state * pgs, const gs_color_space * pcs)
 {
-    int code;
-    gs_color_space cs_old;
-    gs_client_color cc_old;
+    int             code = 0;
+    gs_color_space  cs_old = *pgs->color_space;
+    gs_client_color cc_old = *pgs->ccolor;
 
     if (pgs->in_cachedevice)
 	return_error(gs_error_undefined);
-    if (pcs->id == pgs->color_space->id) {	/* same color space */
-	cs_full_init_color(pgs->ccolor, pcs);
-	return 0;
+
+    if (pcs->id != pgs->color_space->id) {
+        pcs->type->adjust_cspace_count(pcs, 1);
+        *pgs->color_space = *pcs;
+	pgs->cspace_id = pcs->id;
+        if ( (code = pcs->type->install_cspace(pcs, pgs)) < 0    ||
+              (pgs->overprint                                 &&
+               (code = pcs->type->set_overprint(pcs, pgs)) < 0  )  ) {
+            *pgs->color_space = cs_old;
+            pcs->type->adjust_cspace_count(pcs, -1);
+        } else
+            cs_old.type->adjust_cspace_count(&cs_old, -1);
     }
-    cs_old = *pgs->color_space;
-    cc_old = *pgs->ccolor;
-    (*pcs->type->adjust_cspace_count)(pcs, 1);
-    *pgs->color_space = *pcs;
-    if ((code = (*pcs->type->install_cspace)(pcs, pgs)) < 0)
-	goto rcs;
-    cs_full_init_color(pgs->ccolor, pcs);
-    (*cs_old.type->adjust_color_count)(&cc_old, &cs_old, -1);
-    (*cs_old.type->adjust_cspace_count)(&cs_old, -1);
-    pgs->orig_cspace_index = pcs->type->index;
-    {
-	const gs_color_space *pccs = pcs;
-	const gs_color_space *pbcs;
 
-	while ((pbcs = gs_cspace_base_space(pccs)) != 0)
-	    pccs = pbcs;
-	pgs->orig_base_cspace_index = pccs->type->index;
+    if (code >= 0) {
+        cs_full_init_color(pgs->ccolor, pcs);
+        cs_old.type->adjust_color_count(&cc_old, &cs_old, -1);
+        gx_unset_dev_color(pgs);
     }
-    gx_unset_dev_color(pgs);
-    return code;
-    /* Restore the color space if installation failed. */
-rcs:*pgs->color_space = cs_old;
-    (*pcs->type->adjust_cspace_count)(pcs, -1);
+
     return code;
 }
 
@@ -74,11 +67,6 @@
 {
     return pgs->color_space;
 }
-gs_color_space_index
-gs_currentcolorspace_index(const gs_state *pgs)
-{
-    return pgs->orig_cspace_index;
-}
 
 /* setcolor */
 int
@@ -164,20 +152,21 @@
 
 /* Define the Indexed color space type. */
 private cs_proc_base_space(gx_base_space_Indexed);
-private cs_proc_equal(gx_equal_Indexed);
 private cs_proc_restrict_color(gx_restrict_Indexed);
 private cs_proc_concrete_space(gx_concrete_space_Indexed);
 private cs_proc_concretize_color(gx_concretize_Indexed);
 private cs_proc_install_cspace(gx_install_Indexed);
+private cs_proc_set_overprint(gx_set_overprint_Indexed);
 private cs_proc_adjust_cspace_count(gx_adjust_cspace_Indexed);
 const gs_color_space_type gs_color_space_type_Indexed = {
     gs_color_space_index_Indexed, false, false,
     &st_color_space_Indexed, gx_num_components_1,
-    gx_base_space_Indexed, gx_equal_Indexed,
+    gx_base_space_Indexed,
     gx_init_paint_1, gx_restrict_Indexed,
     gx_concrete_space_Indexed,
     gx_concretize_Indexed, NULL,
     gx_default_remap_color, gx_install_Indexed,
+    gx_set_overprint_Indexed,
     gx_adjust_cspace_Indexed, gx_no_adjust_color_count
 };
 
@@ -230,35 +219,6 @@
     return (const gs_color_space *)&(pcs->params.indexed.base_space);
 }
 
-/* Test whether one Indexed color space equals another. */
-private bool
-gx_equal_Indexed(const gs_color_space *pcs1, const gs_color_space *pcs2)
-{
-    const gs_color_space *base = gx_base_space_Indexed(pcs1);
-    uint hival = pcs1->params.indexed.hival;
-
-    if (!gs_color_space_equal(base, gx_base_space_Indexed(pcs2)))
-	return false;
-    if (hival == pcs2->params.indexed.hival ||
-	/*
-	 * In principle, a table-specified Indexed space could be equal
-	 * to a procedure-specified Indexed space, but we don't bother
-	 * to detect this.
-	 */
-	pcs1->params.indexed.use_proc != pcs2->params.indexed.use_proc
-	)
-	return false;
-    if (pcs1->params.indexed.use_proc) {
-	return !memcmp(pcs1->params.indexed.lookup.map->values,
-		       pcs2->params.indexed.lookup.map->values,
-		       pcs1->params.indexed.lookup.map->num_values *
-		         sizeof(pcs1->params.indexed.lookup.map->values[0]));
-    } else {
-	return !memcmp(&pcs1->params.indexed.lookup.table.data,
-		       &pcs2->params.indexed.lookup.table.data,
-		       gs_color_space_num_components(base) * (hival + 1));
-    }
-}
 
 /* Color space installation ditto. */
 
@@ -269,6 +229,15 @@
 	((const gs_color_space *) & pcs->params.indexed.base_space, pgs);
 }
 
+/* Color space overprint setting ditto. */
+
+private int
+gx_set_overprint_Indexed(const gs_color_space * pcs, gs_state * pgs)
+{
+    return (*pcs->params.indexed.base_space.type->set_overprint)
+	((const gs_color_space *) & pcs->params.indexed.base_space, pgs);
+}
+
 /* Color space reference count adjustment ditto. */
 
 private void
@@ -469,6 +438,15 @@
     const gs_color_space *pbcs =
     (const gs_color_space *)&pcs->params.indexed.base_space;
 
+#ifdef DEBUG
+    /* 
+     * Check that we are using the current color space, even though
+     * this is not required for this routine.
+     */
+    if (pcs->id != pis->cspace_id)
+	dprintf("gx_concrete_space_CIE: color space id mismatch");
+#endif
+
     return cs_concrete_space(pbcs, pis);
 }
 
@@ -485,6 +463,15 @@
 	(const gs_color_space *)&pcs->params.indexed.base_space;
     gs_client_color cc;
     int code = gs_cspace_indexed_lookup(&pcs->params.indexed, index, &cc);
+
+#ifdef DEBUG
+    /* 
+     * Check that we are using the current color space, even though
+     * this is not required for this routine.
+     */
+    if (pcs->id != pis->cspace_id)
+	dprintf("gx_concrete_space_CIE: color space id mismatch");
+#endif
 
     if (code < 0)
 	return code;

Index: gscolor2.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gscolor2.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gscolor2.h	16 Jun 2002 08:45:42 -0000	1.6
+++ gscolor2.h	22 Aug 2002 07:12:29 -0000	1.7
@@ -38,11 +38,6 @@
 const gs_client_color *gs_currentcolor(const gs_state *);
 int gs_setcolor(gs_state *, const gs_client_color *);
 
-/*
- * gs_currentcolorspace_index returns the index of the current color space
- * *before* any substitution.
- */
-gs_color_space_index gs_currentcolorspace_index(const gs_state *);
 
 /* CIE-specific routines */
 #ifndef gs_cie_render_DEFINED

Index: gscpixel.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gscpixel.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gscpixel.c	21 Feb 2002 22:24:52 -0000	1.5
+++ gscpixel.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -22,30 +22,27 @@
 #include "gxcspace.h"
 #include "gscpixel.h"
 #include "gxdevice.h"
+#include "gxistate.h"
+#include "gsovrc.h"
+#include "gsstate.h"
 
 /* Define the DevicePixel color space type. */
-private cs_proc_equal(gx_equal_DevicePixel);
 private cs_proc_restrict_color(gx_restrict_DevicePixel);
 private cs_proc_remap_concrete_color(gx_remap_concrete_DevicePixel);
 private cs_proc_concretize_color(gx_concretize_DevicePixel);
+private cs_proc_set_overprint(gx_set_overprint_DevicePixel);
 private const gs_color_space_type gs_color_space_type_DevicePixel = {
     gs_color_space_index_DevicePixel, true, false,
     &st_base_color_space, gx_num_components_1,
-    gx_no_base_space, gx_equal_DevicePixel,
+    gx_no_base_space,
     gx_init_paint_1, gx_restrict_DevicePixel,
     gx_same_concrete_space,
     gx_concretize_DevicePixel, gx_remap_concrete_DevicePixel,
     gx_default_remap_color, gx_no_install_cspace,
+    gx_set_overprint_DevicePixel,
     gx_no_adjust_cspace_count, gx_no_adjust_color_count
 };
 
-/* Test whether one DevicePixel color space equals another. */
-private bool
-gx_equal_DevicePixel(const gs_color_space *pcs1, const gs_color_space *pcs2)
-{
-    return pcs1->params.pixel.depth == pcs2->params.pixel.depth;
-}
-
 /* Initialize a DevicePixel color space. */
 int
 gs_cspace_init_DevicePixel(gs_color_space * pcs, int depth)
@@ -87,16 +84,44 @@
 gx_concretize_DevicePixel(const gs_client_color * pc, const gs_color_space * pcs,
 			  frac * pconc, const gs_imager_state * pis)
 {
+#ifdef DEBUG
+    /* 
+     * Check that we are using the current color space, even though
+     * this is not required for this routine.
+     */
+    if (pcs->id != pis->cspace_id)
+	dprintf("gx_concrete_space_CIE: color space id mismatch");
+#endif
+
     /****** NOT ENOUGH BITS IN float OR frac ******/
     pconc[0] = (frac) (ulong) pc->paint.values[0];
     return 0;
 }
 
 private int
-gx_remap_concrete_DevicePixel(const frac * pconc,
+gx_remap_concrete_DevicePixel(const frac * pconc, const gs_color_space * pcs,
 	gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
 			      gs_color_select_t select)
 {
+#ifdef DEBUG
+    /* 
+     * Check that we are using the current color space, even though
+     * this is not required for this routine.
+     */
+    if (pcs->id != pis->cspace_id)
+	dprintf("gx_concrete_space_CIE: color space id mismatch");
+#endif
+
     color_set_pure(pdc, pconc[0] & ((1 << dev->color_info.depth) - 1));
     return 0;
+}
+
+/* DevicePixel disables overprint */
+private int
+gx_set_overprint_DevicePixel(const gs_color_space * pcs, gs_state * pgs)
+{
+    gs_overprint_params_t   params;
+
+    params.retain_any_comps = false;
+    return gs_state_update_overprint(pgs, &params);
 }

Index: gscscie.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gscscie.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gscscie.c	21 Feb 2002 22:24:52 -0000	1.6
+++ gscscie.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -49,11 +49,12 @@
 const gs_color_space_type gs_color_space_type_CIEDEFG = {
     gs_color_space_index_CIEDEFG, true, true,
     &st_color_space_CIEDEFG, gx_num_components_4,
-    gx_no_base_space, gx_cspace_not_equal,
+    gx_no_base_space,
     gx_init_CIE, gx_restrict_CIEDEFG,
     gx_concrete_space_CIE,
     gx_concretize_CIEDEFG, NULL,
     gx_default_remap_color, gx_install_CIE,
+    gx_spot_colors_set_overprint,
     gx_adjust_cspace_CIEDEFG, gx_no_adjust_color_count
 };
 
@@ -65,11 +66,12 @@
 const gs_color_space_type gs_color_space_type_CIEDEF = {
     gs_color_space_index_CIEDEF, true, true,
     &st_color_space_CIEDEF, gx_num_components_3,
-    gx_no_base_space, gx_cspace_not_equal,
+    gx_no_base_space,
     gx_init_CIE, gx_restrict_CIEDEF,
     gx_concrete_space_CIE,
     gx_concretize_CIEDEF, NULL,
     gx_default_remap_color, gx_install_CIE,
+    gx_spot_colors_set_overprint,
     gx_adjust_cspace_CIEDEF, gx_no_adjust_color_count
 };
 
@@ -81,11 +83,12 @@
 const gs_color_space_type gs_color_space_type_CIEABC = {
     gs_color_space_index_CIEABC, true, true,
     &st_color_space_CIEABC, gx_num_components_3,
-    gx_no_base_space, gx_cspace_not_equal,
+    gx_no_base_space,
     gx_init_CIE, gx_restrict_CIEABC,
     gx_concrete_space_CIE,
     gx_concretize_CIEABC, NULL,
     gx_remap_CIEABC, gx_install_CIE,
+    gx_spot_colors_set_overprint,
     gx_adjust_cspace_CIEABC, gx_no_adjust_color_count
 };
 
@@ -97,14 +100,17 @@
 const gs_color_space_type gs_color_space_type_CIEA = {
     gs_color_space_index_CIEA, true, true,
     &st_color_space_CIEA, gx_num_components_1,
-    gx_no_base_space, gx_cspace_not_equal,
+    gx_no_base_space,
     gx_init_CIE, gx_restrict_CIEA,
     gx_concrete_space_CIE,
     gx_concretize_CIEA, NULL,
     gx_default_remap_color, gx_install_CIE,
+    gx_spot_colors_set_overprint,
     gx_adjust_cspace_CIEA, gx_no_adjust_color_count
 };
 
+private gs_color_space rgb_cs, cmyk_cs;
+
 /* Determine the concrete space underlying a CIEBased space. */
 const gs_color_space *
 gx_concrete_space_CIE(const gs_color_space * pcs, const gs_imager_state * pis)
@@ -113,10 +119,13 @@
 
     if (pcie == 0 || pcie->RenderTable.lookup.table == 0 ||
 	pcie->RenderTable.lookup.m == 3
-	)
-	return gs_cspace_DeviceRGB(pis);
-    else			/* pcie->RenderTable.lookup.m == 4 */
-	return gs_cspace_DeviceCMYK(pis);
+	) {
+	gs_cspace_init_DeviceRGB(&rgb_cs);  /* idempotent initialization */
+        return &rgb_cs;
+    } else {			/* pcie->RenderTable.lookup.m == 4 */
+	gs_cspace_init_DeviceCMYK(&rgb_cs); /* idempotent initialization */
+	return &cmyk_cs;
+    }
 }
 
 /* Install a CIE space in the graphics state. */

Index: gscsepr.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gscsepr.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- gscsepr.c	16 Jun 2002 05:48:55 -0000	1.16
+++ gscsepr.c	22 Aug 2002 07:12:29 -0000	1.17
@@ -27,6 +27,10 @@
 #include "gxfixed.h"		/* for gxcolor2.h */
 #include "gxcolor2.h"		/* for gs_indexed_map */
 #include "gzstate.h"		/* for pgs->overprint */
+#include "gscdevn.h"		/* for alloc_device_n_map */
+#include "gxcdevn.h"		/* for gs_device_n_map_s */
+#include "gxcmap.h"
+#include "gxdevcli.h"
 
 /* ---------------- Color space ---------------- */
 
@@ -36,7 +40,6 @@
 
 /* Define the Separation color space type. */
 private cs_proc_base_space(gx_alt_space_Separation);
-private cs_proc_equal(gx_equal_Separation);
 private cs_proc_init_color(gx_init_Separation);
 private cs_proc_concrete_space(gx_concrete_space_Separation);
 private cs_proc_concretize_color(gx_concretize_Separation);
@@ -47,11 +50,12 @@
 const gs_color_space_type gs_color_space_type_Separation = {
     gs_color_space_index_Separation, true, false,
     &st_color_space_Separation, gx_num_components_1,
-    gx_alt_space_Separation, gx_equal_Separation,
+    gx_alt_space_Separation,
     gx_init_Separation, gx_restrict01_paint_1,
     gx_concrete_space_Separation,
     gx_concretize_Separation, gx_remap_concrete_Separation,
     gx_remap_Separation, gx_install_Separation,
+    gx_comp_map_set_overprint,
     gx_adjust_cspace_Separation, gx_no_adjust_color_count
 };
 
@@ -79,44 +83,57 @@
 private const gs_color_space *
 gx_alt_space_Separation(const gs_color_space * pcs)
 {
-    return (const gs_color_space *)&(pcs->params.separation.alt_space);
-}
-
-/* Test whether one Separation color space equals another. */
-private bool
-gx_equal_Separation(const gs_color_space *pcs1, const gs_color_space *pcs2)
-{
-    return (gs_color_space_equal(gx_alt_space_Separation(pcs1),
-				 gx_alt_space_Separation(pcs2)) &&
-	    pcs1->params.separation.sname == pcs2->params.separation.sname &&
-	    ((pcs1->params.separation.map->proc.tint_transform ==
-	        pcs2->params.separation.map->proc.tint_transform &&
-	      pcs1->params.separation.map->proc_data ==
-	        pcs2->params.separation.map->proc_data) ||
-	     !memcmp(pcs1->params.separation.map->values,
-		     pcs2->params.separation.map->values,
-		     pcs1->params.separation.map->num_values *
-		     sizeof(pcs1->params.separation.map->values[0]))));
+    return pcs->params.separation.use_alt_cspace
+	   ? (const gs_color_space *)&(pcs->params.separation.alt_space)
+    	   : NULL;
 }
 
 /* Get the concrete space for a Separation space. */
-/* (We don't support concrete Separation spaces yet.) */
 private const gs_color_space *
 gx_concrete_space_Separation(const gs_color_space * pcs,
 			     const gs_imager_state * pis)
 {
-    const gs_color_space *pacs =
-	(const gs_color_space *)&pcs->params.separation.alt_space;
+#ifdef DEBUG
+    /* 
+     * Check that we are using the current color space, even though
+     * this is not required for this routine.
+     */
+    if (pcs->id != pis->cspace_id)
+	dprintf("gx_concrete_space_Separation: color space id mismatch");
+#endif
 
-    return cs_concrete_space(pacs, pis);
+    /*
+     * Check if we are using the alternate color space.
+     */
+    if (pis->color_component_map.use_alt_cspace) {
+        const gs_color_space *pacs =
+	    (const gs_color_space *)&pcs->params.separation.alt_space;
+
+        return cs_concrete_space(pacs, pis);
+    }
+    /*
+     * Separation color spaces are concrete (when not using alt. color space).
+     */
+    return pcs;
 }
 
+private int
+check_Separation_component_name(const gs_color_space * pcs, gs_state * pgs);
+
 /* Install a Separation color space. */
 private int
 gx_install_Separation(const gs_color_space * pcs, gs_state * pgs)
 {
-    return (*pcs->params.separation.alt_space.type->install_cspace)
+    int code = check_Separation_component_name(pcs, pgs);
+
+    if (code < 0)
+       return code;
+    pgs->color_space->params.separation.use_alt_cspace =
+	using_alt_color_space(pgs);
+    if (pgs->color_space->params.separation.use_alt_cspace)
+        return (*pcs->params.separation.alt_space.type->install_cspace)
 	((const gs_color_space *) & pcs->params.separation.alt_space, pgs);
+    return 0;
 }
 
 /* Adjust the reference count of a Separation color space. */
@@ -132,64 +149,30 @@
 /* ------ Constructors/accessors ------ */
 
 /*
- * The default separation tint transformation function. This will just return
- * the information in the cache or, if the cache is of zero size, set all
- * components in the alternative color space to 0.
- *
- * No special cases are provided for this routine, as the use of separations
- * (particular in this form) is sufficiently rare to not have a significant
- * performance impact.
+ * Build a separation color space.
  */
-private int
-map_tint_value(const gs_separation_params * pcssepr, floatp in_val,
-	       float *out_vals)
+int
+gs_build_Separation(
+		    gs_color_space * pcspace,
+		    const gs_color_space * palt_cspace,
+		    gs_memory_t * pmem
+)
 {
-    int ncomps =
-    cs_num_components((const gs_color_space *)&pcssepr->alt_space);
-    int nentries = pcssepr->map->num_values / ncomps;
-    int indx;
-    const float *pv = pcssepr->map->values;
-    int i;
+    gs_separation_params * pcssepr = &pcspace->params.separation;
+    int code;
 
-    if (nentries == 0) {
-	for (i = 0; i < ncomps; i++)
-	    out_vals[i] = 0.0;
-	return 0;
-    }
-    if (in_val > 1)
-	indx = nentries - 1;
-    else if (in_val <= 0)
-	indx = 0;
-    else
-	indx = (int)(in_val * nentries + 0.5);
-    pv += indx * ncomps;
+    if (palt_cspace == 0 || !palt_cspace->type->can_be_alt_space)
+	return_error(gs_error_rangecheck);
 
-    for (i = 0; i < ncomps; i++)
-	out_vals[i] = pv[i];
+    code = alloc_device_n_map(&pcssepr->map, pmem, "gs_cspace_build_Separation");
+    if (pcssepr->map == NULL) {
+	gs_free_object(pmem, pcspace, "gs_cspace_build_Separation");
+	return_error(gs_error_VMerror);
+    }
     return 0;
 }
 
 /*
- *  Allocate the indexed map required by a separation color space. 
- */
-private gs_indexed_map *
-alloc_separation_map(const gs_color_space * palt_cspace, int cache_size,
-		     gs_memory_t * pmem)
-{
-    int num_values =
-	(cache_size == 0 ? 0 :
-	 cache_size * gs_color_space_num_components(palt_cspace));
-    gs_indexed_map *pimap;
-    int code = alloc_indexed_map(&pimap, num_values, pmem,
-				 "gs_cspace_build_Separation");
-
-    if (code < 0)
-	return 0;
-    pimap->proc.tint_transform = map_tint_value;
-    return pimap;
-}
-
-/*
  * Build a separation color space.
  *
  * The values array provided with separation color spaces is actually cached
@@ -205,8 +188,8 @@
 			      gs_memory_t * pmem
 )
 {
-    gs_color_space *pcspace = 0;
-    gs_separation_params *pcssepr = 0;
+    gs_color_space *pcspace = NULL;
+    gs_separation_params *pcssepr = NULL;
     int code;
 
     if (palt_cspace == 0 || !palt_cspace->type->can_be_alt_space)
@@ -215,57 +198,41 @@
     code = gs_cspace_alloc(&pcspace, &gs_color_space_type_Separation, pmem);
     if (code < 0)
 	return code;
-    pcssepr = &pcspace->params.separation;
-    pcssepr->map = alloc_separation_map(palt_cspace, cache_size, pmem);
-    if (pcssepr->map == 0) {
+ 
+    code = gs_build_Separation(pcspace, palt_cspace, pmem);
+    if (code < 0) {
 	gs_free_object(pmem, pcspace, "gs_cspace_build_Separation");
-	return_error(gs_error_VMerror);
+	return code;
     }
-    pcssepr->sname = sname;
+    pcssepr->sep_name = sname;
     gs_cspace_init_from((gs_color_space *) & pcssepr->alt_space, palt_cspace);
     *ppcspace = pcspace;
     return 0;
 }
 
 /*
- * Get the cached value array for a separation color space. This will return
- * a null pointer if the color space is not a separation color space, or if
- * the separation color space has a cache size of 0.
- */
-float *
-gs_cspace_get_sepr_value_array(const gs_color_space * pcspace)
-{
-    if (gs_color_space_get_index(pcspace) != gs_color_space_index_Separation)
-	return 0;
-    return pcspace->params.separation.map->values;
-}
-
-/*
  * Set the tint transformation procedure used by a Separation color space.
  */
 int
 gs_cspace_set_sepr_proc(gs_color_space * pcspace,
-	    int (*proc) (const gs_separation_params *, floatp, float *))
+			int (*proc)(const float *,
+                                    float *,
+                                    const gs_imager_state *,
+                                    void *
+				    ),
+			void *proc_data
+			)
 {
-    gs_indexed_map *pimap;
+    gs_device_n_map *pimap;
 
     if (gs_color_space_get_index(pcspace) != gs_color_space_index_Separation)
 	return_error(gs_error_rangecheck);
     pimap = pcspace->params.separation.map;
-    pimap->proc.tint_transform = proc;
-    pimap->proc_data = 0;
-    return 0;
-}
-
-/* Map a Separation tint using a Function. */
-private int
-map_sepr_using_function(const gs_separation_params * pcssepr,
-			floatp in_val, float *out_vals)
-{
-    float in = in_val;
-    gs_function_t *const pfn = pcssepr->map->proc_data;
+    pimap->tint_transform = proc;
+    pimap->tint_transform_data = proc_data;
+    pimap->cache_valid = false;
 
-    return gs_function_evaluate(pfn, &in, out_vals);
+    return 0;
 }
 
 /*
@@ -274,18 +241,18 @@
 int
 gs_cspace_set_sepr_function(const gs_color_space *pcspace, gs_function_t *pfn)
 {
-    gs_indexed_map *pimap;
+    gs_device_n_map *pimap;
 
     if (gs_color_space_get_index(pcspace) != gs_color_space_index_Separation ||
-	pfn->params.m != 1 ||
-	pfn->params.n !=
+	pfn->params.m != 1 || pfn->params.n !=
 	  gs_color_space_num_components((const gs_color_space *)
 					&pcspace->params.separation.alt_space)
 	)
 	return_error(gs_error_rangecheck);
     pimap = pcspace->params.separation.map;
-    pimap->proc.tint_transform = map_sepr_using_function;
-    pimap->proc_data = pfn;
+    pimap->tint_transform = map_devn_using_function;
+    pimap->tint_transform_data = pfn;
+    pimap->cache_valid = false;
     return 0;
 }
 
@@ -297,49 +264,15 @@
 gs_cspace_get_sepr_function(const gs_color_space *pcspace)
 {
     if (gs_color_space_get_index(pcspace) == gs_color_space_index_Separation &&
-	pcspace->params.separation.map->proc.tint_transform ==
-	  map_sepr_using_function)
-	return pcspace->params.separation.map->proc_data;
-    return 0;
-}
-
-/* ---------------- Graphics state ---------------- */
-
-/* setoverprint */
-void
-gs_setoverprint(gs_state * pgs, bool ovp)
-{
-    pgs->overprint = ovp;
-}
-
-/* currentoverprint */
-bool
-gs_currentoverprint(const gs_state * pgs)
-{
-    return pgs->overprint;
-}
-
-/* setoverprintmode */
-int
-gs_setoverprintmode(gs_state * pgs, int mode)
-{
-    if (mode < 0 || mode > 1)
-	return_error(gs_error_rangecheck);
-    pgs->overprint_mode = mode;
+	pcspace->params.separation.map->tint_transform ==
+	  map_devn_using_function)
+	return pcspace->params.separation.map->tint_transform_data;
     return 0;
 }
 
-/* currentoverprintmode */
-int
-gs_currentoverprintmode(const gs_state * pgs)
-{
-    return pgs->overprint_mode;
-}
-
 /* ------ Internal procedures ------ */
 
 /* Initialize a Separation color. */
-
 private void
 gx_init_Separation(gs_client_color * pcc, const gs_color_space * pcs)
 {
@@ -363,56 +296,124 @@
 gx_concretize_Separation(const gs_client_color *pc, const gs_color_space *pcs,
 			 frac *pconc, const gs_imager_state *pis)
 {
-    float tint;
+    float ftemp;
     int code;
     gs_client_color cc;
     const gs_color_space *pacs =
-    (const gs_color_space *)&pcs->params.separation.alt_space;
-
-    if (pcs->params.separation.sep_type == SEP_ALL) {
-	/* "All" means setting all device components to same value. */
-	const gs_color_space *pconcs = cs_concrete_space(pacs, pis);
-	int i, n = cs_num_components(pconcs);
-	frac conc;
-	gs_client_color hack_color = *pc;
-
-	/* Invert the photometric interpretation for additive
-         * color spaces because separations are always subtractive.
-         * fixme: this code sets all colorants in the alternative
-         * color space, not the destination color space. This is
-         * wrong.
-         */
-	if(n==1 || n==3)
-	    hack_color.paint.values[0] = 1 - pc->paint.values[0];
-	/* hack: using DeviceGray's function to concretize single component color : */
-	code = gx_concretize_DeviceGray(&hack_color, pacs, &conc, pis);
+	(const gs_color_space *)&pcs->params.separation.alt_space;
+    
+    if (pcs->params.separation.sep_type == SEP_OTHER &&
+        pcs->params.separation.use_alt_cspace) {
+        gs_device_n_map *map = pcs->params.separation.map;
 
-	for (i = 0; i < n; i++)
-	    pconc[i] = conc;
+	/* Check the 1-element cache first. */
+	if (map->cache_valid && map->tint[0] == pc->paint.values[0]) {
+	    int i, num_out = gs_color_space_num_components(pacs);
 
-	return code;
+	    for (i = 0; i < num_out; ++i)
+		pconc[i] = map->conc[i];
+	    return 0;
+	}
+        code = (*pcs->params.separation.map->tint_transform)
+	    (pc->paint.values, &cc.paint.values[0],
+	     pis, pcs->params.separation.map->tint_transform_data);
+        if (code < 0)
+	    return code;
+	return cs_concretize_color(&cc, pacs, pconc, pis);
     }
-
-    tint = pc->paint.values[0];
-    if (tint < 0)
-	tint = 0;
-    else if (tint > 1)
-	tint = 1;
-    /* We always map into the alternate color space. */
-    code = (*pcs->params.separation.map->proc.tint_transform) (&pcs->params.separation, tint, &cc.paint.values[0]);
-    if (code < 0)
-	return code;
-    return (*pacs->type->concretize_color) (&cc, pacs, pconc, pis);
+    else {
+    	pconc[0] = unit_frac(pc->paint.values[0], ftemp);
+    }
+    return 0;
 }
 
 private int
-gx_remap_concrete_Separation(const frac * pconc,
+gx_remap_concrete_Separation(const frac * pconc,  const gs_color_space * pcs,
 	gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
 			     gs_color_select_t select)
-{				/* We don't support concrete Separation colors yet. */
-    return_error(gs_error_rangecheck);
+{
+#ifdef DEBUG
+    /* 
+     * Check that we are using the current color space, even though
+     * this is not required for this routine.
+     */
+    if (pcs->id != pis->cspace_id)
+	dprintf("gx_remap_concrete_Separation: color space id mismatch");
+#endif
+
+    if (pis->color_component_map.use_alt_cspace) {
+        const gs_color_space *pacs =
+	    (const gs_color_space *)&pcs->params.separation.alt_space;
+
+	return (*pacs->type->remap_concrete_color)
+				(pconc, pacs, pdc, pis, dev, select);
+    }
+    else {
+        gx_remap_concrete_separation(pconc[0], pdc, pis, dev, select);
+        return 0;
+    }
 }
 
+/*
+ * Check that the color component name for a Separation color space
+ * matches the device colorant names.  Also build a gs_devicen_color_map
+ * structure.
+ */
+private int
+check_Separation_component_name(const gs_color_space * pcs, gs_state * pgs)
+{
+    const gs_separation_name name = pcs->params.separation.sep_name;
+    int colorant_number;
+    byte * pname;
+    uint name_size;
+    gs_devicen_color_map * pcolor_component_map
+	= &pgs->color_component_map;
+    const gx_device * dev = pgs->device;
+
+    pcolor_component_map->num_components = 1;
+    pcolor_component_map->num_colorants = dev->color_info.num_components;
+    pcolor_component_map->sep_type = pcs->params.separation.sep_type;
+    /*
+     * If this is a None or All separation then we do not need to
+     * use the alternate color space.
+     */
+    if (pcs->params.separation.sep_type != SEP_OTHER) {
+	pcolor_component_map->use_alt_cspace = false;
+	return 0;
+    }
+    /*
+     * Always use the alternate color space if the current device is
+     * using an additive color model.  Separations are only for use
+     * with a subtractive color model.
+     */
+    if (dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE) {
+	pcolor_component_map->use_alt_cspace = true;
+	return 0;
+    }
+    /*
+     * Get the character string and length for the component name.
+     */
+    pgs->client_procs.get_colorname_string(name, &pname, &name_size);
+    /*
+     * Compare the colorant name to the device's.  If the device's
+     * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
+     * colorant is in the SeparationNames list but not in the
+     * SeparationOrder list.
+     */
+    colorant_number = (*dev_proc(dev, get_color_comp_index))
+				    (dev, (const char *)pname, name_size, 0);
+    if (colorant_number >= 0) {		/* If valid colorant name */
+	pcolor_component_map->color_map[0] =
+		    (colorant_number == GX_DEVICE_COLOR_MAX_COMPONENTS) ? -1
+		    					   : colorant_number;
+	pcolor_component_map->use_alt_cspace = false;
+    }
+    else
+	pcolor_component_map->use_alt_cspace = true;
+    return 0;
+}
+
+
 /* ---------------- Notes on real Separation colors ---------------- */
 
 typedef ulong gs_separation;	/* BOGUS */
@@ -428,6 +429,10 @@
     gx_color_value tint)
 
 /*
+ * This next comment is outdated since the Separation color space no longer
+ * has the multi element cache (lookup table) however the remainder is
+ * still appropriate.
+ *
  * In principle, setting a Separation color space, or setting the device
  * when the current color space is a Separation space, calls the
  * lookup_separation device procedure to obtain the separation ID and
@@ -440,9 +445,4 @@
  * turning it into a macro, and gx_remap_DeviceXXX, by calling the
  * cmap_proc procedure directly).  Some care will be required for the
  * implicit temporary resetting of the color space in [color]image.
- *
- * For actual remapping of Separation colors, we need cmap_separation_direct
- * and cmap_separation_halftoned, just as for the other device color spaces.
- * So we need to break apart gx_render_gray in gxdither.c so it can also
- * do the job for separations.
  */

Index: gscsepr.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gscsepr.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gscsepr.h	16 Jun 2002 08:45:42 -0000	1.7
+++ gscsepr.h	22 Aug 2002 07:12:29 -0000	1.8
@@ -22,66 +22,57 @@
 
 #include "gscspace.h"
 
-/* Graphics state */
-bool gs_currentoverprint(const gs_state *);
-void gs_setoverprint(gs_state *, bool);
-/* Overprint mode is a PDF feature, but we include it here. */
-int gs_currentoverprintmode(const gs_state *);
-int gs_setoverprintmode(gs_state *, int);
 
 /*
  * Separation color spaces.
  *
- * The API for creating Separation color space objects exposes the fact that
- * they normally cache the results of sampling the tint_transform procedure,
- * and use the cache to convert colors when necessary.  When a language
- * interpreter sets up a Separation space, it may either provide a
- * tint_tranform procedure that will be called each time (specifying the
- * cache size as 0), or it may fill in the cache directly and provide a
- * dummy procedure.
+ * With the implementation of full DeviceN support, the API for creating
+ * A Separation color space object has changed.  Separation color spaces
+ * are treated as a single component version of a DeviceN color space.
+ * The /All separation and the /None separation are the only exceptions.
+ * The /All separation and the /None separation is each treated as its own
+ * case and thus forms the majority of the remaining Separation color space
+ * code.
  *
- * By default, the tint transformation procedure will simple return the
- * entries in the cache. If this function is called when the cache size is
- * 0, all color components in the alternative color space will be set to 0.
+ * The earlier API which had a multi element cache has been removed.
+ * The tint transform procedure now is executed as required and must
+ * be executable without doing a call out.
  */
 extern int gs_cspace_build_Separation(
-				      gs_color_space ** ppcspace,
-				      gs_separation_name sname,
-				      const gs_color_space * palt_cspace,
-				      int cache_size,
-				      gs_memory_t * pmem
-				      );
-
-/* Get the cached value array for a Separation color space. */
-/* VMS limits procedure names to 31 characters. */
-extern float *gs_cspace_get_sepr_value_array(
-					     const gs_color_space * pcspace
-					     );
-/* BACKWARD COMPATIBILITY */
-#define gs_cspace_get_separation_value_array gs_cspace_get_sepr_value_array
-
-/* Set the tint transformation procedure for a Separation color space. */
-/* VMS limits procedure names to 31 characters, and some systems only */
-/* compare the first 23 characters. */
-extern int gs_cspace_set_sepr_proc(
-				   gs_color_space * pcspace,
-				   int (*proc)(const gs_separation_params *,
-					       floatp,
-					       float *
-					       )
-				   );
-/* BACKWARD COMPATIBILITY */
-#define gs_cspace_set_tint_xform_proc gs_cspace_set_sepr_proc
-#define gs_cspace_set_tint_transform_proc gs_cspace_set_tint_xform_proc
+					 gs_color_space ** ppcspace,
+					 gs_separation_name sname,
+					 const gs_color_space * palt_cspace,
+					 int cache_size,
+					 gs_memory_t * pmem
+					 );
+/*
+ * This routine builds the central part of the Separation color space.
+ * It does not allocate a structure for the color space or initialize it.
+ */
+extern int gs_build_Separation(
+				  gs_color_space * pcspace,
+				  const gs_color_space * palt_cspace,
+				  gs_memory_t * pmem
+				  );
 
 /* Set the Separation tint transformation procedure to a Function. */
 #ifndef gs_function_DEFINED
 typedef struct gs_function_s gs_function_t;
 #  define gs_function_DEFINED
 #endif
+int gs_cspace_set_sepr_proc(gs_color_space * pcspace,
+			int (*proc)(const float *,
+				    float *,
+				    const gs_imager_state *,
+				    void *
+				    ),
+			void *proc_data
+			);
+/*
+ * Set the Separation tint transformation procedure to a Function.
+ */
 int gs_cspace_set_sepr_function(const gs_color_space *pcspace,
-				gs_function_t *pfn);
-
+				    gs_function_t *pfn);
 /*
  * If the Separation tint transformation procedure is a Function,
  * return the function object, otherwise return 0.

Index: gscspace.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gscspace.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gscspace.c	21 Feb 2002 22:24:52 -0000	1.6
+++ gscspace.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -25,6 +25,10 @@
 #include "gxcmap.h"
 #include "gxcspace.h"
 #include "gxistate.h"
+#include "gsovrc.h"
+#include "gsstate.h"
+#include "gsdevice.h"
+#include "gxdevcli.h"
 
 /*
  * Define the standard color space types.  We include DeviceCMYK in the base
@@ -35,31 +39,37 @@
 private const gs_color_space_type gs_color_space_type_DeviceGray = {
     gs_color_space_index_DeviceGray, true, true,
     &st_base_color_space, gx_num_components_1,
-    gx_no_base_space, gx_cspace_is_equal,
+    gx_no_base_space,
     gx_init_paint_1, gx_restrict01_paint_1,
     gx_same_concrete_space,
     gx_concretize_DeviceGray, gx_remap_concrete_DGray,
     gx_remap_DeviceGray, gx_no_install_cspace,
+    gx_spot_colors_set_overprint,
     gx_no_adjust_cspace_count, gx_no_adjust_color_count
 };
 private const gs_color_space_type gs_color_space_type_DeviceRGB = {
     gs_color_space_index_DeviceRGB, true, true,
     &st_base_color_space, gx_num_components_3,
-    gx_no_base_space, gx_cspace_is_equal,
+    gx_no_base_space,
     gx_init_paint_3, gx_restrict01_paint_3,
     gx_same_concrete_space,
     gx_concretize_DeviceRGB, gx_remap_concrete_DRGB,
     gx_remap_DeviceRGB, gx_no_install_cspace,
+    gx_spot_colors_set_overprint,
     gx_no_adjust_cspace_count, gx_no_adjust_color_count
 };
+
+private cs_proc_set_overprint(gx_set_overprint_DeviceCMYK);
+
 private const gs_color_space_type gs_color_space_type_DeviceCMYK = {
     gs_color_space_index_DeviceCMYK, true, true,
     &st_base_color_space, gx_num_components_4,
-    gx_no_base_space, gx_cspace_is_equal,
+    gx_no_base_space,
     gx_init_paint_4, gx_restrict01_paint_4,
     gx_same_concrete_space,
     gx_concretize_DeviceCMYK, gx_remap_concrete_DCMYK,
     gx_remap_DeviceCMYK, gx_no_install_cspace,
+    gx_set_overprint_DeviceCMYK,
     gx_no_adjust_cspace_count, gx_no_adjust_color_count
 };
 
@@ -67,22 +77,6 @@
 public_st_color_space();
 public_st_base_color_space();
 
-/* Return the shared instances of the color spaces. */
-const gs_color_space *
-gs_cspace_DeviceGray(const gs_imager_state * pis)
-{
-    return pis->shared->device_color_spaces.named.Gray;
-}
-const gs_color_space *
-gs_cspace_DeviceRGB(const gs_imager_state * pis)
-{
-    return pis->shared->device_color_spaces.named.RGB;
-}
-const gs_color_space *
-gs_cspace_DeviceCMYK(const gs_imager_state * pis)
-{
-    return pis->shared->device_color_spaces.named.CMYK;
-}
 
 /* ------ Create/copy/destroy ------ */
 
@@ -106,7 +100,8 @@
 
     if (pcspace == 0)
 	return_error(gs_error_VMerror);
-    gs_cspace_init(pcspace, pcstype, mem);
+    if (pcstype != 0)
+        gs_cspace_init(pcspace, pcstype, mem);
     *ppcspace = pcspace;
     return 0;
 }
@@ -114,37 +109,70 @@
 int
 gs_cspace_init_DeviceGray(gs_color_space *pcs)
 {
-    gs_cspace_init(pcs, &gs_color_space_type_DeviceGray, NULL);
+    /* parameterless color space; no re-entrancy problems */
+    static gs_color_space  dev_gray_proto;
+
+    if (dev_gray_proto.id == 0)
+        gs_cspace_init( &dev_gray_proto,
+                        &gs_color_space_type_DeviceGray,
+                        NULL );
+    *pcs = dev_gray_proto;
     return 0;
 }
 int
 gs_cspace_build_DeviceGray(gs_color_space ** ppcspace, gs_memory_t * pmem)
 {
-    return gs_cspace_alloc(ppcspace, &gs_color_space_type_DeviceGray, pmem);
+    int     code = gs_cspace_alloc(ppcspace, NULL, pmem);
+
+    if (code >= 0)
+        code = gs_cspace_init_DeviceGray(*ppcspace);
+    return code;
 }
 
 int
 gs_cspace_init_DeviceRGB(gs_color_space *pcs)
 {
-    gs_cspace_init(pcs, &gs_color_space_type_DeviceRGB, NULL);
+    /* parameterless color space; no re-entrancy problems */
+    static gs_color_space  dev_rgb_proto;
+
+    if (dev_rgb_proto.id == 0)
+        gs_cspace_init( &dev_rgb_proto,
+                        &gs_color_space_type_DeviceRGB,
+                        NULL );
+    *pcs = dev_rgb_proto;
     return 0;
 }
 int
 gs_cspace_build_DeviceRGB(gs_color_space ** ppcspace, gs_memory_t * pmem)
 {
-    return gs_cspace_alloc(ppcspace, &gs_color_space_type_DeviceRGB, pmem);
+    int     code = gs_cspace_alloc(ppcspace, NULL, pmem);
+
+    if (code >= 0)
+        code = gs_cspace_init_DeviceRGB(*ppcspace);
+    return code;
 }
 
 int
 gs_cspace_init_DeviceCMYK(gs_color_space *pcs)
 {
-    gs_cspace_init(pcs, &gs_color_space_type_DeviceCMYK, NULL);
+    /* parameterless color space; no re-entrancy problems */
+    static gs_color_space  dev_cmyk_proto;
+
+    if (dev_cmyk_proto.id == 0)
+        gs_cspace_init( &dev_cmyk_proto,
+                        &gs_color_space_type_DeviceCMYK,
+                        NULL );
+    *pcs = dev_cmyk_proto;
     return 0;
 }
 int
 gs_cspace_build_DeviceCMYK(gs_color_space ** ppcspace, gs_memory_t * pmem)
 {
-    return gs_cspace_alloc(ppcspace, &gs_color_space_type_DeviceCMYK, pmem);
+    int     code = gs_cspace_alloc(ppcspace, NULL, pmem);
+
+    if (code >= 0)
+        code = gs_cspace_init_DeviceCMYK(*ppcspace);
+    return code;
 }
 
 /*
@@ -210,14 +238,6 @@
     cs_restrict_color(pcc, pcs);
 }
 
-/* Test whether two color spaces are equal. */
-bool
-gs_color_space_equal(const gs_color_space *pcs1, const gs_color_space *pcs2)
-{
-    return ((pcs1->id == pcs2->id && pcs1->id != gs_no_id) ||
-	    (pcs1->type == pcs1->type && pcs1->type->equal(pcs1, pcs2)));
-}
-
 int
 gx_num_components_1(const gs_color_space * pcs)
 {
@@ -252,26 +272,164 @@
 
 /* ------ Other implementation procedures ------ */
 
-/* Color space equality procedure for color spaces with no parameters. */
-bool
-gx_cspace_is_equal(const gs_color_space *pcs1, const gs_color_space *pcs2)
+/* Null color space installation procedure. */
+int
+gx_no_install_cspace(const gs_color_space * pcs, gs_state * pgs)
+{
+    return 0;
+}
+
+/*
+ * Push an overprint compositor onto the current device indicating that,
+ * at most, the spot color parameters are to be preserved.
+ *
+ * This routine should be used for all Device, CIEBased, and ICCBased
+ * color spaces, except for DeviceCMKY. The latter color space requires a
+ * special verson that supports overprint mode.
+ */
+int
+gx_spot_colors_set_overprint(const gs_color_space * pcs, gs_state * pgs)
+{
+    gs_imager_state *       pis = (gs_imager_state *)pgs;
+    gs_overprint_params_t   params;
+
+    if ((params.retain_any_comps = pis->overprint)) {
+        params.retain_spot_comps = true;
+        params.retain_zeroed_comps = false;
+    }
+    return gs_state_update_overprint(pgs, &params);
+}
+
+
+private bool
+check_single_comp(int comp, frac targ_val, int ncomps, const frac * pval)
+{
+    int     i;
+
+    for (i = 0; i < ncomps; i++) {
+        if ( (i != comp && pval[i] != frac_0)  ||
+             (i == comp && pval[i] != targ_val)  )
+            return false;
+    }
+    return true;
+}
+
+private bool
+gx_is_cmyk_color_model(const gs_state * pgs)
 {
+    gx_device *                     dev = gs_currentdevice(pgs);
+    int                             ncomps = dev->color_info.num_components;
+    int                             cyan_c, magenta_c, yellow_c, black_c;
+    const gx_cm_color_map_procs *   pprocs;
+    cm_map_proc_cmyk((*map_cmyk));
+    frac                            frac_14 = frac_1 / 4;
+    frac                            out[GX_DEVICE_COLOR_MAX_COMPONENTS];
+
+    /* check for the appropriate components */
+    if ( ncomps < 4                                       ||
+         (cyan_c = dev_proc(dev, get_color_comp_index)(
+                       dev,
+                       "Cyan",
+                       sizeof("Cyan") - 1,
+                       -1 )) < 0                          ||
+         cyan_c == GX_DEVICE_COLOR_MAX_COMPONENTS         ||
+         (magenta_c = dev_proc(dev, get_color_comp_index)(
+                          dev,
+                          "Magenta",
+                          sizeof("Magenta") - 1,
+                          -1 )) < 0                       ||
+         magenta_c == GX_DEVICE_COLOR_MAX_COMPONENTS      ||
+         (yellow_c = dev_proc(dev, get_color_comp_index)(
+                        dev,
+                        "Yellow",
+                        sizeof("Yellow") - 1,
+                        -1 )) < 0                         ||
+         yellow_c == GX_DEVICE_COLOR_MAX_COMPONENTS       ||
+         (black_c = dev_proc(dev, get_color_comp_index)(
+                        dev,
+                        "Black",
+                        sizeof("Black") - 1,
+                        -1 )) < 0                         ||
+         black_c == GX_DEVICE_COLOR_MAX_COMPONENTS          )
+        return false;
+
+    /* check the mapping */
+    if ( (pprocs = dev_proc(dev, get_color_mapping_procs)(dev)) == 0 ||
+         (map_cmyk = pprocs->map_cmyk) == 0                            )
+        return false;
+
+    map_cmyk(dev, frac_14, frac_0, frac_0, frac_0, out);
+    if (!check_single_comp(cyan_c, frac_14, ncomps, out))
+        return false;
+    map_cmyk(dev, frac_0, frac_14, frac_0, frac_0, out);
+    if (!check_single_comp(magenta_c, frac_14, ncomps, out))
+        return false;
+    map_cmyk(dev, frac_0, frac_0, frac_14, frac_0, out);
+    if (!check_single_comp(yellow_c, frac_14, ncomps, out))
+        return false;
+    map_cmyk(dev, frac_0, frac_0, frac_0, frac_14, out);
+    if (!check_single_comp(black_c, frac_14, ncomps, out))
+        return false;
+
     return true;
 }
 
-/* Color space equality procedure for cases where a real test is too hard. */
-bool
-gx_cspace_not_equal(const gs_color_space *pcs1, const gs_color_space *pcs2)
+private int
+gx_set_overprint_DeviceCMYK(const gs_color_space * pcs, gs_state * pgs)
 {
-    return false;
+    gs_imager_state *   pis = (gs_imager_state *)pgs;
+
+    /* check if we require special handling */
+    if ( !pis->overprint             ||
+         pis->overprint_mode != 1    ||
+         !gx_is_cmyk_color_model(pgs)  )
+        return gx_spot_colors_set_overprint(pcs, pgs);
+    else {
+        gs_overprint_params_t   params;
+
+        /* we known everything is true */
+        params.retain_any_comps = true;
+        params.retain_spot_comps = true;
+        params.retain_zeroed_comps = true;
+        return gs_state_update_overprint(pgs, &params);
+    }
 }
 
-/* Null color space installation procedure. */
+
+/*
+ * Push the overprint compositor appropriate for the current color map
+ * onto the current device. This procedure is used for Separation and
+ * DeviceN color spaces that are supported in native mode (and, for
+ * Separation, do not involve component "All" or "None").
+ */
 int
-gx_no_install_cspace(const gs_color_space * pcs, gs_state * pgs)
+gx_comp_map_set_overprint(const gs_color_space * pcs, gs_state * pgs)
 {
-    return 0;
+    gs_imager_state *       pis = (gs_imager_state *)pgs;
+    gs_devicen_color_map *  pcmap = &pis->color_component_map;
+    gs_overprint_params_t   params;
+
+    params.retain_any_comps = pis->overprint && pcmap->sep_type != SEP_ALL;
+    if (params.retain_any_comps) {
+        params.retain_zeroed_comps = false;
+        if (!(params.retain_spot_comps = pcmap->use_alt_cspace)) {
+            gs_overprint_clear_all_drawn_comps(&params);
+            if (pcmap->sep_type != SEP_NONE) {
+                int     i, ncomps = pcmap->num_components;
+
+                for (i = 0; i < ncomps; i++) {
+                    int     mcomp = pis->color_component_map.color_map[i];
+
+                    if (mcomp >= 0)
+                        gs_overprint_set_drawn_comp(&params, mcomp);
+                }
+            }
+        }
+    }
+
+    return gs_state_update_overprint(pgs, &params);
 }
+
 
 /* Null reference count adjustment procedure. */
 void

Index: gscspace.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gscspace.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- gscspace.h	16 Jun 2002 08:45:42 -0000	1.11
+++ gscspace.h	22 Aug 2002 07:12:29 -0000	1.12
@@ -21,6 +21,7 @@
 #  define gscspace_INCLUDED
 
 #include "gsmemory.h"
+#include "gsiparam.h"
 
 /*
  * The handling of color spaces in the graphic library is somewhat
@@ -267,28 +268,27 @@
 
 #define gs_base_color_space_size sizeof(gs_base_color_space)
 
+#ifndef gs_device_n_map_DEFINED
+#  define gs_device_n_map_DEFINED
+typedef struct gs_device_n_map_s gs_device_n_map;
+#endif
 
 /*
  * Non-base direct color spaces: Separation and DeviceN.
  * These include a base alternative color space.
  */
 typedef ulong gs_separation_name;	/* BOGUS */
-typedef struct gs_indexed_map_s gs_indexed_map;
 
 typedef enum { SEP_NONE, SEP_ALL, SEP_OTHER } separation_type;
 
 typedef struct gs_separation_params_s {
-    gs_separation_name sname;
+    gs_separation_name sep_name;
     gs_base_color_space alt_space;
-    gs_indexed_map *map;
+    gs_device_n_map *map;
     separation_type sep_type;
+    bool use_alt_cspace;
 } gs_separation_params;
 
-#ifndef gs_device_n_map_DEFINED
-#  define gs_device_n_map_DEFINED
-typedef struct gs_device_n_map_s gs_device_n_map;
-#endif
-
 /*
  * Define callback function for graphics library to ask
  * interpreter about character string representation of
@@ -304,6 +304,7 @@
     uint num_components;
     gs_base_color_space alt_space;
     gs_device_n_map *map;
+    bool use_alt_cspace;
     gs_callback_func_get_colorname_string *get_colorname_string;
 } gs_device_n_params;
 
@@ -326,6 +327,8 @@
  * in PostScript).
  */
 
+typedef struct gs_indexed_map_s gs_indexed_map;
+
 typedef struct gs_indexed_params_s {
     gs_direct_color_space base_space;
     int hival;			/* num_entries - 1 */
@@ -424,27 +427,13 @@
 extern int
     gs_cspace_init_DeviceGray(gs_color_space *pcs),
     gs_cspace_build_DeviceGray(gs_color_space ** ppcspace,
-			       gs_memory_t * pmem),
+				  gs_memory_t * pmem),
     gs_cspace_init_DeviceRGB(gs_color_space *pcs),
     gs_cspace_build_DeviceRGB(gs_color_space ** ppcspace,
-			      gs_memory_t * pmem),
+                              gs_memory_t * pmem),
     gs_cspace_init_DeviceCMYK(gs_color_space *pcs),
     gs_cspace_build_DeviceCMYK(gs_color_space ** ppcspace,
-			       gs_memory_t * pmem);
-
-/*
- * We preallocate instances of the 3 device color spaces, and provide
- * procedures that return them.  Note that gs_cspace_DeviceCMYK() is
- * defined even if CMYK color support is not included in this configuration.
- */
-#ifndef gs_imager_state_DEFINED
-#  define gs_imager_state_DEFINED
-typedef struct gs_imager_state_s gs_imager_state;
-#endif
-
-const gs_color_space * gs_cspace_DeviceGray(const gs_imager_state * pis);
-const gs_color_space * gs_cspace_DeviceRGB(const gs_imager_state * pis);
-const gs_color_space * gs_cspace_DeviceCMYK(const gs_imager_state * pis);
+                               gs_memory_t * pmem);
 
 /* Copy a color space into one newly allocated by the caller. */
 void gs_cspace_init_from(gs_color_space * pcsto,

Index: gsdcolor.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsdcolor.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gsdcolor.h	16 Jun 2002 08:45:42 -0000	1.7
+++ gsdcolor.h	22 Aug 2002 07:12:29 -0000	1.8
@@ -25,12 +25,18 @@
 #include "gxbitmap.h"
 #include "gxhttile.h"
 #include "gxcindex.h"
+#include "gxwts.h"
 
 #ifndef gx_device_color_DEFINED
 #  define gx_device_color_DEFINED
 typedef struct gx_device_color_s gx_device_color;
 #endif
 
+#ifndef gx_device_saved_color_DEFINED
+#  define gx_device_saved_color_DEFINED
+typedef struct gx_device_color_saved_s  gx_device_color_saved;
+#endif
+
 #ifndef gx_device_halftone_DEFINED
 #  define gx_device_halftone_DEFINED
 typedef struct gx_device_halftone_s gx_device_halftone;
@@ -137,28 +143,10 @@
 #define _color_set_c(pdc, i, b, l)\
   ((pdc)->colors.colored.c_base[i] = (b),\
    (pdc)->colors.colored.c_level[i] = (l))
-void gx_complete_rgb_halftone(gx_device_color *pdevc,
-			      gx_device_halftone *pdht);
-/* Some special clients set the individual components separately. */
-#define color_finish_set_rgb_halftone(pdc, ht)\
-  gx_complete_rgb_halftone(pdc, ht)
-#define color_set_rgb_halftone(pdc, ht, br, lr, bg, lg, bb, lb, a)\
-  (_color_set_c(pdc, 0, br, lr),\
-   _color_set_c(pdc, 1, bg, lg),\
-   _color_set_c(pdc, 2, bb, lb),\
-   (pdc)->colors.colored.alpha = (a),\
-   color_finish_set_rgb_halftone(pdc, ht))
+
 /* Some special clients set the individual components separately. */
-void gx_complete_cmyk_halftone(gx_device_color *pdevc,
-			       gx_device_halftone *pdht);
-#define color_finish_set_cmyk_halftone(pdc, ht)\
-  gx_complete_cmyk_halftone(pdc, ht)
-#define color_set_cmyk_halftone(pdc, ht, bc, lc, bm, lm, by, ly, bk, lk)\
-   (_color_set_c(pdc, 0, bc, lc),\
-    _color_set_c(pdc, 1, bm, lm),\
-    _color_set_c(pdc, 2, by, ly),\
-    _color_set_c(pdc, 3, bk, lk),\
-    color_finish_set_cmyk_halftone(pdc, ht))
+void gx_complete_halftone(gx_device_color *pdevc, int num_comps,
+                          gx_device_halftone *pdht);
 
 /* Note that color_set_null_pattern doesn't set mask.ccolor. */
 #define color_set_null_pattern(pdc)\
@@ -293,6 +281,14 @@
 #endif
 #endif
 	} colored;
+	struct _wts {
+	    const gx_device_halftone *w_ht;
+	    wts_screen_sample_t levels[GX_DEVICE_COLOR_MAX_COMPONENTS];
+	    ushort num_components;
+
+	    /* plane_mask and base_color would be an optimization */
+	    gx_color_index plane_vector[GX_DEVICE_COLOR_MAX_COMPONENTS];
+	} wts;
 	struct _pat {
 	    gx_color_tile *p_tile;
 	} /*(colored) */ pattern;
@@ -316,6 +312,49 @@
 #define st_device_color_max_ptrs (st_client_color_max_ptrs + 2)
 
 /*
+ * For the command list, it is useful to record the most recent device
+ * color placed in a band, so as to avoid sending unnecessary
+ * information. The following structure is used for that purpose. It is
+ * created by the save_dc method, and can be utilized by the write
+ * method. It should otherwise be considered opaque, though it is
+ * guarranteed not to contain pointers to allocated memory (and thus does
+ * not interact with the GC code for containing structures).
+ *
+ * Because halftones are large and seldom changed, they are always sent
+ * as "all bands" commands. Individual device colors, by contrast, are
+ * usually written just for the bands that make use of them. The
+ * distinction between these two cases can only be handled by command
+ * list writer code itself, so this structure does not involve the
+ * halftone. If the halftone changes, however, the write method should
+ * be passed a null pointer for the saved color operand; this will
+ * ensure the the full device color information is written.
+ *
+ * Currently patterns cannot be passed through the command list, so
+ * pattern information is not included in this structure.
+ */
+
+struct gx_device_color_saved_s {
+    gx_device_color_type    type;
+    union _svc {
+        gx_color_index  pure;
+        struct _svbin {
+            gx_color_index  b_color[2];
+            int             b_index;
+        }               binary;
+        struct _svcol {
+            byte    c_base[GX_DEVICE_COLOR_MAX_COMPONENTS];
+            uint    c_level[GX_DEVICE_COLOR_MAX_COMPONENTS];
+            ushort  alpha;
+        }               colored;
+        struct _swts {
+            wts_screen_sample_t levels[GX_DEVICE_COLOR_MAX_COMPONENTS];
+        }               wts;
+    }                       colors;
+    gs_int_point            phase;
+};
+
+
+/*
  * Define the standard device color types.
  * We define them here as pointers to the real types only because a few
  * C compilers don't allow declaring externs with abstract struct types;
@@ -345,6 +384,9 @@
 #endif
 #ifndef gx_dc_type_ht_colored
 extern const gx_device_color_type_t *const gx_dc_type_ht_colored;	/* gxcht.c */
+#endif
+#ifndef gx_dc_type_ht_colored
+extern const gx_device_color_type_t *const gx_dc_type_wts;	/* gxwts.c */
 #endif
 
 #endif /* gsdcolor_INCLUDED */

Index: gsdevice.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsdevice.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- gsdevice.c	21 Feb 2002 22:24:52 -0000	1.14
+++ gsdevice.c	22 Aug 2002 07:12:29 -0000	1.15
@@ -34,6 +34,7 @@
 #include "gxdevice.h"
 #include "gxdevmem.h"
 #include "gxiodev.h"
+#include "gxcspace.h"
 
 /* Include the extern for the device list. */
 extern_gs_lib_device_list();
@@ -396,13 +397,18 @@
 int
 gs_setdevice_no_init(gs_state * pgs, gx_device * dev)
 {
+    gs_color_space *    pcs = pgs->color_space;
+
     /*
      * Just set the device, possibly changing color space but no other
      * device parameters.
      */
     rc_assign(pgs->device, dev, "gs_setdevice_no_init");
     gs_state_update_device(pgs);
-    return 0;
+    if (pgs->overprint)
+        return pcs->type->set_overprint(pcs, pgs);
+    else
+        return 0;
 }
 
 /* Initialize a just-allocated device. */

Index: gsdfilt.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsdfilt.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gsdfilt.c	21 Feb 2002 22:24:52 -0000	1.5
+++ gsdfilt.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -55,84 +55,6 @@
 gs_public_st_simple(st_gs_device_filter, gs_device_filter_t,
 		    "gs_device_filter");
 
-#ifdef DFILTER_TEST
-
-/* The test device filter installs a simple forwarding device which changes
-   the behavior of map_rgb_color to "bleach" colors. It is only here for
-   testing purposes, and isn't necessary to be compiled in production code.
-*/
-
-private gx_color_index
-gs_test_device_filter_map_rgb_color(gx_device * dev,
-				    gx_color_value r, gx_color_value g, gx_color_value b)
-{
-    gx_device_forward * const fdev = (gx_device_forward *)dev;
-    gx_device *tdev = fdev->target;
-
-    r += (gx_max_color_value - r) >> 1;
-    g += (gx_max_color_value - g) >> 1;
-    b += (gx_max_color_value - b) >> 1;
-    return dev_proc(tdev, map_rgb_color)(tdev, r, g, b);
-}
-
-private const gx_device_forward gs_test_device_filter_device =
-{std_device_std_body_open(gx_device_forward, 0,
-			  "Device filter test device", 0, 0, 1, 1),
- {NULL,		/* open_device */
-  NULL,		/* get_initial_matrix */
-  NULL,		/* sync_output */
-  NULL,		/* output_page */
-  NULL,		/* close_device */
-  gs_test_device_filter_map_rgb_color
- }
-};
-
-private int
-gs_test_device_filter_push(gs_device_filter_t *self, gs_memory_t *mem,
-			   gx_device **pdev, gx_device *target)
-{
-    gx_device_forward *fdev;
-
-    fdev = gs_alloc_struct_immovable(mem, gx_device_forward,
-				     &st_device_forward,
-				     "gs_test_device_filter_push");
-    if (fdev == 0)
-	return_error(gs_error_VMerror);
-    gx_device_init((gx_device *)fdev,
-		   (const gx_device *)&gs_test_device_filter_device, mem,
-		   false);
-    gx_device_forward_fill_in_procs(fdev);
-    gx_device_copy_params((gx_device *)fdev, target);
-    gx_device_set_target(fdev, target);
-    *pdev = (gx_device *)fdev;
-    return 0;
-}
-
-private int
-gs_test_device_filter_pop(gs_device_filter_t *self, gs_memory_t *mem,
-			  gs_state *pgs, gx_device *dev)
-{
-    gx_device_set_target((gx_device_forward *)dev, NULL);
-    gs_free_object(mem, self, "gs_test_device_filter_pop");
-    return 0;
-}
-
-int
-gs_test_device_filter(gs_device_filter_t **pdf, gs_memory_t *mem)
-{
-    gs_device_filter_t *df;
-
-    df = gs_alloc_struct(mem, gs_device_filter_t,
-			 &st_gs_device_filter, "gs_test_device_filter");
-    if (df == 0)
-	return_error(gs_error_VMerror);
-    df->push = gs_test_device_filter_push;
-    df->pop = gs_test_device_filter_pop;
-    *pdf = df;
-    return 0;
-}
-#endif
-
 int
 gs_push_device_filter(gs_memory_t *mem, gs_state *pgs, gs_device_filter_t *df)
 {
@@ -146,7 +68,7 @@
 	return_error(gs_error_VMerror);
     rc_increment(pgs->device);
     dfs->next_device = pgs->device;
-    code = df->push(df, mem, &new_dev, pgs->device);
+    code = df->push(df, mem, &new_dev, pgs, pgs->device);
     if (code < 0) {
 	return code;
 	gs_free_object(mem, dfs, "gs_push_device_filter");
@@ -163,17 +85,21 @@
 gs_pop_device_filter(gs_memory_t *mem, gs_state *pgs)
 {
     gs_device_filter_stack_t *dfs_tos = pgs->dfilter_stack;
+    gx_device *tos_device = pgs->device;
     gs_device_filter_t *df;
     int code;
 
     if (dfs_tos == NULL)
 	return_error(gs_error_rangecheck);
     df = dfs_tos->df;
-    code = df->pop(df, mem, pgs, pgs->device);
     pgs->dfilter_stack = dfs_tos->next;
+    code = df->prepop(df, mem, pgs, tos_device);
+    rc_increment(tos_device);
     gs_setdevice_no_init(pgs, dfs_tos->next_device);
     rc_decrement_only(dfs_tos->next_device, "gs_pop_device_filter");
     gs_free_object(mem, dfs_tos, "gs_pop_device_filter");
+    code = df->postpop(df, mem, pgs, tos_device);
+    rc_decrement_only(tos_device, "gs_pop_device_filter");
     return code;
 }
 

Index: gsdfilt.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsdfilt.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gsdfilt.h	21 Feb 2002 22:24:52 -0000	1.5
+++ gsdfilt.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -31,8 +31,6 @@
    chain.
 */
 
-#define DFILTER_TEST
-
 #ifndef gs_device_filter_stack_DEFINED
 #  define gs_device_filter_stack_DEFINED
 typedef struct gs_device_filter_stack_s gs_device_filter_stack_t;
@@ -42,18 +40,15 @@
 typedef struct gs_device_filter_s gs_device_filter_t;
 
 struct gs_device_filter_s {
-    int (*push)(gs_device_filter_t *self, gs_memory_t *mem,
+    int (*push)(gs_device_filter_t *self, gs_memory_t *mem, gs_state *pgs,
 		gx_device **pdev, gx_device *target);
-    int (*pop)(gs_device_filter_t *self, gs_memory_t *mem, gs_state *pgs,
-	       gx_device *dev);
+    int (*prepop)(gs_device_filter_t *self, gs_memory_t *mem, gs_state *pgs,
+		  gx_device *dev);
+    int (*postpop)(gs_device_filter_t *self, gs_memory_t *mem, gs_state *pgs,
+		   gx_device *dev);
 };
 
 extern_st(st_gs_device_filter);
-
-#ifdef DFILTER_TEST
-int gs_test_device_filter(gs_device_filter_t **pdf, gs_memory_t *mem);
-#endif
-
 
 /**
  * gs_push_device_filter: Push a device filter.

Index: gsdparam.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsdparam.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- gsdparam.c	16 Jun 2002 05:48:55 -0000	1.9
+++ gsdparam.c	22 Aug 2002 07:12:29 -0000	1.10
@@ -65,12 +65,6 @@
     return code;
 }
 
-/* Standard ProcessColorModel values. */
-static const char *const pcmsa[] =
-{
-    "", "DeviceGray", "", "DeviceRGB", "DeviceCMYK"
-};
-
 /* Get standard parameters. */
 int
 gx_default_get_params(gx_device * dev, gs_param_list * plist)
@@ -101,7 +95,7 @@
 
     param_string_from_string(dns, dev->dname);
     {
-	const char *cms = pcmsa[colors];
+	const char *cms = get_process_color_model_name(dev);
 
 	/* We might have an uninitialized device with */
 	/* color_info.num_components = 0.... */
@@ -325,8 +319,8 @@
 {
     gdev_input_media_t media;
 
-    media.PageSize[0] = media.PageSize[2] = width_points;
-    media.PageSize[1] = media.PageSize[3] = height_points;
+    media.PageSize[0] = media.PageSize[2] = (float) width_points;
+    media.PageSize[1] = media.PageSize[3] = (float) height_points;
     media.MediaColor = 0;
     media.MediaWeight = 0;
     media.MediaType = 0;
@@ -637,18 +631,26 @@
 	    break;
     }
 
-    /* Now check nominally read-only parameters. */
-    if ((code = param_check_string(plist, "OutputDevice", dev->dname, true)) < 0)
-	ecode = code;
-    if ((code = param_check_string(plist, "ProcessColorModel", pcmsa[colors], colors != 0)) < 0)
-	ecode = code;
+    /* Separation, DeviceN Color, and ProcessColorModel related parameters. */
+    {
+	const char * pcms = get_process_color_model_name(dev);
+
+	if ((code = param_check_string(plist, "ProcessColorModel", pcms, (pcms != NULL))) < 0)
+	    ecode = code;
+    }
     if ((code = param_check_int(plist, "MaxSeparations", 1, true)) < 0)
 	ecode = code;
     if ((code = param_check_bool(plist, "Separations", false, true)) < 0)
 	ecode = code;
-    BEGIN_ARRAY_PARAM(param_read_name_array, "SeparationColorNames", scna, 0, scne) {
+
+    BEGIN_ARRAY_PARAM(param_read_name_array, "SeparationColorNames", scna, scna.size, scne) {
 	break;
     } END_ARRAY_PARAM(scna, scne);
+
+
+    /* Now check nominally read-only parameters. */
+    if ((code = param_check_string(plist, "OutputDevice", dev->dname, true)) < 0)
+	ecode = code;
     if ((code = param_check_string(plist, "Name", dev->dname, true)) < 0)
 	ecode = code;
     if ((code = param_check_int(plist, "Colors", colors, true)) < 0)

Index: gsdps1.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsdps1.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gsdps1.c	21 Aug 2002 17:41:00 -0000	1.5
+++ gsdps1.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -158,7 +158,8 @@
 	 /* DeviceN todo: add wts case */) &&
 	gs_state_color_load(pgs) >= 0 &&
 	(*dev_proc(pgs->device, get_alpha_bits)) (pgs->device, go_graphics)
-	<= 1
+	<= 1 &&
+        (!pgs->overprint || !pgs->overprint_mode)
 	) {
 	uint i;
 	gs_fixed_rect clip_rect;

Index: gsht.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsht.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gsht.c	16 Jun 2002 05:48:55 -0000	1.5
+++ gsht.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -26,10 +26,25 @@
 #include "gzstate.h"
 #include "gxdevice.h"		/* for gzht.h */
 #include "gzht.h"
+#include "gswts.h"
 
 /* Forward declarations */
 void gx_set_effective_transfer(gs_state *);
 
+/*
+ * *HACK ALERT*
+ *
[...939 lines suppressed...]
-	for (i = 0; i < 4; ++i) {
-	    gx_transfer_map *pmap =
-	    pdht->components[pdht->color_indices[i]].corder.
-	    transfer;
+    if (pdht == NULL)
+	return;			/* not initialized yet */
 
-	    if (pmap != 0)
-		pis->effective_transfer.indexed[i] = pmap;
-	}
+    for (i = 0; i < pdht->num_comp; i++) {
+	pmap = pdht->components[i].corder.transfer;
+	if (pmap != NULL)
+	    pis->effective_transfer[i] = pmap;
     }
 }
+
 void
 gx_set_effective_transfer(gs_state * pgs)
 {

Index: gsht1.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsht1.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gsht1.c	16 Jun 2002 05:48:55 -0000	1.6
+++ gsht1.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -25,15 +25,8 @@
 #include "gxdevice.h"		/* for gzht.h */
 #include "gzht.h"
 
-/* Define the size of the halftone tile cache. */
-#define max_tile_bytes_LARGE 4096
-#define max_tile_bytes_SMALL 512
-#if arch_small_memory
-#  define max_tile_cache_bytes max_tile_bytes_SMALL
-#else
-#  define max_tile_cache_bytes\
-     (gs_debug_c('.') ? max_tile_bytes_SMALL : max_tile_bytes_LARGE)
-#endif
+#include "gxwts.h"
+#include "gswts.h"
 
 /* Imports from gscolor.c */
 void load_transfer_map(gs_state *, gx_transfer_map *, floatp);
@@ -47,6 +40,9 @@
 			       gs_threshold2_halftone *, gs_memory_t *);
 private int process_client_order(gx_ht_order *, gs_state *,
 				 gs_client_order_halftone *, gs_memory_t *);
+private int
+gs_sethalftone_try_wts(gs_halftone *pht, gs_state *pgs,
+		       gx_device_halftone *pdht);
 
 /* Structure types */
 public_st_halftone_component();
@@ -164,8 +160,11 @@
     if (code < 0)
 	return code;
     dev_ht.rc.memory = pht->rc.memory;
-    return gx_ht_install(pgs, pht, &dev_ht);
+    if ((code = gx_ht_install(pgs, pht, &dev_ht)) < 0)
+        gx_device_halftone_release(&dev_ht, pht->rc.memory);
+    return code;
 }
+
 /* Prepare the halftone, but don't install it. */
 int
 gs_sethalftone_prepare(gs_state * pgs, gs_halftone * pht,
@@ -175,18 +174,19 @@
     gx_ht_order_component *pocs = 0;
     int code = 0;
 
+/* #define USE_WTS */
+#ifdef USE_WTS
+    if (gs_sethalftone_try_wts(pht, pgs, pdht) == 0)
+	return 0;
+#endif
+
     switch (pht->type) {
 	case ht_type_colorscreen:
 	    {
 		gs_screen_halftone *phc =
-		pht->params.colorscreen.screens.indexed;
-		static const gs_ht_separation_name cnames[4] =
-		{
-		    gs_ht_separation_Default, gs_ht_separation_Red,
-		    gs_ht_separation_Green, gs_ht_separation_Blue
-		};
-		static const int cindex[4] =
-		{3, 0, 1, 2};
+		    pht->params.colorscreen.screens.indexed;
+		static const int cindex[4] = {3, 0, 1, 2};
+		static const char * color_names[4] = {"Gray", "Red", "Green", "Blue"};
 		int i;
 
 		pocs = gs_alloc_struct_array(mem, 4,
@@ -205,25 +205,11 @@
 		    if (code < 0)
 			break;
 		    poc->corder = senum.order;
-		    poc->cname = cnames[i];
+		    poc->comp_number = gs_color_name_component_number(pgs->device,
+		    	(char *)color_names[i], strlen(color_names[i]), pht->type);
+		    poc->cname = 0;  /* name index values are not known (or needed) */
 		    if (i == 0)	/* Gray = Default */
-			pdht->order = senum.order;
-		    else {
-			uint tile_bytes = senum.order.raster *
-			    (senum.order.num_bits / senum.order.width);
-			uint num_tiles =
-			    max_tile_cache_bytes / tile_bytes + 1;
-			gx_ht_cache *pcache =
-			    gx_ht_alloc_cache(mem, num_tiles,
-					      tile_bytes * num_tiles);
-
-			if (pcache == 0) {
-			    code = gs_note_error(gs_error_VMerror);
-			    break;
-			}
-			poc->corder.cache = pcache;
-			gx_ht_init_cache(pcache, &poc->corder);
-		    }
+			pdht->order = poc->corder;	/* Save default value */
 		}
 		if (code < 0)
 		    break;
@@ -275,9 +261,9 @@
 		    return_error(gs_error_VMerror);
 		poc_next = pocs + 1;
 		for (i = 0; i < count; i++, phc++) {
-		    gx_ht_order_component *poc;
+		    gx_ht_order_component *poc = poc_next;		    
 
-		    if (phc->cname == gs_ht_separation_Default) {
+		    if (phc->comp_number == GX_DEVICE_COLOR_MAX_COMPONENTS) {
 			if (have_Default) {
 			    /* Duplicate Default */
 			    code = gs_note_error(gs_error_rangecheck);
@@ -291,6 +277,8 @@
 			break;
 		    } else
 			poc = poc_next++;
+
+		    poc->comp_number = phc->comp_number;
 		    poc->cname = phc->cname;
 		    switch (phc->type) {
 			case ht_type_spot:
@@ -315,6 +303,7 @@
 		    }
 		    if (code < 0)
 			break;
+#if 0
 		    if (poc != pocs) {
 			gx_ht_cache *pcache =
 			gx_ht_alloc_cache(mem, 4,
@@ -329,6 +318,7 @@
 			poc->corder.cache = pcache;
 			gx_ht_init_cache(pcache, &poc->corder);
 		    }
+#endif
 		}
 		if (code < 0)
 		    break;
@@ -365,10 +355,13 @@
 
     if (proc == 0 && pmc->proc == 0)
 	return 0;
-    pmap = gs_alloc_struct(mem, gx_transfer_map, &st_transfer_map,
-			   "process_transfer");
-    if (pmap == 0)
-	return_error(gs_error_VMerror);
+    /*
+     * The transfer funtion is referenced by the order, so start the
+     * reference count at 1.
+     */
+    rc_alloc_struct_1(pmap, gx_transfer_map, &st_transfer_map, mem,
+		      return_error(gs_error_VMerror),
+		      "process_transfer");
     pmap->proc = proc;		/* 0 => use closure */
     pmap->closure = *pmc;
     pmap->id = gs_next_ids(1);
@@ -573,4 +566,120 @@
 	return code;
     return process_transfer(porder, pgs, NULL,
 			    &phcop->transfer_closure, mem);
+}
+
+private const gx_ht_order_procs_t wts_order_procs = {
+};
+
+/**
+ * gs_sethalftone_try_wts: Try creating a wts-based device halftone.
+ * @pht: Client halftone.
+ * @pdht: Device halftone to initialize.
+ *
+ * Tries initializing @pdht based on data from @pht, using WTS.
+ *
+ * Return value: 0 on success, 1 to indicate that the initialization
+ * was not done, and that the legacy initialization code path should
+ * be used.
+ **/
+private int
+gs_sethalftone_try_wts(gs_halftone *pht, gs_state *pgs,
+		       gx_device_halftone *pdht)
+{
+    gx_device *dev = pgs->device;
+
+    /* todo: we probably want to fail if AccurateScreens is false */
+
+    if (pht->type != ht_type_multiple)
+	/* Only work with Type 5 halftones. todo: we probably want
+	   to relax this. */
+	return 1;
+
+#if 0
+    if (dev->color_info.separable_and_linear != GX_CINFO_SEP_LIN &&
+	pht->params.multiple.num_comp > 1)
+	/* WTS is only enabled for separable or monochrome devices. */
+	return 1;
+#endif
+
+    /* only work with bilevel (not multilevel) devices */
+    if (dev->color_info.num_components != dev->color_info.depth)
+	return 1;
+
+    if (pht->type == ht_type_multiple) {
+	gs_halftone_component *components = pht->params.multiple.components;
+	uint num_comp = pht->params.multiple.num_comp;
+	int i;
+	gx_ht_order_component *pocs;
+	gx_ht_order_component *poc_next;
+	int code = 0;
+	bool have_Default = false;
+
+	for (i = 0; i < num_comp; i++) {
+	    if (components[i].type != ht_type_spot)
+		return 1;
+	}
+
+	pocs = gs_alloc_struct_array( pgs->memory,
+                                      num_comp,
+                                      gx_ht_order_component,
+                                      &st_ht_order_component_element,
+                                      "gs_sethalftone_try_wts" );
+	/* pocs = malloc(num_comp * sizeof(gx_ht_order_component)); */
+	poc_next = &pocs[1];
+	for (i = 0; i < num_comp; i++) {
+	    gs_halftone_component *component = &components[i];
+	    gs_spot_halftone *spot = &component->params.spot;
+	    gs_screen_halftone *h = &spot->screen;
+	    gx_wts_cell_params_t *wcp;
+	    gs_wts_screen_enum_t *wse;
+	    gs_matrix imat;
+	    gx_ht_order_component *poc;
+
+	    if (component->comp_number == GX_DEVICE_COLOR_MAX_COMPONENTS) {
+		if (have_Default) {
+		    /* Duplicate Default */
+		    code = gs_note_error(gs_error_rangecheck);
+		    break;
+		}
+		poc = pocs;
+		have_Default = true;
+	    } else if (i == num_comp - 1 && !have_Default) {
+		/* No Default */
+		code = gs_note_error(gs_error_rangecheck);
+		break;
+	    } else
+		poc = poc_next++;
+
+	    gs_deviceinitialmatrix(gs_currentdevice(pgs), &imat);
+
+	    wcp = wts_pick_cell_size(h, &imat);
+	    wse = gs_wts_screen_enum_new(wcp);
+
+	    poc->corder.wse = wse;
+	    poc->corder.wts = NULL;
+	    poc->corder.procs = &wts_order_procs;
+	    poc->corder.data_memory = NULL;
+	    poc->corder.num_levels = 0;
+	    poc->corder.num_bits = 0;
+	    poc->corder.levels = NULL;
+	    poc->corder.bit_data = NULL;
+	    poc->corder.cache = NULL;
+	    poc->corder.transfer = NULL;
+	    poc->comp_number = component->comp_number;
+	    poc->cname = component->cname;
+	    code = process_transfer( &poc->corder,
+                                     pgs,
+                                     spot->transfer,
+                                     &spot->transfer_closure,
+                                     pgs->memory );
+	    if (code < 0)
+		break;
+	}
+	/* todo: cleanup on error */
+	pdht->components = pocs;
+	pdht->num_comp = num_comp;
+	return code;
+    }
+    return 1;
 }

Index: gshtscr.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gshtscr.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- gshtscr.c	16 Jun 2002 05:48:55 -0000	1.9
+++ gshtscr.c	22 Aug 2002 07:12:29 -0000	1.10
@@ -24,6 +24,7 @@
 #include "gzstate.h"
 #include "gxdevice.h"           /* for gzht.h */
 #include "gzht.h"
+#include "gswts.h"
 
 /* Define whether to force all halftones to be strip halftones, */
 /* for debugging. */
@@ -235,7 +236,7 @@
                             gs_memory_t * mem)
 {
     gs_matrix imat;
-    ulong max_size = pgs->ht_cache->bits_size;
+    ulong max_size = max_tile_cache_bytes;
     int code;
 
     if (phsp->frequency < 0.1)
@@ -464,44 +465,47 @@
     penum->halftone.type = ht_type_screen;
     penum->halftone.params.screen = *phsp;
     penum->x = penum->y = 0;
-    penum->strip = porder->num_levels / porder->width;
-    penum->shift = porder->shift;
-    /*
-     * We want a transformation matrix that maps the parallelogram
-     * (0,0), (U,V), (U-V',V+U'), (-V',U') to the square (+/-1, +/-1).
-     * If the coefficients are [a b c d e f] and we let
-     *      u = U = M/R, v = V = N/R,
-     *      r = -V' = -N'/R', s = U' = M'/R',
-     * then we just need to solve the equations:
-     *      a*0 + c*0 + e = -1      b*0 + d*0 + f = -1
-     *      a*u + c*v + e = 1       b*u + d*v + f = 1
-     *      a*r + c*s + e = -1      b*r + d*s + f = 1
-     * This has the following solution:
-     *      Q = 2 / (M*M' + N*N')
-     *      a = Q * R * M'
-     *      b = -Q * R' * N
-     *      c = Q * R * N'
-     *      d = Q * R' * M
-     *      e = -1
-     *      f = -1
-     */
-    {
-        const int M = porder->params.M, N = porder->params.N, R = porder->params.R;
-        const int M1 = porder->params.M1, N1 = porder->params.N1, R1 = porder->params.R1;
-        double Q = 2.0 / ((long)M * M1 + (long)N * N1);
 
-        penum->mat.xx = Q * (R * M1);
-        penum->mat.xy = Q * (-R1 * N);
-        penum->mat.yx = Q * (R * N1);
-        penum->mat.yy = Q * (R1 * M);
-        penum->mat.tx = -1.0;
-        penum->mat.ty = -1.0;
-        gs_matrix_invert(&penum->mat, &penum->mat_inv);
+    if (porder->wse == NULL) {
+	penum->strip = porder->num_levels / porder->width;
+	penum->shift = porder->shift;
+	/*
+	 * We want a transformation matrix that maps the parallelogram
+	 * (0,0), (U,V), (U-V',V+U'), (-V',U') to the square (+/-1, +/-1).
+	 * If the coefficients are [a b c d e f] and we let
+	 *      u = U = M/R, v = V = N/R,
+	 *      r = -V' = -N'/R', s = U' = M'/R',
+	 * then we just need to solve the equations:
+	 *      a*0 + c*0 + e = -1      b*0 + d*0 + f = -1
+	 *      a*u + c*v + e = 1       b*u + d*v + f = 1
+	 *      a*r + c*s + e = -1      b*r + d*s + f = 1
+	 * This has the following solution:
+	 *      Q = 2 / (M*M' + N*N')
+	 *      a = Q * R * M'
+	 *      b = -Q * R' * N
+	 *      c = Q * R * N'
+	 *      d = Q * R' * M
+	 *      e = -1
+	 *      f = -1
+	 */
+	{
+	    const int M = porder->params.M, N = porder->params.N, R = porder->params.R;
+	    const int M1 = porder->params.M1, N1 = porder->params.N1, R1 = porder->params.R1;
+	    double Q = 2.0 / ((long)M * M1 + (long)N * N1);
+
+	    penum->mat.xx = Q * (R * M1);
+	    penum->mat.xy = Q * (-R1 * N);
+	    penum->mat.yx = Q * (R * N1);
+	    penum->mat.yy = Q * (R1 * M);
+	    penum->mat.tx = -1.0;
+	    penum->mat.ty = -1.0;
+	    gs_matrix_invert(&penum->mat, &penum->mat_inv);
+	}
+	if_debug7('h', "[h]Screen: (%dx%d)/%d [%f %f %f %f]\n",
+		  porder->width, porder->height, porder->params.R,
+		  penum->mat.xx, penum->mat.xy,
+		  penum->mat.yx, penum->mat.yy);
     }
-    if_debug7('h', "[h]Screen: (%dx%d)/%d [%f %f %f %f]\n",
-              porder->width, porder->height, porder->params.R,
-              penum->mat.xx, penum->mat.xy,
-              penum->mat.yx, penum->mat.yy);
     return 0;
 }
 
@@ -514,6 +518,15 @@
     double sx, sy; /* spot center in spot coords (integers) */
     gs_point spot_center; /* device coords */
 
+    if (penum->order.wse) {
+	int code;
+	code = gs_wts_screen_enum_currentpoint(penum->order.wse, ppt);
+	if (code > 0) {
+	    wts_sort_blue(penum->order.wse);
+	}
+	return code;
+    }
+
     if (penum->y >= penum->strip) {     /* all done */
         gx_ht_construct_spot_order(&penum->order);
         return 1;
@@ -558,26 +571,30 @@
 int
 gs_screen_next(gs_screen_enum * penum, floatp value)
 {
-    ht_sample_t sample;
-    int width = penum->order.width;
-    gx_ht_bit *bits = (gx_ht_bit *)penum->order.bit_data;
+    if (penum->order.wse) {
+	return gs_wts_screen_enum_next (penum->order.wse, value);
+    } else {
+	ht_sample_t sample;
+	int width = penum->order.width;
+	gx_ht_bit *bits = (gx_ht_bit *)penum->order.bit_data;
 
-    if (value < -1.0 || value > 1.0)
-        return_error(gs_error_rangecheck);
-    sample = (ht_sample_t) ((value + 1) * max_ht_sample);
+	if (value < -1.0 || value > 1.0)
+	    return_error(gs_error_rangecheck);
+	sample = (ht_sample_t) ((value + 1) * max_ht_sample);
 #ifdef DEBUG
-    if (gs_debug_c('H')) {
-        gs_point pt;
+	if (gs_debug_c('H')) {
+	    gs_point pt;
 
-        gs_screen_currentpoint(penum, &pt);
-        dlprintf6("[H]sample x=%d y=%d (%f,%f): %f -> %u\n",
-                  penum->x, penum->y, pt.x, pt.y, value, sample);
-    }
+	    gs_screen_currentpoint(penum, &pt);
+	    dlprintf6("[H]sample x=%d y=%d (%f,%f): %f -> %u\n",
+		      penum->x, penum->y, pt.x, pt.y, value, sample);
+	}
 #endif
-    bits[penum->y * width + penum->x].mask = sample;
-    if (++(penum->x) >= width)
-        penum->x = 0, ++(penum->y);
-    return 0;
+	bits[penum->y * width + penum->x].mask = sample;
+	if (++(penum->x) >= width)
+	    penum->x = 0, ++(penum->y);
+	return 0;
+    }
 }
 
 /* Install a fully constructed screen in the gstate. */
@@ -585,9 +602,12 @@
 gs_screen_install(gs_screen_enum * penum)
 {
     gx_device_halftone dev_ht;
+    int code;
 
     dev_ht.rc.memory = penum->halftone.rc.memory;
     dev_ht.order = penum->order;
     dev_ht.components = 0;
-    return gx_ht_install(penum->pgs, &penum->halftone, &dev_ht);
+    if ((code = gx_ht_install(penum->pgs, &penum->halftone, &dev_ht)) < 0)
+        gx_device_halftone_release(&dev_ht, dev_ht.rc.memory);
+    return code;
 }

Index: gshtx.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gshtx.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gshtx.c	21 Feb 2002 22:24:52 -0000	1.4
+++ gshtx.c	22 Aug 2002 07:12:29 -0000	1.5
@@ -101,7 +101,8 @@
     pht->params.ht_multiple.num_comp = num_comps;
 
     for (i = 0; i < num_comps; i++) {
-	phtc[i].cname = gs_ht_separation_Default;
+        phtc[i].comp_number = i;
+	phtc[i].cname = 0;
 	phtc[i].type = ht_type_none;
     }
 
@@ -117,7 +118,6 @@
 gs_ht_set_spot_comp(
 		       gs_ht * pht,
 		       int comp,
-		       gs_ht_separation_name sepname,
 		       floatp freq,
 		       floatp angle,
 		       float (*spot_func) (floatp, floatp),
@@ -133,9 +133,6 @@
     if (phtc->type != ht_type_none)
 	return_error(gs_error_invalidaccess);
 
-    phtc->cname = (pht->params.ht_multiple.num_comp == 1
-		   ? gs_ht_separation_Default
-		   : sepname);
     phtc->type = ht_type_spot;
     phtc->params.ht_spot.screen.frequency = freq;
     phtc->params.ht_spot.screen.angle = angle;
@@ -158,7 +155,6 @@
 gs_ht_set_threshold_comp(
 			    gs_ht * pht,
 			    int comp,
-			    gs_ht_separation_name sepname,
 			    int width,
 			    int height,
 			    const gs_const_string * thresholds,
@@ -173,9 +169,6 @@
     if (phtc->type != ht_type_none)
 	return_error(gs_error_invalidaccess);
 
-    phtc->cname = (pht->params.ht_multiple.num_comp == 1
-		   ? gs_ht_separation_Default
-		   : sepname);
     phtc->type = ht_type_threshold;
     phtc->params.ht_threshold.width = width;
     phtc->params.ht_threshold.height = height;
@@ -222,24 +215,16 @@
 )
 {
     int i;
-    bool have_default = false;
     int num_comps = pht->params.ht_multiple.num_comp;
 
     if (pht->type != ht_type_multiple)
 	return_error(gs_error_unregistered);
     for (i = 0; i < num_comps; i++) {
 	gs_ht_component *phtc = &(pht->params.ht_multiple.components[i]);
-
 	if ((phtc->type != ht_type_spot) && (phtc->type != ht_type_threshold))
 	    return_error(gs_error_unregistered);
-	if (phtc->cname == gs_ht_separation_Default) {
-	    if (have_default)
-		return_error(gs_error_rangecheck);
-	    else
-		have_default = true;
-	}
     }
-    return have_default ? 0 : gs_error_rangecheck;
+    return 0;
 }
 
 /*
@@ -294,7 +279,7 @@
 					     &st_ht_order_component_element,
 							   "alloc_ht_order"
     );
-    int inext = 1;
+    int inext = 0;
     int i;
 
     if (pocs == 0)
@@ -319,21 +304,13 @@
 	}
 	pmap->proc = gs_mapped_transfer;
 	pmap->id = gs_next_ids(1);
-	if (phtc->cname == gs_ht_separation_Default) {
-	    pocs->corder.levels = 0;
-	    pocs->corder.bit_data = 0;
-	    pocs->corder.cache = 0;
-	    pocs->corder.transfer = pmap;
-	    pocs->cname = gs_ht_separation_Default;
-	    comp2order[i] = 0;
-	} else {
-	    pocs[inext].corder.levels = 0;
-	    pocs[inext].corder.bit_data = 0;
-	    pocs[inext].corder.cache = 0;
-	    pocs[inext].corder.transfer = pmap;
-	    pocs[inext].cname = phtc->cname;
-	    comp2order[i] = inext++;
-	}
+	pocs[inext].corder.levels = 0;
+	pocs[inext].corder.bit_data = 0;
+	pocs[inext].corder.cache = 0;
+	pocs[inext].corder.transfer = pmap;
+	pocs[inext].cname = phtc->cname;
+        pocs[inext].comp_number = phtc->comp_number;
+	comp2order[i] = inext++;
     }
 
     return pocs;
@@ -491,7 +468,9 @@
     }
 
     /* at last, actually install the halftone in the graphic state */
-    return gx_ht_install(pgs, (gs_halftone *) pht, &dev_ht);
+    if ((code = gx_ht_install(pgs, (gs_halftone *) pht, &dev_ht)) < 0)
+        gx_device_halftone_release(&dev_ht, pmem);
+    return code;
 }
 
 /* ---------------- Mask-defined halftones ---------------- */
@@ -578,7 +557,7 @@
  */
 int
 gs_ht_set_mask_comp(gs_ht * pht,
-		    int component_index, gs_ht_separation_name sepr_name,
+		    int component_index,
 		    int width, int height, int num_levels,
 		    const byte * masks,		/* width x height x num_levels bits */
 		    gs_ht_transfer_proc transfer,
@@ -592,9 +571,6 @@
     if (phtc->type != ht_type_none)
 	return_error(gs_error_invalidaccess);
 
-    phtc->cname =
-	(pht->params.ht_multiple.num_comp == 1 ? gs_ht_separation_Default :
-	 sepr_name);
     phtc->type = ht_type_client_order;
     phtc->params.client_order.width = width;
     phtc->params.client_order.height = height;

Index: gshtx.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gshtx.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gshtx.h	16 Jun 2002 08:45:42 -0000	1.5
+++ gshtx.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -21,9 +21,9 @@
 #  define gshtx_INCLUDED
 
 #include "gsmemory.h"
-#include "gscsepnm.h"
 #include "gsht1.h"
 #include "gxtmap.h"
+#include "gscspace.h"
 
 /*
  * The stand-alone halftone structures are opaque, and are placed in an opaque
@@ -88,26 +88,24 @@
 extern int gs_ht_build(gs_ht ** ppht, uint num_comps, gs_memory_t * pmem);
 
 extern int gs_ht_set_spot_comp(
-			       gs_ht * pht,
-			       int component_index,
-			       gs_ht_separation_name sepr_name,
-			       floatp freq,
-			       floatp angle,
-			       float (*spot_func) (floatp, floatp),
-			       bool accurate,
-			       gs_ht_transfer_proc transfer,
-			       const void *client_data
+				     gs_ht * pht,
+				     int component_index,
+				     floatp freq,
+				     floatp angle,
+				     float (*spot_func) (floatp, floatp),
+				     bool accurate,
+				     gs_ht_transfer_proc transfer,
+				     const void *client_data
 			       );
 
 extern int gs_ht_set_threshold_comp(
-				    gs_ht * pht,
-				    int component_index,
-				    gs_ht_separation_name sepr_name,
-				    int width,
-				    int height,
-				    const gs_const_string * thresholds,
-				    gs_ht_transfer_proc transfer,
-				    const void *client_data
+					  gs_ht * pht,
+					  int component_index,
+					  int width,
+					  int height,
+					  const gs_const_string * thresholds,
+					  gs_ht_transfer_proc transfer,
+					  const void *client_data
 				    );
 
 /*
@@ -120,15 +118,14 @@
  * Note that the client is responsible for releasing the mask data.
  */
 extern int gs_ht_set_mask_comp(
-			       gs_ht * pht,
-			       int component_index,
-			       gs_ht_separation_name sepr_name,
-			       int width,
-			       int height,
-			       int num_levels,
-			       const byte * masks,	/* width x height x num_levels */
-			       gs_ht_transfer_proc transfer,
-			       const void *client_data
+				     gs_ht * pht,
+				     int component_index,
+				     int width,
+				     int height,
+				     int num_levels,
+				     const byte * masks,	/* width x height x num_levels */
+				     gs_ht_transfer_proc transfer,
+				     const void *client_data
 			       );
 
 extern void gs_ht_reference(gs_ht * pht);

Index: gsicc.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsicc.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gsicc.c	21 Feb 2002 22:24:52 -0000	1.7
+++ gsicc.c	22 Aug 2002 07:12:29 -0000	1.8
@@ -123,7 +123,6 @@
  */
 private cs_proc_num_components(gx_num_components_CIEICC);
 private cs_proc_base_space(gx_alt_space_CIEICC);
-private cs_proc_equal(gx_equal_CIEICC);
 private cs_proc_init_color(gx_init_CIEICC);
 private cs_proc_restrict_color(gx_restrict_CIEICC);
 private cs_proc_concrete_space(gx_concrete_space_CIEICC);
@@ -137,7 +136,6 @@
     &st_color_space_CIEICC,         /* stype - structure descriptor */
     gx_num_components_CIEICC,       /* num_components */
     gx_alt_space_CIEICC,            /* base_space */
-    gx_equal_CIEICC,                /* equal */
     gx_init_CIEICC,                 /* init_color */
     gx_restrict_CIEICC,             /* restrict_color */
     gx_concrete_space_CIEICC,       /* concrete_space */
@@ -145,6 +143,7 @@
     NULL,                           /* remap_concrete_color */
     gx_default_remap_color,         /* remap_color */
     gx_install_CIE,                 /* install_cpsace */
+    gx_spot_colors_set_overprint,   /* set_overprint */
     gx_adjust_cspace_CIEICC,        /* adjust_cspace_count */
     gx_no_adjust_color_count        /* adjust_color_count */
 };
@@ -169,58 +168,6 @@
     return (pcs->params.icc.picc_info->picc == NULL)
                 ? (const gs_color_space *)&pcs->params.icc.alt_space
                 : NULL;
-}
-
-/*
- * Return true if two ICCBased color spaces are equal. This routine is allowed
- * to return false even if the color spaces are equal (but not the converse),
- * so the following simple algorithm is used:
- *
- *   1. If one color space uses its alternative space, but the other does not,
- *      the two spaces are not the same.
- *
- *   2. If both color spaces use the alternative space, we recursively apply
- *      the question of equality to the base spaces.
- *
- *   3. If neither color space uses the alternative color space, the two
- *      spaces are considered the same only if they reference the same 
- *      data stream (which implies they must have the same number of
- *      components), and make use of the same ranges. No attempt is made to
- *      look into the stream (profile) contents.
- */
-private bool
-gx_equal_CIEICC(const gs_color_space * pcs0, const gs_color_space * pcs1)
-{
-    const gs_icc_params *   picc_params0 = &pcs0->params.icc;
-    const gs_icc_params *   picc_params1 = &pcs1->params.icc;
-    const gs_cie_icc *      picc_info0 = picc_params0->picc_info;
-    const gs_cie_icc *      picc_info1 = picc_params1->picc_info;
-
-    if (picc_info0->picc == NULL) {
-        if (picc_info1->picc != NULL)
-            return false;
-        return picc_params0->alt_space.type->equal(
-                        (const gs_color_space *)&picc_params0->alt_space,
-                        (const gs_color_space *)&picc_params1->alt_space );
-    } else if (picc_info1->picc == NULL)
-        return false;
-    else {
-        const gs_range *    pranges0 = picc_info0->Range.ranges;
-        const gs_range *    pranges1 = picc_info1->Range.ranges;
-        int                 i, ncomps = picc_info0->num_components;
-
-        if   ( picc_info0->instrp != picc_info1->instrp  ||
-               picc_info0->file_id != picc_info1->file_id  )
-            return false;
-
-        for ( i = 0;
-               i < ncomps &&
-               pranges0[i].rmin == pranges1[i].rmin &&
-               pranges0[i].rmax == pranges1[i].rmax;
-               i++ )
-            ;
-        return i == ncomps;
-    }
 }
 
 /*

Index: gsimage.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsimage.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gsimage.c	22 Jun 2002 11:16:12 -0000	1.7
+++ gsimage.c	22 Aug 2002 07:12:29 -0000	1.8
@@ -209,9 +209,19 @@
     } else {
 	if (pgs->in_cachedevice)
 	    return_error(gs_error_undefined);
-	if (image.ColorSpace == NULL)
-	    image.ColorSpace =
-		gs_cspace_DeviceGray((const gs_imager_state *)pgs);
+	if (image.ColorSpace == NULL) {
+            /* parameterless color space - no re-entrancy problems */
+            static gs_color_space cs;
+
+            /*
+             * Mutiple initialization of a DeviceGray color space is
+             * not harmful, as the space has no parameters. Use of a
+             * non-current color space is potentially incorrect, but
+             * it appears this case doesn't arise.
+             */
+            gs_cspace_init_DeviceGray(&cs);
+	    image.ColorSpace = &cs;
+        }
     }
     code = gs_image_begin_typed((const gs_image_common_t *)&image, pgs,
 				image.ImageMask | image.CombineWithColor,

Index: gsiparam.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsiparam.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gsiparam.h	16 Jun 2002 08:45:42 -0000	1.7
+++ gsiparam.h	22 Aug 2002 07:12:29 -0000	1.8
@@ -279,13 +279,6 @@
 #define gs_image_t_init_mask(pim, write_1s)\
   gs_image_t_init_mask_adjust(pim, write_1s, true)
 
-/* init_gray and init_color require a (const) imager state. */
-#define gs_image_t_init_gray(pim, pis)\
-  gs_image_t_init(pim, gs_cspace_DeviceGray(pis))
-#define gs_image_t_init_rgb(pim, pis)\
-  gs_image_t_init(pim, gs_cspace_DeviceRGB(pis))
-#define gs_image_t_init_cmyk(pim, pis)\
-  gs_image_t_init(pim, gs_cspace_DeviceCMYK(pis))
 
 /****** REMAINDER OF FILE UNDER CONSTRUCTION. PROCEED AT YOUR OWN RISK. ******/
 

Index: gsistate.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsistate.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gsistate.c	21 Feb 2002 22:24:52 -0000	1.6
+++ gsistate.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -39,9 +39,6 @@
 /* the same construct everywhere else. */
 extern /*const*/ gx_color_map_procs *const cmap_procs_default;
 
-/* Structure descriptors */
-private_st_imager_state_shared();
-
 /* GC procedures for gx_line_params */
 private
 ENUM_PTRS_WITH(line_params_enum_ptrs, gx_line_params *plp) return 0;
@@ -60,19 +57,17 @@
 private 
 ENUM_PTRS_BEGIN(imager_state_enum_ptrs)
     ENUM_SUPER(gs_imager_state, st_line_params, line_params, st_imager_state_num_ptrs - st_line_params_num_ptrs);
-    ENUM_PTR(0, gs_imager_state, shared);
-    ENUM_PTR(1, gs_imager_state, client_data);
-    ENUM_PTR(2, gs_imager_state, opacity.mask);
-    ENUM_PTR(3, gs_imager_state, shape.mask);
-    ENUM_PTR(4, gs_imager_state, transparency_stack);
-#define E1(i,elt) ENUM_PTR(i+5,gs_imager_state,elt);
+    ENUM_PTR(0, gs_imager_state, client_data);
+    ENUM_PTR(1, gs_imager_state, opacity.mask);
+    ENUM_PTR(2, gs_imager_state, shape.mask);
+    ENUM_PTR(3, gs_imager_state, transparency_stack);
+#define E1(i,elt) ENUM_PTR(i+4,gs_imager_state,elt);
     gs_cr_state_do_ptrs(E1)
 #undef E1
 ENUM_PTRS_END
 private RELOC_PTRS_BEGIN(imager_state_reloc_ptrs)
 {
     RELOC_SUPER(gs_imager_state, st_line_params, line_params);
-    RELOC_PTR(gs_imager_state, shared);
     RELOC_PTR(gs_imager_state, client_data);
     RELOC_PTR(gs_imager_state, opacity.mask);
     RELOC_PTR(gs_imager_state, shape.mask);
@@ -80,24 +75,14 @@
 #define R1(i,elt) RELOC_PTR(gs_imager_state,elt);
     gs_cr_state_do_ptrs(R1)
 #undef R1
-} RELOC_PTRS_END
-
-/* Free device color spaces. */
-void
-gx_device_color_spaces_free(gx_device_color_spaces_t *pdcs, gs_memory_t *mem,
-			    client_name_t cname)
-{
-    int i;
-
-    for (i = countof(pdcs->indexed); --i >= 0; ) {
-	gs_color_space *pcs = pdcs->indexed[i];
+    {
+        int i = GX_DEVICE_COLOR_MAX_COMPONENTS - 1;
 
-	if (pcs) {
-	    gs_cspace_release(pcs);
-	    gs_free_object(mem, pcs, cname);
-	}
+        for (; i >= 0; i--)
+            RELOC_PTR(gs_imager_state, effective_transfer[i]);
     }
-}
+} RELOC_PTRS_END
+
 
 /* Initialize an imager state, other than the parts covered by */
 /* gs_imager_state_initial. */
@@ -106,44 +91,13 @@
 {
     return gray;
 }
-private void
-rc_free_imager_shared(gs_memory_t * mem, void *data, client_name_t cname)
-{
-    gs_imager_state_shared_t * const shared =
-	(gs_imager_state_shared_t *)data;
-
-    gx_device_color_spaces_free(&shared->device_color_spaces, mem,
-				"shared device color space");
-    rc_free_struct_only(mem, data, cname);
-}
 
 int
 gs_imager_state_initialize(gs_imager_state * pis, gs_memory_t * mem)
 {
+    int i;
     pis->memory = mem;
     pis->client_data = 0;
-    /* Preallocate color spaces. */
-    {
-	int code;
-	gs_imager_state_shared_t *shared;
-
-	rc_alloc_struct_1(shared, gs_imager_state_shared_t,
-			  &st_imager_state_shared, mem,
-			  return_error(gs_error_VMerror),
-			  "gs_imager_state_init(shared)");
-	shared->device_color_spaces.named.Gray =
-	    shared->device_color_spaces.named.RGB =
-	    shared->device_color_spaces.named.CMYK = 0; /* in case we bail out */
-	shared->rc.free = rc_free_imager_shared;
-	if ((code = gs_cspace_build_DeviceGray(&shared->device_color_spaces.named.Gray, mem)) < 0 ||
-	    (code = gs_cspace_build_DeviceRGB(&shared->device_color_spaces.named.RGB, mem)) < 0 ||
-	    (code = gs_cspace_build_DeviceCMYK(&shared->device_color_spaces.named.CMYK, mem)) < 0
-	    ) {
-	    rc_free_imager_shared(mem, shared, "gs_imager_state_init(shared)");
-	    return code;
-	}
-	pis->shared = shared;
-    }
     pis->opacity.mask = 0;
     pis->shape.mask = 0;
     pis->transparency_stack = 0;
@@ -156,26 +110,25 @@
 	    pis->screen_phase[i].x = pis->screen_phase[i].y = 0;
     }
     pis->dev_ht = 0;
-    pis->ht_cache = 0;
     pis->cie_render = 0;
     pis->black_generation = 0;
     pis->undercolor_removal = 0;
     /* Allocate an initial transfer map. */
-    rc_alloc_struct_n(pis->set_transfer.colored.gray,
+    rc_alloc_struct_n(pis->set_transfer.gray,
 		      gx_transfer_map, &st_transfer_map,
 		      mem, return_error(gs_error_VMerror),
-		      "gs_imager_state_init(transfer)", 4);
-    pis->set_transfer.colored.gray->proc = imager_null_transfer;
-    pis->set_transfer.colored.gray->id = gs_next_ids(1);
-    pis->set_transfer.colored.gray->values[0] = frac_0;
-    pis->set_transfer.colored.red =
-	pis->set_transfer.colored.green =
-	pis->set_transfer.colored.blue =
-	pis->set_transfer.colored.gray;
-    pis->effective_transfer = pis->set_transfer;
-    pis->cie_joint_caches = 0;
+		      "gs_imager_state_init(transfer)", 1);
+    pis->set_transfer.gray->proc = imager_null_transfer;
+    pis->set_transfer.gray->id = gs_next_ids(1);
+    pis->set_transfer.gray->values[0] = frac_0;
+    pis->set_transfer.red =
+	pis->set_transfer.green =
+	pis->set_transfer.blue = NULL; 
+    for (i = 0; i < GX_DEVICE_COLOR_MAX_COMPONENTS; i++)
+	pis->effective_transfer[i] = pis->set_transfer.gray;
+    pis->cie_joint_caches = NULL;
     pis->cmap_procs = cmap_procs_default;
-    pis->pattern_cache = 0;
+    pis->pattern_cache = NULL;
     return 0;
 }
 
@@ -202,7 +155,6 @@
 void
 gs_imager_state_copied(gs_imager_state * pis)
 {
-    rc_increment(pis->shared);
     rc_increment(pis->opacity.mask);
     rc_increment(pis->shape.mask);
     rc_increment(pis->halftone);
@@ -210,10 +162,10 @@
     rc_increment(pis->cie_render);
     rc_increment(pis->black_generation);
     rc_increment(pis->undercolor_removal);
-    rc_increment(pis->set_transfer.colored.gray);
-    rc_increment(pis->set_transfer.colored.red);
-    rc_increment(pis->set_transfer.colored.green);
-    rc_increment(pis->set_transfer.colored.blue);
+    rc_increment(pis->set_transfer.gray);
+    rc_increment(pis->set_transfer.red);
+    rc_increment(pis->set_transfer.green);
+    rc_increment(pis->set_transfer.blue);
     rc_increment(pis->cie_joint_caches);
 }
 
@@ -227,10 +179,10 @@
     rc_pre_assign(pto->element, pfrom->element, cname)
 
     RCCOPY(cie_joint_caches);
-    RCCOPY(set_transfer.colored.blue);
-    RCCOPY(set_transfer.colored.green);
-    RCCOPY(set_transfer.colored.red);
-    RCCOPY(set_transfer.colored.gray);
+    RCCOPY(set_transfer.blue);
+    RCCOPY(set_transfer.green);
+    RCCOPY(set_transfer.red);
+    RCCOPY(set_transfer.gray);
     RCCOPY(undercolor_removal);
     RCCOPY(black_generation);
     RCCOPY(cie_render);
@@ -238,7 +190,6 @@
     RCCOPY(halftone);
     RCCOPY(shape.mask);
     RCCOPY(opacity.mask);
-    RCCOPY(shared);
 #undef RCCOPY
 }
 
@@ -253,10 +204,10 @@
     rc_decrement(pis->element, cname)
 
     RCDECR(cie_joint_caches);
-    RCDECR(set_transfer.colored.gray);
-    RCDECR(set_transfer.colored.blue);
-    RCDECR(set_transfer.colored.green);
-    RCDECR(set_transfer.colored.red);
+    RCDECR(set_transfer.gray);
+    RCDECR(set_transfer.blue);
+    RCDECR(set_transfer.green);
+    RCDECR(set_transfer.red);
     RCDECR(undercolor_removal);
     RCDECR(black_generation);
     RCDECR(cie_render);
@@ -265,19 +216,11 @@
      * dependent structures as well.
      */
     if (pdht != 0 && pdht->rc.ref_count == 1) {
-	/* Make sure we don't leave dangling pointers in the cache. */
-	gx_ht_cache *pcache = pis->ht_cache;
-
-	if (pcache->order.bit_data == pdht->order.bit_data ||
-	    pcache->order.levels == pdht->order.levels
-	    )
-	    gx_ht_clear_cache(pcache);
 	gx_device_halftone_release(pdht, pdht->rc.memory);
     }
     RCDECR(dev_ht);
     RCDECR(halftone);
     RCDECR(shape.mask);
     RCDECR(opacity.mask);
-    RCDECR(shared);
 #undef RCDECR
 }

Index: gslib.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gslib.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- gslib.c	16 Jun 2002 05:48:55 -0000	1.10
+++ gslib.c	22 Aug 2002 07:12:29 -0000	1.11
@@ -35,7 +35,6 @@
 #include "gsmatrix.h"
 #include "gsstate.h"
 #include "gscspace.h"
-#include "gscssub.h"
 #include "gscolor2.h"
 #include "gscoord.h"
 #include "gscie.h"
@@ -546,6 +545,9 @@
 	0x88, 0xcc, 0x00, 0x44,
 	0xcc, 0x00, 0x44, 0x88
     };
+    gs_color_space gray_cs;
+
+    gs_cspace_init_DeviceGray(&gray_cs);
 
     /*
      * Neither ImageType 3 nor 4 needs a current color,
@@ -597,8 +599,10 @@
     {
 	gs_image1_t image1;
 	void *info1;
+        gs_color_space cs;
 
-	gs_image_t_init_gray(&image1, (const gs_imager_state *)pgs);
+        gs_cspace_init_DeviceGray(&cs);
+	gs_image_t_init(&image1, &cs);
 	/* image */
 	image1.ImageMatrix.xx = W;
 	image1.ImageMatrix.yy = -H;
@@ -649,8 +653,7 @@
 	    0x66
 	};
 
-	gs_image3_t_init(&image3, gs_current_DeviceGray_space(pgs),
-			 interleave_scan_lines);
+	gs_image3_t_init(&image3, &gray_cs, interleave_scan_lines);
 	/* image */
 	image3.ImageMatrix.xx = W;
 	image3.ImageMatrix.yy = -H;
@@ -721,7 +724,7 @@
 	gs_image4_t image4;
 	const byte *data4 = data3;
 
-	gs_image4_t_init(&image4, gs_current_DeviceGray_space(pgs));
+	gs_image4_t_init(&image4, &gray_cs);
 	/* image */
 	image4.ImageMatrix.xx = W;
 	image4.ImageMatrix.yy = -H;
@@ -812,10 +815,13 @@
     };
     gx_device_cmap *cmdev;
     int code;
+    gs_color_space rgb_cs;
+
+    gs_cspace_init_DeviceRGB(&rgb_cs);
 
     gs_scale(pgs, 150.0, 150.0);
     gs_translate(pgs, 0.5, 0.5);
-    gs_setcolorspace(pgs, gs_current_DeviceRGB_space(pgs));
+    gs_setcolorspace(pgs, &rgb_cs);
     spectrum(pgs, 5);
     gs_translate(pgs, 1.2, 0.0);
     /* We must set the CRD before the color space. */
@@ -880,7 +886,7 @@
     /* Fabricate a Type 5 halftone. */
     code = gs_ht_build(&pht, 1, mem);
     dprintf1("ht build code = %d\n", code);
-    code = gs_ht_set_mask_comp(pht, 0, gs_ht_separation_Default,
+    code = gs_ht_set_mask_comp(pht, 0,
 			       4, 4, 4, masks, NULL, NULL);
     dprintf1("set mask code = %d\n", code);
     code = gs_sethalftone(pgs, pht);
@@ -925,15 +931,14 @@
     gs_const_string table;
     gs_color_space *pcs;
     gs_client_color ccolor;
+    gs_color_space rgb_cs;
+
+    gs_cspace_init_DeviceRGB(&rgb_cs);
 
     table.data =
 	(const byte *)"\377\377\377\377\000\000\000\377\000\000\000\000";
     table.size = 12;
-    gs_cspace_build_Indexed(&pcs,
-			    gs_current_DeviceRGB_space(pgs),
-			    4,
-			    &table,
-			    mem);
+    gs_cspace_build_Indexed(&pcs, &rgb_cs, 4, &table, mem);
     ptile.data = pdata;
     ptile.raster = 4;
     ptile.size.x = ptile.size.y = 16;
@@ -1083,8 +1088,16 @@
     eprintf1("putdeviceparams: code=%d\n", code);
     gs_c_param_list_release(&list);
 
+    /* note: initgraphics no longer resets the color or color space */
     gs_erasepage(pgs);
     gs_initgraphics(pgs);
+    {
+        gs_color_space cs;
+
+        gs_cspace_init_DeviceGray(&cs);
+        gs_setcolorspace(pgs, &cs);
+    }
+    
     gs_clippath(pgs);
     gs_pathbbox(pgs, &cliprect);
     eprintf4("	cliprect = [[%g,%g],[%g,%g]]\n",

Index: gspcolor.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gspcolor.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gspcolor.c	21 Feb 2002 22:24:52 -0000	1.6
+++ gspcolor.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -52,16 +52,18 @@
 private cs_proc_init_color(gx_init_Pattern);
 private cs_proc_restrict_color(gx_restrict_Pattern);
 private cs_proc_install_cspace(gx_install_Pattern);
+private cs_proc_set_overprint(gx_set_overprint_Pattern);
 private cs_proc_adjust_cspace_count(gx_adjust_cspace_Pattern);
 private cs_proc_adjust_color_count(gx_adjust_color_Pattern);
 const gs_color_space_type gs_color_space_type_Pattern = {
     gs_color_space_index_Pattern, false, false,
     &st_color_space_Pattern, gx_num_components_Pattern,
-    gx_base_space_Pattern, gx_cspace_not_equal,
+    gx_base_space_Pattern,
     gx_init_Pattern, gx_restrict_Pattern,
     gx_no_concrete_space,
     gx_no_concretize_color, NULL,
     gx_remap_Pattern, gx_install_Pattern,
+    gx_set_overprint_Pattern,
     gx_adjust_cspace_Pattern, gx_adjust_color_Pattern
 };
 
@@ -156,8 +158,6 @@
 	    *(gs_paint_color_space *) pgs->color_space;
 	cs.params.pattern.has_base_space = true;
 	*pgs->color_space = cs;
-	/* Don't change orig_base_cspace_index. */
-	pgs->orig_cspace_index = gs_color_space_index_Pattern;
 	cs_full_init_color(pgs->ccolor, &cs);
 	gx_unset_dev_color(pgs);
     }
@@ -268,6 +268,17 @@
 	return 0;
     return (*pcs->params.pattern.base_space.type->install_cspace)
 	((const gs_color_space *) & pcs->params.pattern.base_space, pgs);
+}
+
+/* Set the overprint compositor for a Pattern color space. */
+private int
+gx_set_overprint_Pattern(const gs_color_space * pcs, gs_state * pgs)
+{
+    if (pcs->params.pattern.has_base_space)
+        return pcs->params.pattern.base_space.type->set_overprint
+	    ((const gs_color_space *)&pcs->params.pattern.base_space, pgs);
+    else
+	return 0;
 }
 
 /* Adjust the reference counts for Pattern color spaces or colors. */

Index: gsptype1.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsptype1.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gsptype1.c	22 Jun 2002 11:16:12 -0000	1.7
+++ gsptype1.c	22 Aug 2002 07:12:29 -0000	1.8
@@ -383,10 +383,8 @@
     const gs_depth_bitmap *pbitmap = &(ppmap->bitmap);
     gs_image_enum *pen =
         gs_image_enum_alloc(gs_state_memory(pgs), "image_PaintProc");
-    const gs_color_space *pcspace =
-    	(ppmap->pcspace == 0 ?
-     	    gs_cspace_DeviceGray((const gs_imager_state *)pgs) :
-     	    ppmap->pcspace);
+    gs_color_space cs;
+    const gs_color_space *pcspace;
     gx_image_enum_common_t *pie;
     /*
      * If the image is transparent then we want to do image type4 processing.
@@ -409,6 +407,14 @@
 
     if (pen == 0)
 	return_error(gs_error_VMerror);
+
+    if (ppmap->pcspace == 0) {
+        gs_cspace_init_DeviceGray(&cs);
+        pcspace = &cs;
+    } else
+        pcspace = ppmap->pcspace;
+    gs_gsave(pgs);
+    gs_setcolorspace(pgs, pcspace);
     if (transparent)
         gs_image4_t_init( (gs_image4_t *) &image, pcspace);
     else
@@ -427,14 +433,18 @@
 	image.i1.Decode[0] = 1.0;
 	image.i1.Decode[1] = 0.0;
     }
-    code = gs_image_begin_typed((const gs_image_common_t *)&image, pgs,
-				false, &pie);
-    if (code < 0)
-	return code;
-    code = gs_image_enum_init(pen, pie, (gs_data_image_t *)&image, pgs);
-    if (code < 0)
-	return code;
-    return bitmap_paint(pen, (gs_data_image_t *) & image, pbitmap, pgs);
+
+    if ( (code = gs_image_begin_typed( (const gs_image_common_t *)&image,
+                                       pgs,
+		                       false,
+                                       &pie )) >= 0 &&
+         (code = gs_image_enum_init( pen,
+                                     pie,
+                                     (gs_data_image_t *)&image,
+                                     pgs )) >= 0      )
+	code = bitmap_paint(pen, (gs_data_image_t *) & image, pbitmap, pgs);
+    gs_grestore(pgs);
+    return code;
 }
 /* Finish painting any kind of bitmap pattern. */
 private int
@@ -600,19 +610,23 @@
  * 'masked_fill_rect' instead of 'masked_fill_rectangle' in order to limit
  * identifier lengths to 32 characters.
  */
+private dev_color_proc_get_dev_halftone(gx_dc_pattern_get_dev_halftone);
 private dev_color_proc_load(gx_dc_pattern_load);
 /*dev_color_proc_fill_rectangle(gx_dc_pattern_fill_rectangle); *//*gxp1fill.h */
 private dev_color_proc_equal(gx_dc_pattern_equal);
 private dev_color_proc_load(gx_dc_pure_masked_load);
 
+private dev_color_proc_get_dev_halftone(gx_dc_pure_masked_get_dev_halftone);
 /*dev_color_proc_fill_rectangle(gx_dc_pure_masked_fill_rect); *//*gxp1fill.h */
 private dev_color_proc_equal(gx_dc_pure_masked_equal);
 private dev_color_proc_load(gx_dc_binary_masked_load);
 
+private dev_color_proc_get_dev_halftone(gx_dc_binary_masked_get_dev_halftone);
 /*dev_color_proc_fill_rectangle(gx_dc_binary_masked_fill_rect); *//*gxp1fill.h */
 private dev_color_proc_equal(gx_dc_binary_masked_equal);
 private dev_color_proc_load(gx_dc_colored_masked_load);
 
+private dev_color_proc_get_dev_halftone(gx_dc_colored_masked_get_dev_halftone);
 /*dev_color_proc_fill_rectangle(gx_dc_colored_masked_fill_rect); *//*gxp1fill.h */
 private dev_color_proc_equal(gx_dc_colored_masked_equal);
 
@@ -621,8 +635,11 @@
 			dc_pattern_enum_ptrs, dc_pattern_reloc_ptrs);
 const gx_device_color_type_t gx_dc_pattern = {
     &st_dc_pattern,
+    gx_dc_pattern_save_dc, gx_dc_pattern_get_dev_halftone,
     gx_dc_pattern_load, gx_dc_pattern_fill_rectangle,
-    gx_dc_default_fill_masked, gx_dc_pattern_equal
+    gx_dc_default_fill_masked, gx_dc_pattern_equal,
+    gx_dc_pattern_write, gx_dc_pattern_read, 
+    gx_dc_pattern_get_nonzero_comps
 };
 
 extern_st(st_dc_ht_binary);
@@ -630,8 +647,11 @@
 			dc_masked_enum_ptrs, dc_masked_reloc_ptrs);
 const gx_device_color_type_t gx_dc_pure_masked = {
     &st_dc_pure_masked,
+    gx_dc_pattern_save_dc, gx_dc_pure_masked_get_dev_halftone,
     gx_dc_pure_masked_load, gx_dc_pure_masked_fill_rect,
-    gx_dc_default_fill_masked, gx_dc_pure_masked_equal
+    gx_dc_default_fill_masked, gx_dc_pure_masked_equal,
+    gx_dc_pattern_write, gx_dc_pattern_read, 
+    gx_dc_pure_get_nonzero_comps
 };
 
 gs_private_st_composite(st_dc_binary_masked, gx_device_color,
@@ -639,8 +659,11 @@
 			dc_binary_masked_reloc_ptrs);
 const gx_device_color_type_t gx_dc_binary_masked = {
     &st_dc_binary_masked,
+    gx_dc_pattern_save_dc, gx_dc_binary_masked_get_dev_halftone,
     gx_dc_binary_masked_load, gx_dc_binary_masked_fill_rect,
-    gx_dc_default_fill_masked, gx_dc_binary_masked_equal
+    gx_dc_default_fill_masked, gx_dc_binary_masked_equal,
+    gx_dc_pattern_write, gx_dc_pattern_read, 
+    gx_dc_ht_binary_get_nonzero_comps
 };
 
 gs_private_st_composite_only(st_dc_colored_masked, gx_device_color,
@@ -648,8 +671,11 @@
 			     dc_masked_enum_ptrs, dc_masked_reloc_ptrs);
 const gx_device_color_type_t gx_dc_colored_masked = {
     &st_dc_colored_masked,
+    gx_dc_pattern_save_dc, gx_dc_colored_masked_get_dev_halftone,
     gx_dc_colored_masked_load, gx_dc_colored_masked_fill_rect,
-    gx_dc_default_fill_masked, gx_dc_colored_masked_equal
+    gx_dc_default_fill_masked, gx_dc_colored_masked_equal,
+    gx_dc_pattern_write, gx_dc_pattern_read, 
+    gx_dc_ht_colored_get_nonzero_comps
 };
 
 #undef gx_dc_type_pattern
@@ -717,6 +743,55 @@
 }
 RELOC_PTRS_END
 
+
+/*
+ * Currently, patterns cannot be passed through the command list, so
+ * there is little reason to save them. We keep this as a distinct
+ * procedure for potential future enhancements.
+ */
+void
+gx_dc_pattern_save_dc(
+    const gx_device_color * pdevc, 
+    gx_device_color_saved * psdc )
+{
+    return;
+}
+
+/*
+ * Colored Type 1 patterns cannot provide a halftone, as multiple
+ * halftones may be used by the PaintProc procedure. Hence, we can only
+ * hope this is a contone device.
+ */
+private const gx_device_halftone *
+gx_dc_pattern_get_dev_halftone(const gx_device_color * pdevc)
+{
+    return 0;
+}
+
+/*
+ * Uncolored Type 1 halftones make use of the halftone impplied by their
+ * base color. Ideally this would be returned via an inhereted method,
+ * but the device color structure does not support such an arrangement.
+ */
+private const gx_device_halftone *
+gx_dc_pure_masked_get_dev_halftone(const gx_device_color * pdevc)
+{
+    return 0;
+}
+
+private const gx_device_halftone *
+gx_dc_binary_masked_get_dev_halftone(const gx_device_color * pdevc)
+{
+    return pdevc->colors.binary.b_ht;
+}
+
+private const gx_device_halftone *
+gx_dc_colored_masked_get_dev_halftone(const gx_device_color * pdevc)
+{
+    return pdevc->colors.colored.c_ht;
+}
+
+
 /* Macros for pattern loading */
 #define FINISH_PATTERN_LOAD\
 	while ( !gx_pattern_cache_lookup(pdevc, pis, dev, select) )\
@@ -817,6 +892,23 @@
 	pdevc1->phase.y == pdevc2->phase.y &&
 	pdevc1->mask.id == pdevc2->mask.id;
 }
+
+/*
+ * For shading and colored tiling patterns, it is not possible to say
+ * which color components have non-zero values. The following routine
+ * indicates this by just returning 1. The procedure is exported for
+ * the benefit of gsptype2.c.
+ */
+int
+gx_dc_pattern_get_nonzero_comps(
+    const gx_device_color * pdevc_ignored,
+    const gx_device *       dev_ignored,
+    gx_color_index *        pcomp_bits_ignored )
+{
+    return 1;
+}
+
+
 private bool
 gx_dc_pure_masked_equal(const gx_device_color * pdevc1,
 			const gx_device_color * pdevc2)
@@ -837,4 +929,29 @@
 {
     return (*gx_dc_type_ht_colored->equal) (pdevc1, pdevc2) &&
 	pdevc1->mask.id == pdevc2->mask.id;
+}
+
+/* currently, patterns cannot be passed through the command list */
+int
+gx_dc_pattern_write(
+    const gx_device_color *         pdevc,
+    const gx_device_color_saved *   psdc,
+    const gx_device *               dev,
+    byte *                          data,
+    uint *                          psize )
+{
+    return_error(gs_error_unknownerror);
+}
+
+int
+gx_dc_pattern_read(
+    gx_device_color *       pdevc,
+    const gs_imager_state * pis,
+    const gx_device_color * prior_devc,
+    const gx_device *       dev,
+    const byte *            data,
+    uint                    size,
+    gs_memory_t *           mem )
+{
+    return_error(gs_error_unknownerror);
 }

Index: gsptype2.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsptype2.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gsptype2.c	21 Feb 2002 22:24:52 -0000	1.7
+++ gsptype2.c	22 Aug 2002 07:12:29 -0000	1.8
@@ -27,6 +27,7 @@
 #include "gxpcolor.h"
 #include "gxstate.h"            /* for gs_state_memory */
 #include "gzpath.h"
+#include "gzstate.h"
 
 /* GC descriptors */
 private_st_pattern2_template();
@@ -112,6 +113,7 @@
                         dc_pattern2_enum_ptrs, dc_pattern2_reloc_ptrs,
                         st_client_color, ccolor);
 
+private dev_color_proc_get_dev_halftone(gx_dc_pattern2_get_dev_halftone);
 private dev_color_proc_load(gx_dc_pattern2_load);
 private dev_color_proc_fill_rectangle(gx_dc_pattern2_fill_rectangle);
 private dev_color_proc_equal(gx_dc_pattern2_equal);
@@ -121,8 +123,11 @@
  */
 const gx_device_color_type_t gx_dc_pattern2 = {
     &st_dc_pattern2,
+    gx_dc_pattern_save_dc, gx_dc_pattern2_get_dev_halftone,
     gx_dc_pattern2_load, gx_dc_pattern2_fill_rectangle,
-    gx_dc_default_fill_masked, gx_dc_pattern2_equal
+    gx_dc_default_fill_masked, gx_dc_pattern2_equal,
+    gx_dc_pattern_write, gx_dc_pattern_read,
+    gx_dc_pattern_get_nonzero_comps
 };
 
 /* Check device color for Pattern Type 2. */
@@ -130,6 +135,16 @@
 gx_dc_is_pattern2_color(const gx_device_color *pdevc)
 {
     return pdevc->type == &gx_dc_pattern2;
+}
+
+/*
+ * The device halftone used by a PatternType 2 patter is that current in
+ * the graphic state at the time of the makepattern call.
+ */
+private const gx_device_halftone *
+gx_dc_pattern2_get_dev_halftone(const gx_device_color * pdevc)
+{
+    return ((gs_pattern2_instance_t *)pdevc->ccolor.pattern)->saved->dev_ht;
 }
 
 /* Load a PatternType 2 color into the cache.  (No effect.) */

Index: gsshade.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsshade.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gsshade.c	21 Apr 2002 02:48:36 -0000	1.7
+++ gsshade.c	22 Aug 2002 07:12:29 -0000	1.8
@@ -62,21 +62,6 @@
 	 * However, Adobe implementations apparently don't necessarily
 	 * check this ahead of time; therefore, we do the same.
 	 */
-#if 0				/*************** */
-	{
-	    int i;
-
-	    for (i = 0; i < m; ++i) {
-		static const float dom_01[2] = { 0.0, 1.0 };
-		const float *dom = (domain != 0 ? &domain[2 * i] : dom_01);
-
-		if (function->params.Domain[2 * i] > dom[0] ||
-		    function->params.Domain[2 * i + 1] < dom[1]
-		    )
-		    return_error(gs_error_rangecheck);
-	    }
-	}
-#endif /*************** */
     }
     return 0;
 }

Index: gsstate.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsstate.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- gsstate.c	16 Jun 2002 05:48:55 -0000	1.15
+++ gsstate.c	22 Aug 2002 07:12:29 -0000	1.16
@@ -27,7 +27,6 @@
 #include "gscolor2.h"
 #include "gscoord.h"		/* for gs_initmatrix */
 #include "gscie.h"
-#include "gscssub.h"
 #include "gxclipsr.h"
 #include "gxcmap.h"
 #include "gxdevice.h"
@@ -37,6 +36,7 @@
 #include "gspath.h"
 #include "gzpath.h"
 #include "gzcpath.h"
+#include "gsovrc.h"
 
 /* Forward references */
 private gs_state *gstate_alloc(gs_memory_t *, client_name_t,
@@ -81,9 +81,6 @@
  *
  *   (3b) Objects whose lifetimes are associated with something else.
  *      Currently these are:
- *              ht_cache, which is associated with the entire gstate
- *                stack, is allocated with the very first graphics state,
- *                and currently is never freed;
  *              pattern_cache, which is associated with the entire
  *                stack, is allocated when first needed, and currently
  *                is never freed;
@@ -239,9 +236,6 @@
     rc_alloc_struct_1(pgs->halftone, gs_halftone, &st_halftone, mem,
 		      goto fail, "gs_state_alloc(halftone)");
     pgs->halftone->type = ht_type_none;
-    pgs->ht_cache = gx_ht_alloc_cache(mem,
-				      gx_ht_cache_default_tiles(),
-				      gx_ht_cache_default_bits());
 
     /* Initialize other things not covered by initgraphics */
 
@@ -256,13 +250,7 @@
     pgs->effective_clip_shared = true;
     /* Initialize things so that gx_remap_color won't crash. */
     gs_cspace_init_DeviceGray(pgs->color_space);
-    {
-	int i;
-
-	for (i = 0; i < countof(pgs->device_color_spaces.indexed); ++i)
-	    pgs->device_color_spaces.indexed[i] = 0;
-    }
-    gx_set_device_color_1(pgs);
+    gx_set_device_color_1(pgs); /* sets colorspace and client color */
     pgs->device = 0;		/* setting device adjusts refcts */
     gs_nulldevice(pgs);
     gs_setalpha(pgs, 1.0);
@@ -280,7 +268,7 @@
     pgs->level = 0;
     pgs->dfilter_stack = 0;
     pgs->transparency_group_stack = 0;
-    if (gs_initgraphics(pgs) >= 0)
+    if (gs_initgraphics(pgs) >= 0) 
 	return pgs;
     /* Something went very wrong. */
 fail:
@@ -351,8 +339,6 @@
     int code;
     gx_clip_path *old_cpath = pgs->view_clip;
     gx_clip_path *new_cpath;
-    gx_device_color_spaces_t save_spaces;
-    int i;
 
     if (old_cpath) {
 	new_cpath =
@@ -366,27 +352,6 @@
     code = gs_gsave(pgs);
     if (code < 0)
 	goto fail;
-    for (i = 0; i < countof(save_spaces.indexed); ++i) {
-	gs_color_space *pcs = pgs->device_color_spaces.indexed[i];
-
-	if (pcs) {
-	    pgs->device_color_spaces.indexed[i] = 0;
-	    code = gs_setsubstitutecolorspace(pgs, (gs_color_space_index)i,
-					      pcs);
-	    if (code < 0) {
-		/*
-		 * Patch the second saved pointer so we won't try to
-		 * gsave after the grestore.
-		 */
-		if (pgs->saved->saved == 0)
-		    pgs->saved->saved = pgs;
-		gs_grestore(pgs);
-		if (pgs->saved == pgs)
-		    pgs->saved = 0;
-		goto fail;
-	    }
-	}
-    }
     if (pgs->effective_clip_path == pgs->view_clip)
 	pgs->effective_clip_path = new_cpath;
     pgs->view_clip = new_cpath;
@@ -408,6 +373,9 @@
     void *pdata = pgs->client_data;
     void *sdata;
     gs_transparency_state_t *tstack = pgs->transparency_stack;
+    bool prior_overprint = pgs->overprint;
+    int  prior_overprint_mode = pgs->overprint_mode;
+    bool same_device = pgs->device == saved->device;
 
     if_debug2('g', "[g]grestore 0x%lx, level was %d\n",
 	      (ulong) saved, pgs->level);
@@ -427,7 +395,14 @@
     if (pgs->show_gstate == saved)
 	pgs->show_gstate = pgs;
     gs_free_object(pgs->memory, saved, "gs_grestore");
-    return 0;
+
+    /* update the overprint compositor, if necessary */
+    if ( !same_device                                                   ||
+         prior_overprint != pgs->overprint                              ||
+         (pgs->overprint && prior_overprint_mode != pgs->overprint_mode)  )
+        return pgs->color_space->type->set_overprint(pgs->color_space, pgs);
+    else
+        return 0;
 }
 
 /* Restore the graphics state per PostScript semantics */
@@ -453,7 +428,6 @@
 gs_grestoreall_for_restore(gs_state * pgs, gs_state * saved)
 {
     int code;
-    gx_device_color_spaces_t freed_spaces;
 
     while (pgs->saved->saved) {
 	code = gs_grestore(pgs);
@@ -464,16 +438,9 @@
     if (pgs->pattern_cache)
 	(*pgs->pattern_cache->free_all) (pgs->pattern_cache);
     pgs->saved->saved = saved;
-    freed_spaces = pgs->device_color_spaces;
     code = gs_grestore(pgs);
     if (code < 0)
 	return code;
-    if (pgs->ht_cache->order.bit_data != pgs->dev_ht->order.bit_data ||
-	pgs->ht_cache->order.levels != pgs->dev_ht->order.levels
-	)
-	gx_ht_clear_cache(pgs->ht_cache);
-    gx_device_color_spaces_free(&freed_spaces, pgs->memory,
-				"gs_grestoreall_for_restore");
     if (pgs->view_clip) {
 	gx_cpath_free(pgs->view_clip, "gs_grestoreall_for_restore");
 	pgs->view_clip = 0;
@@ -501,15 +468,7 @@
 gs_state *
 gs_gstate(gs_state * pgs)
 {
-    gs_state *copied = gs_state_copy(pgs, pgs->memory);
-    int i;
-
-    if (copied == 0)
-	return 0;
-    /* Don't capture the substituted color spaces. */
-    for (i = 0; i < countof(copied->device_color_spaces.indexed); ++i)
-	copied->device_color_spaces.indexed[i] = 0;
-    return copied;
+    return gs_state_copy(pgs, pgs->memory);
 }
 gs_state *
 gs_state_copy(gs_state * pgs, gs_memory_t * mem)
@@ -579,7 +538,9 @@
     pgs->show_gstate =
 	(pgs->show_gstate == pfrom ? pgs : saved_show);
     pgs->transparency_stack = tstack;
-    return 0;
+
+    /* update the overprint compositor */
+    return pgs->color_space->type->set_overprint(pgs->color_space, pgs);
 }
 
 /* Get the allocator pointer of a graphics state. */
@@ -623,7 +584,92 @@
 
 /* ------ Operations on components ------ */
 
-/* Reset most of the graphics state */
+/*
+ * Push an overprint compositor onto the current device. Note that if
+ * the current device already is an overprint compositor, the
+ * create_compositor will update its parameters but not create a new
+ * compositor device.
+ */
+int
+gs_state_update_overprint(gs_state * pgs, const gs_overprint_params_t * pparams)
+{
+    gs_composite_t *    pct = 0;
+    gs_imager_state *   pis = (gs_imager_state *)pgs;
+    int                 code;
+    gx_device *         dev = pgs->device;
+    gx_device *         ovptdev;
+
+    if ( (code = gs_create_overprint(&pct, pparams, pgs->memory)) >= 0 &&
+         (code = dev_proc(dev, create_compositor)( dev,
+                                                   &ovptdev,
+                                                   pct,
+                                                   pis,
+                                                   pgs->memory )) >= 0   ) {
+        if (ovptdev != dev)
+            gx_set_device_only(pgs, ovptdev);
+
+        /* the device methods may have changed even if the device has not */
+        gx_set_cmap_procs((gs_imager_state *)pgs, ovptdev);
+        gx_unset_dev_color(pgs);
+
+    }
+    if (pct != 0)
+        gs_free_object(pgs->memory, pct, "gs_state_update_overprint");
+
+    /* the following hack handles devices that don't support compositors */
+    if (code == gs_error_unknownerror && !pparams->retain_any_comps)
+        code = 0;
+    return code;
+}
+
+/* setoverprint */
+void
+gs_setoverprint(gs_state * pgs, bool ovp)
+{
+    bool    prior_ovp = pgs->overprint;
+
+    pgs->overprint = ovp;
+    if (prior_ovp != ovp)
+        pgs->color_space->type->set_overprint(pgs->color_space, pgs);
+}
+
+/* currentoverprint */
+bool
+gs_currentoverprint(const gs_state * pgs)
+{
+    return pgs->overprint;
+}
+
+/* setoverprintmode */
+int
+gs_setoverprintmode(gs_state * pgs, int mode)
+{
+    int     prior_mode = pgs->overprint_mode;
+
+    if (mode < 0 || mode > 1)
+	return_error(gs_error_rangecheck);
+    pgs->overprint_mode = mode;
+    if (pgs->overprint && prior_mode != mode)
+        pgs->color_space->type->set_overprint(pgs->color_space, pgs);
+    return 0;
+}
+
+/* currentoverprintmode */
+int
+gs_currentoverprintmode(const gs_state * pgs)
+{
+    return pgs->overprint_mode;
+}
+
+
+/*
+ * Reset most of the graphics state.
+ *
+ * NB: This routine no longer resets the current color or current color
+ *     space. It cannot do this for PostScript, due to color substitution.
+ *     Clients should perform the appropriate color/colorspace
+ *     initializaion themselves.
+ */
 int
 gs_initgraphics(gs_state * pgs)
 {
@@ -640,7 +686,6 @@
 	(gs_setdashadapt(pgs, false),
 	 (code = gs_setdotlength(pgs, 0.0, false))) < 0 ||
 	(code = gs_setdotorientation(pgs)) < 0 ||
-	(code = gs_setgray(pgs, 0.0)) < 0 ||
 	(code = gs_setmiterlimit(pgs, gstate_initial.line_params.miter_limit)) < 0
 	)
 	return code;
@@ -856,10 +901,8 @@
 	    gs_state_copy_reason_t reason, client_name_t cname)
 {
     gs_state_parts parts;
-    gx_device_color_spaces_t saved_spaces;
 
     GSTATE_ASSIGN_PARTS(&parts, pto);
-    saved_spaces = pto->device_color_spaces;
     /* Copy the dash pattern if necessary. */
     if (pfrom->line_params.dash.pattern || pto->line_params.dash.pattern) {
 	int code = gstate_copy_dash(pto, pfrom);
@@ -923,7 +966,6 @@
 	}
     }
     GSTATE_ASSIGN_PARTS(pto, &parts);
-    pto->device_color_spaces = saved_spaces;
 #undef RCCOPY
     pto->show_gstate =
 	(pfrom->show_gstate == pfrom ? pto : 0);

Index: gsstate.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsstate.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gsstate.h	16 Jun 2002 08:45:42 -0000	1.5
+++ gsstate.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -26,6 +26,12 @@
 typedef struct gs_state_s gs_state;
 #endif
 
+/* opague type for overprint compositor parameters */
+#ifndef gs_overprint_params_t_DEFINED
+#  define gs_overprint_params_t_DEFINED
+typedef struct gs_overprint_params_s    gs_overprint_params_t;
+#endif
+
 /* Initial allocation and freeing */
 gs_state *gs_state_alloc(gs_memory_t *);	/* 0 if fails */
 int gs_state_free(gs_state *);
@@ -39,6 +45,13 @@
 int gs_copygstate(gs_state * /*to */ , const gs_state * /*from */ ),
       gs_currentgstate(gs_state * /*to */ , const gs_state * /*from */ ),
       gs_setgstate(gs_state * /*to */ , const gs_state * /*from */ );
+
+int gs_state_update_overprint(gs_state *, const gs_overprint_params_t *);
+bool gs_currentoverprint(const gs_state *);
+void gs_setoverprint(gs_state *, bool);
+int gs_currentoverprintmode(const gs_state *);
+int gs_setoverprintmode(gs_state *, int);
+
 int gs_initgraphics(gs_state *);
 
 /* Device control */

Index: gxacpath.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxacpath.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gxacpath.c	21 Feb 2002 22:24:52 -0000	1.5
+++ gxacpath.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -83,7 +83,16 @@
   NULL,
   NULL,
   gx_default_text_begin,
-  gx_default_finish_copydevice
+  gx_default_finish_copydevice,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL
  }
 };
 

Index: gxbitfmt.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxbitfmt.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gxbitfmt.h	21 Feb 2002 22:24:52 -0000	1.4
+++ gxbitfmt.h	22 Aug 2002 07:12:29 -0000	1.5
@@ -43,9 +43,6 @@
   (GB_COLORS_GRAY | GB_COLORS_RGB | GB_COLORS_CMYK)
 #define GB_COLORS_ALL\
   (GB_COLORS_NATIVE | GB_COLORS_STANDARD_ALL)
-#define gb_colors_for_device(dev)\
-  ((dev)->color_info.num_components == 4 ? GB_COLORS_CMYK :\
-   (dev)->color_info.num_components == 3 ? GB_COLORS_RGB : GB_COLORS_GRAY)
 #define GB_COLORS_NAMES\
   "colors_native", "colors_Gray", "colors_RGB", "colors_CMYK"
 

Index: gxcdevn.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxcdevn.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gxcdevn.h	16 Jun 2002 08:45:43 -0000	1.5
+++ gxcdevn.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -30,9 +30,8 @@
 #endif
 struct gs_device_n_map_s {
     rc_header rc;
-    int (*tint_transform)(const gs_device_n_params * params,
-			  const float *in, float *out,
-			  const gs_imager_state *pis, void *data);
+    int (*tint_transform)(const float *in, float *out,
+                          const gs_imager_state *pis, void *data);
     void *tint_transform_data;
     bool cache_valid;
     float tint[GS_CLIENT_COLOR_MAX_COMPONENTS];
@@ -44,6 +43,9 @@
 
 /* Allocate and initialize a DeviceN map. */
 int alloc_device_n_map(gs_device_n_map ** ppmap, gs_memory_t * mem,
-		       client_name_t cname);
+                       client_name_t cname);
+
+/* Check if we are using the alternate color space */
+bool using_alt_color_space(const gs_state * pgs);
 
 #endif /* gxcdevn_INCLUDED */

Index: gxcht.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxcht.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gxcht.c	16 Jun 2002 05:48:55 -0000	1.7
+++ gxcht.c	22 Aug 2002 07:12:29 -0000	1.8
@@ -16,6 +16,7 @@
 
 /* $Id$ */
 /* Color halftone rendering for Ghostscript imaging library */
+#include <assert.h>
 #include "memory_.h"
 #include "gx.h"
 #include "gserrors.h"
@@ -28,6 +29,7 @@
 #include "gxdcolor.h"
 #include "gxistate.h"
 #include "gzht.h"
[...812 lines suppressed...]
 			ptc->bit_shift = 8 - ptc->xbits;
 			goto b;
 		    }
-		    index |= (gx_color_index)(tile_bit & 1) << i;
+		    tcolor |= colors[2 * i + (tile_bit & 1)];
 		}
-	    tcolor = colors[index];
-	    if (tcolor == gx_no_color_index) {
-		/* Map the color value now. */
-		int i;
-
-		for (i = pmin; i <= pmax; ++i)
-		    cv[i] = pvp->values[(index >> i) & 1][i];
-		/****** HACK -- NO WAY TO MAP GENERAL COLORS ******/
-		tcolor = colors[index] =
-		    gx_map_cmyk_color(dev, cv[0], cv[1], cv[2], cv[3]);
-	    }
 	    --x;
 	    switch (dbytes) {
 		case 0:	/* 4 -- might be 2, but we don't support this */

Index: gxcindex.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxcindex.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gxcindex.h	21 Feb 2002 22:24:53 -0000	1.4
+++ gxcindex.h	22 Aug 2002 07:12:29 -0000	1.5
@@ -28,7 +28,7 @@
  * sizeof(gx_color_index) * 8, since for larger values, there aren't enough
  * bits in a gx_color_index to have even 1 bit per component.
  */
-#define GX_DEVICE_COLOR_MAX_COMPONENTS 6
+#define GX_DEVICE_COLOR_MAX_COMPONENTS 16
 
 /*
  * We might change gx_color_index to a pointer or a structure in the
@@ -54,7 +54,11 @@
 #else  /* !TEST_CINDEX_STRUCT */
 
 /* Define the type for device color index (pixel value) data. */
+#ifdef GX_COLOR_INDEX_TYPE
+typedef GX_COLOR_INDEX_TYPE gx_color_index_data;
+#else
 typedef ulong gx_color_index_data;
+#endif
 
 #endif /* (!)TEST_CINDEX_STRUCT */
 
@@ -74,14 +78,16 @@
 typedef gx_color_index_data gx_color_index;
 #define arch_sizeof_color_index arch_sizeof_long
 
-/* Define the 'transparent' color index. */
-#define gx_no_color_index_value (-1)	/* no cast -> can be used in #if */
-
-/* The SGI C compiler provided with Irix 5.2 gives error messages */
-/* if we use the proper definition of gx_no_color_index: */
-/*#define gx_no_color_index ((gx_color_index)gx_no_color_index_value) */
-/* Instead, we must spell out the typedef: */
-#define gx_no_color_index ((unsigned long)gx_no_color_index_value)
+/*
+ * Define the 'transparent' or 'undefined' color index.
+ */
+#define gx_no_color_index_value (~0)	/* no cast -> can be used in #if */
+/*
+ * There was a comment here about the SGI C compiler provided with Irix 5.2
+ * giving error messages.  I hope that was fixed when the value of gx_no_color_index
+ * was changed from (-1) to (~0).  If not then let us know.
+ */
+#define gx_no_color_index ((gx_color_index)gx_no_color_index_value)
 
 #endif /* (!)TEST_CINDEX_POINTER */
 

Index: gxclbits.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxclbits.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gxclbits.c	21 Feb 2002 22:24:53 -0000	1.6
+++ gxclbits.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -304,7 +304,7 @@
 /* If necessary, write out data for a single color map. */
 int
 cmd_put_color_map(gx_device_clist_writer * cldev, cmd_map_index map_index,
-		  const gx_transfer_map * map, gs_id * pid)
+	int comp_num, const gx_transfer_map * map, gs_id * pid)
 {
     byte *dp;
     int code;
@@ -312,27 +312,30 @@
     if (map == 0) {
 	if (pid && *pid == gs_no_id)
 	    return 0;	/* no need to write */
-	code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc, 2);
+	code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc, 3);
 	if (code < 0)
 	    return code;
 	dp[1] = cmd_set_misc_map + (cmd_map_none << 4) + map_index;
+	dp[2] = comp_num;
 	if (pid)
 	    *pid = gs_no_id;
     } else {
 	if (pid && map->id == *pid)
 	    return 0;	/* no need to write */
 	if (map->proc == gs_identity_transfer) {
-	    code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc, 2);
+	    code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc, 3);
 	    if (code < 0)
 		return code;
 	    dp[1] = cmd_set_misc_map + (cmd_map_identity << 4) + map_index;
+	    dp[2] = comp_num;
 	} else {
 	    code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc,
-				      2 + sizeof(map->values));
+				      3 + sizeof(map->values));
 	    if (code < 0)
 		return code;
 	    dp[1] = cmd_set_misc_map + (cmd_map_other << 4) + map_index;
-	    memcpy(dp + 2, map->values, sizeof(map->values));
+	    dp[2] = comp_num;
+	    memcpy(dp + 3, map->values, sizeof(map->values));
 	}
 	if (pid)
 	    *pid = map->id;

Index: gxcldev.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxcldev.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- gxcldev.h	16 Jun 2002 08:45:43 -0000	1.8
+++ gxcldev.h	22 Aug 2002 07:12:29 -0000	1.9
@@ -84,23 +84,13 @@
 				/* order_procs_index */
     cmd_opv_set_ht_data = 0x0a,	/* n, n x (uint|gx_ht_bit|ushort) */
     cmd_opv_end_page = 0x0b,	/* (nothing) */
-    cmd_opv_delta2_color0 = 0x0c,	/* dr5dg6db5 or dc4dm4dy4dk4 */
-#define cmd_delta2_24_bias 0x00102010
-#define cmd_delta2_24_mask 0x001f3f1f
-#define cmd_delta2_32_bias 0x08080808
-#define cmd_delta2_32_mask 0x0f0f0f0f
-    cmd_opv_delta2_color1 = 0x0d,	/* <<same as color0>> */
+    cmd_opv_delta_color0 = 0x0c,	/* See cmd_put_color in gxclutil.c */
+    cmd_opv_delta_color1 = 0x0d,	/* <<same as color0>> */
     cmd_opv_set_copy_color = 0x0e,	/* (nothing) */
     cmd_opv_set_copy_alpha = 0x0f,	/* (nothing) */
-    cmd_op_set_color0 = 0x10,	/* +15 = transparent | */
-				/* +0, color$ | +dcolor+8 | */
-				/* +dr4, dg4db4 | */
-				/* +dc3dm1, dm2dy3dk3 */
+    cmd_op_set_color0 = 0x10,	/* +n = number of low order zero bytes | */
+#define cmd_no_color_index 15	/* +15 = transparent - "no color" */
     cmd_op_set_color1 = 0x20,	/* <<same as color0>> */
-#define cmd_delta1_24_bias 0x00080808
-#define cmd_delta1_24_mask 0x000f0f0f
-#define cmd_delta1_32_bias 0x04040404
-#define cmd_delta1_32_mask 0x07070707
     cmd_op_fill_rect = 0x30,	/* +dy2dh2, x#, w# | +0, rect# */
     cmd_op_fill_rect_short = 0x40,	/* +dh, dx, dw | +0, rect_short */
     cmd_op_fill_rect_tiny = 0x50,	/* +dw+0, rect_tiny | +dw+8 */
@@ -434,15 +424,19 @@
 /* Put out a command to set a color. */
 typedef struct {
     byte set_op;
-    byte delta2_op;
+    byte delta_op;
     bool tile_color;
 } clist_select_color_t;
 extern const clist_select_color_t
       clist_select_color0, clist_select_color1, clist_select_tile_color0,
       clist_select_tile_color1;
+
+/* See comments in gxclutil.c */
 int cmd_put_color(gx_device_clist_writer * cldev, gx_clist_state * pcls,
-		  const clist_select_color_t * select,
-		  gx_color_index color, gx_color_index * pcolor);
+                  const clist_select_color_t * select,
+                  gx_color_index color, gx_color_index * pcolor);
+
+extern const gx_color_index cmd_delta_offsets[];	/* In gxclutil.c */
 
 #define cmd_set_color0(dev, pcls, color0)\
   cmd_put_color(dev, pcls, &clist_select_color0, color0, &(pcls)->colors[0])
@@ -674,8 +668,8 @@
     cmd_map_other		/* other map */
 } cmd_map_contents;
 int cmd_put_color_map(gx_device_clist_writer * cldev,
-		      cmd_map_index map_index,
-		      const gx_transfer_map * map, gs_id * pid);
+                      cmd_map_index map_index, int comp_num,
+                      const gx_transfer_map * map, gs_id * pid);
 
 /*
  * Change tiles for clist_tile_rectangle.  (We make this a separate

Index: gxclimag.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxclimag.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gxclimag.c	16 Jun 2002 05:48:55 -0000	1.6
+++ gxclimag.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -34,6 +34,7 @@
 #include "stream.h"
 #include "strimpl.h"		/* for sisparam.h */
 #include "sisparam.h"
+#include "gxcomp.h"
 
 extern_gx_image_type_table();
 
@@ -809,8 +810,33 @@
 			gx_device ** pcdev, const gs_composite_t * pcte,
 			const gs_imager_state * pis, gs_memory_t * mem)
 {
-    /****** NYI ******/
-    return gx_no_create_compositor(dev, pcdev, pcte, pis, mem);
+    byte *                  dp;
+    uint                    size = 0;
+    int                     code = pcte->type->procs.write(pcte, 0, &size);
+
+    /* always return the same device */
+    *pcdev = dev;
+
+    /* determine the amount of space required */
+    if (code < 0 && code != gs_error_rangecheck)
+        return code;
+    size += 2 + 1;      /* 2 bytes for the command code, one for the id */
+
+    /* overprint applies to all bands */
+    code = set_cmd_put_all_op( dp,
+                               (gx_device_clist_writer *)dev,
+                               cmd_opv_extend,
+                               size );
+    if (code < 0)
+        return code;
+
+    /* insert the command and compositor identifier */
+    dp[1] = cmd_opv_ext_create_compositor;
+    dp[2] = pcte->type->comp_id;
+    dp += 3;
+
+    /* serialize the remainder of the compositor */
+    return pcte->type->procs.write(pcte, dp, &size);
 }
 
 /* ------ Utilities ------ */
@@ -843,7 +869,6 @@
 /* Add commands to represent a halftone order. */
 private int
 cmd_put_ht_order(gx_device_clist_writer * cldev, const gx_ht_order * porder,
-		 gs_ht_separation_name cname,
 		 int component /* -1 = default/gray/black screen */ )
 {
     byte command[cmd_max_intsize(sizeof(long)) * 8];
@@ -861,8 +886,6 @@
 	return_error(gs_error_unregistered);
     /* Put out the order parameters. */
     cp = cmd_put_w(component + 1, command);
-    if (component >= 0)
-	cp = cmd_put_w(cname, cp);
     cp = cmd_put_w(porder->width, cp);
     cp = cmd_put_w(porder->height, cp);
     cp = cmd_put_w(porder->raster, cp);
@@ -877,7 +900,7 @@
     memcpy(dp + 1, command, len);
 
     /* Put out the transfer function, if any. */
-    code = cmd_put_color_map(cldev, cmd_map_ht_transfer, porder->transfer,
+    code = cmd_put_color_map(cldev, cmd_map_ht_transfer, 0, porder->transfer,
 			     NULL);
     if (code < 0)
 	return code;
@@ -932,14 +955,12 @@
 	cmd_put_w(num_comp, dp + 2);
     }
     if (num_comp == 0)
-	return cmd_put_ht_order(cldev, &pdht->order,
-				gs_ht_separation_Default, -1);
+	return cmd_put_ht_order(cldev, &pdht->order, -1);
     {
 	int i;
 
 	for (i = num_comp; --i >= 0;) {
-	    int code = cmd_put_ht_order(cldev, &pdht->components[i].corder,
-					pdht->components[i].cname, i);
+	    int code = cmd_put_ht_order(cldev, &pdht->components[i].corder, i);
 
 	    if (code < 0)
 		return code;
@@ -966,12 +987,12 @@
     /* If we need to map RGB to CMYK, put out b.g. and u.c.r. */
     if (write_rgb_to_cmyk) {
 	code = cmd_put_color_map(cldev, cmd_map_black_generation,
-				 pis->black_generation,
+				 0, pis->black_generation,
 				 &cldev->black_generation_id);
 	if (code < 0)
 	    return code;
 	code = cmd_put_color_map(cldev, cmd_map_undercolor_removal,
-				 pis->undercolor_removal,
+				 0, pis->undercolor_removal,
 				 &cldev->undercolor_removal_id);
 	if (code < 0)
 	    return code;
@@ -980,39 +1001,76 @@
     {
 	uint which = 0;
 	bool all_same = true;
+	bool send_default_comp = false;
 	int i;
+	gs_id default_comp_id, xfer_ids[4];
+
+	/*
+	 * Determine the ids for the transfer functions that we currently
+	 * have in the set_transfer structure.  The halftone xfer funcs
+	 * are sent in cmd_put_ht_order().
+	 */
+#define get_id(pis, color, color_num) \
+    ((pis->set_transfer.color != NULL && pis->set_transfer.color_num >= 0) \
+	? pis->set_transfer.color->id\
+	: pis->set_transfer.gray->id)
+
+        xfer_ids[0] = get_id(pis, red, red_component_num);
+        xfer_ids[1] = get_id(pis, green, green_component_num);
+        xfer_ids[2] = get_id(pis, blue, blue_component_num);
+	xfer_ids[3] = default_comp_id = pis->set_transfer.gray->id;
+#undef get_id
 
 	for (i = 0; i < countof(cldev->transfer_ids); ++i) {
-	    if (pis->effective_transfer.indexed[i]->id !=
-		cldev->transfer_ids[i]
-		)
+	    if (xfer_ids[i] != cldev->transfer_ids[i])
 		which |= 1 << i;
-	    if (pis->effective_transfer.indexed[i]->id !=
-		pis->effective_transfer.indexed[0]->id
-		)
+	    if (xfer_ids[i] != default_comp_id)
 		all_same = false;
+	    if (xfer_ids[i] == default_comp_id &&
+		cldev->transfer_ids[i] != default_comp_id)
+		send_default_comp = true;
 	}
 	/* There are 3 cases for transfer functions: nothing to write, */
 	/* a single function, and multiple functions. */
 	if (which == 0)
 	    return 0;
-	if (which == (1 << countof(cldev->transfer_ids)) - 1 && all_same) {
-	    code = cmd_put_color_map(cldev, cmd_map_transfer,
-				     pis->effective_transfer.indexed[0],
-				     &cldev->transfer_ids[0]);
+	/*
+	 * Send default transfer function if changed or we need it for a
+	 * component
+	 */
+	if (send_default_comp || cldev->transfer_ids[0] != default_comp_id) {
+	    gs_id dummy = gs_no_id;
+
+	    code = cmd_put_color_map(cldev, cmd_map_transfer, 0,
+		pis->set_transfer.gray, &dummy);
 	    if (code < 0)
 		return code;
-	    for (i = 1; i < countof(cldev->transfer_ids); ++i)
-		cldev->transfer_ids[i] = cldev->transfer_ids[0];
-	} else
-	    for (i = 0; i < countof(cldev->transfer_ids); ++i) {
-		code = cmd_put_color_map(cldev,
-				   (cmd_map_index) (cmd_map_transfer_0 + i),
-					 pis->effective_transfer.indexed[i],
-					 &cldev->transfer_ids[i]);
-		if (code < 0)
-		    return code;
-	    }
+	    /* Sending a default will force all xfers to default */
+	    for (i = 0; i < countof(cldev->transfer_ids); ++i)
+		cldev->transfer_ids[i] = default_comp_id;
+	}
+	/* Send any transfer functions which have changed */
+	if (cldev->transfer_ids[0] != xfer_ids[0]) {
+	    code = cmd_put_color_map(cldev, cmd_map_transfer_0,
+			pis->set_transfer.red_component_num,
+			pis->set_transfer.red, &cldev->transfer_ids[0]);
+	    if (code < 0)
+		return code;
+	}
+	if (cldev->transfer_ids[1] != xfer_ids[1]) {
+	    code = cmd_put_color_map(cldev, cmd_map_transfer_1,
+			pis->set_transfer.green_component_num,
+			pis->set_transfer.green, &cldev->transfer_ids[1]);
+	    if (code < 0)
+		return code;
+	}
+	if (cldev->transfer_ids[2] != xfer_ids[2]) {
+	    code = cmd_put_color_map(cldev, cmd_map_transfer_2,
+			pis->set_transfer.blue_component_num,
+			pis->set_transfer.blue, &cldev->transfer_ids[2]);
+	    if (code < 0)
+		return code;
+	}
     }
 
     return 0;

Index: gxclip.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxclip.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- gxclip.c	16 Jun 2002 05:48:55 -0000	1.8
+++ gxclip.c	22 Aug 2002 07:12:29 -0000	1.9
@@ -88,7 +88,16 @@
   gx_no_create_compositor,
   gx_forward_get_hardware_params,
   gx_default_text_begin,
-  gx_default_finish_copydevice
+  gx_default_finish_copydevice,
+  NULL,			/* begin_transparency_group */
+  NULL,			/* end_transparency_group */
+  NULL,			/* begin_transparency_mask */
+  NULL,			/* end_transparency_mask */
+  NULL,			/* discard_transparency_layer */
+  gx_forward_get_color_mapping_procs,
+  gx_forward_get_color_comp_index,
+  gx_forward_encode_color,
+  gx_forward_decode_color
  }
 };
 

Index: gxclip2.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxclip2.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gxclip2.c	21 Feb 2002 22:24:53 -0000	1.5
+++ gxclip2.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -80,7 +80,16 @@
   gx_no_create_compositor,
   gx_forward_get_hardware_params,
   gx_default_text_begin,
-  gx_default_finish_copydevice
+  gx_default_finish_copydevice,
+  NULL,			/* begin_transparency_group */
+  NULL,			/* end_transparency_group */
+  NULL,			/* begin_transparency_mask */
+  NULL,			/* end_transparency_mask */
+  NULL,			/* discard_transparency_layer */
+  gx_forward_get_color_mapping_procs,
+  gx_forward_get_color_comp_index,
+  gx_forward_encode_color,
+  gx_forward_decode_color
  }
 };
 

Index: gxclipm.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxclipm.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gxclipm.c	16 Jun 2002 05:48:55 -0000	1.6
+++ gxclipm.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -79,7 +79,16 @@
   gx_no_create_compositor,
   gx_forward_get_hardware_params,
   gx_default_text_begin,
-  gx_default_finish_copydevice
+  gx_default_finish_copydevice,
+  NULL,			/* begin_transparency_group */
+  NULL,			/* end_transparency_group */
+  NULL,			/* begin_transparency_mask */
+  NULL,			/* end_transparency_mask */
+  NULL,			/* discard_transparency_layer */
+  gx_forward_get_color_mapping_procs,
+  gx_forward_get_color_comp_index,
+  gx_forward_encode_color,
+  gx_forward_decode_color
  }
 };
 

Index: gxclist.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxclist.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gxclist.c	16 Jun 2002 05:48:55 -0000	1.6
+++ gxclist.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -121,7 +121,16 @@
     clist_create_compositor,
     gx_forward_get_hardware_params,
     gx_default_text_begin,
-    gx_default_finish_copydevice
+    gx_default_finish_copydevice,
+    NULL,			/* begin_transparency_group */
+    NULL,			/* end_transparency_group */
+    NULL,			/* begin_transparency_mask */
+    NULL,			/* end_transparency_mask */
+    NULL,			/* discard_transparency_layer */
+    gx_forward_get_color_mapping_procs,
+    gx_forward_get_color_comp_index,
+    gx_forward_encode_color,
+    gx_forward_decode_color
 };
 
 /* ------ Define the command set and syntax ------ */

Index: gxclpath.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxclpath.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- gxclpath.c	16 Jun 2002 05:48:55 -0000	1.12
+++ gxclpath.c	22 Aug 2002 07:12:29 -0000	1.13
@@ -143,18 +143,19 @@
     } else if (gx_dc_is_colored_halftone(pdcolor)) {
 	const gx_device_halftone *pdht = pdcolor->colors.colored.c_ht;
 	int num_comp = cldev->color_info.num_components;
-	byte buf[4 + 4 * cmd_max_intsize(sizeof(pdcolor->colors.colored.c_level[0]))];
-	byte *bp = buf;
 	int i;
 	byte cmd;
-	uint short_bases = 0;
-	ulong bases = 0;
-	byte flags = 0;
 	byte *dp;
 	int code;
+	byte buf[ GX_DEVICE_COLOR_MAX_COMPONENTS *
+		(1 + cmd_max_intsize(sizeof(pdcolor->colors.colored.c_level[0]))) ];
+	byte * bp = buf;
+	ulong flags = 0, short_bases = 0;
+	bool use_short_cmd = true;
 
 	pcls->colors_used.or |=
 	    colored_halftone_colors_used(cldev, pdcolor);
+
 	/****** HOW TO TELL IF COLOR IS ALREADY SET? ******/
 	if (pdht->id != cldev->device_halftone_id) {
 	    int code = cmd_put_halftone(cldev, pdht, pdht->type);
@@ -163,30 +164,47 @@
 		return code;
 	    cldev->device_halftone_id = pdht->id;
 	}
-	for (i = 0; i < num_comp; ++i) {
+        /*
+	 * Check if we can use the short command form.  We can do this if
+	 * the base values fit into one bit.
+	 */
+	for (i = 0; i < num_comp; i++) {
 	    uint base = pdcolor->colors.colored.c_base[i];
 
-	    if (base > 31)
+	    /* sanity check */
+	    if (base > 0x1f)
 		return_error(gs_error_rangecheck);
-	    bases |= base << ((3 - i) * 5);
-	    short_bases |= base << (3 - i);
-	    if (pdcolor->colors.colored.c_level[i])
-		flags |= 0x80 >> i;
+
+	    /* check for 1-bit (short command) case */
+	    if (use_short_cmd = (use_short_cmd && base <= 1))
+		short_bases = (short_bases << 1) | base;
+
+	    /* set the flags */
+	    flags = (flags << 1)
+		| (pdcolor->colors.colored.c_level[i] != 0 ? 1 : 0);
 	}
-	if (bases & 0xf7bde) {
-	    /* Some base value requires more than 1 bit. */
-	    cmd = cmd_opv_set_color;
-	    *bp++ = flags | (byte)(bases >> 16);
-	    *bp++ = (byte) (bases >> 8);
-	    *bp++ = (byte) bases;
-	} else {
-	    /* The bases all fit in 1 bit each. */
+	/* Now put the data into the buffer */
+	if (use_short_cmd) {
 	    cmd = cmd_opv_set_color_short;
-	    *bp++ = flags | (byte)short_bases;
+	    /* use a variation of the old encoding for <= 4 components */
+	    if (num_comp <= 4)
+		*bp++ = ((flags << 4) | short_bases) << (4 - num_comp);
+	    else {
+		bp = cmd_put_w(flags, bp);
+		bp = cmd_put_w(short_bases, bp);
+	    }
+	} else {
+	    cmd = cmd_opv_set_color;
+	    bp = cmd_put_w(flags, bp);
+	    for (i = 0; i < num_comp; i++)
+		bp = cmd_put_w(pdcolor->colors.colored.c_base[i], bp);
 	}
-	for (i = 0; i < num_comp; ++i)
-	    if (flags & (0x80 >> i))
+
+	flags <<= 8 * sizeof(flags) - num_comp;
+	for (i = 0; flags != 0; flags <<= 1, i++) {
+	    if ((flags & (1LU << (8 * sizeof(flags) - 1))) != 0)
 		bp = cmd_put_w((uint)pdcolor->colors.colored.c_level[i], bp);
+	}
 	/****** IGNORE alpha ******/
 	code = set_cmd_put_op(dp, cldev, pcls, cmd, bp - buf + 1);
 	if (code < 0)

Index: gxclpath.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxclpath.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- gxclpath.h	16 Jun 2002 08:45:43 -0000	1.9
+++ gxclpath.h	22 Aug 2002 07:12:29 -0000	1.10
@@ -59,11 +59,17 @@
 /* Extend the command set.  See gxcldev.h for more information. */
 typedef enum {
     cmd_op_misc2 = 0xd0,	/* (see below) */
-    cmd_opv_set_color = 0xd0,	/* pqrsaaaa abbbbbcc cccddddd */
-				/* (level[0] if p) (level[1] if q) */
-				/* (level[2] if r) (level[3] if s) */
+    cmd_opv_set_color = 0xd0,	/* Used if base values do not fit into 1 bit */
+    				/* #flags,#base[0],...#base[num_comp-1] if flags */
 				/* colored halftone with base colors a,b,c,d */
-    cmd_opv_set_color_short = 0xd1,	/* pqrsabcd, level[i] as above */
+    cmd_opv_set_color_short = 0xd1,	/* Used if base values fit into 1 bit */
+    					/* If num_comp <= 4 then use: */
+    					/* pqrsabcd, where a = base[0] */
+					/* b = base[1], c= base[2], d = base[3] */
+					/* p = level[0], q = level[1] */
+					/* r = level[2], s = level[3] */
+    					/* If num_comp > 4 then use: */
+					/* #flags, #bases */
     cmd_opv_set_fill_adjust = 0xd2,	/* adjust_x/y(fixed) */
     cmd_opv_set_ctm = 0xd3,	/* [per sput/sget_matrix] */
     cmd_opv_set_color_space = 0xd4,	/* base(4)Indexed?(2)0(2) */
@@ -100,7 +106,7 @@
 				/* flags# (0 = same raster & data_x, */
 				/* 1 = new raster & data_x, lsb first), */
 				/* [raster#, [data_x#,]]* <data> */
-    cmd_opv_put_params = 0xdf,	/* (nothing) */
+    cmd_opv_extend = 0xdf,	/* command, varies */
     cmd_op_segment = 0xe0,	/* (see below) */
     cmd_opv_rmoveto = 0xe0,	/* dx%, dy% */
     cmd_opv_rlineto = 0xe1,	/* dx%, dy% */
@@ -144,6 +150,19 @@
     cmd_opv_htpolyfill = 0xfa,
     cmd_opv_colorpolyfill = 0xfb
 } gx_cmd_xop;
+
+/*
+ * Further extended command set. This code always occupies a byte, which
+ * is the second byte of a command whose first byte is cmd_opv_extend.
+ */
+typedef enum {
+    cmd_opv_ext_put_params = 0x00,          /* serialized parameter list */
+    cmd_opv_ext_create_compositor = 0x01,   /* compositor id,
+                                             * serialized compositor */
+    cmd_opv_ext_put_halftone = 0x02,        /* length, serialized halftone */
+    cmd_opv_ext_put_drawing_color = 0x03    /* length, color type id,
+                                             * serialized color */
+} gx_cmd_ext_op;
 
 #define cmd_segment_op_num_operands_values\
   2, 2, 1, 1, 4, 6, 6, 6, 4, 4, 4, 4, 2, 2, 0, 0

Index: gxclrast.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxclrast.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- gxclrast.c	1 Jul 2002 14:27:43 -0000	1.16
+++ gxclrast.c	22 Aug 2002 07:12:29 -0000	1.17
@@ -36,19 +36,18 @@
 #include "gxcmap.h"
 #include "gxcolor2.h"
 #include "gxcspace.h"		/* for gs_color_space_type */
-#include "gxht.h"
-#include "gxdht.h"
 #include "gxdhtres.h"
 #include "gxgetbit.h"
 #include "gxpaint.h"		/* for gx_fill/stroke_params */
 #include "gxhttile.h"
 #include "gxiparam.h"
+#include "gdevht.h"
[...924 lines suppressed...]
 		int i = map_index - cmd_map_transfer_0;
 
-		if_debug1('L', " transfer[%d]", i);
-		rc_unshare_struct(pis->set_transfer.indexed[i], gx_transfer_map,
-				  &st_transfer_map, mem,
-				  return_error(gs_error_VMerror),
-				  "cmd_select_map(transfer)");
-		map = pis->set_transfer.indexed[i];
-		pis->effective_transfer.indexed[i] = map;
+	        if_debug1('L', " transfer[%d]", i);
 	    }
-transfer:   if (cont != cmd_map_other) {
+	    rc_unshare_struct(*pmap, gx_transfer_map, &st_transfer_map, mem,
+		return_error(gs_error_VMerror), "cmd_select_map(transfer)");
+	    map = *pmap;
+
+transfer2:  if (cont != cmd_map_other) {
 		gx_set_identity_transfer(map);
 		*pmdata = 0;
 		*pcount = 0;

Index: gxclread.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxclread.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gxclread.c	16 Jun 2002 05:48:56 -0000	1.7
+++ gxclread.c	22 Aug 2002 07:12:29 -0000	1.8
@@ -28,6 +28,7 @@
 #include "gxcldev.h"
 #include "gxgetbit.h"
 #include "gxhttile.h"
+#include "gdevht.h"
 #include "gdevplnx.h"
 /*
  * We really don't like the fact that gdevprn.h is included here, since

Index: gxclutil.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxclutil.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gxclutil.c	21 Feb 2002 22:24:53 -0000	1.7
+++ gxclutil.c	22 Aug 2002 07:12:29 -0000	1.8
@@ -330,127 +330,188 @@
     return dp + 1;
 }
 
-/* Define the encodings of the different settable colors. */
+#ifndef sizeof_gx_color_index
+#define sizeof_gx_color_index 8
+#endif
+
+/*
+ * This next two arrays are used for the 'delta' mode of placing a color
+ * in the clist.  These arrays are indexed by the number of bytes in the
+ * color value (the depth).
+ *
+ * Delta values are calculated by subtracting the old value for the color
+ * from the desired new value.  Then each byte of the differenece is
+ * examined.  For most bytes, if the difference fits into 4 bits (signed)
+ * then those bits are packed into the clist along with an opcode.  If
+ * the size of the color (the depth) is an odd number of bytes then instead
+ * of four bits per byte, extra bits are used for the upper three bytes
+ * of the color.  In this case, five bits are used for the first byte,
+ * six bits for the second byte, and five bits for third byte.  This
+ * maximizes the chance that the 'delta' mode can be used for placing
+ * colors in the clist.
+ */
+const gx_color_index cmd_delta_offsets[] = {
+	0,
+	0,
+	0x0808,
+	0x102010,
+	0x08080808,
+#if sizeof_gx_color_index > 4
+	0x1020100808,
+	0x080808080808,
+	0x10201008080808,
+	0x0808080808080808,
+#endif
+	0};
+
+private const gx_color_index cmd_delta_masks[] = {
+	0,
+	0,
+	0x0f0f,
+	0x1f3f1f,
+	0x0f0f0f0f,
+#if sizeof_gx_color_index > 4
+	0x1f3f1f0f0f,
+	0x0f0f0f0f0f0f,
+	0x1f3f1f0f0f0f0f,
+	0x0f0f0f0f0f0f0f0f,
+#endif
+	0};
+
+
+/*
+ * There are currently only four different color "types" that can be placed
+ * into the clist.  These are called "color0", "color1", and "tile_color0",
+ * and "tile_color1".  There are separate command codes for color0 versus
+ * color1, both for the full value and delta commands - see cmd_put_color.
+ * Tile colors are preceded by a cmd_opv_set_tile_color command.
+ */
 const clist_select_color_t
-    clist_select_color0 = {cmd_op_set_color0, cmd_opv_delta2_color0, 0},
-    clist_select_color1 = {cmd_op_set_color1, cmd_opv_delta2_color1, 0},
-    clist_select_tile_color0 = {cmd_op_set_color0, cmd_opv_delta2_color0, 1},
-    clist_select_tile_color1 = {cmd_op_set_color1, cmd_opv_delta2_color1, 1};
+    clist_select_color0 = {cmd_op_set_color0, cmd_opv_delta_color0, 0},
+    clist_select_color1 = {cmd_op_set_color1, cmd_opv_delta_color1, 0},
+    clist_select_tile_color0 = {cmd_op_set_color0, cmd_opv_delta_color0, 1},
+    clist_select_tile_color1 = {cmd_op_set_color1, cmd_opv_delta_color1, 1};
+
+/*
+ * This routine is used to place a color into the clist.  Colors, in the
+ * clist, can be specified either as by a full value or by a "delta" value.
+ *
+ * See the comments before cmd_delta_offsets[] for a description of the
+ * 'delta' mode.  The delta mode may allow for a smaller command in the clist.
+ *
+ * For the full value mode, values are sent as a cmd code plus n bytes of
+ * data.  To minimize the number of bytes, a count is made of any low order
+ * bytes which are zero.  This count is packed into the low order 4 bits
+ * of the cmd code.  The data for these bytes are not sent.
+ *
+ * The gx_no_color_index value is treated as a special case.  This is done
+ * because it is both a commonly sent value and because it may require
+ * more bytes then the other color values.
+ *
+ * Parameters:
+ *   cldev - Pointer to clist device
+ *   pcls - Pointer to clist state
+ *   select - Descriptor record for type of color being sent.  See comments
+ *       by clist_select_color_t.
+ *   color - The new color value.
+ *   pcolor - Pointer to previous color value.  (If the color value is the
+ *       same as the previous value then nothing is placed into the clist.)
+ *
+ * Returns:
+ *   Error code
+ *   clist and pcls and cldev may be updated.
+ */
 int
 cmd_put_color(gx_device_clist_writer * cldev, gx_clist_state * pcls,
 	      const clist_select_color_t * select,
 	      gx_color_index color, gx_color_index * pcolor)
 {
-    byte *dp;
-    long diff = (long)color - (long)(*pcolor);
-    byte op, op_delta2;
+    byte * dp;		/* This is manipulated by the set_cmd_put_op macro */
+    gx_color_index diff = color - *pcolor;
+    byte op, op_delta;
     int code;
 
     if (diff == 0)
 	return 0;
+
+    /* If this is a tile color then send tile color type */
     if (select->tile_color) {
 	code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_tile_color, 1);
 	if (code < 0)
 	    return code;
     }
     op = select->set_op;
-    op_delta2 = select->delta2_op;
+    op_delta = select->delta_op;
     if (color == gx_no_color_index) {
 	/*
 	 * We must handle this specially, because it may take more
 	 * bytes than the color depth.
 	 */
-	code = set_cmd_put_op(dp, cldev, pcls, op + 15, 1);
+	code = set_cmd_put_op(dp, cldev, pcls, op + cmd_no_color_index, 1);
 	if (code < 0)
 	    return code;
     } else {
-	long delta;
-	byte operand;
-
-	switch ((cldev->color_info.depth + 15) >> 3) {
-	    case 5:
-		if (!((delta = diff + cmd_delta1_32_bias) &
-		      ~cmd_delta1_32_mask) &&
-		    (operand =
-		     (byte) ((delta >> 23) + ((delta >> 18) & 1))) != 0 &&
-		    operand != 15
-		    ) {
-		    code = set_cmd_put_op(dp, cldev, pcls,
-					  (byte) (op + operand), 2);
-		    if (code < 0)
-			return code;
-		    dp[1] = (byte) (((delta >> 10) & 0300) +
-				    (delta >> 5) + delta);
-		    break;
-		}
-		if (!((delta = diff + cmd_delta2_32_bias) &
-		      ~cmd_delta2_32_mask)
-		    ) {
-		    code = set_cmd_put_op(dp, cldev, pcls, op_delta2, 3);
-		    if (code < 0)
-			return code;
-		    dp[1] = (byte) ((delta >> 20) + (delta >> 16));
-		    dp[2] = (byte) ((delta >> 4) + delta);
-		    break;
-		}
-		code = set_cmd_put_op(dp, cldev, pcls, op, 5);
-		if (code < 0)
-		    return code;
-		*++dp = (byte) (color >> 24);
-		goto b3;
-	    case 4:
-		if (!((delta = diff + cmd_delta1_24_bias) &
-		      ~cmd_delta1_24_mask) &&
-		    (operand = (byte) (delta >> 16)) != 0 &&
-		    operand != 15
-		    ) {
-		    code = set_cmd_put_op(dp, cldev, pcls,
-					  (byte) (op + operand), 2);
-		    if (code < 0)
-			return code;
-		    dp[1] = (byte) ((delta >> 4) + delta);
-		    break;
-		}
-		if (!((delta = diff + cmd_delta2_24_bias) &
-		      ~cmd_delta2_24_mask)
-		    ) {
-		    code = set_cmd_put_op(dp, cldev, pcls, op_delta2, 3);
-		    if (code < 0)
-			return code;
-		    dp[1] = ((byte) (delta >> 13) & 0xf8) +
-			((byte) (delta >> 11) & 7);
-		    dp[2] = (byte) (((delta >> 3) & 0xe0) + delta);
-		    break;
-		}
-		code = set_cmd_put_op(dp, cldev, pcls, op, 4);
-		if (code < 0)
-		    return code;
-b3:		*++dp = (byte) (color >> 16);
-		goto b2;
-	    case 3:
-		code = set_cmd_put_op(dp, cldev, pcls, op, 3);
-		if (code < 0)
-		    return code;
-b2:		*++dp = (byte) (color >> 8);
-		goto b1;
-	    case 2:
-		if (diff >= -7 && diff < 7) {
-		    code = set_cmd_put_op(dp, cldev, pcls,
-					  op + (int)diff + 8, 1);
-		    if (code < 0)
-			return code;
-		    break;
-		}
-		code = set_cmd_put_op(dp, cldev, pcls, op, 2);
-		if (code < 0)
-		    return code;
-b1:		dp[1] = (byte) color;
+	/* Check if the "delta" mode command can be used. */
+	int num_bytes = (cldev->color_info.depth + 7) >> 3;
+	int delta_bytes = (num_bytes + 1) / 2;
+	gx_color_index delta_offset = cmd_delta_offsets[num_bytes];
+	gx_color_index delta_mask = cmd_delta_masks[num_bytes];
+	gx_color_index delta = (diff + delta_offset) & delta_mask;
+	bool use_delta = (color == (*pcolor + delta - delta_offset));
+	int bytes_dropped = 0;
+	gx_color_index data = color;
+	
+	/*
+	 * If we use the full value mode, we do not send low order bytes
+	 * which are zero. Determine how many low order bytes are zero.
+	 */
+	if (color == 0) {
+	    bytes_dropped = num_bytes;
+	}
+	else  {
+	    while ((data & 0xff) == 0) {
+	        bytes_dropped++;
+		data >>= 8; 
+	    }
+	}
+	
+	/* Now send one of the two command forms */
+	if (use_delta && delta_bytes < num_bytes - bytes_dropped) {
+	    code = set_cmd_put_op(dp, cldev, pcls,
+	    				op_delta, delta_bytes + 1);
+	    if (code < 0)
+	        return code;
+	    /*
+	     * If we have an odd number of bytes then use extra bits for
+	     * the high order three bytes of the color.
+	     */
+	    if ((num_bytes >= 3) && (num_bytes & 1)) {
+		data = delta >> ((num_bytes - 3) * 8);
+	        dp[delta_bytes--] = (byte)(((data >> 13) & 0xf8) + ((data >> 11) & 0x07));
+	        dp[delta_bytes--] = (byte)(((data >> 3) & 0xe0) + (data & 0x1f));
+	    }
+	    for(; delta_bytes>0; delta_bytes--) {
+	        dp[delta_bytes] = (byte)((delta >> 4) + delta);
+		delta >>= 16;
+	    }
+	}
+	else {
+	    num_bytes -= bytes_dropped;
+	    code = set_cmd_put_op(dp, cldev, pcls,
+	    			(byte)(op + bytes_dropped), num_bytes + 1);
+	    if (code < 0)
+	        return code;
+	    for(; num_bytes>0; num_bytes--) {
+	        dp[num_bytes] = (byte)data;
+		data >>= 8;
+	    }
 	}
     }
     *pcolor = color;
     return 0;
 }
 
+
 /* Put out a command to set the tile colors. */
 int
 cmd_set_tile_colors(gx_device_clist_writer * cldev, gx_clist_state * pcls,
@@ -577,14 +638,15 @@
 	gs_param_list_serialize(param_list, local_buf, sizeof(local_buf));
     if (param_length > 0) {
 	/* Get cmd buffer space for serialized */
-	code = set_cmd_put_all_op(dp, cldev, cmd_opv_put_params,
-				  1 + sizeof(unsigned) + param_length);
+	code = set_cmd_put_all_op(dp, cldev, cmd_opv_extend,
+				  2 + sizeof(unsigned) + param_length);
 	if (code < 0)
 	    return code;
 
 	/* write param list to cmd list: needs to all fit in cmd buffer */
 	if_debug1('l', "[l]put_params, length=%d\n", param_length);
-	++dp;
+	dp[1] = cmd_opv_ext_put_params;
+	dp += 2;
 	memcpy(dp, &param_length, sizeof(unsigned));
 	dp += sizeof(unsigned);
 	if (param_length > sizeof(local_buf)) {

Index: gxcmap.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxcmap.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gxcmap.c	21 Feb 2002 22:24:53 -0000	1.5
+++ gxcmap.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -29,6 +29,9 @@
 #include "gxlum.h"
 #include "gzstate.h"
 #include "gxdither.h"
+#include "gxcdevn.h"
+#include "string_.h"
+
 
 /* Structure descriptor */
 public_st_device_color();
@@ -44,107 +47,354 @@
 }
[...1387 lines suppressed...]
+    pcv[0] = gx_color_value_from_byte((color >> 24) & 0xff);
+    pcv[1] = gx_color_value_from_byte((color >> 16) & 0xff);
+    pcv[2] = gx_color_value_from_byte((color >> 8) & 0xff);
+    pcv[3] = gx_color_value_from_byte(color & 0xff);
+    return 0;
+}
+
 /* Default mapping between RGB+alpha and RGB. */
 
 gx_color_index
 gx_default_map_rgb_alpha_color(gx_device * dev,
  gx_color_value r, gx_color_value g, gx_color_value b, gx_color_value alpha)
 {				/* Colors have been premultiplied: we don't need to do it here. */
-    return gx_map_rgb_color(dev, r, g, b);
+    gx_color_value cv[3];
+    cv[0] = r; cv[1] = g; cv[2] = b;
+    return (*dev_proc(dev, map_rgb_color))(dev, cv);
 }
 
 int

Index: gxcmap.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxcmap.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gxcmap.h	16 Jun 2002 08:45:43 -0000	1.5
+++ gxcmap.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -46,15 +46,77 @@
 	    const gs_imager_state *, gx_device *, gs_color_select_t)
 #define cmap_proc_rgb_alpha(proc)\
   void proc(frac, frac, frac, frac, gx_device_color *,\
-	    const gs_imager_state *, gx_device *, gs_color_select_t)
+	       const gs_imager_state *, gx_device *, gs_color_select_t)
+#define cmap_proc_separation(proc)\
+  void proc(frac, gx_device_color *, const gs_imager_state *,\
+	       gx_device *, gs_color_select_t)
+#define cmap_proc_devicen(proc)\
+  void proc(const frac *, gx_device_color *, const gs_imager_state *, \
+	       gx_device *, gs_color_select_t)
 
-/* Because of a bug in the Watcom C compiler, */
-/* we have to split the struct from the typedef. */
+/*
+ * List of mapping functions from the standard color spaces to the
+ * device color model. Any unused component will be mapped to 0.
+ */
+#define cm_map_proc_gray(proc) \
+    void proc (gx_device * dev, frac gray, \
+              frac * out)
+
+#define cm_map_proc_rgb(proc) \
+    void proc (gx_device * dev, \
+	      const gs_imager_state *pis, \
+              frac r, frac g, frac b, \
+              frac * out)
+
+#define cm_map_proc_cmyk(proc) \
+    void proc (gx_device * dev, \
+              frac c, frac m, frac y, frac k, \
+              frac * out)
+
+/*
+ * The following procedures come from the device.  It they are
+ * specified then  they are used to convert from the given
+ * color space to the device's color model.  Otherwise the
+ * standard conversions are used.  The procedures must be defined
+ * for a DeviceN color model
+ *
+ * Because of a bug in the Watcom C compiler, we have to split the
+ * struct from the typedef.
+ */
+struct gx_cm_color_map_procs_s {
+    cm_map_proc_gray((*map_gray));
+    cm_map_proc_rgb((*map_rgb));
+    cm_map_proc_cmyk((*map_cmyk));
+};
+
+typedef struct gx_cm_color_map_procs_s  gx_cm_color_map_procs;
+
+/*
+ * Make some routine global for use in the forwarding device.
+ */
+cm_map_proc_gray(gray_cs_to_gray_cm);
+cm_map_proc_rgb(rgb_cs_to_rgb_cm);
+cm_map_proc_cmyk(cmyk_cs_to_cmyk_cm);
+
+/*
+ * Color mapping may now be device specific, so the color space
+ * to color model mapping is separated from other maps, such as
+ * applying the current transfer function or halftone.
+ *
+ * The routine pointed to by get_cmap_procs (a field in the image
+ * state; see gxistate.h) should initialize the cm_color_map_procs
+ * pointer, using the get_color_mapping_procs method of the device.
+ *
+ * Because of a bug in the Watcom C compiler, we have to split the
+ * struct from the typedef.
+ */
 struct gx_color_map_procs_s {
     cmap_proc_gray((*map_gray));
     cmap_proc_rgb((*map_rgb));
     cmap_proc_cmyk((*map_cmyk));
     cmap_proc_rgb_alpha((*map_rgb_alpha));
+    cmap_proc_separation((*map_separation));
+    cmap_proc_devicen((*map_devicen));
 };
 typedef struct gx_color_map_procs_s gx_color_map_procs;
 
@@ -85,31 +147,122 @@
   ((pis)->cmap_procs->map_cmyk)(cc, cm, cy, ck, pdc, pis, dev, select)
 #define gx_remap_concrete_rgb_alpha(cr, cg, cb, ca, pdc, pis, dev, select)\
   ((pis)->cmap_procs->map_rgb_alpha)(cr, cg, cb, ca, pdc, pis, dev, select)
+#define gx_remap_concrete_separation(pcc, pdc, pis, dev, select)\
+  ((pis)->cmap_procs->map_separation)(pcc, pdc, pis, dev, select)
+#define gx_remap_concrete_devicen(pcc, pdc, pis, dev, select)\
+  ((pis)->cmap_procs->map_devicen)(pcc, pdc, pis, dev, select)
 
-/* Map a color, with optional tracing if we are debugging. */
+/* Map a color */
 #include "gxcindex.h"
 #include "gxcvalue.h"
-gx_color_index gx_proc_map_rgb_color(gx_device *,
-			   gx_color_value, gx_color_value, gx_color_value);
-gx_color_index gx_proc_map_rgb_alpha_color(gx_device *,
-	   gx_color_value, gx_color_value, gx_color_value, gx_color_value);
-gx_color_index gx_proc_map_cmyk_color(gx_device *,
-	   gx_color_value, gx_color_value, gx_color_value, gx_color_value);
-#ifdef DEBUG
-/* Use procedures in gxcmap.c */
-#  define gx_map_rgb_color(dev, vr, vg, vb)\
-     gx_proc_map_rgb_color(dev, vr, vg, vb)
-#  define gx_map_rgb_alpha_color(dev, vr, vg, vb, va)\
-     gx_proc_map_rgb_alpha_color(dev, vr, vg, vb, va)
-#  define gx_map_cmyk_color(dev, vc, vm, vy, vk)\
-     gx_proc_map_cmyk_color(dev, vc, vm, vy, vk)
-#else
-#  define gx_map_rgb_color(dev, vr, vg, vb)\
-     (*dev_proc(dev, map_rgb_color))(dev, vr, vg, vb)
-#  define gx_map_rgb_alpha_color(dev, vr, vg, vb, va)\
-     (*dev_proc(dev, map_rgb_alpha_color))(dev, vr, vg, vb, va)
-#  define gx_map_cmyk_color(dev, vc, vm, vy, vk)\
-     (*dev_proc(dev, map_cmyk_color))(dev, vc, vm, vy, vk)
-#endif
+
+/*
+ * These are the default routines for converting a color space into
+ * a list of device colorants.
+ */
+extern cm_map_proc_gray(gx_default_gray_cs_to_gray_cm);
+extern cm_map_proc_rgb(gx_default_rgb_cs_to_gray_cm);
+extern cm_map_proc_cmyk(gx_default_cmyk_cs_to_gray_cm);
+
+extern cm_map_proc_gray(gx_default_gray_cs_to_rgb_cm);
+extern cm_map_proc_rgb(gx_default_rgb_cs_to_rgb_cm);
+extern cm_map_proc_cmyk(gx_default_cmyk_cs_to_rgb_cm);
+
+extern cm_map_proc_gray(gx_default_gray_cs_to_cmyk_cm);
+extern cm_map_proc_rgb(gx_default_rgb_cs_to_cmyk_cm);
+extern cm_map_proc_cmyk(gx_default_cmyk_cs_to_cmyk_cm);
+
+extern cm_map_proc_gray(gx_default_gray_cs_to_cmyk_cm);
+extern cm_map_proc_rgb(gx_default_rgb_cs_to_cmyk_cm);
+extern cm_map_proc_cmyk(gx_default_cmyk_cs_to_cmyk_cm);
+
+extern cm_map_proc_gray(gx_error_gray_cs_to_cmyk_cm);
+extern cm_map_proc_rgb(gx_error_rgb_cs_to_cmyk_cm);
+extern cm_map_proc_cmyk(gx_error_cmyk_cs_to_cmyk_cm);
+
+
+/*
+  Get the mapping procedures appropriate for the currently set
+  color model.
+ */
+#define dev_t_proc_get_color_mapping_procs(proc, dev_t) \
+    const gx_cm_color_map_procs * (proc)(const dev_t * dev)
+
+#define dev_proc_get_color_mapping_procs(proc) \
+    dev_t_proc_get_color_mapping_procs(proc, gx_device)
+
+/*
+  Convert a color component name into a colorant index.
+*/
+#define dev_t_proc_get_color_comp_index(proc, dev_t) \
+    int (proc)(const dev_t * dev, const char * pname, int name_size, int src_index)
+
+#define dev_proc_get_color_comp_index(proc) \
+    dev_t_proc_get_color_comp_index(proc, gx_device)
+
+/*
+  Map a color into the device's color model.
+*/
+#define dev_t_proc_encode_color(proc, dev_t) \
+    gx_color_index (proc)(dev_t * dev, const gx_color_value colors[])
+
+#define dev_proc_encode_color(proc) \
+    dev_t_proc_encode_color(proc, gx_device)
+
+/*
+  Map a color index from the device's current color model into a list of
+  colorant values.
+*/
+#define dev_t_proc_decode_color(proc, dev_t) \
+    int (proc)(dev_t * dev, gx_color_index cindex, gx_color_value colors[])
+
+#define dev_proc_decode_color(proc) \
+    dev_t_proc_decode_color(proc, gx_device)
+
+
+
+/*
+ * These are the default routines for translating a color component
+ * name into the device colorant index.
+ */
+dev_proc_get_color_comp_index(gx_error_get_color_comp_index);
+dev_proc_get_color_comp_index(gx_default_DevGray_get_color_comp_index);
+dev_proc_get_color_comp_index(gx_default_DevRGB_get_color_comp_index);
+dev_proc_get_color_comp_index(gx_default_DevCMYK_get_color_comp_index);
+
+/*
+ * These are the default routines for getting the color space conversion
+ * routines.
+ */
+dev_proc_get_color_mapping_procs(gx_error_get_color_mapping_procs);
+dev_proc_get_color_mapping_procs(gx_default_DevGray_get_color_mapping_procs);
+dev_proc_get_color_mapping_procs(gx_default_DevRGB_get_color_mapping_procs);
+dev_proc_get_color_mapping_procs(gx_default_DevCMYK_get_color_mapping_procs);
+
+/*
+ * These are the default routines for converting a colorant value list
+ * into a gx_color_index.
+ */
+dev_proc_encode_color(gx_error_encode_color);
+dev_proc_encode_color(gx_default_encode_color);
+
+/*
+ * These are the default routines for converting a colorant value list
+ * into a gx_color_index.
+ */
+dev_proc_encode_color(gx_default_gray_fast_encode);
+dev_proc_encode_color(gx_default_gray_encode);
+
+/*
+ * These are the default routines for converting a gx_color_index into
+ * a list of device colorant values
+ */
+dev_proc_decode_color(gx_error_decode_color);
+dev_proc_decode_color(gx_default_decode_color);
+
+
+#define unit_frac(v, ftemp)\
+  (ftemp = (v),\
+   (is_fneg(ftemp) ? frac_0 : is_fge1(ftemp) ? frac_1 : float2frac(ftemp)))
 
 #endif /* gxcmap_INCLUDED */

Index: gxcomp.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxcomp.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gxcomp.h	16 Jun 2002 08:45:43 -0000	1.5
+++ gxcomp.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -25,6 +25,31 @@
 #include "gxbitfmt.h"
 
 /*
+ * Because compositor information is passed through the command list,
+ * individual compositors must be identified by some means that is
+ * independent of address space. The address of the compositor method
+ * array, gs_composite_type_t (see below), cannot be used, as it is
+ * meaningful only within a single address space.
+ *
+ * In addition, it is desirable the keep the compositor identifier
+ * size as small as possible, as this identifier must be passed through
+ * the command list for all bands whenever the compositor is invoked.
+ * Fortunately, compositor invocation is not so frequent as to warrant
+ * byte-sharing techniques, which most likely would store the identifier
+ * in some unused bits of a command code byte. Hence, the smallest
+ * reasonable size for the identifier is one byte. This allows for up
+ * to 255 compositors, which should be ample (as of this writing, there
+ * are only two compositors, only one of which can be passed through
+ * the command list).
+ *
+ * The following list is intended to enumerate all compositors. We
+ * use definitions rather than an encoding to ensure a one-byte size.
+ */
+#define GX_COMPOSITOR_ALPHA      0x01   /* DPS/Next alpha compositor */
+#define GX_COMPOSITOR_OVERPRINT  0x02   /* overprint/overprintmode compositor */
+
+
+/*
  * Define the abstract superclass for all compositing function types.
  */
 						   /*typedef struct gs_composite_s gs_composite_t; *//* in gscompt.h */
@@ -73,7 +98,8 @@
 
     /*
      * Convert the string representation of a function back to
-     * a structure, allocating the structure.
+     * a structure, allocating the structure. Return the number of
+     * bytes read, or < 0 in the event of an error.
      */
 #define composite_read_proc(proc)\
   int proc(gs_composite_t **ppcte, const byte *data, uint size,\
@@ -82,6 +108,7 @@
 
 } gs_composite_type_procs_t;
 typedef struct gs_composite_type_s {
+    byte comp_id;   /* to identify compositor passed through command list */
     gs_composite_type_procs_t procs;
 } gs_composite_type_t;
 

Index: gxcspace.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxcspace.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gxcspace.h	16 Jun 2002 08:45:43 -0000	1.7
+++ gxcspace.h	22 Aug 2002 07:12:29 -0000	1.8
@@ -88,16 +88,6 @@
   (*(pcs)->type->base_space)(pcs)
 	cs_proc_base_space((*base_space));
 
-    /*
-     * Test whether this color space is equal to another one of the same
-     * type.  Spurious 'false' answers are OK if the real test is too much
-     * work, but spurious 'true' answers are not.
-     */
-
-#define cs_proc_equal(proc)\
-  bool proc(const gs_color_space *, const gs_color_space *)
-	cs_proc_equal((*equal));
-
     /* Construct the initial color value for this space. */
 
 #define cs_proc_init_color(proc)\
@@ -145,8 +135,8 @@
     /* (Only defined for concrete color spaces.) */
 
 #define cs_proc_remap_concrete_color(proc)\
-  int proc(const frac *, gx_device_color *, const gs_imager_state *,\
-    gx_device *, gs_color_select_t)
+  int proc(const frac *, const gs_color_space * pcs, gx_device_color *,\
+	const gs_imager_state *, gx_device *, gs_color_select_t)
 	cs_proc_remap_concrete_color((*remap_concrete_color));
 
     /* Map a color directly to a device color. */
@@ -163,6 +153,22 @@
   int proc(const gs_color_space *, gs_state *)
 	cs_proc_install_cspace((*install_cspace));
 
+    /*
+     * Push the appropriate overprint compositor onto the current device.
+     * This is distinct from install_cspace as it may need to be called
+     * when the overprint parameter is changed.
+     *
+     * This routine need only be called if:
+     *   1. The color space or color model has changed, and overprint
+     *      is true.
+     *   2. The overprint mode setting has changed, and overprint is true.
+     *   3. The overprint mode setting has changed.
+     */
+
+#define cs_proc_set_overprint(proc)\
+  int proc(const gs_color_space *, gs_state *)
+	cs_proc_set_overprint((*set_overprint));
+
     /* Adjust reference counts of indirect color space components. */
 
 #define cs_proc_adjust_cspace_count(proc)\
@@ -204,8 +210,6 @@
 cs_proc_num_components(gx_num_components_3);
 cs_proc_num_components(gx_num_components_4);
 cs_proc_base_space(gx_no_base_space);
-cs_proc_equal(gx_cspace_is_equal);
-cs_proc_equal(gx_cspace_not_equal);
 cs_proc_init_color(gx_init_paint_1);
 cs_proc_init_color(gx_init_paint_3);
 cs_proc_init_color(gx_init_paint_4);
@@ -217,6 +221,8 @@
 cs_proc_concretize_color(gx_no_concretize_color);
 cs_proc_remap_color(gx_default_remap_color);
 cs_proc_install_cspace(gx_no_install_cspace);
+cs_proc_set_overprint(gx_spot_colors_set_overprint);
+cs_proc_set_overprint(gx_comp_map_set_overprint);
 cs_proc_adjust_cspace_count(gx_no_adjust_cspace_count);
 cs_proc_adjust_color_count(gx_no_adjust_color_count);
 

Index: gxdcconv.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxdcconv.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gxdcconv.c	21 Feb 2002 22:24:53 -0000	1.5
+++ gxdcconv.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -66,10 +66,10 @@
      * but they must agree with the ones in gs_init.ps.
      */
     frac bg =
-	(pis->black_generation == NULL ? frac_0 :
+	(pis == NULL ? k : pis->black_generation == NULL ? frac_0 :
 	 gx_map_color_frac(pis, k, black_generation));
     signed_frac ucr =
-	(pis->undercolor_removal == NULL ? frac_0 :
+	(pis == NULL ? k : pis->undercolor_removal == NULL ? frac_0 :
 	 gx_map_color_frac(pis, k, undercolor_removal));
 
     if (ucr == frac_1)

Index: gxdcolor.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxdcolor.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gxdcolor.c	21 Feb 2002 22:24:53 -0000	1.6
+++ gxdcolor.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -21,18 +21,25 @@
 #include "gsbittab.h"
 #include "gxdcolor.h"
 #include "gxdevice.h"
+#include "gxdevcli.h"
 
 /* Define the standard device color types. */
 
 /* 'none' means the color is not defined. */
+private dev_color_proc_save_dc(gx_dc_no_save_dc);
+private dev_color_proc_get_dev_halftone(gx_dc_no_get_dev_halftone);
 private dev_color_proc_load(gx_dc_no_load);
 private dev_color_proc_fill_rectangle(gx_dc_no_fill_rectangle);
 private dev_color_proc_fill_masked(gx_dc_no_fill_masked);
 private dev_color_proc_equal(gx_dc_no_equal);
+private dev_color_proc_write(gx_dc_no_write);
+private dev_color_proc_read(gx_dc_no_read);
+private dev_color_proc_get_nonzero_comps(gx_dc_no_get_nonzero_comps);
 const gx_device_color_type_t gx_dc_type_data_none = {
     &st_bytes,
+    gx_dc_no_save_dc, gx_dc_no_get_dev_halftone,
     gx_dc_no_load, gx_dc_no_fill_rectangle, gx_dc_no_fill_masked,
-    gx_dc_no_equal
+    gx_dc_no_equal, gx_dc_no_write, gx_dc_no_read, gx_dc_no_get_nonzero_comps
 };
 #undef gx_dc_type_none
 const gx_device_color_type_t *const gx_dc_type_none = &gx_dc_type_data_none;
@@ -45,56 +52,71 @@
 private dev_color_proc_equal(gx_dc_null_equal);
 const gx_device_color_type_t gx_dc_type_data_null = {
     &st_bytes,
+    gx_dc_no_save_dc, gx_dc_no_get_dev_halftone,
     gx_dc_null_load, gx_dc_null_fill_rectangle, gx_dc_null_fill_masked,
-    gx_dc_null_equal
+    gx_dc_null_equal, gx_dc_no_write, gx_dc_no_read, gx_dc_no_get_nonzero_comps
 };
 #undef gx_dc_type_null
 const gx_device_color_type_t *const gx_dc_type_null = &gx_dc_type_data_null;
 #define gx_dc_type_null (&gx_dc_type_data_null)
 
+private dev_color_proc_save_dc(gx_dc_pure_save_dc);
 private dev_color_proc_load(gx_dc_pure_load);
 private dev_color_proc_fill_rectangle(gx_dc_pure_fill_rectangle);
 private dev_color_proc_fill_masked(gx_dc_pure_fill_masked);
 private dev_color_proc_equal(gx_dc_pure_equal);
+private dev_color_proc_write(gx_dc_pure_write);
+private dev_color_proc_read(gx_dc_pure_read);
 const gx_device_color_type_t gx_dc_type_data_pure = {
     &st_bytes,
+    gx_dc_pure_save_dc, gx_dc_no_get_dev_halftone,
     gx_dc_pure_load, gx_dc_pure_fill_rectangle, gx_dc_pure_fill_masked,
-    gx_dc_pure_equal
+    gx_dc_pure_equal, gx_dc_pure_write, gx_dc_pure_read,
+    gx_dc_pure_get_nonzero_comps
 };
 #undef gx_dc_type_pure
 const gx_device_color_type_t *const gx_dc_type_pure = &gx_dc_type_data_pure;
 #define gx_dc_type_pure (&gx_dc_type_data_pure)
 
 /*
- * Get the black and white pixel values of a device.  The documentation for
- * the driver API says that map_rgb_color will do the right thing on CMYK
- * devices.  Unfortunately, that isn't true at present, and fixing it is too
- * much work.
+ * Get the black and white pixel values of a device.
  */
 gx_color_index
 gx_device_black(gx_device *dev)
 {
-    if (dev->cached_colors.black == gx_no_color_index)
-	dev->cached_colors.black =
-	    (dev->color_info.num_components == 4 ?
-	     (*dev_proc(dev, map_cmyk_color))
-	     (dev, (gx_color_index)0, (gx_color_index)0, (gx_color_index)0,
-	      gx_max_color_value) :
-	     (*dev_proc(dev, map_rgb_color))
-	     (dev, (gx_color_index)0, (gx_color_index)0, (gx_color_index)0));
+    if (dev->cached_colors.black == gx_no_color_index) {
+	const gx_cm_color_map_procs * cm_procs = dev_proc(dev, get_color_mapping_procs)(dev);
+        int i, ncomps = dev->color_info.num_components;
+        frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
+        gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
+
+    	/* Get color components for black (gray = 0) */
+    	cm_procs->map_gray(dev, frac_0, cm_comps);
+
+        for (i = 0; i < ncomps; i++)
+            cv[i] = frac2cv(cm_comps[i]);
+
+	dev->cached_colors.black = dev_proc(dev, encode_color)(dev, cv);
+    }
     return dev->cached_colors.black;
 }
 gx_color_index
 gx_device_white(gx_device *dev)
 {
-    if (dev->cached_colors.white == gx_no_color_index)
-	dev->cached_colors.white =
-	    (dev->color_info.num_components == 4 ?
-	     (*dev_proc(dev, map_cmyk_color))
-	     (dev, (gx_color_index)0, (gx_color_index)0, (gx_color_index)0,
-	      (gx_color_index)0) :
-	     (*dev_proc(dev, map_rgb_color))
-	     (dev, gx_max_color_value, gx_max_color_value, gx_max_color_value));
+    if (dev->cached_colors.white == gx_no_color_index) {
+	const gx_cm_color_map_procs * cm_procs = dev_proc(dev, get_color_mapping_procs)(dev);
+        int i, ncomps = dev->color_info.num_components;
+        frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
+        gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
+
+    	/* Get color components for white (gray = 1) */
+    	cm_procs->map_gray(dev, frac_1, cm_comps);
+
+        for (i = 0; i < ncomps; i++)
+            cv[i] = frac2cv(cm_comps[i]);
+
+	dev->cached_colors.white = dev_proc(dev, encode_color)(dev, cv);
+    }
     return dev->cached_colors.white;
 }
 
@@ -143,7 +165,62 @@
     return pdevc1->type->equal(pdevc1, pdevc2);
 }
 
+/*
+ * Return a device color type index. This index is used by the command
+ * list processor to identify a device color type, as the type pointer
+ * itself is meaningful only within a single address space.
+ *
+ * Currently, we ignore the pattern device colors as they cannot be
+ * passed through the command list.
+ *
+ * Returns gs_error_unknownerror for an unrecognized type.
+ */
+private  const gx_device_color_type_t * dc_color_type_table[] = {
+    gx_dc_type_none,            /* unset device color */
+    gx_dc_type_null,            /* blank (transparent) device color */
+    gx_dc_type_pure,            /* pure device color */
+    /* gx_dc_type_pattern, */   /* patterns - not used in command list */
+    gx_dc_type_ht_binary,       /* binary halftone device colors */
+    gx_dc_type_ht_colored,      /* general halftone device colors */
+    gx_dc_type_wts              /* well-tempered screen device colors */
+};
+
+int
+gx_get_dc_type_index(const gx_device_color * pdevc)
+{
+    const gx_device_color_type_t *  type = pdevc->type;
+    int                             num_types, i;
+
+    num_types = sizeof(dc_color_type_table) / sizeof(dc_color_type_table[0]);
+    for (i = 0; i < num_types && type != dc_color_type_table[i]; i++)
+        ;
+
+    return i < num_types ? i : gs_error_unknownerror;
+}
+
+/* map a device color type index into the associated method vector */
+const gx_device_color_type_t *
+gx_get_dc_type_from_index(int i)
+{
+    if ( i >= 0                                                          &&
+         i < sizeof(dc_color_type_table) / sizeof(dc_color_type_table[0])  )
+        return dc_color_type_table[i];
+    else
+        return 0;
+}
+
 /* ------ Undefined color ------ */
+private void
+gx_dc_no_save_dc(const gx_device_color * pdevc, gx_device_color_saved * psdc)
+{
+    psdc->type = pdevc->type;
+}
+
+private const gx_device_halftone *
+gx_dc_no_get_dev_halftone(const gx_device_color * pdevc)
+{
+    return 0;
+}
 
 private int
 gx_dc_no_load(gx_device_color *pdevc, const gs_imager_state *ignore_pis,
@@ -185,6 +262,41 @@
     return false;
 }
 
+private int
+gx_dc_no_write(
+    const gx_device_color *         pdevc,      /* ignored */
+    const gx_device_color_saved *   psdc,       /* ignored */
+    const gx_device *               dev,        /* ignored */
+    byte *                          data,       /* ignored */
+    uint *                          psize )
+{
+    *psize = 0;
+    return 0;
+}
+
+private int
+gx_dc_no_read(
+    gx_device_color *       pdevc,
+    const gs_imager_state * pis,                /* ignored */
+    const gx_device_color * prior_devc,         /* ignored */
+    const gx_device *       dev,                /* ignored */
+    const byte *            pdata,              /* ignored */
+    uint                    size,               /* ignored */
+    gs_memory_t *           mem )               /* ignored */
+{
+    pdevc->type = gx_dc_type_none;
+    return 0;
+}
+
+private int
+gx_dc_no_get_nonzero_comps(
+    const gx_device_color * pdevc_ignored,
+    const gx_device *       dev_ignored,
+    gx_color_index *        pcomp_bits_ignored )
+{
+    return 0;
+}
+
 /* ------ Null color ------ */
 
 private int
@@ -220,6 +332,13 @@
 
 /* ------ Pure color ------ */
 
+private void
+gx_dc_pure_save_dc(const gx_device_color * pdevc, gx_device_color_saved * psdc)
+{
+    psdc->type = pdevc->type;
+    psdc->colors.pure = pdevc->colors.pure;
+}
+
 private int
 gx_dc_pure_load(gx_device_color * pdevc, const gs_imager_state * ignore_pis,
 		gx_device * ignore_dev, gs_color_select_t ignore_select)
@@ -288,38 +407,131 @@
 	gx_dc_pure_color(pdevc1) == gx_dc_pure_color(pdevc2);
 }
 
-/* ------ Halftone color initialization ------ */
+/*
+ * Serialize a pure color.
+ *
+ * Operands:
+ *
+ *  pdevc       pointer to device color to be serialized
+ *
+ *  psdc        pointer ot saved version of last serialized color (for
+ *              this band); this is ignored
+ *  
+ *  dev         pointer to the current device, used to retrieve process
+ *              color model information
+ *
+ *  pdata       pointer to buffer in which to write the data
+ *
+ *  psize       pointer to a location that, on entry, contains the size of
+ *              the buffer pointed to by pdata; on return, the size of
+ *              the data required or actually used will be written here.
+ *
+ * Returns:
+ *
+ *  0, with *psize set to the amount of data written, if everything OK
+ *
+ *  gs_error_rangecheck, with *psize set to the size of buffer required,
+ *  if *psize was not large enough
+ *
+ *  < 0, != gs_error_rangecheck, in the event of some other error; in this
+ *  case *psize is not changed.
+ */
+private int
+gx_dc_pure_write(
+    const gx_device_color *         pdevc,
+    const gx_device_color_saved *   psdc,       /* ignored */
+    const gx_device *               dev,
+    byte *                          pdata,
+    uint *                          psize )
+{
+    /* don't bother with optimizations based on psdc */
+    return gx_dc_write_color(pdevc->colors.pure, dev, pdata, psize);
+}
 
-void
-gx_complete_rgb_halftone(gx_device_color *pdevc, gx_device_halftone *pdht)
+/*
+ * Reconstruct a pure device color from its serial representation.
+ *
+ * Operands:
+ *
+ *  pdevc       pointer to the location in which to write the
+ *              reconstructed device color
+ *
+ *  pis         pointer to the current imager state (ignored here)
+ *
+ *  prior_devc  pointer to the current device color (this is provided
+ *              separately because the device color is not part of the
+ *              imager state; it is ignored here)
+ *
+ *  dev         pointer to the current device, used to retrieve process
+ *              color model information
+ *
+ *  pdata       pointer to the buffer to be read
+ *
+ *  size        size of the buffer to be read; this should be large
+ *              enough to hold the entire color description
+ *
+ *  mem         pointer to the memory to be used for allocations
+ *              (ignored here)
+ *
+ * Returns:
+ *
+ *  # of bytes read if everthing OK, < 0 in the event of an error
+ */
+private int
+gx_dc_pure_read(
+    gx_device_color *       pdevc,
+    const gs_imager_state * pis,                /* ignored */
+    const gx_device_color * prior_devc,         /* ignored */
+    const gx_device *       dev,
+    const byte *            pdata,
+    uint                    size,
+    gs_memory_t *           mem )               /* ignored */
 {
-    pdevc->type = gx_dc_type_ht_colored;
-    pdevc->colors.colored.c_ht = pdht;
-    pdevc->colors.colored.num_components = 3;
-    pdevc->colors.colored.plane_mask =
-	(pdevc->colors.colored.c_level[0] != 0) |
-	((pdevc->colors.colored.c_level[1] != 0) << 1) |
-	((pdevc->colors.colored.c_level[2] != 0) << 2);
-    /*
-     * Color rendering won't use the fourth component, but the code that
-     * writes and reads colored halftones in the band list doesn't know that.
-     */
-    pdevc->colors.colored.c_base[3] = 0;
-    pdevc->colors.colored.c_level[3] = 0;
+    pdevc->type = gx_dc_type_pure;
+    return gx_dc_read_color(&pdevc->colors.pure, dev, pdata, size);
+}
+
+int
+gx_dc_pure_get_nonzero_comps(
+    const gx_device_color * pdevc,
+    const gx_device *       dev,
+    gx_color_index *        pcomp_bits )
+{
+    int                     code;
+    gx_color_value          cvals[GX_DEVICE_COLOR_MAX_COMPONENTS];
+
+    code = dev_proc(dev, decode_color)( (gx_device *)dev,
+                                         pdevc->colors.pure,
+                                         cvals );
+    if (code >= 0) {
+        int             i, ncomps = dev->color_info.num_components;
+        gx_color_index  mask = 0x1, comp_bits = 0;
+
+        for (i = 0; i < ncomps; i++, mask <<= 1) {
+            if (cvals[i] != 0)
+                comp_bits |= mask;
+        }
+        *pcomp_bits = comp_bits;
+        code = 0;
+    }
+
+    return code;
 }
 
+/* ------ Halftone color initialization ------ */
+
 void
-gx_complete_cmyk_halftone(gx_device_color *pdevc, gx_device_halftone *pdht)
+gx_complete_halftone(gx_device_color *pdevc, int num_comps, gx_device_halftone *pdht)
 {
+    int i, mask = 0;
+
     pdevc->type = gx_dc_type_ht_colored;
     pdevc->colors.colored.c_ht = pdht;
-    pdevc->colors.colored.num_components = 4;
+    pdevc->colors.colored.num_components = num_comps;
     pdevc->colors.colored.alpha = max_ushort;
-    pdevc->colors.colored.plane_mask =
-	(pdevc->colors.colored.c_level[0] != 0) |
-	((pdevc->colors.colored.c_level[1] != 0) << 1) |
-	((pdevc->colors.colored.c_level[2] != 0) << 2) |
-	((pdevc->colors.colored.c_level[3] != 0) << 3);
+    for (i = 0; i < num_comps; i++)
+        mask |= ((pdevc->colors.colored.c_level[i] != 0 ? 1 : 0) << i);
+    pdevc->colors.colored.plane_mask = mask;
 }
 
 /* ------ Default implementations ------ */
@@ -394,4 +606,115 @@
 	}
     }
     return 0;
+}
+
+/* ------ Serialization identification support ------ */
+
+/*
+ * Utility to write a color index.  Currently, a very simple mechanism
+ * is used, much simpler than that used by other command-list writers. This
+ * should be sufficient for most situations.
+ *
+ * Operands:
+ *
+ *  color       color to be serialized.
+ *
+ *  dev         pointer to the current device, used to retrieve process
+ *              color model information
+ *
+ *  pdata       pointer to buffer in which to write the data
+ *
+ *  psize       pointer to a location that, on entry, contains the size of
+ *              the buffer pointed to by pdata; on return, the size of
+ *              the data required or actually used will be written here.
+ *
+ * Returns:
+ *
+ *  0, with *psize set to the amount of data written, if everything OK
+ *
+ *  gs_error_rangecheck, with *psize set to the size of buffer required,
+ *  if *psize was not large enough
+ *
+ *  < 0, != gs_error_rangecheck, in the event of some other error; in this
+ *  case *psize is not changed.
+ */
+int
+gx_dc_write_color(
+    gx_color_index      color,
+    const gx_device *   dev,
+    byte *              pdata,
+    uint *              psize )
+{
+    int                 depth = dev->color_info.depth;
+    int                 num_bytes = (depth + 8) >> 3;   /* NB: +8, not +7 */
+
+    /* gx_no_color_index is encoded as a single byte */
+    if (color == gx_no_color_index)
+        num_bytes = 1;
+
+    /* check for adequate space */
+    if (*psize < num_bytes) {
+        *psize = num_bytes;
+        return gs_error_rangecheck;
+    }
+    *psize = num_bytes;
+
+    /* gx_no_color_index is a single byte of 0xff */
+    if (color == gx_no_color_index) {
+        *psize = 1;
+        *pdata = 0xff;
+    } else {
+        if (depth < 8 * sizeof(gx_color_index))
+            color &= ((gx_color_index)1 << depth) - 1;
+        while (--num_bytes >= 0) {
+            pdata[num_bytes] = color & 0xff;
+            color >>= 8;
+        }
+    }
+    return 0;
+}
+
+/*
+ * Utility to reconstruct device color from its serial representation.
+ *
+ * Operands:
+ *
+ *  pcolor      pointer to the location in which to write the
+ *              reconstucted color
+ *
+ *  dev         pointer to the current device, used to retrieve process
+ *              color model information
+ *
+ *  pdata       pointer to the buffer to be read
+ *
+ *  size        size of the buffer to be read; this is expected to be
+ *              large enough for the full color
+ *
+ * Returns: # of bytes read, or < 0 in the event of an error
+ */
+int
+gx_dc_read_color(
+    gx_color_index *    pcolor,
+    const gx_device *   dev,
+    const byte *        pdata,
+    int                 size )
+{
+    gx_color_index      color = 0;
+    int                 depth = dev->color_info.depth;
+    int                 i, num_bytes = (depth + 8) >> 3;   /* NB: +8, not +7 */
+
+    /* check that enough data has been provided */
+    if (size < 1 || (pdata[0] != 0xff && size < num_bytes))
+        return gs_error_rangecheck;
+
+    /* check of gx_no_color_index */
+    if (pdata[0] == 0xff) {
+        *pcolor = gx_no_color_index;
+        return 1;
+    }
+
+    /* num_bytes > sizeof(gx_color_index), discard first byte */
+    for (i = (num_bytes >= sizeof(gx_color_index) ? 1 : 0); i < num_bytes; i++)
+        color = (color << 8) | pdata[i];
+    return num_bytes;
 }

Index: gxdcolor.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxdcolor.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gxdcolor.h	16 Jun 2002 08:45:43 -0000	1.6
+++ gxdcolor.h	22 Aug 2002 07:12:29 -0000	1.7
@@ -76,6 +76,26 @@
     gs_memory_type_ptr_t stype;
 
     /*
+     * Accessors.
+     *
+     * The "save_dc" method fills in a gx_device_color_saved structure
+     * for the operand device color. This is may be used with the
+     * "write" and "read" methods (see below) to minimize command list
+     * size.
+     *
+     * The "get_dev_halftone" method returns a pointer to the device
+     * halftone used by the current color, or NULL if there is no such
+     * halftone (i.e.: the device color is a pure color).
+     */
+#define dev_color_proc_save_dc(proc)\
+  void proc(const gx_device_color * pdevc, gx_device_color_saved * psdc)
+			 dev_color_proc_save_dc((*save_dc));
+
+#define dev_color_proc_get_dev_halftone(proc)\
+  const gx_device_halftone * proc(const gx_device_color * pdevc)
+			 dev_color_proc_get_dev_halftone((*get_dev_halftone));
+
+    /*
      * If necessary and possible, load the halftone or Pattern cache
      * with the rendering of this color.
      */
@@ -117,6 +137,96 @@
   bool proc(const gx_device_color *pdevc1, const gx_device_color *pdevc2)
                          dev_color_proc_equal((*equal));
 
+    /*
+     * Serialize and deserialize a device color.
+     *
+     * The "write" routine converts a device color into a string for
+     * writing to the command list. *psize is the amount of space
+     * available. If it is large enough, the procedure sets *psize to
+     * the amount actually used and returns 0; otherwise, if no other
+     * problem is detected, *psize is set to the amount required and
+     * gs_error_rangecheck is returned. If some other error is detected,
+     * *psize is left unchanged and the error code is returned.
+     *
+     * The "read" routine converts the string representation back into
+     * the full device color structure. The value returned is the number
+     * of bytes actually read, or < 0 in the event of an error.
+     *
+     * As with any instance of virtual serialization, the command list
+     * code must include its own identifier of the color space type in
+     * the command list, so as to know which read routine to call. The
+     * procedures gx_dc_get_type_code and gx_dc_get_type_from_code are
+     * provided to support this operation.
+     *
+     * For the write operation, psdc points to the saved version of the
+     * color previously stored for a particular band. When the band is
+     * rendered this will be the current device color just before the
+     * color being serialized is read. This information can be used to
+     * make encoding more efficient. To avoid any optimization, set
+     * psdc to be a null pointer.
+     *
+     * Note that the caller is always responsible for serializing and
+     * transmitting the device halftone, if this is required. Because
+     * device halftones change infrequently, they are transmitted as
+     * "all bands" commands. This is only possible if they are serialized
+     * separately, which is why they cannot be handled by these methods.
+     *
+     * The first device color serialized after the halftone has been
+     * changed should always contain complete information; i.e.: psdc
+     * should be set to a null pointer. This is necessary as the command
+     * list reader will have reset its device color when the halftone is
+     * changed, so informaition from the prior device color will no
+     * longer be available.
+     *
+     * For the read and method, the imager state is passed as an operand,
+     * which allows the routine to access the current device halftone
+     * (always required). Also passed in a pointer to the existing device
+     * color, as this is not part of the imager state. If the writer was
+     * passed a non-null psdc operand, *prior_devc must reflect the
+     * information contained in *psdc.
+     *
+     * NB: For the read method, pdevc and prior_devc may and usually
+     *     will be the same. Code implementing this method must be able
+     *     to handle this situation.
+     *
+     * The device is provided as an operand for both routines to pass
+     * color model information. This allows more compact encoding of
+     * various pieces of information, in particular color indices.
+     */
+#define dev_color_proc_write(proc)\
+  int proc(const gx_device_color *pdevc, const gx_device_color_saved *psdc,\
+    const gx_device * dev, byte *data, uint *psize)
+			dev_color_proc_write((*write));
+
+#define dev_color_proc_read(proc)\
+  int proc(gx_device_color *pdevc, const gs_imager_state * pis,\
+    const gx_device_color *prior_devc, const gx_device * dev,\
+    const byte *data, uint size, gs_memory_t *mem)
+			dev_color_proc_read((*read));
+
+    /*
+     * Identify which color model components have non-zero intensities in
+     * a device color. If this is the case, set the (1 << i)'th bit of
+     * *pcomp_bits to 1; otherwise set it to 0. This method is used to
+     * support PDF's overprint mode. The *pcomp_bits value is known to be
+     * large enough for the number of device color components, and should
+     * be initialized to 0 by the client.
+     *
+     * Returns 0 except for shading and/or color tiling patterns, for
+     * which  1 is returned. For those two "colors", lower level device
+     * colors must be examined to determine the desired information. This
+     * is not a problem for shading colors, as overprint mode does not
+     * apply to them. It is potentially a problem for colored tiling
+     * patterns, but the situations in which it is a problem other, long-
+     * standing implementation difficulties for patterns would also be a
+     * problem.
+     *
+     * Returns of < 0 indicate an error, and shouldn't be possible.
+     */
+#define dev_color_proc_get_nonzero_comps(proc)\
+  int proc(const gx_device_color * pdevc, const gx_device * dev,\
+    gx_color_index * pcomp_bits)
+                         dev_color_proc_get_nonzero_comps((*get_nonzero_comps));
 };
 
 /* Define the default implementation of fill_masked. */
@@ -139,7 +249,19 @@
 #define gx_dc_type_ht_binary (&gx_dc_type_data_ht_binary)
       gx_dc_type_data_ht_binary,	/* gxht.c */
 #define gx_dc_type_ht_colored (&gx_dc_type_data_ht_colored)
-      gx_dc_type_data_ht_colored;	/* gxcht.c */
+      gx_dc_type_data_ht_colored,	/* gxcht.c */
+#define gx_dc_type_wts (&gx_dc_type_data_wts)
+      gx_dc_type_data_wts;	/* gxwts.c */
+
+/* the following are exported for the benefit of gsptype1.c */
+extern  dev_color_proc_get_nonzero_comps(gx_dc_pure_get_nonzero_comps);
+extern  dev_color_proc_get_nonzero_comps(gx_dc_ht_binary_get_nonzero_comps);
+extern  dev_color_proc_get_nonzero_comps(gx_dc_ht_colored_get_nonzero_comps);
+
+/* convert between color types and color type indices */
+extern int gx_get_dc_type_index(const gx_device_color *);
+extern const gx_device_color_type_t * gx_get_dc_type_from_index(int);
+
 
 #define gs_color_writes_pure(pgs)\
   color_writes_pure((pgs)->dev_color, (pgs)->log_op)
@@ -179,5 +301,23 @@
   gx_fill_rectangle_device_rop(x, y, w, h, pdevc, (pgs)->device, lop)
 #define gx_fill_rectangle(x, y, w, h, pdevc, pgs)\
   gx_fill_rectangle_rop(x, y, w, h, pdevc, (pgs)->log_op, pgs)
+
+/*
+ * Utilities to write/read color indices. Currently, a very simple mechanism
+ * is used, much simpler than that used by other command-list writers. This
+ * should be sufficient for most situations.
+ *
+ * The operand set and return values are those of the device color write/read
+ * routines.
+ */
+extern  int     gx_dc_write_color( gx_color_index       color,
+                                   const gx_device *    dev,
+                                   byte *               pdata,
+                                   uint *               psize );
+
+extern  int     gx_dc_read_color( gx_color_index *  pcolor,
+                                  const gx_device * dev,
+                                  const byte *      pdata,
+                                  int               size );
 
 #endif /* gxdcolor_INCLUDED */

Index: gxdevcli.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxdevcli.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- gxdevcli.h	16 Jun 2002 08:45:43 -0000	1.10
+++ gxdevcli.h	22 Aug 2002 07:12:29 -0000	1.11
@@ -35,6 +35,7 @@
 #include "gxcvalue.h"
 #include "gxfixed.h"
 #include "gxtext.h"
+#include "gxcmap.h"
 
 /* See Drivers.htm for documentation of the driver interface. */
 
@@ -176,38 +177,360 @@
     int text_bits;		/* 1,2,4 */
     int graphics_bits;		/* ditto */
 } gx_device_anti_alias_info;
+
+
+/*
+ * Possible values for the separable_and_linear flag in the
+ * gx_device_color_info structure. These form an order, with lower
+ * values having weaker properties.
+ *
+ *  GX_CINFO_SEP_LIN_UNKNOWN
+ *    The properties of the color encoding are not yet known. This is
+ *    always a safe default value.
+ *
+ *  GX_CINFO_SEP_LIN_NONE
+ *    The encoding is not separable and linear. If this value is set,
+ *    the device must provide an encode_color method, either directly
+ *    or via map_rgb_color/map_cmyk_color methods. This setting is
+ *    only legitimate for color models with 4 or fewer components.
+ *
+ *  GX_CINFO_SEP_LIN
+ *    A separable and linear encoding has the separability and
+ *    linearity properties.
+ *
+ *    Encodings with this property are completely characterized 
+ *    by the comp_shift array. Hence, there is no need to provide
+ *    an encode_color procedure for such devices, though the device
+ *    creator may choose to do so for performance reasons (e.g.: when
+ *     each color component is assigned a byte).
+ */
+
+typedef enum {
+    GX_CINFO_UNKNOWN_SEP_LIN = -1,
+    GX_CINFO_SEP_LIN_NONE = 0,
+    GX_CINFO_SEP_LIN
+} gx_color_enc_sep_lin_t;
+
+/*
+ * Color model component polarity. An "unknown" value has been added to
+ * this enumeration.
+ */
+typedef enum {
+    GX_CINFO_POLARITY_UNKNOWN = -1,
+    GX_CINFO_POLARITY_SUBTRACTIVE = 0,
+    GX_CINFO_POLARITY_ADDITIVE
+} gx_color_polarity_t;
+
+/* component index value used to indicate no color component.  */
+#define GX_CINFO_COMP_NO_INDEX 0xff
+
+/*
+ * Additional possible value for cinfo.gray_index, to indicate which
+ * component, if any, qualifies as the "gray" component.
+ */
+#define GX_CINFO_COMP_INDEX_UNKNOWN 0xfe
+
+/*
+ * The enlarged color model information structure: Some of the
+ * information that was implicit in the component number in
+ * the earlier conventions (component names, polarity, mapping
+ * functions) are now explicitly provided.
+ *
+ * Also included is some information regarding the encoding of
+ * color information into gx_color_index. Some of this information
+ * was previously gathered indirectly from the mapping
+ * functions in the existing code, specifically to speed up the
+ * halftoned color rendering operator (see
+ * gx_dc_ht_colored_fill_rectangle in gxcht.c). The information
+ * is now provided explicitly because such optimizations are
+ * more critical when the number of color components is large.
+ *
+ * Note: no pointers have been added to this structure, so there
+ *       is no requirement for a structure descriptor.
+ */
 typedef struct gx_device_color_info_s {
-    int num_components;		/* doesn't include alpha: */
-				/* 0 = alpha only, 1 = gray only, */
-				/* 3 = RGB, 4 = CMYK */
-    int depth;			/* # of bits per pixel */
-    gx_color_value max_gray;	/* # of distinct gray levels -1 */
-    gx_color_value max_color;	/* # of distinct color levels -1 */
-				/* (only relevant if num_comp. > 1) */
-    gx_color_value dither_grays;	/* size of gray ramp for dithering */
-    gx_color_value dither_colors;	/* size of color cube ditto */
-				/* (only relevant if num_comp. > 1) */
+
+    /*
+     * max_components is the maximum number of components for all
+     * color models supported by this device. This does not include
+     * any alpha components.
+     */
+    int max_components;
+
+    /*
+     * The number of color components. This does not include any
+     * alpha-channel information, which may be integrated into
+     * the gx_color_index but is otherwise passed as a separate
+     * component.
+     */
+    int num_components;
+
+    /*
+     * Polarity of the components of the color space, either
+     * additive or subtractive. This is used to interpret transfer
+     * functions and halftone threshold arrays. Possible values
+     * are GX_CM_POLARITY_ADDITIVE or GX_CM_POLARITY_SUBTRACTIVE
+     */
+    gx_color_polarity_t polarity;
+
+    /*
+     * The number of bits of gx_color_index actually used. 
+     * This must be <= sizeof(gx_color_index), which is usually 64.
+     */
+    byte depth;
+
+    /*
+     * Index of the gray color component, if any. The max_gray and
+     * dither_gray values apply to this component only; all other
+     * components use the max_color and dither_color values.
+     *
+     * This will be GX_CINFO_COMP_NO_INDEX if there is no gray 
+     * component.
+     */
+    byte gray_index;
+
+    /*
+     * max_gray and max_color are the number of distinct native
+     * intensity levels, less 1, for the gray and all other color
+     * components, respectively. For nearly all current devices
+     * that support both gray and non-gray components, the two
+     * parameters have the same value.
+     *
+     * dither_grays and dither_colors are the number of intensity
+     * levels between which halftoning can occur, for the gray and
+     * all other color components, respectively. This is
+     * essentially redundant information: in all reasonable cases,
+     * dither_grays = max_gray + 1 and dither_colors = max_color + 1.
+     * These parameters are, however, extensively used in the
+     * current code, and thus have been retained.
+     *
+     * Note that the non-gray values may now be relevant even if
+     * num_components == 1. This simplifies the handling of devices
+     * with configurable color models which may be set for a single
+     * non-gray color model.
+     */
+    gx_color_value max_gray;	/* # of distinct color levels -1 */
+    gx_color_value max_color;
+
+    gx_color_value dither_grays;
+    gx_color_value dither_colors;
+
+    /*
+     * Information to control super-sampling of objects to support
+     * anti-aliasing.
+     */
     gx_device_anti_alias_info anti_alias;
+
+    /*
+     * Flag to indicate if gx_color_index for this device may be divided
+     * into individual fields for each component. This is almost always
+     * the case for printers, and is the case for most modern displays
+     * as well. When this is the case, halftoning may be performed
+     * separately for each component, which greatly simplifies processing
+     * when the number of color components is large.
+     *
+     * If the gx_color_index is separable in this manner, the comp_shift
+     * array provides the location of the low-order bit for each
+     * component. This may be filled in by the client, but need not be.
+     * If it is not provided, it will be calculated based on the values
+     * in the max_gray and max_color fields as follows:
+     *
+     *     comp_shift[num_components - 1] = 0,
+     *     comp_shift[i] = comp_shift[i + 1]
+     *                      + ( i == gray_index ? ceil(log2(max_gray + 1))
+     *                                          : ceil(log2(max_color + 1)) )
+     *
+     * The comp_mask and comp_bits fields should be left empty by the client.
+     * They will be filled in during initialization using the following
+     * mechanism:
+     *
+     *     comp_bits[i] = ( i == gray_index ? ceil(log2(max_gray + 1))
+     *                                      : ceil(log2(max_color + 1)) )
+     *
+     *     comp_mask[i] = (((gx_color_index)1 << comp_bits[i]) - 1)
+     *                       << comp_shift[i]
+     *
+     * (For current devices, it is almost always the case that
+     * max_gray == max_color, if the color model contains both gray and
+     * non-gray components.)
+     *
+     * If separable_and_linear is not set, the data in the other fields
+     * is unpredictable and should be ignored.
+     */
+    gx_color_enc_sep_lin_t separable_and_linear;
+    byte                   comp_shift[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    byte                   comp_bits[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    gx_color_index         comp_mask[GX_DEVICE_COLOR_MAX_COMPONENTS];
+    /*
+     * Pointer to name for the process color model.
+     */
+    const char * cm_name;
+
 } gx_device_color_info;
 
-#define dci_alpha_values(nc,depth,mg,mc,dg,dc,ta,ga)\
-  { nc, depth, mg, mc, dg, dc, { ta, ga } }
+/* NB encoding flag ignored */
+#define dci_extended_alpha_values(mcmp, nc, p, d, gi, mg, \
+		        mc, dg, dc, ta, ga, sl, cn)   \
+    {mcmp /* max components */, \
+     nc /* number components */, \
+     p /* polarity */, \
+     d /* depth */, \
+     gi /* gray index */, \
+     mg /* max gray */, \
+     mc /* max color */, \
+     dg /* dither grays */, \
+     dc /* dither colors */, \
+     { ta, ga } /* antialias info text, graphics */, \
+     sl /* separable_and_linear */, \
+     { 0 } /* component shift */, \
+     { 0 } /* component bits */, \
+     { 0 } /* component mask */, \
+     cn /* process color name */ }
+
+/*
+ * The "has color" macro requires a slightly different definition
+ * with the more general color models.
+ */
+#define gx_device_has_color(dev)                           \
+   ( (dev)->color_info.num_components > 1 ||                \
+     (dev)->color_info.gray_index == GX_CINFO_COMP_NO_INDEX )
+
+
+/* parameter initialization macros for backwards compatibility */
+
+/*
+ * These macros are needed to define values for fields added when
+ * DeviceN compatibility was added.  Previously the graphics
+ * library and the much of the device code examined the number of
+ * components and assume that 1 --> DeviceGray, 3-->DeviceRGB,
+ * and 4--> DeviceCMYK.  Since the old device code does not
+ * specify a color model, these macros make the same assumption.
+ * This assumption is incorrect for a DeviceN device and thus
+ * the following macros should not be used.  The previously
+ * defined macros should be used for new devices.
+ */
+
+#define dci_std_cm_name(nc)                 \
+    ( (nc) == 1 ? "DeviceGray"              \
+                : ((nc) == 3 ? "DeviceRGB"  \
+                             : "DeviceCMYK") )
+
+#define dci_std_polarity(nc)                    \
+    ( (nc) == 4 ? GX_CINFO_POLARITY_SUBTRACTIVE \
+                : GX_CINFO_POLARITY_ADDITIVE )
+
+      /*
+       * Get the default gray_index value, based on the number of color
+       * components. Note that this must be consistent with the index
+       * implicitly used by the get_color_comp_index method and the
+       * procedures in the structure returned by the
+       * get_color_mapping_procs method.
+       */
+#define dci_std_gray_index(nc)    \
+    ((nc) == 3 ? GX_CINFO_COMP_NO_INDEX : (nc) - 1)
+
+#define dci_alpha_values(nc, depth, mg, mc, dg, dc, ta, ga) \
+    dci_extended_alpha_values(nc, nc,			    \
+                              dci_std_polarity(nc),         \
+                              depth,                        \
+                              dci_std_gray_index(nc),       \
+                              mg, mc, dg, dc, ta, ga,       \
+                              GX_CINFO_UNKNOWN_SEP_LIN,     \
+			      dci_std_cm_name(nc) )
+
+
+/*
+ * Determine the depth corresponding to a color_bits specification.
+ * Note that color_bits == 0 ==> depth == 0; surprisingly this
+ * case is used.
+*/
+#define dci_std_color_depth(color_bits)   \
+    ((color_bits) == 1 ? 1 : ((color_bits) + 7) & ~7)
+
+/*
+ * Determine the number of components corresponding to a color_bits
+ * specification. A device is monochrome only if it is bi-level;
+ * the 4 and 8 bit cases are handled as mapped color displays (for
+ * compatibility with existing code). The peculiar color_bits = 0
+ * case is considered monochrome, for no apparent reason.
+ */
+#define dci_std_color_num_components(color_bits)      \
+    ( (color_bits) <= 1 ? 1                           \
+                      : ((color_bits) % 3 == 0 ||     \
+                         (color_bits) == 4     ||     \
+                         (color_bits) == 8       ) ? 3 : 4 )
+
+/*
+ * The number of bits assigned to the gray/black color component,
+ * assuming there is such a component. The underlying assumption
+ * is that any extra bits are assigned to this component.
+ */
+#define dci_std_gray_bits(nc, color_bits)    \
+    ((color_bits) - ((nc) - 1) * ((color_bits) / (nc)))
+
+/*
+ * The number of bits assigned to a color component. The underlying
+ * assumptions are that there is a gray component if nc != 3, and
+ * that the gray component uses any extra bits.
+ */
+#define dci_std_color_bits(nc, color_bits)                        \
+    ( (nc) == 3                                                   \
+        ? (color_bits) / (nc)                                     \
+        : ( (nc) == 1                                             \
+              ? 0                                                 \
+              : ((color_bits) - dci_std_gray_bits(nc, color_bits))\
+                     / ((nc) - 1) ) )
+
+/*
+ * Determine the max_gray and max_color values based on the number
+ * of components and the color_bits value. See the comments above
+ * for information on the underlying assumptions.
+ */
+#define dci_std_color_max_gray(nc, color_bits)            \
+    ( (nc) == 3                                           \
+        ? 0                                               \
+        : ( dci_std_gray_bits(nc, color_bits) >= 8        \
+            ? 255                                         \
+            : (1 << dci_std_gray_bits(nc, color_bits)) - 1 ) )
+
+#define dci_std_color_max_color(nc, color_bits)               \
+    ( (nc) == 1                                               \
+        ? 0                                                   \
+        : ( dci_std_color_bits(nc, color_bits) >= 8           \
+            ? 255                                             \
+            : (1 << dci_std_color_bits(nc, color_bits)) - 1 ) )
+
+
+/*
+ * Define a color model based strictly on the number of bits
+ * available for color representation. Please note, this is only
+ * intended to work for a limited set of devices.
+ */
+#define dci_std_color_(nc, color_bits)                        \
+    dci_values( nc,                                           \
+                dci_std_color_depth(color_bits),              \
+                dci_std_color_max_gray(nc, color_bits),       \
+                dci_std_color_max_color(nc, color_bits),      \
+                dci_std_color_max_gray(nc, color_bits) + 1,   \
+                dci_std_color_max_color(nc, color_bits) + 1 )
+
+#define dci_std_color(color_bits)                             \
+    dci_std_color_( dci_std_color_num_components(color_bits), \
+                    color_bits )
+
 #define dci_values(nc,depth,mg,mc,dg,dc)\
   dci_alpha_values(nc, depth, mg, mc, dg, dc, 1, 1)
-#define dci_std_color(color_bits)\
-  dci_values(\
-    (color_bits == 32 ? 4 : color_bits > 1 ? 3 : 1),\
-    ((color_bits > 1) & (color_bits < 8) ? 8 : color_bits),\
-    (color_bits >= 8 ? 255 : 1),\
-    (color_bits >= 8 ? 255 : color_bits > 1 ? 1 : 0),\
-    (color_bits >= 8 ? 5 : 2),\
-    (color_bits >= 8 ? 5 : color_bits > 1 ? 2 : 0)\
-  )
 #define dci_black_and_white dci_std_color(1)
 #define dci_black_and_white_() dci_black_and_white
 #define dci_color(depth,maxv,dither)\
   dci_values(3, depth, maxv, maxv, dither, dither)
-#define gx_device_has_color(dev) ((dev)->color_info.num_components > 1)
+
+/*
+ * Macro to access the name of the process color model.
+ */
+#define get_process_color_model_name(dev) \
+    ((dev)->color_info.cm_name)
+
 
 /* Structure for device procedures. */
 typedef struct gx_device_procs_s gx_device_procs;
@@ -254,13 +577,6 @@
  * (using the procs record, not the static_procs pointer, to call the
  * driver procedures).
  *
- * Device procedures other than put_params MUST NOT change the state of
- * is_open.  put_params may change the state of is_open from true to false.
- * Changing the state of is_open in any other device procedure may lead to
- * unpredictable misfunctioning.
- * Most device procedures may assume that is_open is true: for details,
- * see the documentation in doc/Drivers.htm.
- *
  * The choice of the name Margins (rather than, say, HWOffset), and the
  * specification in terms of a default device resolution rather than
  * 1/72" units, are due to Adobe.
@@ -353,6 +669,7 @@
 #define assign_dev_procs(todev, fromdev)\
   ((todev)->procs = (fromdev)->procs)
 
+
 /* ---------------- Device procedures ---------------- */
 
 /* Define an opaque type for parameter lists. */
@@ -398,8 +715,7 @@
   dev_t_proc_close_device(proc, gx_device)
 
 #define dev_t_proc_map_rgb_color(proc, dev_t)\
-  gx_color_index proc(dev_t *dev,\
-    gx_color_value red, gx_color_value green, gx_color_value blue)
+  gx_color_index proc(dev_t *dev, const gx_color_value cv[])
 #define dev_proc_map_rgb_color(proc)\
   dev_t_proc_map_rgb_color(proc, gx_device)
 
@@ -470,9 +786,7 @@
 		/* Added in release 2.6 */
 
 #define dev_t_proc_map_cmyk_color(proc, dev_t)\
-  gx_color_index proc(dev_t *dev,\
-    gx_color_value cyan, gx_color_value magenta, gx_color_value yellow,\
-    gx_color_value black)
+  gx_color_index proc(dev_t *dev, const gx_color_value cv[])
 #define dev_proc_map_cmyk_color(proc)\
   dev_t_proc_map_cmyk_color(proc, gx_device)
 
@@ -785,6 +1099,22 @@
 
      /* (end of transparency driver interface extensions) */
 
+     /* (start of DeviceN color support) */
+/*
+ * The following macros are defined in gxcmap.h
+ *
+ * dev_t_proc_get_color_mapping_procs
+ * dev_proc_get_color_mapping_procs
+ * dev_t_proc_get_color_comp_index
+ * dev_proc_get_color_comp_index
+ * dev_t_proc_encode_color
+ * dev_proc_encode_color
+ * dev_t_proc_decode_color
+ * dev_proc_decode_color
+ */
+     /* (end of DeviceN color support) */
+
+
 /* Define the device procedure vector template proper. */
 
 #define gx_device_proc_struct(dev_t)\
@@ -837,7 +1167,13 @@
 	dev_t_proc_begin_transparency_mask((*begin_transparency_mask), dev_t);\
 	dev_t_proc_end_transparency_mask((*end_transparency_mask), dev_t);\
 	dev_t_proc_discard_transparency_layer((*discard_transparency_layer), dev_t);\
+	dev_t_proc_get_color_mapping_procs((*get_color_mapping_procs), dev_t); \
+	dev_t_proc_get_color_comp_index((*get_color_comp_index), dev_t); \
+	dev_t_proc_encode_color((*encode_color), dev_t); \
+	dev_t_proc_decode_color((*decode_color), dev_t); \
 }
+
+
 /*
  * Provide procedures for passing image data.  image_data and end_image
  * are the equivalents of the obsolete driver procedures.  image_plane_data

Index: gxdevice.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxdevice.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- gxdevice.h	18 Jul 2002 11:01:44 -0000	1.9
+++ gxdevice.h	22 Aug 2002 07:12:29 -0000	1.10
@@ -150,6 +150,13 @@
 	offset_margin_values(xoff, yoff, lm, bm, rm, tm),\
 	std_device_part3_()
 
+#define std_device_full_body_type_extended(dtype, pprocs, dname, stype, w, h, xdpi, ydpi, mcomp, ncomp, pol, depth, gi, mg, mc, dg, dc, ef, cn, xoff, yoff, lm, bm, rm, tm)\
+	std_device_part1_(dtype, pprocs, dname, stype, open_init_closed),\
+        dci_extended_alpha_values(mcomp, ncomp, pol, depth, gi, mg, mc, dg, dc, 1, 1, ef, cn), \
+	std_device_part2_(w, h, xdpi, ydpi),\
+	offset_margin_values(xoff, yoff, lm, bm, rm, tm),\
+	std_device_part3_()
+
 #define std_device_full_body(dtype, pprocs, dname, w, h, xdpi, ydpi, ncomp, depth, mg, mc, dg, dc, xoff, yoff, lm, bm, rm, tm)\
 	std_device_full_body_type(dtype, pprocs, dname, 0, w, h, xdpi, ydpi,\
 	    ncomp, depth, mg, mc, dg, dc, xoff, yoff, lm, bm, rm, tm)
@@ -280,8 +287,10 @@
 dev_proc_map_rgb_color(gx_default_rgb_map_rgb_color);
 dev_proc_map_cmyk_color(cmyk_1bit_map_cmyk_color);
 dev_proc_map_color_rgb(cmyk_1bit_map_color_rgb);
+dev_proc_decode_color(cmyk_1bit_map_color_cmyk);
 dev_proc_map_cmyk_color(cmyk_8bit_map_cmyk_color);
 dev_proc_map_color_rgb(cmyk_8bit_map_color_rgb);
+dev_proc_decode_color(cmyk_8bit_map_color_cmyk);
 
 /* Default implementations for forwarding devices */
 dev_proc_get_initial_matrix(gx_forward_get_initial_matrix);
@@ -324,6 +333,10 @@
 /* There is no forward_create_compositor (see Drivers.htm). */
 dev_proc_get_hardware_params(gx_forward_get_hardware_params);
 dev_proc_text_begin(gx_forward_text_begin);
+dev_proc_get_color_mapping_procs(gx_forward_get_color_mapping_procs);
+dev_proc_get_color_comp_index(gx_forward_get_color_comp_index);
+dev_proc_encode_color(gx_forward_encode_color);
+dev_proc_decode_color(gx_forward_decode_color);
 
 /* ---------------- Implementation utilities ---------------- */
 
@@ -338,6 +351,11 @@
 void gx_device_forward_color_procs(gx_device_forward *);
 
 /*
+ * If a device has a linear and separable encode color function then
+ * set up the comp_bits, comp_mask, and comp_shift fields.
+ */
+void set_linear_color_bits_mask_shift(gx_device * dev);
+/*
  * Copy the color mapping procedures from the target if they are
  * standard ones (saving a level of procedure call at mapping time).
  */
@@ -346,11 +364,11 @@
 /* Get the black and white pixel values of a device. */
 gx_color_index gx_device_black(gx_device *dev);
 #define gx_device_black_inline(dev)\
-  ((dev)->cached_colors.black != gx_no_color_index ?\
+  ((dev)->cached_colors.black == gx_no_color_index ?\
    gx_device_black(dev) : (dev)->cached_colors.black)
 gx_color_index gx_device_white(gx_device *dev);
 #define gx_device_white_inline(dev)\
-  ((dev)->cached_colors.white != gx_no_color_index ?\
+  ((dev)->cached_colors.white == gx_no_color_index ?\
    gx_device_white(dev) : (dev)->cached_colors.white)
 
 /* Clear the black/white pixel cache. */

Index: gxdevmem.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxdevmem.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gxdevmem.h	16 Jun 2002 08:45:43 -0000	1.5
+++ gxdevmem.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -112,6 +112,26 @@
 	gx_color_index rgb;	/* cache key */
 	bits32 rgbr, gbrg, brgb;	/* cache value */
     } color24;
+    /* Following is only used for 40-bit color. */
+    struct _c40 {
+	gx_color_index abcde;	/* cache key */
+	bits32 abcd, bcde, cdea, deab, eabc;	/* cache value */
+    } color40;
+    /* Following is only used for 48-bit color. */
+    struct _c48 {
+	gx_color_index abcdef;	/* cache key */
+	bits32 abcd, cdef, efab;	/* cache value */
+    } color48;
+    /* Following is only used for 56-bit color. */
+    struct _c56 {
+	gx_color_index abcdefg;	/* cache key */
+	bits32 abcd, bcde, cdef, defg, efga, fgab, gabc;	/* cache value */
+    } color56;
+    /* Following is only used for 64-bit color. */
+    struct _c64 {
+	gx_color_index abcdefgh;	/* cache key */
+	bits32 abcd, efgh;	/* cache value */
+    } color64;
     /* Following are only used for alpha buffers. */
     /* The client initializes those marked with $; */
     /* they don't change after initialization. */
@@ -145,6 +165,10 @@
 	(byte **)0,		/* line_ptrs (filled in by mem_open) */\
 	{ (byte *)0, 0 },	/* palette (filled in for color) */\
 	{ gx_no_color_index },	/* color24 */\
+	{ gx_no_color_index },	/* color40 */\
+	{ gx_no_color_index },	/* color48 */\
+	{ gx_no_color_index },	/* color56 */\
+	{ gx_no_color_index },	/* color64 */\
 	{ 0, 0 }, 0,		/* scale, log2_alpha_bits */\
 	0, 0, 0, 0,		/* mapped_* */\
 	gx_no_color_index	/* save_color */

Index: gxdht.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxdht.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gxdht.h	16 Jun 2002 08:45:43 -0000	1.7
+++ gxdht.h	22 Aug 2002 07:12:29 -0000	1.8
@@ -21,10 +21,12 @@
 #  define gxdht_INCLUDED
 
 #include "gsrefct.h"
-#include "gscsepnm.h"
 #include "gsmatrix.h"
 #include "gxarith.h"		/* for igcd */
 #include "gxhttype.h"
+#include "gscspace.h"
+#include "gxcindex.h"
+#include "gxfrac.h"
 
 /*
  * We represent a halftone tile as a rectangular super-cell consisting of
@@ -121,6 +123,16 @@
 /* The following awkward expression avoids integer overflow. */
 #define max_ht_sample (ht_sample_t)(((1 << (ht_mask_bits - 2)) - 1) * 2 + 1)
 
+#ifndef wts_screen_t_DEFINED
+#  define wts_screen_t_DEFINED
+typedef struct wts_screen_s wts_screen_t;
+#endif
+
+#ifndef gs_wts_screen_enum_t_DEFINED
+#  define gs_wts_screen_enum_t_DEFINED
+typedef struct gs_wts_screen_enum_s gs_wts_screen_enum_t;
+#endif
+
 /*
  * Define the internal representation of a halftone order.
  * Note that it may include a cached transfer function.
@@ -182,6 +194,13 @@
     int (*render)(gx_ht_tile *tile, int new_bit_level,
 		  const gx_ht_order *order);
 
+    /* Draw a halftone shade into a 1 bit deep buffer. */
+    /* Note: this is a tentative design for a new method. I may not
+       keep it. */
+    int (*draw)(gx_ht_order *order, frac shade,
+		byte *data, int data_raster,
+		int x, int y, int w, int h);
+
 } gx_ht_order_procs_t;
 /*
  * Define the procedure vectors for the supported implementations
@@ -197,6 +216,8 @@
 } gx_ht_order_screen_params_t;
 struct gx_ht_order_s {
     gx_ht_cell_params_t params;	/* parameters defining the cells */
+    gs_wts_screen_enum_t *wse;
+    wts_screen_t *wts;            /* if non-NULL, then rest of the structure is irrelevant */
     ushort width;
     ushort height;
     ushort raster;
@@ -250,7 +271,8 @@
  */
 typedef struct gx_ht_order_component_s {
     gx_ht_order corder;
-    gs_ht_separation_name cname;
+    int comp_number;
+    int cname;
 } gx_ht_order_component;
 
 #define private_st_ht_order_component()	/* in gsht.c */\
@@ -271,12 +293,7 @@
 #endif
 
 /*
- * color_indices is a cache that gives the indices in components of
- * the screens for the 1, 3, or 4 primary color(s).  These indices are
- * always in the same order, namely:
- *      -,-,-,W(gray)
- *      R,G,B,-
- *      C,M,Y,K
+ * Device Halftone Structure definition
  */
 struct gx_device_halftone_s {
     gx_ht_order order;		/* must be first, for subclassing */
@@ -288,9 +305,9 @@
      */
     gs_halftone_type type;
     gx_ht_order_component *components;
+
     uint num_comp;
     /* The following are computed from the above. */
-    uint color_indices[4];
     int lcm_width, lcm_height;	/* LCM of primary color tile sizes, */
     /* max_int if overflowed */
 };

Index: gxdither.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxdither.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gxdither.h	16 Jun 2002 08:45:43 -0000	1.5
+++ gxdither.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -28,49 +28,23 @@
 #endif
 
 /*
- * Note that in the procedures below, the colors are specified by fracs,
- * but the alpha value is a gx_color_value.  This is a design flaw that
- * we might be able to fix eventually.
+ * Render DeviceN possibly by halftoning.
+ *  pcolors = pointer to an array color values (as fracs)
+ *  pdevc - pointer to device color structure
+ *  dev = pointer to device data structure
+ *  pht = pointer to halftone data structure
+ *  ht_phase  = halftone phase
+ *  gray_colorspace = true -> current color space is DeviceGray.
+ *  This is part of a kludge to minimize differences in the
+ *  regression testing.
  */
-
-/* Render a gray, possibly by halftoning. */
-/* Return 0 if complete, 1 if caller must do gx_color_load, <0 on error. */
-int gx_render_device_gray(frac gray, gx_color_value alpha,
-			  gx_device_color * pdevc, gx_device * dev,
-			  gx_device_halftone * dev_ht,
-			  const gs_int_point * ht_phase);
-
-#define gx_render_gray_alpha(gray, alpha, pdevc, pis, dev, select)\
-  gx_render_device_gray(gray, alpha, pdevc, dev, pis->dev_ht,\
-			&pis->screen_phase[select])
-#define gx_render_gray(gray, pdevc, pis, dev, select)\
-  gx_render_gray_alpha(gray, pis->alpha, pdevc, pis, dev, select)
-
-/* Render a color, possibly by halftoning. */
-/* Return as for gx_render_[device_]gray. */
-int gx_render_device_color(frac red, frac green, frac blue, frac white,
-			   bool cmyk, gx_color_value alpha,
-			   gx_device_color * pdevc, gx_device * dev,
-			   gx_device_halftone * pdht,
-			   const gs_int_point * ht_phase);
-
-#define gx_render_color_alpha(r, g, b, w, a, cmyk, pdevc, pis, dev, select)\
-  gx_render_device_color(r, g, b, w, cmyk, a, pdevc, dev,\
-			 pis->dev_ht, &pis->screen_phase[select])
-#define gx_render_color(r, g, b, w, cmyk, pdevc, pis, dev, select)\
-  gx_render_color_alpha(r, g, b, w, pis->alpha, cmyk, pdevc, pis, dev, select)
-#define gx_render_rgb(r, g, b, pdevc, pis, dev, select)\
-  gx_render_color(r, g, b, frac_0, false, pdevc, pis, dev, select)
-#define gx_render_cmyk(c, m, y, k, pdevc, pis, dev, select)\
-  gx_render_color(c, m, y, k, true, pdevc, pis, dev, select)
-#define gx_render_rgb_alpha(r, g, b, a, pdevc, pis, dev, select)\
-  gx_render_color_alpha(r, g, b, frac_0, a, false, pdevc, pis, dev, select)
-
+int gx_render_device_DeviceN(frac * pcolor, gx_device_color * pdevc,
+	gx_device * dev, gx_device_halftone * pdht,
+	const gs_int_point * ht_phase, bool gray_colorspace);
 /*
  * Reduce a colored halftone with 0 or 1 varying plane(s) to a pure color
  * or a binary halftone.
  */
-int gx_reduce_colored_halftone(gx_device_color *pdevc, gx_device *dev,
-			       bool cmyk);
+int gx_devn_reduce_colored_halftone(gx_device_color *pdevc, gx_device *dev);
 
 #endif /* gxdither_INCLUDED */

Index: gxht.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxht.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gxht.c	26 Jun 2002 20:03:21 -0000	1.7
+++ gxht.c	22 Aug 2002 07:12:29 -0000	1.8
@@ -27,6 +27,7 @@
 #include "gxdevice.h"		/* for gzht.h */
 #include "gxistate.h"
 #include "gzht.h"
+#include "gsserial.h"
 
 /* Define the sizes of the halftone cache. */
 #define max_cached_tiles_HUGE 5000	/* not used */
@@ -40,14 +41,21 @@
 /* The type descriptor must be public for Pattern types. */
 gs_public_st_composite(st_dc_ht_binary, gx_device_color, "dc_ht_binary",
 		       dc_ht_binary_enum_ptrs, dc_ht_binary_reloc_ptrs);
+private dev_color_proc_save_dc(gx_dc_ht_binary_save_dc);
+private dev_color_proc_get_dev_halftone(gx_dc_ht_binary_get_dev_halftone);
 private dev_color_proc_load(gx_dc_ht_binary_load);
 private dev_color_proc_fill_rectangle(gx_dc_ht_binary_fill_rectangle);
 private dev_color_proc_equal(gx_dc_ht_binary_equal);
+private dev_color_proc_write(gx_dc_ht_binary_write);
+private dev_color_proc_read(gx_dc_ht_binary_read);
 const gx_device_color_type_t
       gx_dc_type_data_ht_binary =
 {&st_dc_ht_binary,
+ gx_dc_ht_binary_save_dc, gx_dc_ht_binary_get_dev_halftone,
  gx_dc_ht_binary_load, gx_dc_ht_binary_fill_rectangle,
- gx_dc_default_fill_masked, gx_dc_ht_binary_equal
+ gx_dc_default_fill_masked, gx_dc_ht_binary_equal,
+ gx_dc_ht_binary_write, gx_dc_ht_binary_read,
+ gx_dc_ht_binary_get_nonzero_comps
 };
 
 #undef gx_dc_type_ht_binary
@@ -152,7 +160,6 @@
     pcache->bits_size = max_bits;
     pcache->ht_tiles = ht_tiles;
     pcache->num_tiles = max_tiles;
-    pcache->order.data_memory = 0;
     pcache->order.cache = pcache;
     pcache->order.transfer = 0;
     gx_ht_clear_cache(pcache);
@@ -172,6 +179,7 @@
 bool
 gx_check_tile_cache_current(const gs_imager_state * pis)
 {
+#ifdef TO_DO_DEVICEN
     const gx_ht_order *porder = &pis->dev_ht->order;
     gx_ht_cache *pcache = pis->ht_cache;
 
@@ -180,6 +188,9 @@
 	return false;
     /* else */
     return true;
+#else
+    return false;
+#endif
 }
 
 /* Make the cache order current, and return whether */
@@ -187,6 +198,7 @@
 bool
 gx_check_tile_cache(const gs_imager_state * pis)
 {
+#ifdef TO_DO_DEVICEN
     const gx_ht_order *porder = &pis->dev_ht->order;
     gx_ht_cache *pcache = pis->ht_cache;
 
@@ -223,6 +235,9 @@
 	pcache->tiles_fit = (int)fit;
 	return fit;
     }
+#else
+    return false;
+#endif
 }
 
 /*
@@ -235,6 +250,7 @@
 gx_check_tile_size(const gs_imager_state * pis, int w, int y, int h,
 		   gs_color_select_t select, int *ppx)
 {
+#ifdef TO_DO_DEVICEN
     int tsy;
     const gx_strip_bitmap *ptile0;
 
@@ -252,6 +268,9 @@
     /* Tile fits in Y, might fit in X. */
     *ppx = imod(-pis->screen_phase[select].x, ptile0->rep_width);
     return tsy * ptile0->raster;
+#else
+    return -1;
+#endif
 }
 
 /* Render a given level into a halftone cache. */
@@ -305,6 +324,25 @@
     return bt;
 }
 
+/* save information about the operand binary halftone color */
+private void
+gx_dc_ht_binary_save_dc(const gx_device_color * pdevc,
+                        gx_device_color_saved * psdc)
+{
+    psdc->type = pdevc->type;
+    psdc->colors.binary.b_color[0] = pdevc->colors.binary.color[0];
+    psdc->colors.binary.b_color[1] = pdevc->colors.binary.color[1];
+    psdc->colors.binary.b_index = pdevc->colors.binary.b_index;
+    psdc->phase = pdevc->phase;
+}
+
+/* get the halftone used for a binary halftone color */
+private const gx_device_halftone *
+gx_dc_ht_binary_get_dev_halftone(const gx_device_color * pdevc)
+{
+    return pdevc->colors.binary.b_ht;
+}
+
 /* Load the device color into the halftone cache if needed. */
 private int
 gx_dc_ht_binary_load(gx_device_color * pdevc, const gs_imager_state * pis,
@@ -315,8 +353,7 @@
 	(component_index < 0 ?
 	 &pdevc->colors.binary.b_ht->order :
 	 &pdevc->colors.binary.b_ht->components[component_index].corder);
-    gx_ht_cache *pcache =
-	(porder->cache == 0 ? pis->ht_cache : porder->cache);
+    gx_ht_cache *pcache = porder->cache;
 
     if (pcache->order.bit_data != porder->bit_data)
 	gx_ht_init_cache(pcache, porder);
@@ -389,6 +426,287 @@
 	gx_dc_binary_color1(pdevc1) == gx_dc_binary_color1(pdevc2) &&
 	pdevc1->colors.binary.b_level == pdevc2->colors.binary.b_level;
 }
+
+
+/* 
+ * Flags to indicate the pieces of a binary halftone that are included
+ * in its string representation. The first byte of the string holds this
+ * set of flags.
+ *
+ * It is unlikely that two successive binary halftones that are not equal
+ * would have the same level, so that field is always included in the
+ * string representation and therefore has no flag bit.
+ *
+ * The binary halftone tile is never transmitted as part of the string
+ * representation, so there is also no flag bit for it.
+ */
+private const int   dc_ht_binary_has_color0 = 0x01;
+private const int   dc_ht_binary_has_color1 = 0x02;
+private const int   dc_ht_binary_has_index = 0x04;
+private const int   dc_ht_binary_has_phase = 0x08;
+
+
+/*
+ * Serialize a binany halftone device color.
+ *
+ * Operands:
+ *
+ *  pdevc       pointer to device color to be serialized
+ *
+ *  psdc        pointer ot saved version of last serialized color (for
+ *              this band)
+ *  
+ *  dev         pointer to the current device, used to retrieve process
+ *              color model information
+ *
+ *  pdata       pointer to buffer in which to write the data
+ *
+ *  psize       pointer to a location that, on entry, contains the size of
+ *              the buffer pointed to by pdata; on return, the size of
+ *              the data required or actually used will be written here.
+ *
+ * Returns:
+ *
+ *  0, with *psize set to the amount of data written, if everything OK
+ *
+ *  gs_error_rangecheck, with *psize set to the size of buffer required,
+ *  if *psize was not large enough
+ *
+ *  < 0, != gs_error_rangecheck, in the event of some other error; in this
+ *  case *psize is not changed.
+ */
+private int
+gx_dc_ht_binary_write(
+    const gx_device_color *         pdevc,
+    const gx_device_color_saved *   psdc,
+    const gx_device *               dev,
+    byte *                          pdata,
+    uint *                          psize )
+{
+    int                             req_size = 2;   /* flag bits, b_level */
+    int                             flag_bits = 0;  /* just b_level */
+    uint                            tmp_size;
+    byte *                          pdata0 = pdata;
+    int                             code;
+
+    /* check if saved color is of the same type */
+    if (psdc != 0 && psdc->type != pdevc->type)
+        psdc = 0;
+
+    /* check for the information that must be transmitted */
+    if ( psdc == 0                                                      ||
+         pdevc->colors.binary.color[0] != psdc->colors.binary.b_color[0]  ) {
+        flag_bits |= dc_ht_binary_has_color0;
+        tmp_size = 0;
+        (void)gx_dc_write_color( pdevc->colors.binary.color[0],
+                                 dev,
+                                 pdata,
+                                 &tmp_size );
+        req_size += tmp_size;
+    }
+    if ( psdc == 0                                                      ||
+         pdevc->colors.binary.color[1] != psdc->colors.binary.b_color[1]  ) {
+        flag_bits |= dc_ht_binary_has_color1;
+        tmp_size = 0;
+        (void)gx_dc_write_color( pdevc->colors.binary.color[1],
+                                 dev,
+                                 pdata,
+                                 &tmp_size );
+        req_size += tmp_size;
+    }
+    if ( psdc == 0                                                  ||
+         pdevc->colors.binary.b_index != psdc->colors.binary.b_index  ) {
+        flag_bits |= dc_ht_binary_has_index;
+        req_size += 1;
+    }
+    if ( psdc == 0                       ||
+         pdevc->phase.x != psdc->phase.x ||
+         pdevc->phase.y != psdc->phase.y   ) {
+        flag_bits |= dc_ht_binary_has_phase;
+        /* the phases are known to be positive */
+        req_size += enc_u_sizexy(pdevc->phase);
+    }
+
+    /* check if sufficient space has been provided */
+    if (req_size > *psize) {
+        *psize = req_size;
+        return gs_error_rangecheck;
+    }
+
+    /* write out the flag byte and b_level */
+    *pdata++ = (byte)flag_bits;
+    *pdata++ = (byte)pdevc->colors.binary.b_level;
+
+    /* write out such other parts of the device color as are required */
+    if ((flag_bits & dc_ht_binary_has_color0) != 0) {
+        tmp_size = req_size - (pdata - pdata0);
+        code = gx_dc_write_color( pdevc->colors.binary.color[0],
+                                  dev,
+                                  pdata,
+                                  &tmp_size );
+        if (code < 0)
+            return code;
+        pdata += tmp_size;
+    }
+    if ((flag_bits & dc_ht_binary_has_color1) != 0) {
+        tmp_size = req_size - (pdata - pdata0);
+        code = gx_dc_write_color( pdevc->colors.binary.color[1],
+                                  dev,
+                                  pdata,
+                                  &tmp_size );
+        if (code < 0)
+            return code;
+        pdata += tmp_size;
+    }
+    if ((flag_bits & dc_ht_binary_has_index) != 0)
+        *pdata++ = pdevc->colors.binary.b_index;
+    if ((flag_bits & dc_ht_binary_has_phase) != 0)
+        enc_u_putxy(pdevc->phase, pdata);
+
+    *psize = pdata - pdata0;
+    return 0;
+}
+
+/*
+ * Reconstruct a binary halftone device color from its serial representation.
+ *
+ * Operands:
+ *
+ *  pdevc       pointer to the location in which to write the
+ *              reconstructed device color
+ *
+ *  pis         pointer to the current imager state (to access the
+ *              current halftone)
+ *
+ *  prior_devc  pointer to the current device color (this is provided
+ *              separately because the device color is not part of the
+ *              imager state)
+ *
+ *  dev         pointer to the current device, used to retrieve process
+ *              color model information
+ *
+ *  pdata       pointer to the buffer to be read
+ *
+ *  size        size of the buffer to be read; this should be large
+ *              enough to hold the entire color description
+ *
+ *  mem         pointer to the memory to be used for allocations
+ *              (ignored here)
+ *
+ * Returns:
+ *
+ *  # of bytes read if everthing OK, < 0 in the event of an error
+ */
+private int
+gx_dc_ht_binary_read(
+    gx_device_color *       pdevc,
+    const gs_imager_state * pis,
+    const gx_device_color * prior_devc,
+    const gx_device *       dev,        /* ignored */
+    const byte *            pdata,
+    uint                    size,
+    gs_memory_t *           mem )       /* ignored */
+{
+    gx_device_color         devc;
+    const byte *            pdata0 = pdata;
+    int                     code, flag_bits;
+
+    /* if prior information is available, use it */
+    if (prior_devc != 0 && prior_devc->type == gx_dc_type_ht_binary)
+        devc = *prior_devc;
+    else {
+        memset(&devc, 0, sizeof(devc));   /* clear pointers */
+        devc.type = gx_dc_type_ht_binary;
+    }
+
+    /* the halftone is always taken from the imager state */
+    devc.colors.binary.b_ht = pis->dev_ht;
+
+    /* cache is not porvided until the device color is used */
+    devc.colors.binary.b_tile = 0;
+
+    /* verify the minimum amount of information */
+    if ((size -= 2) < 0)
+        return_error(gs_error_rangecheck);
+    flag_bits = *pdata++;
+    devc.colors.binary.b_level = *pdata++;
+
+    /* read the other information provided */
+    if ((flag_bits & dc_ht_binary_has_color0) != 0) {
+        code = gx_dc_read_color( &devc.colors.binary.color[0],
+                                 dev,
+                                 pdata,
+                                 size );
+        if (code < 0)
+            return code;
+        size -= code;
+    }
+    if ((flag_bits & dc_ht_binary_has_color0) != 0) {
+        code = gx_dc_read_color( &devc.colors.binary.color[1],
+                                 dev,
+                                 pdata,
+                                 size );
+        if (code < 0)
+            return code;
+        size -= code;
+    }
+    if ((flag_bits & dc_ht_binary_has_index) != 0) {
+        if (--size < 0)
+            return_error(gs_error_rangecheck);
+        devc.colors.binary.b_index = *pdata++;
+    }
+    if ((flag_bits & dc_ht_binary_has_phase) != 0) {
+        /* we know the phase contains at least two bytes */
+        if (size < 2)
+            return_error(gs_error_rangecheck);
+        enc_u_getxy(pdevc->phase, pdata);
+    }
+
+    /* everything looks good */
+    *pdevc = devc;
+    return pdata - pdata0;
+}
+
+
+/*
+ * Get the nonzero components of a binary halftone. This is used to
+ * distinguish components that are given zero intensity due to halftoning
+ * from those for which the original color intensity was in fact zero.
+ *
+ * Since this device color type involves only a single halftone component,
+ * we can reasonably assume that b_level != 0. Hence, we need to check
+ * for components with identical intensities in color[0] and color[1].
+ */
+int
+gx_dc_ht_binary_get_nonzero_comps(
+    const gx_device_color * pdevc,
+    const gx_device *       dev,
+    gx_color_index *        pcomp_bits )
+{
+    int                     code;
+    gx_color_value          cvals_0[GX_DEVICE_COLOR_MAX_COMPONENTS],
+                            cvals_1[GX_DEVICE_COLOR_MAX_COMPONENTS];
+
+    if ( (code = dev_proc(dev, decode_color)( (gx_device *)dev,
+                                              pdevc->colors.binary.color[0],
+                                              cvals_0 )) >= 0 &&
+         (code = dev_proc(dev, decode_color)( (gx_device *)dev,
+                                              pdevc->colors.binary.color[0],
+                                              cvals_0 )) >= 0   ) {
+        int     i, ncomps = dev->color_info.num_components;
+        int     mask = 0x1, comp_bits = 0;
+
+        for (i = 0; i < ncomps; i++, mask <<= 1) {
+            if (cvals_0[i] != cvals_1[i])
+                comp_bits |= mask;
+        }
+        *pcomp_bits = comp_bits;
+        code = 0;
+    }
+
+    return code;
+}
+
 
 /* Initialize the tile cache for a given screen. */
 /* Cache as many different levels as will fit. */

Index: gxht.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxht.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gxht.h	16 Jun 2002 08:45:43 -0000	1.5
+++ gxht.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -20,11 +20,11 @@
 #ifndef gxht_INCLUDED
 #  define gxht_INCLUDED
 
-#include "gscsepnm.h"
 #include "gsht1.h"
 #include "gsrefct.h"
 #include "gxhttype.h"
 #include "gxtmap.h"
+#include "gscspace.h"
 
 /*
  * Halftone types. Note that for this implementation there are only
@@ -137,7 +137,8 @@
 
 /* Define the elements of a Type 5 halftone. */
 typedef struct gs_halftone_component_s {
-    gs_ht_separation_name cname;
+    int comp_number;
+    int cname;
     gs_halftone_type type;
     union {
 	gs_spot_halftone spot;	/* Type 1 */

Index: gxicolor.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxicolor.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gxicolor.c	21 Feb 2002 22:24:53 -0000	1.5
+++ gxicolor.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -120,12 +120,11 @@
     int vci, vdi;
     const gs_color_space *pcs = penum->pcs;
     cs_proc_remap_color((*remap_color)) = pcs->type->remap_color;
+    cs_proc_remap_concrete_color((*remap_concrete_color)) =
+	    pcs->type->remap_concrete_color;
     gs_client_color cc;
     bool device_color = penum->device_color;
     const gx_color_map_procs *cmap_procs = gx_get_cmap_procs(pis, dev);
-    cmap_proc_rgb((*map_3)) = cmap_procs->map_rgb;
-    cmap_proc_cmyk((*map_4)) =
-	(penum->alpha ? cmap_procs->map_rgb_alpha : cmap_procs->map_cmyk);
     bits32 mask = penum->mask_color.mask;
     bits32 test = penum->mask_color.test;
     gx_image_clue *pic = &clues[0];
@@ -219,10 +218,30 @@
 		goto mapped;
 	    }
 	    if (device_color) {
-		(*map_4)(byte2frac(next.v[0]), byte2frac(next.v[1]),
+		frac frac_color[4];
+
+		if (penum->alpha) {
+		    /*
+		     * We do not have support for DeviceN color and alpha.
+		     */
+		    cmap_procs->map_rgb_alpha
+			(byte2frac(next.v[0]), byte2frac(next.v[1]),
 			 byte2frac(next.v[2]), byte2frac(next.v[3]),
 			 pdevc_next, pis, dev,
 			 gs_color_select_source);
+		    goto mapped;
+		}
+		/*
+		 * We can call the remap concrete_color for the colorspace
+		 * directly since device_color is only true if the colorspace
+		 * is concrete.
+		 */
+		frac_color[0] = byte2frac(next.v[0]);
+		frac_color[1] = byte2frac(next.v[1]);
+		frac_color[2] = byte2frac(next.v[2]);
+		frac_color[3] = byte2frac(next.v[3]);
+		remap_concrete_color(frac_color, pcs, pdevc_next, pis,
+					    dev, gs_color_select_source);
 		goto mapped;
 	    }
 	    decode_sample(next.v[3], cc, 3);
@@ -260,10 +279,17 @@
 		goto mapped;
 	    }
 	    if (device_color) {
-		(*map_3)(byte2frac(next.v[0]), byte2frac(next.v[1]),
-			 byte2frac(next.v[2]),
-			 pdevc_next, pis, dev,
-			 gs_color_select_source);
+		frac frac_color[3];
+		/*
+		 * We can call the remap concrete_color for the colorspace
+		 * directly since device_color is only true if the colorspace
+		 * is concrete.
+		 */
+		frac_color[0] = byte2frac(next.v[0]);
+		frac_color[1] = byte2frac(next.v[1]);
+		frac_color[2] = byte2frac(next.v[2]);
+		remap_concrete_color(frac_color, pcs, pdevc_next, pis,
+						dev, gs_color_select_source);
 		goto mapped;
 	    }
 	    goto do3;
@@ -340,7 +366,7 @@
 	/* xrun/irun and xprev */
         /*
 	 * Note;  This section is nearly a copy of a simlar section below
-         * for processing the image pixel in the loop.  This would have been
+         * for processing the last image pixel in the loop.  This would have been
          * made into a subroutine except for complications about the number of
          * variables that would have been needed to be passed to the routine.
 	 */

Index: gximag3x.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gximag3x.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- gximag3x.c	16 Jun 2002 05:48:56 -0000	1.11
+++ gximag3x.c	22 Aug 2002 07:12:29 -0000	1.12
@@ -238,7 +238,7 @@
 	if (code < 0)
 	    goto out1;
 	penum->mask[i].mdev = mdev;
-	gs_image_t_init_gray(&mask[i].image, pis); /* gray is bogus */
+        gs_image_t_init(&mask[i].image, pmcs);
 	mask[i].image.ColorSpace = pmcs;
 	mask[i].image.adjust = false;
 	{

Index: gximage2.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gximage2.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gximage2.c	21 Feb 2002 22:24:53 -0000	1.4
+++ gximage2.c	22 Aug 2002 07:12:29 -0000	1.5
@@ -29,6 +29,7 @@
 #include "gxgetbit.h"
 #include "gxiparam.h"
 #include "gxpath.h"
+#include "gscolor2.h"
 
 /* Forward references */
 private dev_proc_begin_typed_image(gx_begin_image2);
@@ -111,23 +112,29 @@
     gs_state *pgs = pim->DataSource;
     gx_device *sdev = gs_currentdevice(pgs);
     int depth = sdev->color_info.depth;
-
-/****** ONLY HANDLE depth <= 8 FOR PixelCopy ******/
-    bool pixel_copy = pim->PixelCopy && depth <= 8 &&
-    !memcmp(&dev->color_info, &sdev->color_info,
-	    sizeof(dev->color_info));
+    bool pixel_copy = pim->PixelCopy;
     bool has_alpha;
-    bool direct_copy;
+    bool direct_copy = false;
     image2_data_t idata;
     byte *row;
     uint row_size, source_size;
     gx_image_enum_common_t *info;
     gs_matrix smat, dmat;
-    gs_color_space cs;
-    const gs_color_space *pcs;
     int code;
 
-    gs_image_t_init_rgb(&idata.image, pis);
+    /* verify that color models are the same for PixelCopy */
+    if ( pixel_copy                            &&
+         memcmp( &dev->color_info,
+                 &sdev->color_info,
+                 sizeof(dev->color_info) ) != 0  )
+        return_error(gs_error_typecheck);
+
+/****** ONLY HANDLE depth <= 8 FOR PixelCopy ******/
+    if (pixel_copy && depth <= 8)
+        return_error(gs_error_unregistered);
+
+    gs_image_t_init(&idata.image, gs_currentcolorspace((const gs_state *)pis));
+
     /* Add Decode entries for K and alpha */
     idata.image.Decode[6] = idata.image.Decode[8] = 0.0;
     idata.image.Decode[7] = idata.image.Decode[9] = 1.0;
@@ -152,38 +159,36 @@
     row = gs_alloc_bytes(mem, row_size, "gx_begin_image2");
     if (row == 0)
 	return_error(gs_error_VMerror);
-    if (pixel_copy &&
-	(pcpath == NULL ||
-	 gx_cpath_includes_rectangle(pcpath,
+    if (pixel_copy) {
+	idata.image.BitsPerComponent = depth;
+	has_alpha = false;	/* no separate alpha channel */
+
+	if ( pcpath == NULL ||
+	     gx_cpath_includes_rectangle(pcpath,
 				     int2fixed(idata.bbox.p.x),
 				     int2fixed(idata.bbox.p.y),
 				     int2fixed(idata.bbox.q.x),
-				     int2fixed(idata.bbox.q.y)))
-	) {
-	gs_matrix mat;
+				     int2fixed(idata.bbox.q.y)) ) {
+	    gs_matrix mat;
 
-	idata.image.BitsPerComponent = depth;
-	gs_cspace_init_DevicePixel(&cs, depth);
-	pcs = &cs;
-	/*
-	 * Figure 7.2 of the Adobe 3010 Supplement says that we should
-	 * compute CTM x ImageMatrix here, but I'm almost certain it
-	 * should be the other way around.  Also see gdevx.c.
-	 */
-	gs_matrix_multiply(&idata.image.ImageMatrix, &smat, &mat);
-	direct_copy =
-	    (is_xxyy(&dmat) || is_xyyx(&dmat)) &&
+
+	    /*
+	     * Figure 7.2 of the Adobe 3010 Supplement says that we should
+	     * compute CTM x ImageMatrix here, but I'm almost certain it
+	     * should be the other way around.  Also see gdevx.c.
+	     */
+	    gs_matrix_multiply(&idata.image.ImageMatrix, &smat, &mat);
+	    direct_copy =
+	        (is_xxyy(&dmat) || is_xyyx(&dmat)) &&
 #define eqe(e) mat.e == dmat.e
-	    eqe(xx) && eqe(xy) && eqe(yx) && eqe(yy);
+	        eqe(xx) && eqe(xy) && eqe(yx) && eqe(yy);
 #undef eqe
-	has_alpha = false;	/* no separate alpha channel */
+        }
     } else {
-	pixel_copy = false;
 	idata.image.BitsPerComponent = 8;
-	/* Always use RGB source color for now. */
-	pcs = gs_cspace_DeviceRGB(pis);
-	direct_copy = false;
-	/*
+
+	/* Always use RGB source color for now.
+         *
 	 * The source device has alpha if the same RGB values with
 	 * different alphas map to different pixel values.
 	 ****** THIS IS NOT GOOD ENOUGH: WE WANT TO SKIP TRANSFERRING
@@ -211,7 +216,6 @@
 		 gx_max_color_value, gx_max_color_value);
 	}
     }
-    idata.image.ColorSpace = pcs;
     idata.image.Alpha =
 	(has_alpha ? gs_image_alpha_last : gs_image_alpha_none);
     if (smat.yy < 0) {

Index: gximono.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gximono.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gximono.c	21 Feb 2002 22:24:53 -0000	1.6
+++ gximono.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -77,16 +77,6 @@
     return 0;
 }
 
-/* ------ Rendering procedure ------ */
-
-/* Provide a fake map_gray procedure for the DevicePixel color space. */
-private void
-no_map_gray(frac pixel, gx_device_color * pdc, const gs_imager_state * pis,
-	    gx_device * dev, gs_color_select_t select)
-{
-    color_set_pure(pdc, frac2byte(pixel));
-}
-
 /*
  * Rendering procedure for general mono-component images, dealing with
  * multiple bit-per-sample images, general transformations, arbitrary
@@ -102,7 +92,6 @@
     gs_logical_operation_t lop = penum->log_op;
     const bool masked = penum->masked;
     const gs_color_space *pcs;	/* only set for non-masks */
-    cmap_proc_gray((*map_gray));	/* ditto */
     cs_proc_remap_color((*remap_color));	/* ditto */
     gs_client_color cc;
     gx_device_color *pdevc = &penum->icolor1;	/* color for masking */
@@ -122,8 +111,6 @@
     if (!color_is_set(pdevc)) {\
 	if ((uint)(sample_value - mask_base) < mask_limit)\
 	    color_set_null(pdevc);\
-	else if (penum->device_color)\
-	    (*map_gray)(byte2frac(sample_value), pdevc, pis, dev, gs_color_select_source);\
 	else {\
 	    decode_sample(sample_value, cc, 0);\
 	    code = (*remap_color)(&cc, pcs, pdevc, pis, dev, gs_color_select_source);\
@@ -157,6 +144,9 @@
      * whether all tiles fit in the cache.  We may bypass the latter check
      * for masked images with a pure color.
      */
+
+    /* TO_DO_DEVICEN - The gx_check_tile_cache_current() routine is bogus */
+
     if (pis == 0 || !gx_check_tile_cache_current(pis)) {
         image_init_clues(penum, penum->bps, penum->spp);
     }
@@ -165,14 +155,7 @@
     xrun = dda_current(next.x);
     if (!masked) {
 	pcs = penum->pcs;	/* (may not be set for masks) */
-	if (penum->device_color)
-	    map_gray =
-		(gs_color_space_get_index(pcs) ==
-		 gs_color_space_index_DeviceGray ?
-		 gx_get_cmap_procs(pis, dev)->map_gray :
-		 no_map_gray /*DevicePixel */ );
-	else
-	    remap_color = pcs->type->remap_color;
+        remap_color = pcs->type->remap_color;
     }
     run = *psrc;
     /* Find the last transition in the input. */

Index: gxipixel.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxipixel.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gxipixel.c	16 Jun 2002 05:48:56 -0000	1.6
+++ gxipixel.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -252,10 +252,7 @@
 	y_extent.y = float2fixed(rh * mat.yy + mat.ty) - mty;
     }
     if (masked) {	/* This is imagemask. */
-	if (bps != 1 || pcs != NULL || penum->alpha ||
-	    !((decode[0] == 0.0 && decode[1] == 1.0) ||
-	      (decode[0] == 1.0 && decode[1] == 0.0))
-	    ) {
+	if (bps != 1 || pcs != NULL || penum->alpha || decode[0] == decode[1]) {
 	    gs_free_object(mem, penum, "gx_default_begin_image");
 	    return_error(gs_error_rangecheck);
 	}
@@ -263,7 +260,7 @@
 	color_set_pure(&penum->icolor0, gx_no_color_index);
 	penum->icolor1 = *pdcolor;
 	memcpy(&penum->map[0].table.lookup4x1to32[0],
-	       (decode[0] == 0 ? lookup4x1to32_inverted :
+	       (decode[0] < decode[1] ? lookup4x1to32_inverted :
 		lookup4x1to32_identity),
 	       16 * 4);
 	penum->map[0].decoding = sd_none;

Index: gxiscale.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxiscale.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gxiscale.c	6 Mar 2002 19:15:15 -0000	1.6
+++ gxiscale.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -295,7 +295,7 @@
 		    }
 #endif
 		    code = (*pconcs->type->remap_concrete_color)
-			(psrc, &devc, pis, dev, gs_color_select_source);
+			(psrc, pcs, &devc, pis, dev, gs_color_select_source);
 		    if (code < 0)
 			return code;
 		    if (color_is_pure(&devc)) {

Index: gxistate.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxistate.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- gxistate.h	16 Jun 2002 08:45:43 -0000	1.11
+++ gxistate.h	22 Aug 2002 07:12:29 -0000	1.12
@@ -30,6 +30,7 @@
 #include "gxline.h"
 #include "gxmatrix.h"
 #include "gxtmap.h"
+#include "gscspace.h"
 
 /*
   Define the subset of the PostScript graphics state that the imager library
@@ -106,16 +107,15 @@
  */
 
 /* Define the interior structure of a transfer function. */
-typedef struct gx_transfer_colored_s {
-    /* The components must be in this order: */
-    gx_transfer_map *red;	/* (RC) */
-    gx_transfer_map *green;	/* (RC) */
-    gx_transfer_map *blue;	/* (RC) */
-    gx_transfer_map *gray;	/* (RC) */
-} gx_transfer_colored;
-typedef union gx_transfer_s {
-    gx_transfer_map *indexed[4];	/* (RC) */
-    gx_transfer_colored colored;
+typedef struct gx_transfer_s {
+    int red_component_num;
+    gx_transfer_map *red;		/* (RC) */
+    int green_component_num;
+    gx_transfer_map *green;		/* (RC) */
+    int blue_component_num;
+    gx_transfer_map *blue;		/* (RC) */
+    int gray_component_num;
+    gx_transfer_map *gray;		/* (RC) */
 } gx_transfer;
 
 #define gs_color_rendering_state_common\
@@ -126,8 +126,6 @@
 	gs_int_point screen_phase[gs_color_select_count];\
 		/* dev_ht depends on halftone and device resolution. */\
 	gx_device_halftone *dev_ht;		/* (RC) */\
-		/* The contents of ht_cache depend on dev_ht. */\
-	struct gx_ht_cache_s *ht_cache;		/* (Shared) by all gstates */\
 \
 		/* Color (device-dependent): */\
 \
@@ -140,15 +138,23 @@
 		/* dictionaries.  (In Level 1 systems, set_transfer and */\
 		/* effective_transfer are always the same.) */\
 	gx_transfer set_transfer;		/* members are (RC) */\
-	gx_transfer effective_transfer;		/* see below */\
+	gx_transfer_map *effective_transfer[GX_DEVICE_COLOR_MAX_COMPONENTS]; /* see below */\
 \
 		/* Color caches: */\
 \
+		/* Id of color space for which cached information */\
+		/* applies. Note that this may differ from */\
+		/* cie_joint_caches->cspace_id, as the joint cache */\
+		/* is not rebuilt until needed */\
+	gs_id cspace_id;\
+\
 		/* cie_joint_caches depend on cie_render and */\
 		/* the color space. */\
 	struct gx_cie_joint_caches_s *cie_joint_caches;		/* (RC) */\
 		/* cmap_procs depend on the device's color_info. */\
 	const struct gx_color_map_procs_s *cmap_procs;		/* static */\
+		/* DeviceN component map for current color space */\
+	gs_devicen_color_map color_component_map;\
 		/* The contents of pattern_cache depend on the */\
 		/* the color space and the device's color_info and */\
 		/* resolution. */\
@@ -163,47 +169,36 @@
 #define gs_cr_state_do_rc_ptrs(m)\
   m(halftone) m(dev_ht) m(cie_render)\
   m(black_generation) m(undercolor_removal)\
-  m(set_transfer.colored.red) m(set_transfer.colored.green)\
-  m(set_transfer.colored.blue) m(set_transfer.colored.gray)\
+  m(set_transfer.red) m(set_transfer.green)\
+  m(set_transfer.blue) m(set_transfer.gray)\
   m(cie_joint_caches)
 
 /* Enumerate the pointers in a c.r. state. */
 #define gs_cr_state_do_ptrs(m)\
-  m(0,halftone) m(1,dev_ht) m(2,ht_cache)\
-  m(3,cie_render) m(4,black_generation) m(5,undercolor_removal)\
-  m(6,set_transfer.colored.red) m(7,set_transfer.colored.green)\
-  m(8,set_transfer.colored.blue) m(9,set_transfer.colored.gray)\
-  m(10,effective_transfer.colored.red) m(11,effective_transfer.colored.green)\
-  m(12,effective_transfer.colored.blue) m(13,effective_transfer.colored.gray)\
-  m(14,cie_joint_caches) m(15,pattern_cache)
-#define st_cr_state_num_ptrs 16
-
+  m(0,halftone) m(1,dev_ht)\
+  m(2,cie_render) m(3,black_generation) m(4,undercolor_removal)\
+  m(5,set_transfer.red) m(6,set_transfer.green)\
+  m(7,set_transfer.blue) m(8,set_transfer.gray)\
+  m(9,cie_joint_caches) m(10,pattern_cache)
+  /*
+   * We handle effective_transfer specially in gsistate.c since its pointers
+   * are not enumerated for garbage collection but they are are relocated.
+   */
 /*
- * Define constant values that can be allocated once and shared among
- * all imager states in an address space.
+ * This count does not include the effective_transfer pointers since they
+ * are not enumerated for GC.
  */
-#ifndef gs_color_space_DEFINED
-#  define gs_color_space_DEFINED
-typedef struct gs_color_space_s gs_color_space;
-#endif
-typedef union gx_device_color_spaces_s {
-    struct dcn_ {
-	gs_color_space *Gray;
-	gs_color_space *RGB;
-	gs_color_space *CMYK;
-    } named;
-    gs_color_space *indexed[3];
-} gx_device_color_spaces_t;
-typedef struct gs_imager_state_shared_s {
-    rc_header rc;
-    gx_device_color_spaces_t device_color_spaces;
-} gs_imager_state_shared_t;
+#define st_cr_state_num_ptrs 11
+
+
+typedef struct gs_devicen_color_map_s {
+    bool use_alt_cspace;
+    separation_type sep_type;
+    uint num_components;	/* Input - Duplicate of value in gs_device_n_params */
+    uint num_colorants;		/* Number of colorants - output */ 
+    int color_map[GS_CLIENT_COLOR_MAX_COMPONENTS];
+} gs_devicen_color_map;
 
-#define private_st_imager_state_shared()	/* in gsistate.c */\
-  gs_private_st_ptrs3(st_imager_state_shared, gs_imager_state_shared_t,\
-    "gs_imager_state_shared", imager_state_shared_enum_ptrs,\
-    imager_state_shared_reloc_ptrs, device_color_spaces.named.Gray,\
-    device_color_spaces.named.RGB, device_color_spaces.named.CMYK)
 
 /* Define the imager state structure itself. */
 typedef struct gs_transparency_source_s {
@@ -219,7 +214,6 @@
 #define gs_imager_state_common\
 	gs_memory_t *memory;\
 	void *client_data;\
-	gs_imager_state_shared_t *shared;\
 	gx_line_params line_params;\
 	gs_matrix_fixed ctm;\
 	gs_logical_operation_t log_op;\
@@ -239,7 +233,7 @@
 	  (*get_cmap_procs)(const gs_imager_state *, const gx_device *);\
 	gs_color_rendering_state_common
 #define st_imager_state_num_ptrs\
-  (st_line_params_num_ptrs + st_cr_state_num_ptrs + 5)
+  (st_line_params_num_ptrs + st_cr_state_num_ptrs + 4)
 /* Access macros */
 #define ctm_only(pis) (*(const gs_matrix *)&(pis)->ctm)
 #define ctm_only_writable(pis) (*(gs_matrix *)&(pis)->ctm)
@@ -261,7 +255,7 @@
 
 /* Initialization for gs_imager_state */
 #define gs_imager_state_initial(scale)\
-  0, 0, 0, { gx_line_params_initial },\
+  0, 0, { gx_line_params_initial },\
    { scale, 0.0, 0.0, -(scale), 0.0, 0.0 },\
   lop_default, gx_max_color_value, BLEND_MODE_Compatible,\
    { 1.0, 0 }, { 1.0, 0 }, 0/*false*/, 0, 0/*false*/, 0, 1.0,\
@@ -289,9 +283,6 @@
 void gs_imager_state_pre_assign(gs_imager_state *to,
 				const gs_imager_state *from);
 
-/* Free device color spaces.  Perhaps this should be declared elsewhere? */
-void gx_device_color_spaces_free(gx_device_color_spaces_t *pdcs,
-				 gs_memory_t *mem, client_name_t cname);
 
 /* Release an imager state. */
 void gs_imager_state_release(gs_imager_state * pis);

Index: gxpcmap.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxpcmap.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- gxpcmap.c	16 Jun 2002 05:48:56 -0000	1.6
+++ gxpcmap.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -30,6 +30,7 @@
 #include "gxdevice.h"
 #include "gxdevmem.h"
 #include "gxpcolor.h"
+#include "gxp1impl.h"
 #include "gzstate.h"
 
 /* Define the default size of the Pattern cache. */
@@ -121,10 +122,19 @@
      gx_default_begin_typed_image,
      pattern_accum_get_bits_rectangle,
      NULL,
-     NULL,
+     gx_default_create_compositor,
      NULL,
      gx_default_text_begin,
-     gx_default_finish_copydevice
+     gx_default_finish_copydevice,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL
  },
  0,				/* target */
  0, 0, 0, 0			/* bitmap_memory, bits, mask, instance */
@@ -296,6 +306,9 @@
 {
     gx_device_pattern_accum *const padev = (gx_device_pattern_accum *) dev;
 
+    /* opt out early if nothing to render (some may think this a bug) */
+    if (color0 == gx_no_color_index && color1 == gx_no_color_index)
+        return 0;
     if (padev->bits)
 	(*dev_proc(padev->target, copy_mono))
 	    (padev->target, data, data_x, raster, id, x, y, w, h,

Index: gxpcolor.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxpcolor.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gxpcolor.h	16 Jun 2002 08:45:43 -0000	1.5
+++ gxpcolor.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -115,6 +115,19 @@
 #define gx_dc_type_pattern (&gx_dc_pattern)
 
 /*
+ * These device color methods are shared amongst pattern types.
+ */
+extern dev_color_proc_save_dc(gx_dc_pattern_save_dc);
+extern dev_color_proc_write(gx_dc_pattern_write);
+extern dev_color_proc_read(gx_dc_pattern_read);
+
+/*
+ * For shading and colored tiling patterns, it is not possible to say
+ * which color components have non-zero values.
+ */
+extern dev_color_proc_get_nonzero_comps(gx_dc_pattern_get_nonzero_comps);
+
+/*
  * Define a color tile, an entry in the rendered Pattern cache (and
  * eventually in the colored halftone cache).  Note that the depth is
  * not sufficient to ensure that the rendering matches a given device;

Index: gxshade.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxshade.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- gxshade.c	21 Aug 2002 17:41:21 -0000	1.13
+++ gxshade.c	22 Aug 2002 07:12:29 -0000	1.14
@@ -22,7 +22,6 @@
 #include "gsrect.h"
 #include "gxcspace.h"
 #include "gscie.h"		/* requires gscspace.h */
-#include "gscindex.h"
 #include "gxdevcli.h"
 #include "gxistate.h"
 #include "gxdht.h"		/* for computing # of different colors */
@@ -307,12 +306,12 @@
 	    break;
 	}
     if (num_colors <= 32) {
-	/****** WRONG FOR MULTI-PLANE HALFTONES ******/
-	num_colors *= pis->dev_ht->order.num_levels;
-    }
-    if (psh->head.type == 2 || psh->head.type == 3) {
-	max_error *= 0.25;
-	num_colors *= 2.0;
+	gx_ht_order_component *components = pis->dev_ht->components;
+	if (components && components[0].corder.wts)
+	    num_colors = 256;
+	else
+	    /****** WRONG FOR MULTI-PLANE HALFTONES ******/
+	    num_colors *= pis->dev_ht->components[0].corder.num_levels;
     }
     if (max_error < 1.0 / num_colors)
 	max_error = 1.0 / num_colors;

Index: gxstate.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxstate.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- gxstate.h	16 Jun 2002 08:45:43 -0000	1.5
+++ gxstate.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -26,6 +26,8 @@
 typedef struct gs_state_s gs_state;
 
 #endif
+#include "gscspace.h"
+
 
 /*
  * The interfaces in this file are for internal use only, primarily by the
@@ -48,6 +50,9 @@
 typedef void *(*gs_state_alloc_proc_t) (gs_memory_t * mem);
 typedef int (*gs_state_copy_proc_t) (void *to, const void *from);
 typedef void (*gs_state_free_proc_t) (void *old, gs_memory_t * mem);
+typedef int (*get_colorname_string_proc_t) (gs_separation_name colorname_index,
+			unsigned char **ppstr, unsigned int *pname_size);
+
 typedef enum {
     copy_for_gsave,		/* from = current, to = new(saved) */
     copy_for_grestore,		/* from = saved, to = current */
@@ -66,6 +71,7 @@
     gs_state_copy_proc_t copy;
     gs_state_free_proc_t free;
     gs_state_copy_for_proc_t copy_for;
+    get_colorname_string_proc_t get_colorname_string;
 } gs_state_client_procs;
 void gs_state_set_client(gs_state *, void *, const gs_state_client_procs *);
 

Index: gzht.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gzht.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- gzht.h	16 Jun 2002 08:45:43 -0000	1.8
+++ gzht.h	22 Aug 2002 07:12:29 -0000	1.9
@@ -127,6 +127,24 @@
     gx_ht_tile *(*render_ht)(gx_ht_cache *, int); /* rendering procedure */
 };
 
+/* Define the sizes of the halftone cache. */
+#define max_cached_tiles_HUGE 5000	/* not used */
+#define max_ht_bits_HUGE 1000000	/* not used */
+#define max_cached_tiles_LARGE 577
+#define max_ht_bits_LARGE 100000
+#define max_cached_tiles_SMALL 25
+#define max_ht_bits_SMALL 1000
+
+/* Define the size of the halftone tile cache. */
+#define max_tile_bytes_LARGE 4096
+#define max_tile_bytes_SMALL 512
+#if arch_small_memory
+#  define max_tile_cache_bytes max_tile_bytes_SMALL
+#else
+#  define max_tile_cache_bytes\
+     (gs_debug_c('.') ? max_tile_bytes_SMALL : max_tile_bytes_LARGE)
+#endif
+
 /* We don't mark from the tiles pointer, and we relocate the tiles en masse. */
 #define private_st_ht_tiles()	/* in gxht.c */\
   gs_private_st_composite(st_ht_tiles, gx_ht_tile, "ht tiles",\
@@ -187,11 +205,10 @@
 
 /*
  * Install a device halftone in an imager state.  Note that this does not
- * read or update the client halftone.  There is a special check for pdht ==
- * pis->dev_ht, for the benefit of the band rendering code.
+ * read or update the client halftone.
  */
 int gx_imager_dev_ht_install(gs_imager_state * pis,
-			     const gx_device_halftone * pdht,
+			     gx_device_halftone * pdht,
 			     gs_halftone_type type,
 			     const gx_device * dev);
 
@@ -200,8 +217,7 @@
  * level of the gs_halftone and the gx_device_halftone, and take ownership
  * of any substructures.
  */
-int gx_ht_install(gs_state *, const gs_halftone *,
-		  const gx_device_halftone *);
+int gx_ht_install(gs_state *, const gs_halftone *, gx_device_halftone *);
 
 /* Reestablish the effective transfer functions, taking into account */
 /* any overrides from halftone dictionaries. */
@@ -209,4 +225,30 @@
 void gx_imager_set_effective_xfer(gs_imager_state * pis);
 void gx_set_effective_transfer(gs_state * pgs);
 
+/*
+ * This routine will take a color name (defined by a ptr and size) and
+ * check if this is a valid colorant name for the current device.  If
+ * so then the device's colorant number is returned.
+ *
+ * Two other checks are also made.  If the name is "Default" then a value
+ * of GX_DEVICE_COLOR_MAX_COMPONENTS is returned.  This is done to
+ * simplify the handling of default halftones.
+ *
+ * If the halftone type is colorscreen or multiple colorscreen, then we
+ * also check for Red/Cyan, Green/Magenta, Blue/Yellow, and Gray/Black
+ * component name pairs.  This is done since the setcolorscreen and
+ * sethalftone types 2 and 4 imply the dual name sets.
+ *
+ * A negative value is returned if the color name is not found.
+ */
+int gs_color_name_component_number(const gx_device * dev, char * pname,
+				int name_size, int halftonetype);
+/*
+ * See gs_color_name_component_number for main description.
+ *
+ * This version converts a name index value into a string and size and
+ * then call gs_color_name_component_number.
+ */
+int gs_cname_to_colorant_number(gs_state * pgs, gs_separation_name cname,
+				 int halftonetype);
 #endif /* gzht_INCLUDED */

Index: gzstate.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gzstate.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- gzstate.h	21 Feb 2002 22:24:53 -0000	1.7
+++ gzstate.h	22 Aug 2002 07:12:29 -0000	1.8
@@ -94,10 +94,7 @@
 
     /* Color (device-independent): */
 
-    gs_color_space_index	/* before substitution */
-        orig_cspace_index, orig_base_cspace_index;
     gs_color_space *color_space; /* after substitution */
-    gx_device_color_spaces_t device_color_spaces; /* substituted spaces */
     gs_client_color *ccolor;
 
     /* Color caches: */
@@ -146,10 +143,7 @@
   m(4,view_clip) m(5,effective_clip_path)\
   m(6,color_space) m(7,ccolor) m(8,dev_color)\
   m(9,font) m(10,root_font) m(11,show_gstate) /*m(---,device)*/\
-  m(12,transparency_group_stack)\
-  m(13,device_color_spaces.named.Gray)\
-  m(14,device_color_spaces.named.RGB)\
-  m(15,device_color_spaces.named.CMYK)
-#define gs_state_num_ptrs 16
+  m(12,transparency_group_stack)
+#define gs_state_num_ptrs 13
 
 #endif /* gzstate_INCLUDED */

Index: idparam.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/idparam.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- idparam.c	21 Feb 2002 22:24:53 -0000	1.5
+++ idparam.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -235,12 +235,12 @@
 
 	return len;
     }
-    if (!r_has_type(pdval, t_array))
+    if (!r_is_array(pdval))
 	return_error(e_typecheck);
     size = r_size(pdval);
     if (size > len)
 	return_error(over_error);
-    code = float_params(pdval->value.refs + size - 1, size, fvec);
+    code = process_float_array(pdval, size, fvec);
     return (code < 0 ? code :
 	    size == len || under_error >= 0 ? size :
 	    gs_note_error(under_error));

Index: igstate.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/igstate.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- igstate.h	16 Jun 2002 04:47:10 -0000	1.6
+++ igstate.h	22 Aug 2002 07:12:29 -0000	1.7
@@ -24,6 +24,7 @@
 #include "gxstate.h"		/* for 'client data' access */
 #include "imemory.h"
 #include "istruct.h"		/* for gstate obj definition */
+#include "gxcindex.h"
 
 /*
  * From the interpreter's point of view, the graphics state is largely opaque,
@@ -118,12 +119,8 @@
     /* Screen_procs are only relevant if setscreen was */
     /* executed more recently than sethalftone */
     /* (for this graphics context). */
-    union {
-	ref indexed[4];
-	struct {
-	    /* The components must be in this order: */
-	    ref red, green, blue, gray;
-	} colored;
+    struct {
+	ref red, green, blue, gray;
     } screen_procs,		/* halftone screen procedures */
           transfer_procs;	/* transfer procedures */
     ref black_generation;	/* (procedure) */
@@ -138,6 +135,17 @@
 	ref dict;		/* CIE color rendering dictionary */
 	ref_cie_render_procs procs;	/* (see above) */
     } colorrendering;
+    /*
+     * Use_cie_color tracks the UseCIEColor parameter of the page
+     * device. This parameter may, during initialization, be read
+     * through the .getuseciecolor operator, and set (in Level 3)
+     * via the .setuseciecolor operator.
+     *
+     * Previously, the UseCIEColor color space substitution feature
+     * was implemented in the graphic library. It is now implemented
+     * strictly in the interpreter.
+     */
+    ref use_cie_color;
     /*
      * Halftone is relevant only if sethalftone was executed
      * more recently than setscreen for this graphics context.

Index: iimage.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/iimage.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- iimage.h	16 Jun 2002 04:47:10 -0000	1.5
+++ iimage.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -23,21 +23,30 @@
 
 /* These procedures are exported by zimage.c for other modules. */
 
-/* Exported for zcolor1.c */
-int zimage_opaque_setup(i_ctx_t *i_ctx_p, os_ptr op, bool multi,
-			gs_image_alpha_t alpha, const gs_color_space * pcs,
-			int npop);
+/*
+ * Define a structure for image parameters other than those defined
+ * in the gs_*image*_t structure.
+ */
+typedef struct image_params_s {
+    bool MultipleDataSources;
+    ref DataSource[gs_image_max_components];
+    const float *pDecode;
+} image_params;
 
-/* Exported for zimage2.c */
-int zimage_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
-		 const ref * sources, bool uses_color, int npop);
+/* Extract and check parameters for an image. */
+int data_image_params(const ref *op, gs_data_image_t *pim,
+                      image_params *pip, bool require_DataSource,
+                      int num_components, int max_bits_per_component,
+                      bool has_alpha);
+int pixel_image_params(i_ctx_t *i_ctx_p, const ref *op,
+                       gs_pixel_image_t *pim, image_params * pip,
+                       int max_bits_per_component, bool has_alpha);
 
-/* Exported for zcolor3.c */
-int zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
-		      gx_image_enum_common_t * pie,
-		      const ref * sources, int npop);
+/* Exported for zimage3.c and ztrans.c */
+int zimage_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
+                 const ref * sources, bool uses_color, int npop);
 
-/* Exported for zcolor1.c and zdpnext.c. */
-int zimage_multiple(i_ctx_t *i_ctx_p, bool has_alpha);
+/* Exported for zdpnext.c */
+int image1_setup(i_ctx_t * i_ctx_p, bool has_alpha);
 
 #endif /* iimage_INCLUDED */

Index: iimage2.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/iimage2.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- iimage2.h	16 Jun 2002 04:47:10 -0000	1.5
+++ iimage2.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -21,32 +21,15 @@
 #ifndef iimage2_INCLUDED
 #  define iimage2_INCLUDED
 
-/* These procedures are exported by zimage2.c for other modules. */
-
-/*
- * Define a structure for image parameters other than those defined
- * in the gs_*image*_t structure.
- */
-typedef struct image_params_s {
-    bool MultipleDataSources;
-    ref DataSource[gs_image_max_components];
-    const float *pDecode;
-} image_params;
-
-/* Extract and check parameters for an image. */
-int data_image_params(const ref *op, gs_data_image_t *pim,
-		      image_params *pip, bool require_DataSource,
-		      int num_components, int max_bits_per_component);
-int pixel_image_params(i_ctx_t *i_ctx_p, const ref *op,
-		       gs_pixel_image_t *pim, image_params * pip,
-		       int max_bits_per_component);
+/* This procedure is exported by zimage2.c for other modules. */
 
 /*
  * Process an image that has no explicit source data.  This isn't used by
  * standard Level 2, but it's a very small procedure and is needed by
  * both zdps.c and zdpnext.c.
  */
-int process_non_source_image(i_ctx_t *i_ctx_p, const gs_image_common_t * pim,
-			     client_name_t cname);
+int process_non_source_image(i_ctx_t *i_ctx_p,
+                             const gs_image_common_t * pim,
+                             client_name_t cname);
 
 #endif /* iimage2_INCLUDED */

Index: int.mak
===================================================================
RCS file: /cvs/ghostscript/gs/src/int.mak,v
retrieving revision 1.81
retrieving revision 1.82
diff -u -d -r1.81 -r1.82
--- int.mak	19 Jun 2002 15:52:29 -0000	1.81
+++ int.mak	22 Aug 2002 07:12:29 -0000	1.82
@@ -248,7 +248,7 @@
 bfont_h=$(PSSRC)bfont.h $(ifont_h)
 icontext_h=$(PSSRC)icontext.h $(gsstype_h) $(icstate_h)
 ifilter_h=$(PSSRC)ifilter.h $(istream_h) $(ivmspace_h)
-igstate_h=$(PSSRC)igstate.h $(gsstate_h) $(gxstate_h) $(imemory_h) $(istruct_h)
+igstate_h=$(PSSRC)igstate.h $(gsstate_h) $(gxstate_h) $(imemory_h) $(istruct_h) $(gxcindex_h)
 iscan_h=$(PSSRC)iscan.h $(sa85x_h) $(sstring_h)
 sbhc_h=$(PSSRC)sbhc.h $(shc_h)
 # Include files for optional features
@@ -570,8 +570,8 @@
 	$(CP_) $(PSD)psl1.dev $(PSD)level1.dev
 
 $(PSD)psl1.dev : $(INT_MAK) $(ECHOGS_XE)\
- $(PSD)psbase.dev $(PSD)bcp.dev $(PSD)hsb.dev $(PSD)path1.dev $(PSD)type1.dev
-	$(SETMOD) $(PSD)psl1 -include $(PSD)psbase $(PSD)bcp $(PSD)hsb $(PSD)path1 $(PSD)type1
+ $(PSD)psbase.dev $(PSD)bcp.dev $(PSD)path1.dev $(PSD)type1.dev
+	$(SETMOD) $(PSD)psl1 -include $(PSD)psbase $(PSD)bcp $(PSD)path1 $(PSD)type1
 	$(ADDMOD) $(PSD)psl1 -emulator PostScript PostScriptLevel1
 
 # -------- Level 1 color extensions (CMYK color and colorimage) -------- #
@@ -625,18 +625,6 @@
 $(PSD)usedsc.dev : $(INT_MAK) $(ECHOGS_XE) $(PSD)dscparse.dev
 	$(SETMOD) $(PSD)usedsc -include $(PSD)dscparse -ps gs_dscp
 
-# ---------------- HSB color ---------------- #
-
-hsb_=$(PSOBJ)zhsb.$(OBJ)
-$(PSD)hsb.dev : $(INT_MAK) $(ECHOGS_XE) $(hsb_) $(GLD)hsblib.dev
-	$(SETMOD) $(PSD)hsb $(hsb_)
-	$(ADDMOD) $(PSD)hsb -include $(GLD)hsblib
-	$(ADDMOD) $(PSD)hsb -oper zhsb
-
-$(PSOBJ)zhsb.$(OBJ) : $(PSSRC)zhsb.c $(OP)\
- $(gshsb_h) $(igstate_h) $(store_h)
-	$(PSCC) $(PSO_)zhsb.$(OBJ) $(C_) $(PSSRC)zhsb.c
-
 # ---- Level 1 path miscellany (arcs, pathbbox, path enumeration) ---- #
 
 path1_=$(PSOBJ)zpath1.$(OBJ)
@@ -1148,7 +1136,7 @@
 	$(SETMOD) $(PSD)psl2read $(psl2read_)
 	$(ADDMOD) $(PSD)psl2read -include $(PSD)psl2int $(PSD)dps2read
 	$(ADDMOD) $(PSD)psl2read -oper zcolor2_l2 zcsindex_l2
-	$(ADDMOD) $(PSD)psl2read -oper zht2_l2 zimage2_l2
+	$(ADDMOD) $(PSD)psl2read -oper zht2_l2
 
 $(PSOBJ)zcolor2.$(OBJ) : $(PSSRC)zcolor2.c $(OP) $(string__h)\
  $(gscolor_h) $(gscssub_h) $(gsmatrix_h) $(gsstruct_h)\
@@ -1679,6 +1667,10 @@
  $(igstate_h) $(oper_h) $(store_h)
 	$(PSCC) $(PSO_)zmisc3.$(OBJ) $(C_) $(PSSRC)zmisc3.c
 
+$(PSOBJ)zcolor3.$(OBJ) : $(PSSRC)zcolor3.c $(GH)\
+ $(oper_h) $(igstate_h)
+	$(PSCC) $(PSO_)zcolor3.$(OBJ) $(C_) $(PSSRC)zcolor3.c
+
 $(PSOBJ)zshade.$(OBJ) : $(PSSRC)zshade.c $(memory__h) $(OP)\
  $(gscolor2_h) $(gscolor3_h) $(gscspace_h) $(gsfunc3_h)\
  $(gsptype2_h) $(gsshade_h) $(gsstruct_h) $(gsuid_h)\
@@ -1689,7 +1681,8 @@
 	$(PSCC) $(PSO_)zshade.$(OBJ) $(C_) $(PSSRC)zshade.c
 
 psl3read_1=$(PSOBJ)zcsdevn.$(OBJ) $(PSOBJ)zfunc3.$(OBJ) $(PSOBJ)zfsample.$(OBJ)
-psl3read_2=$(PSOBJ)zimage3.$(OBJ) $(PSOBJ)zmisc3.$(OBJ) $(PSOBJ)zshade.$(OBJ)
+psl3read_2=$(PSOBJ)zimage3.$(OBJ) $(PSOBJ)zmisc3.$(OBJ) $(PSOBJ)zcolor3.$(OBJ)\
+ $(PSOBJ)zshade.$(OBJ)
 psl3read_=$(psl3read_1) $(psl3read_2)
 
 # Note: we need the ReusableStreamDecode filter for shadings.
@@ -1699,7 +1692,7 @@
 	$(ADDMOD) $(PSD)psl3read $(psl3read_2)
 	$(ADDMOD) $(PSD)psl3read -oper zcsdevn
 	$(ADDMOD) $(PSD)psl3read -oper zfsample
-	$(ADDMOD) $(PSD)psl3read -oper zimage3 zmisc3 zshade
+	$(ADDMOD) $(PSD)psl3read -oper zimage3 zmisc3 zcolor3_l3 zshade
 	$(ADDMOD) $(PSD)psl3read -functiontype 2 3
 	$(ADDMOD) $(PSD)psl3read -ps gs_ll3
 	$(ADDMOD) $(PSD)psl3read -include $(PSD)frsd $(PSD)fzlib

Index: iutil.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/iutil.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- iutil.c	16 Jun 2002 03:48:22 -0000	1.6
+++ iutil.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -95,7 +95,7 @@
 	/*
 	 * Only a few cases need be considered here:
 	 * integer/real (and vice versa), name/string (and vice versa),
-	 * and extended operators.
+	 * arrays, and extended operators.
 	 */
 	switch (r_type(pref1)) {
 	    case t_integer:
@@ -116,6 +116,13 @@
 		name_string_ref(pref2, &nref);
 		pref2 = &nref;
 		break;
+
+		/* differing array types can match if length is 0 */
+	    case t_array:
+	    case t_mixedarray:
+	    case t_shortarray:
+		return r_is_array(pref2) &&
+		       r_size(pref1) == 0 && r_size(pref2) == 0;
 	    default:
 		if (r_btype(pref1) != r_btype(pref2))
 		    return false;
@@ -127,11 +134,13 @@
      */
     switch (r_btype(pref1)) {
 	case t_array:
-	    return (pref1->value.refs == pref2->value.refs &&
+	    return ((pref1->value.refs == pref2->value.refs ||
+	             r_size(pref1) == 0) &&
 		    r_size(pref1) == r_size(pref2));
 	case t_mixedarray:
 	case t_shortarray:
-	    return (pref1->value.packed == pref2->value.packed &&
+	    return ((pref1->value.packed == pref2->value.packed ||
+	             r_size(pref1) == 0) &&
 		    r_size(pref1) == r_size(pref2));
 	case t_boolean:
 	    return (pref1->value.boolval == pref2->value.boolval);
@@ -731,6 +740,34 @@
 		return_error(e_typecheck);
 	}
     return 0;
+}
+
+/* Get N numeric parameters (as floating point numbers) from an array */
+int
+process_float_array(const ref * parray, int count, float * pval)
+{
+    int         code = 0, indx0 = 0;
+
+    /* we assume parray is an array of some type, of adequate length */
+    if (r_has_type(parray, t_array))
+        return float_params(parray->value.refs + count - 1, count, pval);
+
+    /* short/mixed array; convert the entries to refs */
+    while (count > 0 && code >= 0) {
+        int     i, subcount;
+        ref     ref_buff[20];   /* 20 is arbitrary */
+
+        subcount = (count > countof(ref_buff) ? countof(ref_buff) : count);
+        for (i = 0; i < subcount && code >= 0; i++)
+            code = array_get(parray, (long)(i + indx0), &ref_buff[i]);
+        if (code >= 0)
+            code = float_params(ref_buff + subcount - 1, subcount, pval);
+        count -= subcount;
+        pval += subcount;
+        indx0 += subcount;
+    }
+
+    return code;
 }
 
 /* Get a single real parameter. */

Index: iutil.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/iutil.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- iutil.h	16 Jun 2002 04:47:10 -0000	1.5
+++ iutil.h	22 Aug 2002 07:12:29 -0000	1.6
@@ -114,6 +114,9 @@
 /* float_params can lose accuracy for large integers. */
 int float_params(const ref *, int, float *);
 
+/* process_float_array can lose accuracy for large integers */
+int process_float_array(const ref *, int, float *);
+
 /* Get a single real parameter. */
 /* The only possible error is e_typecheck. */
 int real_param(const ref *, double *);

Index: lib.mak
===================================================================
RCS file: /cvs/ghostscript/gs/src/lib.mak,v
retrieving revision 1.89
retrieving revision 1.90
diff -u -d -r1.89 -r1.90
--- lib.mak	24 Jun 2002 05:14:15 -0000	1.89
+++ lib.mak	22 Aug 2002 07:12:29 -0000	1.90
@@ -118,6 +118,7 @@
 gsmemret_h=$(GLSRC)gsmemret.h $(gsmemory_h)
 gsnogc_h=$(GLSRC)gsnogc.h $(gsgc_h)
 gsrefct_h=$(GLSRC)gsrefct.h
+gsserial_h=$(GLSRC)gsserial.h
 gsstype_h=$(GLSRC)gsstype.h
 gx_h=$(GLSRC)gx.h $(stdio__h) $(gdebug_h)\
  $(gserror_h) $(gsio_h) $(gsmemory_h) $(gstypes_h)
@@ -255,6 +256,10 @@
  $(gsnotify_h) $(gsstruct_h)
 	$(GLCC) $(GLO_)gsnotify.$(OBJ) $(C_) $(GLSRC)gsnotify.c
 
+$(GLOBJ)gsserial.$(OBJ) : $(GLSRC)gsserial.c $(stdpre_h) $(gstypes_h)\
+ $(gsserial_h)
+	$(GLCC) $(GLO_)gsserial.$(OBJ) $(C_) $(GLSRC)gsserial.c
+
 $(GLOBJ)gsutil.$(OBJ) : $(GLSRC)gsutil.c $(AK) $(memory__h) $(string__h)\
  $(gconfigv_h)\
  $(gserror_h) $(gserrors_h) $(gsmemory_h) $(gsrect_h) $(gstypes_h)\
@@ -304,6 +309,7 @@
 gshsb_h=$(GLSRC)gshsb.h
 gsht_h=$(GLSRC)gsht.h
 gsht1_h=$(GLSRC)gsht1.h $(gsht_h)
+gswts_h=$(GLSRC)gswts.h
 gsjconf_h=$(GLSRC)gsjconf.h $(arch_h) $(stdpre_h)
 gslib_h=$(GLSRC)gslib.h
 gslparam_h=$(GLSRC)gslparam.h
@@ -356,6 +362,7 @@
 gxlum_h=$(GLSRC)gxlum.h
 gxmatrix_h=$(GLSRC)gxmatrix.h $(gsmatrix_h)
 gxmclip_h=$(GLSRC)gxmclip.h $(gxclip_h)
+gxoprect_h=$(GLSRC)gxoprect.h
 gxp1impl_h=$(GLSRC)gxp1impl.h
 gxpaint_h=$(GLSRC)gxpaint.h
 gxpath_h=$(GLSRC)gxpath.h $(gscpm_h) $(gslparam_h) $(gspenum_h) $(gsrect_h)
@@ -370,19 +377,23 @@
 gxcdevn_h=$(GLSRC)gxcdevn.h $(gsrefct_h) $(gxcindex_h)
 gxchar_h=$(GLSRC)gxchar.h $(gschar_h) $(gxtext_h)
 gxchrout_h=$(GLSRC)gxchrout.h
+gxwts_h=$(GLSRC)gxwts.h
 gsdcolor_h=$(GLSRC)gsdcolor.h $(gsccolor_h)\
- $(gxarith_h) $(gxbitmap_h) $(gxcindex_h) $(gxhttile_h)
+ $(gxarith_h) $(gxbitmap_h) $(gxcindex_h) $(gxhttile_h) $(gxwts_h)
 gxdcolor_h=$(GLSRC)gxdcolor.h\
  $(gscsel_h) $(gsdcolor_h) $(gsropt_h) $(gsstruct_h)
+gscspace_h=$(GLSRC)gscspace.h $(gsmemory_h)
 gxdevcli_h=$(GLSRC)gxdevcli.h $(std_h)\
  $(gscompt_h) $(gsdcolor_h) $(gsiparam_h) $(gsmatrix_h)\
  $(gsrefct_h) $(gsropt_h) $(gsstruct_h) $(gstparam_h) $(gsxfont_h)\
  $(gxbitmap_h) $(gxcindex_h) $(gxcvalue_h) $(gxfixed_h)\
- $(gxtext_h)
+ $(gxtext_h) $(gscspace_h)
 gxdevice_h=$(GLSRC)gxdevice.h $(stdio__h)\
  $(gsfname_h) $(gsmalloc_h) $(gsparam_h) $(gxdevcli_h) $(gxstdio_h)
 gxdht_h=$(GLSRC)gxdht.h\
- $(gscsepnm_h) $(gsmatrix_h) $(gsrefct_h) $(gxarith_h) $(gxhttype_h)
+ $(gsmatrix_h) $(gsrefct_h) $(gxarith_h) $(gxhttype_h) $(gscspace_h)\
+ $(gxcindex_h) $(gxfrac_h)
+gxdhtserial_h=$(GLSRC)gxdhtserial.h
 gxdither_h=$(GLSRC)gxdither.h $(gxfrac_h)
 gxclip2_h=$(GLSRC)gxclip2.h $(gxmclip_h)
 gxclipm_h=$(GLSRC)gxclipm.h $(gxmclip_h)
@@ -401,16 +412,16 @@
 gscrdp_h=$(GLSRC)gscrdp.h $(gscie_h) $(gsparam_h)
 gscspace_h=$(GLSRC)gscspace.h $(gsmemory_h)
 gscdevn_h=$(GLSRC)gscdevn.h $(gscspace_h)
+gxdevndi_h=$(GLSRC)gxdevndi.h $(gxfrac_h)
 gscindex_h=$(GLSRC)gscindex.h $(gscspace_h)
 gscolor2_h=$(GLSRC)gscolor2.h $(gscindex_h) $(gsptype1_h)
 gscsepr_h=$(GLSRC)gscsepr.h $(gscspace_h)
-gscssub_h=$(GLSRC)gscssub.h $(gscspace_h)
 gxdcconv_h=$(GLSRC)gxdcconv.h $(gxfrac_h)
 gxfmap_h=$(GLSRC)gxfmap.h $(gsrefct_h) $(gsstype_h) $(gxfrac_h) $(gxtmap_h)
 gxcmap_h=$(GLSRC)gxcmap.h $(gscsel_h) $(gxcindex_h) $(gxcvalue_h) $(gxfmap_h)
 gxistate_h=$(GLSRC)gxistate.h\
- $(gscsel_h) $(gsrefct_h) $(gsropt_h) $(gstparam_h)\
- $(gxcmap_h) $(gxcvalue_h) $(gxfixed_h) $(gxline_h) $(gxmatrix_h) $(gxtmap_h)
+ $(gscsel_h) $(gsrefct_h) $(gsropt_h) $(gstparam_h) $(gxcmap_h) $(gxcvalue_h)\
+ $(gxfixed_h) $(gxline_h) $(gxmatrix_h) $(gxtmap_h) $(gscspace_h)
 gxclist_h=$(GLSRC)gxclist.h $(gscspace_h)\
  $(gxband_h) $(gxbcache_h) $(gxclio_h) $(gxdevbuf_h) $(gxistate_h)\
  $(gxrplane_h)
@@ -418,7 +429,7 @@
  $(gscolor2_h) $(gsmatrix_h) $(gsrefct_h) $(gxbitmap_h)
 gxcspace_h=$(GLSRC)gxcspace.h\
  $(gscspace_h) $(gsccolor_h) $(gscsel_h) $(gxfrac_h)
-gxht_h=$(GLSRC)gxht.h $(gsht1_h) $(gscsepnm_h) $(gsrefct_h) $(gxhttype_h) $(gxtmap_h)
+gxht_h=$(GLSRC)gxht.h $(gsht1_h) $(gsrefct_h) $(gxhttype_h) $(gxtmap_h) $(gscspace_h)
 gxcie_h=$(GLSRC)gxcie.h $(gscie_h)
 gxpcolor_h=$(GLSRC)gxpcolor.h\
  $(gspcolor_h) $(gxcspace_h) $(gxdevice_h) $(gxdevmem_h) $(gxpcache_h)
@@ -532,7 +543,7 @@
 $(GLOBJ)gxcht.$(OBJ) : $(GLSRC)gxcht.c $(GXERR) $(memory__h)\
  $(gsutil_h)\
  $(gxarith_h) $(gxcmap_h) $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h)\
- $(gxistate_h) $(gxmatrix_h) $(gzht_h)
+ $(gxistate_h) $(gxmatrix_h) $(gzht_h) $(gsserial_h)
 	$(GLCC) $(GLO_)gxcht.$(OBJ) $(C_) $(GLSRC)gxcht.c
 
 $(GLOBJ)gxclip.$(OBJ) : $(GLSRC)gxclip.c $(GX)\
@@ -559,11 +570,6 @@
  $(gsbittab_h) $(gserrors_h) $(gxdcolor_h) $(gxdevice_h)
 	$(GLCC) $(GLO_)gxdcolor.$(OBJ) $(C_) $(GLSRC)gxdcolor.c
 
-$(GLOBJ)gxdither.$(OBJ) : $(GLSRC)gxdither.c $(GX)\
- $(gsstruct_h) $(gsdcolor_h)\
- $(gxcmap_h) $(gxdevice_h) $(gxdither_h) $(gxlum_h) $(gzht_h)
-	$(GLCC) $(GLO_)gxdither.$(OBJ) $(C_) $(GLSRC)gxdither.c
-
 $(GLOBJ)gxfill.$(OBJ) : $(GLSRC)gxfill.c $(GXERR)\
  $(gsstruct_h)\
  $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxhttile_h)\
@@ -573,7 +579,8 @@
 
 $(GLOBJ)gxht.$(OBJ) : $(GLSRC)gxht.c $(GXERR) $(memory__h)\
  $(gsbitops_h) $(gsstruct_h) $(gsutil_h)\
- $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gzht_h)
+ $(gxdcolor_h) $(gxdevice_h) $(gxfixed_h) $(gxistate_h) $(gzht_h)\
+ $(gsserial_h)
 	$(GLCC) $(GLO_)gxht.$(OBJ) $(C_) $(GLSRC)gxht.c
 
 $(GLOBJ)gxhtbit.$(OBJ) : $(GLSRC)gxhtbit.c $(GXERR) $(memory__h)\
@@ -581,6 +588,15 @@
  $(gxbitmap_h) $(gxdht_h) $(gxdhtres_h) $(gxhttile_h) $(gxtmap_h)
 	$(GLCC) $(GLO_)gxhtbit.$(OBJ) $(C_) $(GLSRC)gxhtbit.c
 
+$(GLOBJ)gxwts.$(OBJ) : $(GLSRC)gxwts.c $(GXERR) $(gxwts_h)\
+ $(stdpre_h) $(memory__h) $(gxstate_h) $(gxht_h) $(math__h) $(gxdevcli_h)\
+ $(gxdht_h)
+	$(GLCC) $(GLO_)gxwts.$(OBJ) $(C_) $(GLSRC)gxwts.c
+
+$(GLOBJ)gswts.$(OBJ) : $(GLSRC)gswts.c $(GXERR) $(gxwts_h) $(gswts_h)\
+ $(stdpre_h) $(gx_h) $(gxstate_h) $(gsht_h) $(math__h) $(gxfrac_h)
+	$(GLCC) $(GLO_)gswts.$(OBJ) $(C_) $(GLSRC)gswts.c
+
 $(GLOBJ)gxidata.$(OBJ) : $(GLSRC)gxidata.c $(GXERR) $(memory__h)\
  $(gxcpath_h) $(gxdevice_h) $(gximage_h)
 	$(GLCC) $(GLO_)gxidata.$(OBJ) $(C_) $(GLSRC)gxidata.c
@@ -680,7 +696,7 @@
 	$(GLCC) $(GLO_)gschar.$(OBJ) $(C_) $(GLSRC)gschar.c
 
 $(GLOBJ)gscolor.$(OBJ) : $(GLSRC)gscolor.c $(GXERR)\
- $(gsccolor_h) $(gscssub_h) $(gsstruct_h) $(gsutil_h)\
+ $(gsccolor_h) $(gsstruct_h) $(gsutil_h)\
  $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h) $(gzstate_h)
 	$(GLCC) $(GLO_)gscolor.$(OBJ) $(C_) $(GLSRC)gscolor.c
 
@@ -695,18 +711,26 @@
 
 $(GLOBJ)gscspace.$(OBJ) : $(GLSRC)gscspace.c $(GXERR) $(memory__h)\
  $(gsccolor_h) $(gsstruct_h) $(gsutil_h)\
- $(gxcmap_h) $(gxcspace_h) $(gxistate_h)
+ $(gxcmap_h) $(gxcspace_h) $(gxistate_h) $(gsovrc_h) $(gsstate_h)\
+ $(gsdevice_h) $(gxdevcli_h)
 	$(GLCC) $(GLO_)gscspace.$(OBJ) $(C_) $(GLSRC)gscspace.c
 
-$(GLOBJ)gscssub.$(OBJ) : $(GLSRC)gscssub.c $(GXERR)\
- $(gscssub_h) $(gxcspace_h) $(gxdevcli_h) $(gzstate_h)
-	$(GLCC) $(GLO_)gscssub.$(OBJ) $(C_) $(GLSRC)gscssub.c
+$(GLOBJ)gsovrc.$(OBJ) : $(GLSRC)gsovrc.c $(GXERR)\
+ $(memory__h) $(gsutil_h) $(gxcomp_h) $(gxdevice_h) $(gsdevice_h) $(gxgetbit_h)\
+ $(gsovrc_h) $(gxdcolor_h) $(gxoprect_h) $(gsbitops_h) $(gxistate_h)
+	$(GLCC) $(GLO_)gsovrc.$(OBJ) $(C_) $(GLSRC)gsovrc.c
+
+$(GLOBJ)gxoprect.$(OBJ) : $(GLSRC)gxoprect.c $(GXERR)\
+ $(memory__h) $(gsutil_h) $(gxdevice_h) $(gsdevice_h) $(gxgetbit_h)\
+ $(gxoprect_h) $(gsbitops_h)
+	$(GLCC) $(GLO_)gxoprect.$(OBJ) $(C_) $(GLSRC)gxoprect.c
 
 $(GLOBJ)gsdevice.$(OBJ) : $(GLSRC)gsdevice.c $(GXERR)\
  $(ctype__h) $(memory__h) $(string__h) $(gp_h)\
  $(gscdefs_h) $(gscoord_h) $(gsfname_h) $(gsmatrix_h)\
  $(gspaint_h) $(gspath_h) $(gsstruct_h)\
- $(gxcmap_h) $(gxdevice_h) $(gxdevmem_h) $(gxiodev_h) $(gzstate_h)
+ $(gxcmap_h) $(gxdevice_h) $(gxdevmem_h) $(gxiodev_h) $(gzstate_h)\
+ $(gxcspace_h)
 	$(GLCC) $(GLO_)gsdevice.$(OBJ) $(C_) $(GLSRC)gsdevice.c
 
 $(GLOBJ)gsdfilt.$(OBJ) : $(GLSRC)gsdfilt.c $(GXERR)\
@@ -742,11 +766,12 @@
 	$(GLCC) $(GLO_)gsgdata.$(OBJ) $(C_) $(GLSRC)gsgdata.c
 
 $(GLOBJ)gsht.$(OBJ) : $(GLSRC)gsht.c $(GXERR) $(memory__h)\
- $(gsstruct_h) $(gsutil_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+ $(gsstruct_h) $(gsutil_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)\
+ $(gswts.h)
 	$(GLCC) $(GLO_)gsht.$(OBJ) $(C_) $(GLSRC)gsht.c
 
 $(GLOBJ)gshtscr.$(OBJ) : $(GLSRC)gshtscr.c $(GXERR) $(math__h)\
- $(gsstruct_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+ $(gsstruct_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h) $(gswts_h)
 	$(GLCC) $(GLO_)gshtscr.$(OBJ) $(C_) $(GLSRC)gshtscr.c
 
 $(GLOBJ)gsimage.$(OBJ) : $(GLSRC)gsimage.c $(GXERR) $(memory__h)\
@@ -812,10 +837,11 @@
 	$(GLCC) $(GLO_)gspath.$(OBJ) $(C_) $(GLSRC)gspath.c
 
 $(GLOBJ)gsstate.$(OBJ) : $(GLSRC)gsstate.c $(GXERR) $(memory__h)\
- $(gsalpha_h) $(gscie_h) $(gscolor2_h) $(gscoord_h) $(gscssub_h)\
+ $(gsalpha_h) $(gscie_h) $(gscolor2_h) $(gscoord_h) \
  $(gspath_h) $(gsstruct_h) $(gsutil_h)\
  $(gxclipsr_h) $(gxcmap_h) $(gxcspace_h) $(gxdevice_h) $(gxpcache_h)\
- $(gzstate_h) $(gzht_h) $(gzline_h) $(gzpath_h) $(gzcpath_h)
+ $(gzstate_h) $(gzht_h) $(gzline_h) $(gzpath_h) $(gzcpath_h)\
+ $(gsovrc_h)
 	$(GLCC) $(GLO_)gsstate.$(OBJ) $(C_) $(GLSRC)gsstate.c
 
 $(GLOBJ)gstext.$(OBJ) : $(GLSRC)gstext.c $(memory__h) $(gdebug_h)\
@@ -872,6 +898,22 @@
  $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
 	$(GLCC) $(GLO_)gdevm32.$(OBJ) $(C_) $(GLSRC)gdevm32.c
 
+$(GLOBJ)gdevm40.$(OBJ) : $(GLSRC)gdevm40.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+	$(GLCC) $(GLO_)gdevm40.$(OBJ) $(C_) $(GLSRC)gdevm40.c
+
+$(GLOBJ)gdevm48.$(OBJ) : $(GLSRC)gdevm48.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+	$(GLCC) $(GLO_)gdevm48.$(OBJ) $(C_) $(GLSRC)gdevm48.c
+
+$(GLOBJ)gdevm56.$(OBJ) : $(GLSRC)gdevm56.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+	$(GLCC) $(GLO_)gdevm56.$(OBJ) $(C_) $(GLSRC)gdevm56.c
+
+$(GLOBJ)gdevm64.$(OBJ) : $(GLSRC)gdevm64.c $(GX) $(memory__h)\
+ $(gxdevice_h) $(gxdevmem_h) $(gdevmem_h)
+	$(GLCC) $(GLO_)gdevm64.$(OBJ) $(C_) $(GLSRC)gdevm64.c
+
 $(GLOBJ)gdevmpla.$(OBJ) : $(GLSRC)gdevmpla.c $(GXERR) $(memory__h)\
  $(gsbitops_h)\
  $(gxdevice_h) $(gxdevmem_h) $(gxgetbit_h) $(gdevmem_h) $(gdevmpla_h)
@@ -971,7 +1013,7 @@
 	$(GLCC) $(GLO_)gdevdgbr.$(OBJ) $(C_) $(GLSRC)gdevdgbr.c
 
 $(GLOBJ)gdevnfwd.$(OBJ) : $(GLSRC)gdevnfwd.c $(GXERR)\
- $(gxdevice_h)
+ $(gxdevice_h) $(gxcmap_h) $(memory__h)
 	$(GLCC) $(GLO_)gdevnfwd.$(OBJ) $(C_) $(GLSRC)gdevnfwd.c
 
 ### Other device support
@@ -988,21 +1030,22 @@
 # Note: gschar.c is no longer required for a standard build;
 # we include it only for backward compatibility for library clients.
 LIB3s=$(GLOBJ)gscedata.$(OBJ) $(GLOBJ)gscencs.$(OBJ) $(GLOBJ)gschar.$(OBJ) $(GLOBJ)gscolor.$(OBJ)
-LIB4s=$(GLOBJ)gscoord.$(OBJ) $(GLOBJ)gscparam.$(OBJ) $(GLOBJ)gscspace.$(OBJ) $(GLOBJ)gscssub.$(OBJ)
+LIB4s= $(GLOBJ)gscoord.$(OBJ) $(GLOBJ)gscparam.$(OBJ) $(GLOBJ)gscspace.$(OBJ) $(GLOBJ)gsovrc.$(OBJ) $(GLOBJ)gxoprect.$(OBJ)
 LIB5s=$(GLOBJ)gsdevice.$(OBJ) $(GLOBJ)gsdevmem.$(OBJ) $(GLOBJ)gsdparam.$(OBJ) $(GLOBJ)gsdfilt.$(OBJ)
 LIB6s=$(GLOBJ)gsfname.$(OBJ) $(GLOBJ)gsfont.$(OBJ) $(GLOBJ)gsgdata.$(OBJ)
-LIB7s=$(GLOBJ)gsht.$(OBJ) $(GLOBJ)gshtscr.$(OBJ)
+LIB7s=$(GLOBJ)gsht.$(OBJ) $(GLOBJ)gshtscr.$(OBJ) $(GLOBJ)gswts.$(OBJ)
 LIB8s=$(GLOBJ)gsimage.$(OBJ) $(GLOBJ)gsimpath.$(OBJ) $(GLOBJ)gsinit.$(OBJ)
 LIB9s=$(GLOBJ)gsiodev.$(OBJ) $(GLOBJ)gsistate.$(OBJ) $(GLOBJ)gsline.$(OBJ)
 LIB10s=$(GLOBJ)gsmalloc.$(OBJ) $(GLOBJ)gsmatrix.$(OBJ) $(GLOBJ)gsmemlok.$(OBJ)
 LIB11s=$(GLOBJ)gsmemory.$(OBJ) $(GLOBJ)gsmemret.$(OBJ) $(GLOBJ)gsmisc.$(OBJ) $(GLOBJ)gsnotify.$(OBJ)
 LIB12s=$(GLOBJ)gspaint.$(OBJ) $(GLOBJ)gsparam.$(OBJ) $(GLOBJ)gspath.$(OBJ)
-LIB13s=$(GLOBJ)gsstate.$(OBJ) $(GLOBJ)gstext.$(OBJ) $(GLOBJ)gsutil.$(OBJ)
+LIB13s=$(GLOBJ)gsserial.$(OBJ) $(GLOBJ)gsstate.$(OBJ) $(GLOBJ)gstext.$(OBJ)\
+  $(GLOBJ)gsutil.$(OBJ)
 LIB1x=$(GLOBJ)gxacpath.$(OBJ) $(GLOBJ)gxbcache.$(OBJ) $(GLOBJ)gxccache.$(OBJ)
 LIB2x=$(GLOBJ)gxccman.$(OBJ) $(GLOBJ)gxchar.$(OBJ) $(GLOBJ)gxcht.$(OBJ)
 LIB3x=$(GLOBJ)gxclip.$(OBJ) $(GLOBJ)gxcmap.$(OBJ) $(GLOBJ)gxcpath.$(OBJ)
-LIB4x=$(GLOBJ)gxdcconv.$(OBJ) $(GLOBJ)gxdcolor.$(OBJ) $(GLOBJ)gxdither.$(OBJ)
-LIB5x=$(GLOBJ)gxfill.$(OBJ) $(GLOBJ)gxht.$(OBJ) $(GLOBJ)gxhtbit.$(OBJ)
+LIB4x=$(GLOBJ)gxdcconv.$(OBJ) $(GLOBJ)gxdcolor.$(OBJ)
+LIB5x=$(GLOBJ)gxfill.$(OBJ) $(GLOBJ)gxht.$(OBJ) $(GLOBJ)gxhtbit.$(OBJ) $(GLOBJ)gxwts.$(OBJ)
 LIB6x=$(GLOBJ)gxidata.$(OBJ) $(GLOBJ)gxifast.$(OBJ) $(GLOBJ)gximage.$(OBJ)
 LIB7x=$(GLOBJ)gximage1.$(OBJ) $(GLOBJ)gximono.$(OBJ) $(GLOBJ)gxipixel.$(OBJ)
 LIB8x=$(GLOBJ)gxpaint.$(OBJ) $(GLOBJ)gxpath.$(OBJ) $(GLOBJ)gxpath2.$(OBJ)
@@ -1012,10 +1055,11 @@
 LIB2d=$(GLOBJ)gdevdgbr.$(OBJ) $(GLOBJ)gdevnfwd.$(OBJ) $(GLOBJ)gdevmem.$(OBJ) $(GLOBJ)gdevplnx.$(OBJ)
 LIB3d=$(GLOBJ)gdevm1.$(OBJ) $(GLOBJ)gdevm2.$(OBJ) $(GLOBJ)gdevm4.$(OBJ) $(GLOBJ)gdevm8.$(OBJ)
 LIB4d=$(GLOBJ)gdevm16.$(OBJ) $(GLOBJ)gdevm24.$(OBJ) $(GLOBJ)gdevm32.$(OBJ) $(GLOBJ)gdevmpla.$(OBJ)
+LIB4e=$(GLOBJ)gdevm40.$(OBJ) $(GLOBJ)gdevm48.$(OBJ) $(GLOBJ)gdevm56.$(OBJ) $(GLOBJ)gdevm64.$(OBJ)
 LIBs=$(LIB0s) $(LIB1s) $(LIB2s) $(LIB3s) $(LIB4s) $(LIB5s) $(LIB6s) $(LIB7s)\
  $(LIB8s) $(LIB9s) $(LIB10s) $(LIB11s) $(LIB12s) $(LIB13s)
 LIBx=$(LIB1x) $(LIB2x) $(LIB3x) $(LIB4x) $(LIB5x) $(LIB6x) $(LIB7x) $(LIB8x) $(LIB9x) $(LIB10x)
-LIBd=$(LIB1d) $(LIB2d) $(LIB3d) $(LIB4d)
+LIBd=$(LIB1d) $(LIB2d) $(LIB3d) $(LIB4d) $(LIB4e)
 LIB_ALL=$(LIBs) $(LIBx) $(LIBd)
 # We include some optional library modules in the dependency list,
 # but not in the link, to catch compilation problems.
@@ -1035,6 +1079,7 @@
 	$(ADDMOD) $(GLD)libs $(LIB11s)
 	$(ADDMOD) $(GLD)libs $(LIB12s)
 	$(ADDMOD) $(GLD)libs $(LIB13s)
+	$(ADDCOMP) $(GLD)libs overprint
 	$(ADDMOD) $(GLD)libs -init gshtscr gsutil
 	$(ADDMOD) $(GLD)libs -include $(GLD)gsiodevs
 
@@ -1057,6 +1102,7 @@
 	$(ADDMOD) $(GLD)libd $(LIB2d)
 	$(ADDMOD) $(GLD)libd $(LIB3d)
 	$(ADDMOD) $(GLD)libd $(LIB4d)
+	$(ADDMOD) $(GLD)libd $(LIB4e)
 
 $(GLD)libcore.dev : $(LIB_MAK) $(ECHOGS_XE)\
  $(GLD)libs.dev $(GLD)libx.dev $(GLD)libd.dev\
@@ -1441,6 +1487,7 @@
 
 # ---------------- Banded ("command list") devices ---------------- #
 
+gdevht_h=$(GLSRC)gdevht.h $(gzht_h)
 gxcldev_h=$(GLSRC)gxcldev.h $(gxclist_h) $(gsropt_h) $(gxht_h) $(gxtmap_h) $(gxdht_h)\
  $(strimpl_h) $(scfx_h) $(srlx_h)
 gxclpage_h=$(GLSRC)gxclpage.h $(gxclio_h)
@@ -1451,7 +1498,7 @@
 clbase3_=$(GLOBJ)gxclutil.$(OBJ) $(GLOBJ)gsparams.$(OBJ)
 # gxclrect.c requires rop_proc_table, so we need gsroptab here.
 clbase4_=$(GLOBJ)gsroptab.$(OBJ) $(GLOBJ)stream.$(OBJ)
-clpath_=$(GLOBJ)gxclimag.$(OBJ) $(GLOBJ)gxclpath.$(OBJ)
+clpath_=$(GLOBJ)gxclimag.$(OBJ) $(GLOBJ)gxclpath.$(OBJ) $(GLOBJ)gxdhtserial.$(OBJ)
 clist_=$(clbase1_) $(clbase2_) $(clbase3_) $(clbase4_) $(clpath_)
 $(GLD)clist.dev : $(LIB_MAK) $(ECHOGS_XE) $(clist_)\
  $(GLD)cl$(BAND_LIST_STORAGE).dev\
@@ -1464,6 +1511,10 @@
 	$(ADDMOD) $(GLD)clist -include $(GLD)cl$(BAND_LIST_STORAGE)
 	$(ADDMOD) $(GLD)clist -include $(GLD)cfe $(GLD)cfd $(GLD)rle $(GLD)rld $(GLD)psl2cs
 
+$(GLOBJ)gdevht.$(OBJ) : $(GLSRC)gdevht.c $(GXERR)\
+ $(gdevht_h) $(gxdcconv_h) $(gxdcolor_h) $(gxdevice_h) $(gxdither_h)
+	$(GLCC) $(GLO_)gdevht.$(OBJ) $(C_) $(GLSRC)gdevht.c
+
 $(GLOBJ)gxclist.$(OBJ) : $(GLSRC)gxclist.c $(GXERR) $(memory__h) $(string__h)\
  $(gp_h) $(gpcheck_h) $(gsparams_h)\
  $(gxcldev_h) $(gxclpath_h) $(gxdevice_h) $(gxdevmem_h)
@@ -1479,20 +1530,19 @@
 
 $(GLOBJ)gxclrast.$(OBJ) : $(GLSRC)gxclrast.c $(GXERR)\
  $(memory__h) $(gp_h) $(gpcheck_h)\
- $(gsbitops_h) $(gscdefs_h) $(gscoord_h) $(gsdevice_h) $(gserrors_h)\
+ $(gdevht_h)\
+ $(gsbitops_h) $(gscdefs_h) $(gscoord_h) $(gsdevice_h)\
  $(gsiparm4_h) $(gsparams_h) $(gsstate_h)\
- $(gxcldev_h) $(gxclpath_h)\
- $(gxcmap_h) $(gxcolor2_h) $(gxcspace_h)\
- $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxdht_h) $(gxdhtres_h)\
- $(gxgetbit_h) $(gxht_h) $(gxiparam_h) $(gxhttile_h)\
- $(gxpaint_h)\
- $(gzacpath_h) $(gzcpath_h) $(gzht_h) $(gzpath_h)\
- $(stream_h) $(strimpl_h)
+ $(gxcldev_h) $(gxclpath_h) $(gxcmap_h) $(gxcolor2_h) $(gxcspace_h)\
+ $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxdhtres_h) $(gxgetbit_h)\
+ $(gxhttile_h) $(gxiparam_h) $(gxpaint_h)\
+ $(gzacpath_h) $(gzcpath_h) $(gzpath_h)\
+ $(stream_h) $(strimpl_h) $(gxcomp_h)
 	$(GLCC) $(GLO_)gxclrast.$(OBJ) $(C_) $(GLSRC)gxclrast.c
 
 $(GLOBJ)gxclread.$(OBJ) : $(GLSRC)gxclread.c $(GXERR)\
  $(memory__h) $(gp_h) $(gpcheck_h)\
- $(gdevplnx_h) $(gdevprn_h)\
+ $(gdevht_h) $(gdevplnx_h) $(gdevprn_h)\
  $(gscoord_h) $(gsdevice_h)\
  $(gxcldev_h) $(gxdevice_h) $(gxdevmem_h) $(gxgetbit_h) $(gxhttile_h)\
  $(stream_h) $(strimpl_h)
@@ -1506,7 +1556,7 @@
  $(gscdefs_h) $(gscspace_h)\
  $(gxarith_h) $(gxcldev_h) $(gxclpath_h) $(gxcspace_h)\
  $(gxdevice_h) $(gxdevmem_h) $(gxfmap_h) $(gxiparam_h) $(gxpath_h)\
- $(sisparam_h) $(stream_h) $(strimpl_h)
+ $(sisparam_h) $(stream_h) $(strimpl_h) $(gxcomp_h)
 	$(GLCC) $(GLO_)gxclimag.$(OBJ) $(C_) $(GLSRC)gxclimag.c
 
 $(GLOBJ)gxclpath.$(OBJ) : $(GLSRC)gxclpath.c $(GXERR)\
@@ -1517,6 +1567,11 @@
  $(stream_h)
 	$(GLCC) $(GLO_)gxclpath.$(OBJ) $(C_) $(GLSRC)gxclpath.c
 
+$(GLOBJ)gxdhtserial.$(OBJ) : $(GLSRC)gxdhtserial.c $(memory__h) $(GXERR)\
+ $(gscdefs_h) $(gsstruct_h) $(gsutil_h) $(gzstate_h) $(gxdevice_h) $(gzht_h)\
+ $(gswts_h) $(gxdhtres_h) $(gsserial_h) $(gxdhtserial_h)
+	$(GLCC) $(GLO_)gxdhtserial.$(OBJ) $(C_) $(GLSRC)gxdhtserial.c
+
 $(GLOBJ)gxclutil.$(OBJ) : $(GLSRC)gxclutil.c $(GXERR) $(memory__h) $(string__h)\
  $(gp_h) $(gpcheck_h)\
  $(gsparams_h)\
@@ -1529,8 +1584,7 @@
 $(GLD)clfile.dev : $(LIB_MAK) $(ECHOGS_XE) $(clfile_)
 	$(SETMOD) $(GLD)clfile $(clfile_)
 
-$(GLOBJ)gxclfile.$(OBJ) : $(GLSRC)gxclfile.c\
- $(stdio__h) $(string__h) $(unistd__h)\
+$(GLOBJ)gxclfile.$(OBJ) : $(GLSRC)gxclfile.c $(stdio__h) $(string__h)\
  $(gp_h) $(gsmemory_h) $(gserror_h) $(gserrors_h) $(gxclio_h)
 	$(GLCC) $(GLO_)gxclfile.$(OBJ) $(C_) $(GLSRC)gxclfile.c
 
@@ -1598,7 +1652,7 @@
 # ---------------- Extended halftone support ---------------- #
 # This is only used by one non-PostScript-based project.
 
-gshtx_h=$(GLSRC)gshtx.h $(gscsepnm_h) $(gsht1_h) $(gsmemory_h) $(gxtmap_h)
+gshtx_h=$(GLSRC)gshtx.h $(gsht1_h) $(gsmemory_h) $(gxtmap_h) $(gscspace_h)
 
 htxlib_=$(GLOBJ)gshtx.$(OBJ)
 $(GLD)htxlib.dev : $(LIB_MAK) $(ECHOGS_XE) $(htxlib_)
@@ -1968,13 +2022,14 @@
 	$(SETMOD) $(GLD)cmyklib $(cmyklib_)
 
 $(GLOBJ)gscolor1.$(OBJ) : $(GLSRC)gscolor1.c $(GXERR)\
- $(gsccolor_h) $(gscolor1_h) $(gscssub_h) $(gsstruct_h) $(gsutil_h)\
+ $(gsccolor_h) $(gscolor1_h) $(gsstruct_h) $(gsutil_h)\
  $(gxcmap_h) $(gxcspace_h) $(gxdcconv_h) $(gxdevice_h)\
- $(gzstate_h)
+ $(gzstate_h) $(gxhttype_h)
 	$(GLCC) $(GLO_)gscolor1.$(OBJ) $(C_) $(GLSRC)gscolor1.c
 
 $(GLOBJ)gsht1.$(OBJ) : $(GLSRC)gsht1.c $(GXERR) $(memory__h)\
- $(gsstruct_h) $(gsutil_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)
+ $(gsstruct_h) $(gsutil_h) $(gxdevice_h) $(gzht_h) $(gzstate_h)\
+ $(gxwts_h) $(gswts_h)
 	$(GLCC) $(GLO_)gsht1.$(OBJ) $(C_) $(GLSRC)gsht1.c
 
 colimlib_=$(GLOBJ)gxicolor.$(OBJ)
@@ -1990,16 +2045,6 @@
  $(gzstate_h)
 	$(GLCC) $(GLO_)gxicolor.$(OBJ) $(C_) $(GLSRC)gxicolor.c
 
-# ---------------- HSB color ---------------- #
-
-hsblib_=$(GLOBJ)gshsb.$(OBJ)
-$(GLD)hsblib.dev : $(LIB_MAK) $(ECHOGS_XE) $(hsblib_)
-	$(SETMOD) $(GLD)hsblib $(hsblib_)
-
-$(GLOBJ)gshsb.$(OBJ) : $(GLSRC)gshsb.c $(GX)\
- $(gscolor_h) $(gshsb_h) $(gxfrac_h)
-	$(GLCC) $(GLO_)gshsb.$(OBJ) $(C_) $(GLSRC)gshsb.c
-
 # ---- Level 1 path miscellany (arcs, pathbbox, path enumeration) ---- #
 
 path1lib_=$(GLOBJ)gspath1.$(OBJ)
@@ -2119,7 +2164,8 @@
 	$(SETMOD) $(GLD)cspixlib $(cspixlib_)
 
 $(GLOBJ)gscpixel.$(OBJ) : $(GLSRC)gscpixel.c $(GXERR)\
- $(gsrefct_h) $(gscpixel_h) $(gxcspace_h) $(gxdevice_h)
+ $(gsrefct_h) $(gscpixel_h) $(gxcspace_h) $(gxdevice_h) $(gxistate_h)\
+ $(gsovrc_h) $(gsstate_h)
 	$(GLCC) $(GLO_)gscpixel.$(OBJ) $(C_) $(GLSRC)gscpixel.c
 
 # ---------------- CIE color ---------------- #
@@ -2186,7 +2232,8 @@
 
 $(GLOBJ)gscsepr.$(OBJ) : $(GLSRC)gscsepr.c $(GXERR) $(memory__h)\
  $(gscsepr_h) $(gsfunc_h) $(gsmatrix_h) $(gsrefct_h)\
- $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) $(gzstate_h)
+ $(gxcolor2_h) $(gxcspace_h) $(gxfixed_h) $(gzstate_h)\
+ $(gscdevn_h) $(gxcdevn_h) $(gxcmap_h) $(gxdevcli_h)
 	$(GLCC) $(GLO_)gscsepr.$(OBJ) $(C_) $(GLSRC)gscsepr.c
 
 # ================ Display Postscript extensions ================ #
@@ -2229,6 +2276,7 @@
 dpnxtlib_=$(GLOBJ)gsalphac.$(OBJ)
 $(GLD)dpnxtlib.dev : $(LIB_MAK) $(ECHOGS_XE) $(dpnxtlib_)
 	$(SETMOD) $(GLD)dpnxtlib $(dpnxtlib_)
+	$(ADDCOMP) $(GLD)dpnxtlib alpha
 
 # ================ PostScript LanguageLevel 3 support ================ #
 
@@ -2237,12 +2285,18 @@
  $(gxcdevn_h) $(gxcspace_h)
 	$(GLCC) $(GLO_)gscdevn.$(OBJ) $(C_) $(GLSRC)gscdevn.c
 
+$(GLOBJ)gxdevndi.$(OBJ) : $(GLSRC)gxdevndi.c $(GX)\
+ $(gsstruct_h) $(gsdcolor_h)\
+ $(gxcmap_h) $(gxdevice_h) $(gxdevndi_h) $(gxlum_h) $(gzht_h)
+	$(GLCC) $(GLO_)gxdevndi.$(OBJ) $(C_) $(GLSRC)gxdevndi.c
+
 $(GLOBJ)gsclipsr.$(OBJ) : $(GLSRC)gsclipsr.c $(GXERR)\
  $(gsclipsr_h) $(gsstruct_h) $(gxclipsr_h) $(gxfixed_h) $(gxpath_h)\
  $(gzstate_h)
 	$(GLCC) $(GLO_)gsclipsr.$(OBJ) $(C_) $(GLSRC)gsclipsr.c
 
-psl3lib_=$(GLOBJ)gsclipsr.$(OBJ) $(GLOBJ)gscdevn.$(OBJ)
+psl3lib_=$(GLOBJ)gsclipsr.$(OBJ) $(GLOBJ)gscdevn.$(OBJ) $(GLOBJ)gxdevndi.$(OBJ)
+
 $(GLD)psl3lib.dev : $(LIB_MAK) $(ECHOGS_XE) $(psl3lib_)\
  $(GLD)imasklib.dev $(GLD)shadelib.dev $(GLD)gxfapiu$(UFST_BRIDGE).dev
 	$(SETMOD) $(GLD)psl3lib $(psl3lib_)
@@ -2287,7 +2341,7 @@
  $(gsstruct_h) $(gstparam_h)\
  $(gxblend_h) $(gxdcolor_h) $(gxdevice_h) $(gxiparam_h) $(gxistate_h)\
  $(gxtext_h)\
- $(gzstate_h) $(gdevp14_h)
+ $(gzstate_h) $(gdevp14_h) $(gsovrc_h)
 	$(GLCC) $(GLO_)gdevp14.$(OBJ) $(C_) $(GLSRC)gdevp14.c
 
 translib_=$(GLOBJ)gstrans.$(OBJ) $(GLOBJ)gximag3x.$(OBJ)\
@@ -2319,7 +2373,8 @@
 
 $(GLOBJ)gsptype2.$(OBJ) : $(GLSRC)gsptype2.c $(GX)\
  $(gscspace_h) $(gsmatrix_h) $(gsptype2_h) $(gsshade_h) $(gsstate_h)\
- $(gxcolor2_h) $(gxdcolor_h) $(gxpcolor_h) $(gxstate_h) $(gzpath_h)
+ $(gxcolor2_h) $(gxdcolor_h) $(gxpcolor_h) $(gxstate_h) $(gzpath_h)\
+ $(gzstate_h)
 	$(GLCC) $(GLO_)gsptype2.$(OBJ) $(C_) $(GLSRC)gsptype2.c
 
 $(GLOBJ)gsshade.$(OBJ) : $(GLSRC)gsshade.c $(GXERR)\
@@ -2495,7 +2550,7 @@
 $(GLOBJ)gslib.$(OBJ) : $(GLSRC)gslib.c $(AK)\
  $(math__h) $(stdio__h) $(string__h)\
  $(gx_h) $(gp_h)\
- $(gsalloc_h) $(gscssub_h) $(gserrors_h) $(gsmatrix_h)\
+ $(gsalloc_h) $(gserrors_h) $(gsmatrix_h)\
  $(gsrop_h) $(gsstate_h) $(gscspace_h)\
  $(gscdefs_h) $(gscie_h) $(gscolor2_h) $(gscoord_h) $(gscrd_h)\
  $(gshtx_h) $(gsiparm3_h) $(gsiparm4_h) $(gslib_h) $(gsparam_h)\

Index: msvc32.mak
===================================================================
RCS file: /cvs/ghostscript/gs/src/msvc32.mak,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- msvc32.mak	3 Apr 2002 20:14:28 -0000	1.29
+++ msvc32.mak	22 Aug 2002 07:12:29 -0000	1.30
@@ -209,12 +209,25 @@
 IJSEXECTYPE=win
 !endif
 
+# 1 --> Use 64 bits for gx_color_index.  This is required only for
+# non standard devices or DeviceN process color model devices.
+USE_LARGE_COLOR_INDEX=0
+
+!if $(USE_LARGE_COLOR_INDEX) == 1
+# Definitions to force gx_color_index to 64 bits
+LARGEST_UINTEGER_TYPE=unsigned __int64
+GX_COLOR_INDEX_TYPE=$(LARGEST_UINTEGER_TYPE)
+
+CFLAGS=/DGX_COLOR_INDEX_TYPE="$(GX_COLOR_INDEX_TYPE)"
+!endif
+
 # Define any other compilation flags.
 
 !ifndef CFLAGS
 CFLAGS=
 !endif
 
+#
 # Do not edit the next group of lines.
 
 #!include $(COMMONDIR)\msvcdefs.mak
@@ -508,6 +521,7 @@
 DEVICE_DEVS18=$(DD)pj.dev $(DD)pjxl.dev $(DD)pjxl300.dev $(DD)jetp3852.dev $(DD)r4081.dev
 DEVICE_DEVS19=$(DD)lbp8.dev $(DD)m8510.dev $(DD)necp6.dev $(DD)bjc600.dev $(DD)bjc800.dev
 DEVICE_DEVS20=$(DD)pnm.dev $(DD)pnmraw.dev $(DD)ppm.dev $(DD)ppmraw.dev
+DEVICE_DEVS21=$(DD)spotrgb.dev $(DD)spotcmyk.dev $(DD)devicen.dev $(DD)bmpsep1.dev $(DD)bmpsep8.dev $(DD)bmp16m.dev $(DD)bmp32b.dev
 !endif
 
 # FAPI compilation options :

Index: openvms.mak
===================================================================
RCS file: /cvs/ghostscript/gs/src/openvms.mak,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- openvms.mak	3 Apr 2002 18:25:03 -0000	1.23
+++ openvms.mak	22 Aug 2002 07:12:29 -0000	1.24
@@ -235,6 +235,7 @@
 DEVICE_DEVS18=
 DEVICE_DEVS19=
 DEVICE_DEVS20=
+DEVICE_DEVS21=
 
 # Choose the language feature(s) to include.  See gs.mak for details.
 

Index: unix-gcc.mak
===================================================================
RCS file: /cvs/ghostscript/gs/src/unix-gcc.mak,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -d -r1.33 -r1.34
--- unix-gcc.mak	19 Apr 2002 00:54:31 -0000	1.33
+++ unix-gcc.mak	22 Aug 2002 07:12:29 -0000	1.34
@@ -215,7 +215,7 @@
 # and shared object builds.
 
 CFLAGS_STANDARD=-O2
-CFLAGS_DEBUG=-g -O
+CFLAGS_DEBUG=-g -O0
 CFLAGS_PROFILE=-pg -O2
 CFLAGS_SO=-fPIC
 
@@ -386,8 +386,8 @@
 #DEVICE_DEVS19=
 #DEVICE_DEVS20=
 
-DEVICE_DEVS1=$(DD)bmpmono.dev $(DD)bmpgray.dev $(DD)bmpsep1.dev $(DD)bmpsep8.dev $(DD)bmp16.dev $(DD)bmp256.dev $(DD)bmp16m.dev $(DD)bmp32b.dev
-DEVICE_DEVS2=
+DEVICE_DEVS1=$(DD)bmpmono.dev $(DD)bmpgray.dev $(DD)bmpsep1.dev $(DD)bmpsep8.dev $(DD)bmp16.dev $(DD)bmp256.dev $(DD)bmp16m.dev $(DD)bmp32b.dev $(DD)stcolor.dev
+DEVICE_DEVS2=$(DD)epson.dev $(DD)eps9high.dev $(DD)eps9mid.dev $(DD)epsonc.dev $(DD)ibmpro.dev
 DEVICE_DEVS3=$(DD)deskjet.dev $(DD)djet500.dev $(DD)laserjet.dev $(DD)ljetplus.dev $(DD)ljet2p.dev $(DD)ljet3.dev $(DD)ljet3d.dev $(DD)ljet4.dev $(DD)ljet4d.dev $(DD)lj5mono.dev $(DD)lj5gray.dev
 DEVICE_DEVS4=$(DD)cdeskjet.dev $(DD)cdjcolor.dev $(DD)cdjmono.dev $(DD)cdj550.dev $(DD)pj.dev $(DD)pjxl.dev $(DD)pjxl300.dev
 DEVICE_DEVS5=$(DD)uniprint.dev $(DD)ijs.dev
@@ -407,6 +407,7 @@
 DEVICE_DEVS18=
 DEVICE_DEVS19=
 DEVICE_DEVS20=$(DD)cljet5.dev $(DD)cljet5c.dev
+DEVICE_DEVS21=$(DD)spotrgb.dev $(DD)spotcmyk.dev $(DD)devicen.dev $(DD)xcf.dev $(DD)bmpsep1.dev $(DD)bmpsep8.dev $(DD)bmp16m.dev $(DD)bmp32b.dev
 
 # ---------------------------- End of options --------------------------- #
 
@@ -424,7 +425,7 @@
 
 # Define the compilation rules and flags.
 
-CCFLAGS=$(GENOPT) $(CAPOPT) $(CFLAGS)
+CCFLAGS=$(GENOPT) $(CAPOPT) $(CFLAGS) -DGX_COLOR_INDEX_TYPE='unsigned long long'
 CC_=$(CC) `cat $(AK)` $(CCFLAGS)
 CCAUX=$(CC) `cat $(AK)`
 CC_LEAF=$(CC_) -fomit-frame-pointer

Index: watclib.mak
===================================================================
RCS file: /cvs/ghostscript/gs/src/watclib.mak,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- watclib.mak	29 Mar 2002 00:19:09 -0000	1.17
+++ watclib.mak	22 Aug 2002 07:12:29 -0000	1.18
@@ -117,7 +117,7 @@
 !include $(GLSRCDIR)\wccommon.mak
 
 !ifndef FEATURE_DEVS
-FEATURE_DEVS=$(GLD)patlib.dev $(GLD)path1lib.dev $(GLD)hsblib.dev
+FEATURE_DEVS=$(GLD)patlib.dev $(GLD)path1lib.dev
 !endif
 !ifndef DEVICE_DEVS
 DEVICE_DEVS=$(DD)vga.dev

Index: zcolor.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zcolor.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- zcolor.c	16 Jun 2002 03:43:50 -0000	1.8
+++ zcolor.c	22 Aug 2002 07:12:29 -0000	1.9
@@ -26,141 +26,331 @@
 #include "gxfixed.h"
 #include "gxmatrix.h"
 #include "gzstate.h"
+#include "gxdcolor.h"		/* for gxpcolor.h */
 #include "gxdevice.h"
+#include "gxdevmem.h"		/* for gxpcolor.h */
 #include "gxcmap.h"
+#include "gxcspace.h"
+#include "gxcolor2.h"
+#include "gxpcolor.h"
+#include "idict.h"
 #include "icolor.h"
 
-/* Imported from gsht.c */
-void gx_set_effective_transfer(gs_state *);
 
-/* Define the number of stack slots needed for zcolor_remap_one. */
-const int zcolor_remap_one_ostack = 4;
-const int zcolor_remap_one_estack = 3;
+/* imported from gsht.c */
+extern  void    gx_set_effective_transfer(gs_state *);
 
-/* - currentgray <gray> */
+/* define the number of stack slots needed for zcolor_remap_one */
+const int   zcolor_remap_one_ostack = 4;
+const int   zcolor_remap_one_estack = 3;
+
+
+/* utility to test whether a Pattern instance uses a base space */
+private inline bool
+pattern_instance_uses_base_space(const gs_pattern_instance_t * pinst)
+{
+    return pinst->type->procs.uses_base_space(
+                   pinst->type->procs.get_pattern(pinst) );
+}
+
+/*
+ *  -   currentcolor   <param1>  ...  <paramN>
+ *
+ * Return the current color. <paramN> may be a dictionary or a null
+ * object, if the current color space is a pattern color space. The
+ * other parameters will be numeric.
+ *
+ * Note that the results of this operator differ slightly from those of
+ * most currentcolor implementations. If a color component value is 
+ * integral (e.g.: 0, 1), it will be pushed on the stack as an integer.
+ * Most currentcolor implementations, including the earlier
+ * implementation in Ghostscript, would push real objects for all
+ * color spaces except indexed color space. The approach taken here is
+ * equally legitimate, and avoids special handling of indexed color
+ * spaces.
+ */
 private int
-zcurrentgray(i_ctx_t *i_ctx_p)
+zcurrentcolor(i_ctx_t * i_ctx_p)
 {
-    os_ptr op = osp;
-    float gray;
-    int code = gs_currentgray(igs, &gray);
+    os_ptr                  op = osp;
+    const gs_color_space *  pcs = gs_currentcolorspace(igs);
+    const gs_client_color * pcc = gs_currentcolor(igs);
+    int                     i, n = cs_num_components(pcs);
+    bool                    push_pattern = n < 0;
+
+    /* check for pattern */
+    if (push_pattern) {
+        gs_pattern_instance_t * pinst = pcc->pattern;
+
+        if (pinst == 0 || !pattern_instance_uses_base_space(pinst))
+            n = 1;
+        else
+            n = -n;
+    }
+
+    /* check for sufficient space on the stack */
+    push(n);
+    op -= n - 1;
+
+    /* push the numeric operands, if any */
+    if (push_pattern)
+        --n;
+    for (i = 0; i < n; i++, op++) {
+        float   rval = pcc->paint.values[i];
+        int     ival = (int)rval;
+
+        /* the following handles indexed color spaces */
+        if (rval == ival)
+            make_int(op, ival);
+        else
+            make_real(op, rval);
+    }
+
+    /* push the pattern dictionary or null object, if appropriate */
+    if (push_pattern)
+        *op = istate->pattern;
 
-    if (code < 0)
-	return code;
-    push(1);
-    make_real(op, gray);
     return 0;
 }
 
-/* - currentrgbcolor <red> <green> <blue> */
+/*
+ *  -   .currentcolorspace   <array>
+ *
+ * Return the current color space. Unlike the prior implementation, the
+ * istate->color_space.array field will now always have a legitimate
+ * (array) value.
+ */
 private int
-zcurrentrgbcolor(i_ctx_t *i_ctx_p)
+zcurrentcolorspace(i_ctx_t * i_ctx_p)
 {
-    os_ptr op = osp;
-    float par[3];
-    int code = gs_currentrgbcolor(igs, par);
+    os_ptr  op = osp;   /* required by "push" macro */
 
-    if (code < 0)
-	return code;
-    push(3);
-    make_floats(op - 2, par, 3);
+    push(1);
+    *op = istate->colorspace.array;
     return 0;
 }
 
-/* - currenttransfer <proc> */
+/*
+ *  -   .getuseciecolor   <bool>
+ *
+ * Return the current setting of the use_cie_color graphic state parameter,
+ * which tracks the UseCIEColor page device parameter. This parameter may be
+ * read (via this operator) at all language leves, but may only be set (via
+ * the .setuseciecolor operator; see zcolor2.c) only in language level 3.
+ *
+ * We hanlde this parameter separately from the page device primarily for
+ * performance reasons (the parameter may be queried frequently), but as a
+ * side effect achieve proper behavior relative to the langauge level. The
+ * interpreter is always initialized with this parameter set to false, and
+ * it can only be updated (via setpagedevice) in language level 3.
+ */
 private int
-zcurrenttransfer(i_ctx_t *i_ctx_p)
+zgetuseciecolor(i_ctx_t * i_ctx_p)
 {
-    os_ptr op = osp;
+    os_ptr  op = osp;
 
     push(1);
-    *op = istate->transfer_procs.colored.gray;
+    *op = istate->use_cie_color;
     return 0;
 }
 
-/* - processcolors <int> - */
-/* Note: this is an undocumented operator that is not supported */
-/* in Level 2. */
+/*
+ *  <param1>  ...  <paramN>   setcolor   -
+ *
+ * Set the current color. All of the parameters except the topmost (paramN) are
+ * numbers; the topmost (and possibly only) entry may be pattern dictionary or
+ * a null object.
+ *
+ * The use of one operator to set both patterns and "normal" colors is
+ * consistent with Adobe's documentation, but primarily reflects the use of
+ * gs_setcolor for both purposes in the graphic library. An alternate
+ * implementation would use a .setpattern operator, which would interface with
+ * gs_setpattern.
+ *
+ * This operator is hidden by a pseudo-operator of the same name, so it will
+ * only be invoked under controlled situations. Hence, it does no operand
+ * checking.
+ */
 private int
-zprocesscolors(i_ctx_t *i_ctx_p)
+zsetcolor(i_ctx_t * i_ctx_p)
 {
-    os_ptr op = osp;
+    os_ptr                  op = osp;
+    const gs_color_space *  pcs = gs_currentcolorspace(igs);
+    gs_client_color         cc;
+    int                     n_comps, n_numeric_comps, num_offset = 0, code;
 
-    push(1);
-    make_int(op, gs_currentdevice(igs)->color_info.num_components);
-    return 0;
+    /* initialize the client color pattern pointer for GC */
+    cc.pattern = 0;
+
+    /* check for a pattern color space */
+    if ((n_comps = cs_num_components(pcs)) < 0) {
+        n_comps = -n_comps;
+        if (r_has_type(op, t_dictionary)) {
+            ref *   pImpl;
+
+            dict_find_string(op, "Implementation", &pImpl);
+            cc.pattern = r_ptr(pImpl, gs_pattern_instance_t);
+            n_numeric_comps = ( pattern_instance_uses_base_space(cc.pattern)
+                                  ? n_comps - 1
+                                  : 0 );
+        } else
+            n_numeric_comps = 0;
+        num_offset = 1;
+    } else
+        n_numeric_comps = n_comps;
+
+    /* gather the numeric operands */
+    float_params(op - num_offset, n_numeric_comps, cc.paint.values);
+ 
+    /* pass the color to the graphic library */
+    if ((code = gs_setcolor(igs, &cc)) >= 0) {
+        if (n_comps > n_numeric_comps) {
+            istate->pattern = *op;      /* save pattern dict or null */
+            n_comps = n_numeric_comps + 1;
+        }
+        pop(n_comps);
+    }
+
+    return code;
 }
 
-/* <gray> setgray - */
+/*
+ *  <array>   setcolorspace   -
+ *
+ * Set the nominal color space. This color space will be pushd by the
+ * currentcolorspace operator, but is not directly used to pass color
+ * space information to the graphic library.
+ *
+ * This operator can only be called from within the setcolorspace
+ * pseudo-operator; the definition of the latter will override this
+ * definition. Because error cheching is performed by the pseudo-
+ * operator, it need not be repeated here.
+ */
 private int
-zsetgray(i_ctx_t *i_ctx_p)
+zsetcolorspace(i_ctx_t * i_ctx_p)
 {
-    os_ptr op = osp;
-    double gray;
-    int code;
+    os_ptr  op = osp;
 
-    if (real_param(op, &gray) < 0)
-	return_op_typecheck(op);
-    if ((code = gs_setgray(igs, gray)) < 0)
-	return code;
-    make_null(&istate->colorspace.array);
+    istate->colorspace.array = *op;
     pop(1);
     return 0;
 }
 
-/* <red> <green> <blue> setrgbcolor - */
+/*
+ *  <int>   .setdevcspace   -
+ *
+ * Set a parameterless color space. This is now used to set the
+ * DeviceGray, DeviceRGB, and DeviceCMYK color spaces, rather than
+ * the setgray/setrgbcolor/setcmykcolor operators. All PostScript-based
+ * color space substitution will have been accomplished before this
+ * operator is called.
+ *
+ * The use of an integer to indicate the specific color space is 
+ * historical and on the whole not particularly desirable, as it ties
+ * the PostScript code to a specific enumeration. This may be modified
+ * in the future.
+ *
+ * As with setcolorspace, this operator is called only under controlled
+ * circumstances, hence it does no operand error checking.
+ */
 private int
-zsetrgbcolor(i_ctx_t *i_ctx_p)
+zsetdevcspace(i_ctx_t * i_ctx_p)
 {
-    os_ptr op = osp;
-    double par[3];
-    int code;
 
-    if ((code = num_params(op, 3, par)) < 0 ||
-	(code = gs_setrgbcolor(igs, par[0], par[1], par[2])) < 0
-	)
-	return code;
-    make_null(&istate->colorspace.array);
-    pop(3);
+    gs_color_space  cs;
+    int             code;
+
+    switch((gs_color_space_index)osp->value.intval) {
+      default:  /* can't happen */
+      case gs_color_space_index_DeviceGray:
+        gs_cspace_init_DeviceGray(&cs);
+        break;
+
+      case gs_color_space_index_DeviceRGB:
+        gs_cspace_init_DeviceRGB(&cs);
+        break;
+
+      case gs_color_space_index_DeviceCMYK:
+        gs_cspace_init_DeviceCMYK(&cs);
+        break;
+    }
+    if ((code = gs_setcolorspace(igs, &cs)) >= 0)
+        pop(1);
+    return code;
+}
+
+
+/*  -   currenttransfer   <proc> */
+private int
+zcurrenttransfer(i_ctx_t *i_ctx_p)
+{
+    os_ptr  op = osp;
+
+    push(1);
+    *op = istate->transfer_procs.gray;
+    return 0;
+}
+
+/*
+ *  -   processcolors   <int>  -
+ *
+ * Note: this is an undocumented operator that is not supported
+ * in Level 2.
+ */
+private int
+zprocesscolors(i_ctx_t * i_ctx_p)
+{
+    os_ptr  op = osp;
+
+    push(1);
+    make_int(op, gs_currentdevice(igs)->color_info.num_components);
     return 0;
 }
 
 /* <proc> settransfer - */
 private int
-zsettransfer(i_ctx_t *i_ctx_p)
+zsettransfer(i_ctx_t * i_ctx_p)
 {
-    os_ptr op = osp;
-    int code;
+    os_ptr  op = osp;
+    int     code;
 
     check_proc(*op);
     check_ostack(zcolor_remap_one_ostack - 1);
     check_estack(1 + zcolor_remap_one_estack);
-    istate->transfer_procs.colored.red =
-	istate->transfer_procs.colored.green =
-	istate->transfer_procs.colored.blue =
-	istate->transfer_procs.colored.gray = *op;
-    code = gs_settransfer_remap(igs, gs_mapped_transfer, false);
-    if (code < 0)
-	return code;
+    istate->transfer_procs.red =
+        istate->transfer_procs.green =
+        istate->transfer_procs.blue =
+        istate->transfer_procs.gray = *op;
+    if ((code = gs_settransfer_remap(igs, gs_mapped_transfer, false)) < 0)
+        return code;
     push_op_estack(zcolor_reset_transfer);
     pop(1);
-    return zcolor_remap_one(i_ctx_p, &istate->transfer_procs.colored.gray,
-			    igs->set_transfer.colored.gray, igs,
-			    zcolor_remap_one_finish);
+    return zcolor_remap_one( i_ctx_p,
+                             &istate->transfer_procs.gray,
+                             igs->set_transfer.gray,
+                             igs,
+                             zcolor_remap_one_finish );
 }
 
-/* ------ Internal routines ------ */
 
-/* Prepare to remap one color component */
-/* (also used for black generation and undercolor removal). */
-/* Use the 'for' operator to gather the values. */
-/* The caller must have done the necessary check_ostack and check_estack. */
+/*
+ * Internal routines
+ */
+
+/*
+ * Prepare to remap one color component (also used for black generation
+ * and undercolor removal). Use the 'for' operator to gather the values.
+ * The caller must have done the necessary check_ostack and check_estack.
+ */
 int
-zcolor_remap_one(i_ctx_t *i_ctx_p, const ref * pproc,
-		 gx_transfer_map * pmap, const gs_state * pgs,
-		 op_proc_t finish_proc)
+zcolor_remap_one(
+    i_ctx_t *           i_ctx_p,
+    const ref *         pproc,
+    gx_transfer_map *   pmap,
+    const gs_state *    pgs,
+    op_proc_t           finish_proc )
 {
-    os_ptr op;
+    os_ptr              op;
 
     /*
      * Detect the identity function, which is a common value for one or
@@ -242,19 +432,24 @@
 
 /* ------ Initialization procedure ------ */
 
-const op_def zcolor_op_defs[] =
+const op_def    zcolor_op_defs[] = 
 {
-    {"0currentgray", zcurrentgray},
-    {"0currentrgbcolor", zcurrentrgbcolor},
-    {"0currenttransfer", zcurrenttransfer},
-    {"0processcolors", zprocesscolors},
-    {"1setgray", zsetgray},
-    {"3setrgbcolor", zsetrgbcolor},
-    {"1settransfer", zsettransfer},
-		/* Internal operators */
-    {"1%zcolor_remap_one_finish", zcolor_remap_one_finish},
-    {"1%zcolor_remap_one_signed_finish", zcolor_remap_one_signed_finish},
-    {"0%zcolor_reset_transfer", zcolor_reset_transfer},
-    {"0%zcolor_remap_color", zcolor_remap_color},
+    { "0currentcolor", zcurrentcolor },
+    { "0currentcolorspace", zcurrentcolorspace },
+    { "0.getuseciecolor", zgetuseciecolor },
+    { "1setcolor", zsetcolor },
+    { "1setcolorspace", zsetcolorspace },
+    { "1.setdevcspace", zsetdevcspace },
+
+    /* basic transfer operators */
+    { "0currenttransfer", zcurrenttransfer },
+    { "0processcolors", zprocesscolors },
+    { "1settransfer", zsettransfer },
+
+    /* internal operators */
+    { "1%zcolor_remap_one_finish", zcolor_remap_one_finish },
+    { "1%zcolor_remap_one_signed_finish", zcolor_remap_one_signed_finish },
+    { "0%zcolor_reset_transfer", zcolor_reset_transfer },
+    { "0%zcolor_remap_color", zcolor_remap_color },
     op_def_end(0)
 };

Index: zcolor1.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zcolor1.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- zcolor1.c	21 Feb 2002 22:24:54 -0000	1.5
+++ zcolor1.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -29,7 +29,6 @@
 #include "gxdevice.h"
 #include "gxcmap.h"
 #include "gscolor1.h"
-#include "gscssub.h"
 #include "gxcspace.h"
 #include "icolor.h"
 #include "iimage.h"
@@ -45,21 +44,6 @@
     return 0;
 }
 
-/* - currentcmykcolor <cyan> <magenta> <yellow> <black> */
-private int
-zcurrentcmykcolor(i_ctx_t *i_ctx_p)
-{
-    os_ptr op = osp;
-    float par[4];
-    int code = gs_currentcmykcolor(igs, par);
-
-    if (code < 0)
-	return code;
-    push(4);
-    make_floats(op - 3, par, 4);
-    return 0;
-}
-
 /* - currentcolortransfer <redproc> <greenproc> <blueproc> <grayproc> */
 private int
 zcurrentcolortransfer(i_ctx_t *i_ctx_p)
@@ -67,10 +51,10 @@
     os_ptr op = osp;
 
     push(4);
-    op[-3] = istate->transfer_procs.colored.red;
-    op[-2] = istate->transfer_procs.colored.green;
-    op[-1] = istate->transfer_procs.colored.blue;
-    *op = istate->transfer_procs.colored.gray;
+    op[-3] = istate->transfer_procs.red;
+    op[-2] = istate->transfer_procs.green;
+    op[-1] = istate->transfer_procs.blue;
+    *op = istate->transfer_procs.gray;
     return 0;
 }
 
@@ -106,23 +90,6 @@
 			    zcolor_remap_one_finish);
 }
 
-/* <cyan> <magenta> <yellow> <black> setcmykcolor - */
-private int
-zsetcmykcolor(i_ctx_t *i_ctx_p)
-{
-    os_ptr op = osp;
-    double par[4];
-    int code;
-
-    if ((code = num_params(op, 4, par)) < 0 ||
-	(code = gs_setcmykcolor(igs, par[0], par[1], par[2], par[3])) < 0
-	)
-	return code;
-    make_null(&istate->colorspace.array);
-    pop(4);
-    return 0;
-}
-
 /* <redproc> <greenproc> <blueproc> <grayproc> setcolortransfer - */
 private int
 zsetcolortransfer(i_ctx_t *i_ctx_p)
@@ -136,10 +103,10 @@
     check_proc(*op);
     check_ostack(zcolor_remap_one_ostack * 4 - 4);
     check_estack(1 + zcolor_remap_one_estack * 4);
-    istate->transfer_procs.colored.red = op[-3];
-    istate->transfer_procs.colored.green = op[-2];
-    istate->transfer_procs.colored.blue = op[-1];
-    istate->transfer_procs.colored.gray = *op;
+    istate->transfer_procs.red = op[-3];
+    istate->transfer_procs.green = op[-2];
+    istate->transfer_procs.blue = op[-1];
+    istate->transfer_procs.gray = *op;
     if ((code = gs_setcolortransfer_remap(igs,
 				     gs_mapped_transfer, gs_mapped_transfer,
 				     gs_mapped_transfer, gs_mapped_transfer,
@@ -150,19 +117,19 @@
     pop(4);
     push_op_estack(zcolor_reset_transfer);
     if ((code = zcolor_remap_one(i_ctx_p,
-				 &istate->transfer_procs.colored.red,
-				 igs->set_transfer.colored.red, igs,
+				 &istate->transfer_procs.red,
+				 igs->set_transfer.red, igs,
 				 zcolor_remap_one_finish)) < 0 ||
 	(code = zcolor_remap_one(i_ctx_p,
-				 &istate->transfer_procs.colored.green,
-				 igs->set_transfer.colored.green, igs,
+				 &istate->transfer_procs.green,
+				 igs->set_transfer.green, igs,
 				 zcolor_remap_one_finish)) < 0 ||
 	(code = zcolor_remap_one(i_ctx_p,
-				 &istate->transfer_procs.colored.blue,
-				 igs->set_transfer.colored.blue, igs,
+				 &istate->transfer_procs.blue,
+				 igs->set_transfer.blue, igs,
 				 zcolor_remap_one_finish)) < 0 ||
-	(code = zcolor_remap_one(i_ctx_p, &istate->transfer_procs.colored.gray,
-				 igs->set_transfer.colored.gray, igs,
+	(code = zcolor_remap_one(i_ctx_p, &istate->transfer_procs.gray,
+				 igs->set_transfer.gray, igs,
 				 zcolor_remap_one_finish)) < 0
 	)
 	return code;
@@ -190,27 +157,16 @@
 			    zcolor_remap_one_signed_finish);
 }
 
-/* <width> <height> <bits/comp> <matrix> */
-/*      <datasrc_0> ... <datasrc_ncomp-1> true <ncomp> colorimage - */
-/*      <datasrc> false <ncomp> colorimage - */
-private int
-zcolorimage(i_ctx_t *i_ctx_p)
-{
-    return zimage_multiple(i_ctx_p, false);
-}
 
 /* ------ Initialization procedure ------ */
 
 const op_def zcolor1_op_defs[] =
 {
     {"0currentblackgeneration", zcurrentblackgeneration},
-    {"0currentcmykcolor", zcurrentcmykcolor},
     {"0currentcolortransfer", zcurrentcolortransfer},
     {"0currentundercolorremoval", zcurrentundercolorremoval},
     {"1setblackgeneration", zsetblackgeneration},
-    {"4setcmykcolor", zsetcmykcolor},
     {"4setcolortransfer", zsetcolortransfer},
     {"1setundercolorremoval", zsetundercolorremoval},
-    {"7colorimage", zcolorimage},
     op_def_end(0)
 };

Index: zcolor2.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zcolor2.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- zcolor2.c	31 Jul 2002 04:43:45 -0000	1.9
+++ zcolor2.c	22 Aug 2002 07:12:29 -0000	1.10
@@ -19,295 +19,37 @@
 #include "ghost.h"
 #include "string_.h"
 #include "oper.h"
-#include "gscolor.h"
-#include "gscssub.h"
 #include "gsmatrix.h"
 #include "gsstruct.h"
 #include "gxcspace.h"
-#include "gxfixed.h"		/* for gxcolor2.h */
-#include "gxcolor2.h"
-#include "gxdcolor.h"		/* for gxpcolor.h */
-#include "gxdevice.h"
-#include "gxdevmem.h"		/* for gxpcolor.h */
-#include "gxpcolor.h"
-#include "estack.h"
-#include "ialloc.h"
-#include "istruct.h"
-#include "idict.h"
-#include "iname.h"
-#include "idparam.h"
+#include "gscolor2.h"
 #include "igstate.h"
 #include "store.h"
 
-/* Forward references */
-private int store_color_params(os_ptr, const gs_paint_color *,
-			       const gs_color_space *);
-private int load_color_params(os_ptr, gs_paint_color *,
-			      const gs_color_space *);
-
-/* Test whether a Pattern instance uses a base space. */
-inline private bool
-pattern_instance_uses_base_space(const gs_pattern_instance_t *pinst)
-{
-    return pinst->type->procs.uses_base_space(pinst->type->procs.get_pattern(pinst));
-}
-
-/* - currentcolor <param1> ... <paramN> */
-private int
-zcurrentcolor(i_ctx_t *i_ctx_p)
-{
-    os_ptr op = osp;
-    const gs_client_color *pc = gs_currentcolor(igs);
-    const gs_color_space *pcs = gs_currentcolorspace(igs);
-    int n;
-
-    check_ostack(5);		/* Worst case: CMYK + pattern */
-    if (pcs->type->index == gs_color_space_index_Pattern) {
-	gs_pattern_instance_t *pinst = pc->pattern;
-
-	n = 1;
-	if (pinst != 0 && pattern_instance_uses_base_space(pinst))	/* uncolored */
-	    n += store_color_params(op, &pc->paint,
-		   (const gs_color_space *)&pcs->params.pattern.base_space);
-	op[n] = istate->pattern;
-    } else
-	n = store_color_params(op, &pc->paint, pcs);
-    push(n);
-    return 0;
-}
-
-/* - .currentcolorspace <array|int> */
-private int
-zcurrentcolorspace(i_ctx_t *i_ctx_p)
-{
-    os_ptr op = osp;
-
-    push(1);
-    *op = istate->colorspace.array;
-    if (r_has_type(op, t_null)) {
-	/*
-	 * Return the color space index.  This is only possible
-	 * for the parameterless color spaces.
-	 */
-	gs_color_space_index csi = gs_currentcolorspace_index(igs);
-
-	make_int(op, (int)(csi));
-    }
-    return 0;
-}
-
-/*
- * Look up the device colorant names for a given color model.
- * ****** THIS WILL NEED REVISITING FOR DeviceN COLORS. ******
- */
-private int
-device_color_idx(const gx_device *dev, uint nidx[4])
-{ 
-    int i, ncomps = dev->color_info.num_components;
-    const char *const *comp_names;
-    static const char *const gray_names[] = {"Gray"};
-    static const char *const rgb_names[] = {"Red", "Green", "Blue"};
-    static const char *const cmyk_names[] = {"Cyan", "Magenta", "Yellow", "Black"};
-
-    switch(ncomps) {
-    case 1:
-	comp_names = gray_names; break;
-    case 3:
-	comp_names = rgb_names; break;
-    case 4:
-	comp_names = cmyk_names; break;
-    default:  /* fixme: DeviceN color model not supported */
-	return_error(e_rangecheck);
-    }
-    for (i = 0; i < ncomps; i++) { 
-	ref rname;
-	int code = name_ref((const byte *)comp_names[i], strlen(comp_names[i]), &rname, 0);
-
-	if (code < 0)
-	    return code;
-	nidx[i] = name_index(&rname);
-    }
-    return 0;
-}
-
-/* Test whether one set of colorant names is a subset of another. */
-private int
-is_subset_idx(uint *set, int set_len, gs_separation_name *subset, int sub_len)
-{ 
-    int i, j, is_subset = 1; 
-  
-    if(set_len < sub_len)
-      return 0;
-    for (i=0; i < sub_len && is_subset; ++i) { 
-        for(j=0; j < set_len && set[j] != subset[i]; ++j)
-          ; /* no-op */
-        is_subset &= j < set_len;
-    }
-    return is_subset;   
-}
-
-/* <param1> ... <paramN> setcolor - */
-private int
-zsetcolor(i_ctx_t *i_ctx_p)
-{
-    os_ptr op = osp;
-    gs_client_color c;
-    const gs_color_space *pcs = gs_currentcolorspace(igs);
-    int n, code;
-    gs_pattern_instance_t *pinst = 0;
-
-    if (pcs->type->index == gs_color_space_index_Pattern) {
-	/* Make sure *op is a real Pattern. */
-	ref *pImpl;
-
-	if (r_has_type(op, t_null)) {
-	    c.pattern = 0;
-	    n = 1;
-	} else {
-	    check_type(*op, t_dictionary);
-	    check_dict_read(*op);
-	    /*
-	     * We have no way to check for a subclass of st_pattern_instance,
-	     * so just make sure the structure is large enough.
-	     */
-	    if (dict_find_string(op, "Implementation", &pImpl) <= 0 ||
-		!r_is_struct(pImpl) ||
-		gs_object_size(imemory, r_ptr(pImpl, const void)) <
-		sizeof(gs_pattern_instance_t)
-		)
-		return_error(e_rangecheck);
-	    pinst = r_ptr(pImpl, gs_pattern_instance_t);
-	    c.pattern = pinst;
-	    if (pattern_instance_uses_base_space(pinst)) {	/* uncolored */
-		if (!pcs->params.pattern.has_base_space)
-		    return_error(e_rangecheck);
-		n = load_color_params(op - 1, &c.paint,
-				      (const gs_color_space *)&pcs->params.pattern.base_space);
-		if (n < 0)
-		    return n;
-		n++;
-	    } else
-		n = 1;
-	}
-    } else {
-	n = load_color_params(op, &c.paint, pcs);
-	c.pattern = 0;		/* for GC */
-    }
-    if (n < 0)
-	return n;
-    code = gs_setcolor(igs, &c);
-    if (code < 0)
-	return code;
-    if (pinst != 0)
-	istate->pattern = *op;
-    pop(n);
-    return code;
-}
 
 /*
- * This operator will check if the current colorspace is DeviceN and the
- * alternate colorspace is being used.  This strange function is part of a
- * kludge to get around a spec violation in Adobe Photoshop 5+.  See
- * comments in front of setcolor in lib/gs_ll3.ps for more info.
+ *  -   .useralternate   <bool>
+ *
+ * Push true if the current color space contains a base or alternate
+ * color space and makes use of that color space (e.g.: a Separation
+ * color space for a component not supported by the process color model.
  */
 private int
-zcheckdevicenaltused(i_ctx_t *i_ctx_p)        /* - .checkdevicenaltused <bool> */
+zusealternate(i_ctx_t * i_ctx_p)
 {
-    os_ptr op = osp;
-    const gs_color_space *pcs = gs_currentcolorspace(igs);
-    bool result = false;
-    int code;
-
-    if(pcs->type->index == gs_color_space_index_DeviceN) {
-        gs_color_space_type const *pcst = pcs->type;
-        int num_comp    = pcst->num_components(pcs);
-        gx_device const *dev  = gs_currentdevice(igs);
-        int num_ink  = dev->color_info.num_components;
-        gs_separation_name *idx_comp=pcs->params.device_n.names;
-        uint idx_ink[4];
+    os_ptr                  op = osp;
+    const gs_color_space *  pcs = gs_currentcolorspace(igs);
 
-        code=device_color_idx(dev, idx_ink);
-        if(code >= 0 && !is_subset_idx(idx_ink, num_ink, idx_comp, num_comp)) { 
-            result = true;
-        }
-    }
     push(1);
-    make_bool(op, result ? 1 : 0);
-    return 0;
-}
-
-/*
- * This operator will discard the components for a DeviceN alternate
- * color space.  This strange function is part of a kludge to get around
- * a spec violation in Adobe Photoshop 5+.  See comments in front of
- * setcolor in lib/gs_ll3.ps for more info.
- */
-private int
-zdiscardaltcolor(i_ctx_t *i_ctx_p) /* <param1> ... <paramN> .discardaltcolor - */
-{
-    os_ptr op = osp;
-    const gs_color_space *pcs = gs_currentcolorspace(igs);
-    int n = 0;
-
-    if(pcs->type->index == gs_color_space_index_DeviceN)
-      n = gs_color_space_num_components((gs_color_space *)
-                                      &pcs->params.device_n.alt_space);
-    pop(n);
+    make_bool(op, cs_base_space(pcs) != 0);
     return 0;
 }
 
-/* <array> .setcolorspace - */
-private int
-zsetcolorspace(i_ctx_t *i_ctx_p)
-{
-    os_ptr op = osp;
-
-    check_type(*op, t_array);
-    istate->colorspace.array = *op;
-    pop(1);
-    return 0;
-}
 
 /* ------ Initialization procedure ------ */
 
-const op_def zcolor2_l2_op_defs[] =
-{
+const op_def    zcolor2_l2_op_defs[] = {
     op_def_begin_level2(),
-    {"0currentcolor", zcurrentcolor},
-    {"0.currentcolorspace", zcurrentcolorspace},
-    {"1.setcolor", zsetcolor},
-    {"1.setcolorspace", zsetcolorspace},
-    {"0.checkdevicenaltused", zcheckdevicenaltused},
-    {"0.discardaltcolor", zdiscardaltcolor},
+    { "0.usealternate", zusealternate },
     op_def_end(0)
 };
-
-/* ------ Internal procedures ------ */
-
-/* Store non-pattern color values on the operand stack. */
-/* Return the number of values stored. */
-private int
-store_color_params(os_ptr op, const gs_paint_color * pc,
-		   const gs_color_space * pcs)
-{
-    int n = cs_num_components(pcs);
-
-    if (pcs->type->index == gs_color_space_index_Indexed)
-	make_int(op + 1, (int)pc->values[0]);
-    else
-	make_floats(op + 1, pc->values, n);
-    return n;
-}
-
-/* Load non-pattern color values from the operand stack. */
-/* Return the number of values stored. */
-private int
-load_color_params(os_ptr op, gs_paint_color * pc, const gs_color_space * pcs)
-{
-    int n = cs_num_components(pcs);
-    int code = float_params(op, n, pc->values);
-
-    if (code < 0)
-	return code;
-    return n;
-}

Index: zcsdevn.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zcsdevn.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- zcsdevn.c	21 Feb 2002 22:24:54 -0000	1.9
+++ zcsdevn.c	22 Aug 2002 07:12:29 -0000	1.10
@@ -62,6 +62,7 @@
     gs_device_n_map *pmap;
     uint num_components;
     gs_color_space cs;
+    const gs_color_space * pacs;
     ref_colorspace cspace_old;
     gs_function_t *pfn;
     int code;
@@ -86,26 +87,19 @@
     check_proc(pcsa[2]);
     
     /* The alternate color space has been selected as the current color space */
-    cs = *gs_currentcolorspace(igs);
-    if (!cs.type->can_be_alt_space)
-	return_error(e_rangecheck);
-    /*
-     * Allocate space for DeviceN color map function.  This can be either
-     * a type 4 function or we can collecte data for a color cube (type 0
-     * function).
-     */
-    code = alloc_device_n_map(&pmap, imemory, ".setdevicenspace(map)");
+    pacs = gs_currentcolorspace(igs);
+    cs = *pacs;
+    /* See zcsindex.c for why we use memmove here. */
+    memmove(&cs.params.device_n.alt_space, &cs,
+	    sizeof(cs.params.device_n.alt_space));
+    gs_cspace_init(&cs, &gs_color_space_type_DeviceN, NULL);
+    code = gs_build_DeviceN(&cs, num_components, pacs, imemory);
     if (code < 0)
 	return code;
+    names = cs.params.device_n.names;
+    pmap = cs.params.device_n.map;
 
-    /* Allocate space for color names list and copy names from input array. */
-    names = (gs_separation_name *)
-	ialloc_byte_array(num_components, sizeof(gs_separation_name),
-			  ".setdevicenspace(names)");
-    if (names == 0) {
-	ifree_object(pmap, ".setdevicenspace(map)");
-	return_error(e_VMerror);
-    }
+    /* Pick up the names of the components */
     {
 	uint i;
 	ref sname;
@@ -134,10 +128,6 @@
 
     /* Now set the current color space as DeviceN */
 
-    /* See zcsindex.c for why we use memmove here. */
-    memmove(&cs.params.device_n.alt_space, &cs,
-	    sizeof(cs.params.device_n.alt_space));
-    gs_cspace_init(&cs, &gs_color_space_type_DeviceN, NULL);
     cspace_old = istate->colorspace;
     /*
      * pcsa is a pointer to element 1 (2nd element)  in the DeviceN
@@ -145,11 +135,7 @@
      * which is the tint transform.
      */
     istate->colorspace.procs.special.device_n.layer_names = pcsa[0];
-    istate->colorspace.procs.special.device_n.tint_transform = pcsa[2];
-    cs.params.device_n.names = names;
-    cs.params.device_n.num_components = num_components;
-    cs.params.device_n.map = pmap;
-    cs.params.device_n.get_colorname_string = gs_get_colorname_string;
+    istate->colorspace.procs.special.device_n.tint_transform = pcsa[2];    
     pfn = ref_function(pcsa + 2);	/* See comment above */
     if (!pfn)
 	code = gs_note_error(e_rangecheck);
@@ -162,9 +148,13 @@
     }
     gs_cspace_set_devn_function(&cs, pfn);
     code = gs_setcolorspace(igs, &cs);
+    if (code < 0) {
+	istate->colorspace = cspace_old;
+	return code;
+    }
     rc_decrement(pmap, ".setdevicenspace(map)");  /* build sets rc = 1 */
     pop(1);
-    return code;
+    return 0;
 }
 
 
@@ -176,4 +166,3 @@
     {"1.setdevicenspace", zsetdevicenspace},
     op_def_end(0)
 };
-

Index: zcssepr.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zcssepr.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- zcssepr.c	16 Jun 2002 03:43:50 -0000	1.11
+++ zcssepr.c	22 Aug 2002 07:12:29 -0000	1.12
@@ -22,7 +22,6 @@
 #include "gsstruct.h"
 #include "gscolor.h"
 #include "gsmatrix.h"		/* for gxcolor2.h */
-#include "gscsepr.h"
 #include "gxcspace.h"
 #include "gxfixed.h"		/* ditto */
 #include "gxcolor2.h"
@@ -34,31 +33,22 @@
 #include "iname.h"
 #include "ivmspace.h"
 #include "store.h"
+#include "gscsepr.h"
+#include "gscdevn.h"
+#include "gxcdevn.h"
 
 /* Imported from gscsepr.c */
 extern const gs_color_space_type gs_color_space_type_Separation;
+/* Imported from gscdevn.c */
+extern const gs_color_space_type gs_color_space_type_DeviceN;
 
-/* Forward references */
-private int separation_map1(i_ctx_t *);
-
-/* Define the separation cache size.  This makes many useful tint values */
-/* map to integer cache indices. */
-#define SEPARATION_CACHE_SIZE 360
-
-/* Tint transform procedure that just consults the cache. */
-private int
-lookup_tint(const gs_separation_params * params, floatp tint, float *values)
-{
-    int m = cs_num_components((const gs_color_space *)&params->alt_space);
-    const gs_indexed_map *map = params->map;
-    int value_index =
-	(tint < 0 ? 0 : tint > 1 ? map->num_values - m :
-	 (int)(tint * SEPARATION_CACHE_SIZE + 0.5) * m);
-    const float *pv = &map->values[value_index];
-
-    memcpy(values, pv, sizeof(*values) * m);
-    return 0;
-}
+/*
+ * Adobe first created the separation colorspace type and then later created
+ * the DeviceN colorspace.  Logically the separation colorspace is the same
+ * as a DeviceN colorspace with a single component, except for the /None and
+ * /All parameter values.  We treat the separation colorspace as a DeviceN
+ * colorspace except for the /All case.
+ */
 
 /* <array> .setseparationspace - */
 /* The current color space is the alternate space for the separation space. */
@@ -68,16 +58,31 @@
     os_ptr op = osp;
     const ref *pcsa;
     gs_color_space cs;
+    const gs_color_space * pacs;
     ref_colorspace cspace_old;
-    uint edepth = ref_stack_count(&e_stack);
-    gs_indexed_map *map = 0;
-    ref sname, tname1, tname2;
+    ref sname, name_none, name_all;
+    gs_separation_name *names = NULL;
+    gs_device_n_map *pmap = NULL;
+    gs_function_t *pfn = NULL;
     separation_type sep_type;
     int code;
 
+    /* Verify that we have an array as our input parameter */
     check_read_type(*op, t_array);
     if (r_size(op) != 4)
 	return_error(e_rangecheck);
+
+    /* The alternate color space has been selected as the current color space */
+    pacs = gs_currentcolorspace(igs);
+    cs = *pacs;
+    if (!cs.type->can_be_alt_space)
+	return_error(e_rangecheck);
+
+    /*
+     * pcsa is a pointer to element 1 (2nd element)  in the Separation colorspace
+     * description array.  Thus pcsa[2] is element #3 (4th element) which is the
+     * tint transform.
+     */
     pcsa = op->value.const_refs + 1;
     sname = *pcsa;
     switch (r_type(&sname)) {
@@ -92,82 +97,46 @@
 	    break;
     }
 
-    if ((code = name_ref((const byte *)"All", 3, &tname1, 0)) < 0)
+    if ((code = name_ref((const byte *)"All", 3, &name_all, 0)) < 0)
 	return code;
-    if ((code = name_ref((const byte *)"None", 4, &tname2, 0)) < 0)
+    if ((code = name_ref((const byte *)"None", 4, &name_none, 0)) < 0)
 	return code;
-    sep_type = ( name_eq(&sname, &tname1) ? SEP_ALL :
-	         name_eq(&sname, &tname2) ? SEP_NONE : SEP_OTHER);
+    sep_type = ( name_eq(&sname, &name_all) ? SEP_ALL :
+	         name_eq(&sname, &name_none) ? SEP_NONE : SEP_OTHER);
 
+    /* Check tint transform procedure. */
+    /* See comment above about psca */
     check_proc(pcsa[2]);
-    cs = *gs_currentcolorspace(igs);
-    if (!cs.type->can_be_alt_space)
+    pfn = ref_function(pcsa + 2);
+    if (pfn == NULL)
 	return_error(e_rangecheck);
-    if (sep_type == SEP_OTHER) {
-	code = zcs_begin_map(i_ctx_p, &map, &pcsa[2], SEPARATION_CACHE_SIZE + 1,
-			     (const gs_direct_color_space *)&cs,
-			     separation_map1);
-	if (code < 0)
-	    return code;
-        map->proc.tint_transform = lookup_tint;
-    }
 
+    cspace_old = istate->colorspace;
     /* See zcsindex.c for why we use memmove here. */
     memmove(&cs.params.separation.alt_space, &cs,
-	    sizeof(cs.params.separation.alt_space));
+	        sizeof(cs.params.separation.alt_space));
+    /* Now set the current color space as Separation */
+    code = gs_build_Separation(&cs, pacs, imemory);
+    if (code < 0)
+	return code;
+    pmap = cs.params.separation.map;
     gs_cspace_init(&cs, &gs_color_space_type_Separation, NULL);
-    cs.params.separation.sname = name_index(&sname);
-    cs.params.separation.map = map;
     cs.params.separation.sep_type = sep_type;
-    cspace_old = istate->colorspace;
+    cs.params.separation.sep_name = name_index(&sname);
     istate->colorspace.procs.special.separation.layer_name = pcsa[0];
     istate->colorspace.procs.special.separation.tint_transform = pcsa[2];
-    code = gs_setcolorspace(igs, &cs);
+    if (code >= 0)
+        code = gs_cspace_set_sepr_function(&cs, pfn);
+    if (code >= 0)
+	code = gs_setcolorspace(igs, &cs);
     if (code < 0) {
 	istate->colorspace = cspace_old;
-	ref_stack_pop_to(&e_stack, edepth);
+	ifree_object(pmap, ".setseparationspace(pmap)");
 	return code;
     }
+    rc_decrement(pmap, ".setseparationspace(pmap)");  /* build sets rc = 1 */
     pop(1);
-    return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack);	/* installation will load the caches */
-}
-
-/* Continuation procedure for saving transformed tint values. */
-private int
-separation_map1(i_ctx_t *i_ctx_p)
-{
-    os_ptr op = osp;
-    es_ptr ep = esp;
-    int i = (int)ep[csme_index].value.intval;
-
-    if (i >= 0) {		/* i.e., not first time */
-	int m = (int)ep[csme_num_components].value.intval;
-	int code = float_params(op, m, &r_ptr(&ep[csme_map], gs_indexed_map)->values[i * m]);
-
-	if (code < 0)
-	    return code;
-	pop(m);
-	op -= m;
-	if (i == (int)ep[csme_hival].value.intval) {	/* All done. */
-	    /*
-	     * If the tint_transform procedure is a Function, recognize it
-	     * as such now.
-	     */
-	    gs_function_t *pfn = ref_function(&ep[csme_proc]);
-
-	    if (pfn)
-		gs_cspace_set_sepr_function(gs_currentcolorspace(igs), pfn);
-	    esp -= num_csme;
-	    return o_pop_estack;
-	}
-    }
-    push(1);
-    ep[csme_index].value.intval = ++i;
-    make_real(op, i / (float)SEPARATION_CACHE_SIZE);
-    make_op_estack(ep + 1, separation_map1);
-    ep[2] = ep[csme_proc];	/* tint_transform */
-    esp = ep + 2;
-    return o_push_estack;
+    return 0;
 }
 
 /* - currentoverprint <bool> */
@@ -228,7 +197,5 @@
     {"1setoverprint", zsetoverprint},
     {"1.setoverprintmode", zsetoverprintmode},
     {"1.setseparationspace", zsetseparationspace},
-		/* Internal operators */
-    {"1%separation_map1", separation_map1},
     op_def_end(0)
 };

Index: zdevice.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zdevice.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- zdevice.c	21 Feb 2002 22:24:54 -0000	1.6
+++ zdevice.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -161,7 +161,7 @@
 	depth_option = depths[std_depth];
 	if (depth_option == 0)
 	    return_error(e_rangecheck);
-	options |= depth_option | gb_colors_for_device(dev);
+	options |= depth_option | GB_COLORS_NATIVE;
 	depth = (dev->color_info.num_components +
 		 (options & GB_ALPHA_NONE ? 0 : 1)) * std_depth;
     }

Index: zdfilter.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zdfilter.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- zdfilter.c	14 Jun 2002 09:42:54 -0000	1.5
+++ zdfilter.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -36,24 +36,7 @@
 #include "store.h"
 #include "gsdfilt.h"
 
-#ifdef DFILTER_TEST
-private int
-/* - .pushtestdevicefilter - */
-zpushtestdevicefilter(i_ctx_t *i_ctx_p)
-{
-    gs_device_filter_t *df;
-    int code;
-    gs_memory_t *mem = gs_memory_stable(imemory);
-
-    code = gs_test_device_filter(&df, mem);
-    if (code < 0)
-	return code;
-    code = gs_push_device_filter(mem, igs, df);
-    return code;
-}
-#endif
-
-/* pushpdf14devicefilter is defined in zdtrans.c */
+/* pushpdf14devicefilter is defined in ztrans.c */
 
 /* - .popdevicefilter - */
 private int
@@ -66,9 +49,6 @@
 
 const op_def zdfilter_op_defs[] =
 {
-#ifdef DFILTER_TEST
-    {"0.pushtestdevicefilter", zpushtestdevicefilter},
-#endif
     {"0.popdevicefilter", zpopdevicefilter},
     op_def_end(0)
 };

Index: zdpnext.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zdpnext.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- zdpnext.c	16 Jun 2002 03:43:50 -0000	1.6
+++ zdpnext.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -76,9 +76,6 @@
  *   (including halftoning if needed).
  */
 
-/* Imported procedures */
-int zimage_multiple(i_ctx_t *i_ctx_p, bool has_alpha);  /* in zcolor1.c */
-
 /*
  * Define the operand and bookeeping structure for a compositing operation.
  */
@@ -96,14 +93,13 @@
 private void end_composite(i_ctx_t *, alpha_composite_state_t *);
 private int xywh_param(os_ptr, double[4]);
 
-/* <width> <height> <bits/comp> <matrix> */
-/*      <datasrc_0> ... <datasrc_ncomp-1> true <ncomp> alphaimage - */
-/*      <datasrc> false <ncomp> alphaimage - */
+/* <dict> .alphaimage - */
+/* This is the dictionary version of the alphaimage operator, which is */
+/* now a pseudo-operator (see gs_dpnxt.ps). */
 private int
 zalphaimage(i_ctx_t *i_ctx_p)
 {
-    /* Essentially the whole implementation is shared with colorimage. */
-    return zimage_multiple(i_ctx_p, true);
+    return image1_setup(i_ctx_p, true);
 }
 
 /* <destx> <desty> <width> <height> <op> compositerect - */
@@ -336,7 +332,7 @@
 {
     {"0currentalpha", zcurrentalpha},
     {"1setalpha", zsetalpha},
-    {"7alphaimage", zalphaimage},
+    {"1.alphaimage", zalphaimage},
     {"8composite", zcomposite},
     {"5compositerect", zcompositerect},
     {"8dissolve", zdissolve},
@@ -419,9 +415,9 @@
 	    if (max_v != (1 << depth) - 1)
 		return 0;
 	    for (i = 0; i <= max_v; ++i) {
-		gx_color_value v = CV(i);
-
-		if ((*dev_proc(dev, map_rgb_color)) (dev, v, v, v) != i)
+		gx_color_value v[3];
+                v[0] = v[1] = v[2] = CV(i);
+		if ((*dev_proc(dev, map_rgb_color)) (dev, v) != i)
 		    return 0;
 	    }
 	    return true;
@@ -433,13 +429,17 @@
 		const int gs = depth / 3, rs = gs * 2;
 
 		for (i = 0; i <= max_v; ++i) {
-		    gx_color_value v = CV(i);
-
-		    if ((*dev_proc(dev, map_rgb_color)) (dev, v, CV0, CV0) !=
+		    gx_color_value red[3];
+                    gx_color_value green[3];
+                    gx_color_value blue[3];
+                    red[0] = CV(i); red[1] = CV0, red[2] = CV0;
+                    green[0] = CV0; green[1] = CV(i); green[2] = CV0;
+                    blue[0] = CV0; blue[1] = CV0; blue[2] = CV(i);
+		    if ((*dev_proc(dev, map_rgb_color)) (dev, red) !=
 			i << rs ||
-			(*dev_proc(dev, map_rgb_color)) (dev, CV0, v, CV0) !=
+			(*dev_proc(dev, map_rgb_color)) (dev, green) !=
 			i << gs ||
-			(*dev_proc(dev, map_rgb_color)) (dev, CV0, CV0, v) !=
+			(*dev_proc(dev, map_rgb_color)) (dev, blue) !=
 			i	/*<< bs */
 			)
 			return 0;
@@ -454,15 +454,22 @@
 		const int ys = depth / 4, ms = ys * 2, cs = ys * 3;
 
 		for (i = 0; i <= max_v; ++i) {
-		    gx_color_value v = CV(i);
-
-		    if ((*dev_proc(dev, map_cmyk_color)) (dev, v, CV0, CV0, CV0) !=
+                    
+		    gx_color_value cyan[4];
+                    gx_color_value magenta[4];
+                    gx_color_value yellow[4];
+                    gx_color_value black[4];
+                    cyan[0] = CV(i); cyan[1] = cyan[2] = cyan[3] = CV0;
+                    magenta[1] = CV(i); magenta[0] = magenta[2] = magenta[3] = CV0;
+                    yellow[2] = CV(i); yellow[0] = yellow[1] = yellow[3] = CV0;
+                    black[3] = CV(i); black[0] = black[1] = black[2] = CV0;
+		    if ((*dev_proc(dev, map_cmyk_color)) (dev, cyan) !=
 			i << cs ||
-			(*dev_proc(dev, map_cmyk_color)) (dev, CV0, v, CV0, CV0) !=
+			(*dev_proc(dev, map_cmyk_color)) (dev, magenta) !=
 			i << ms ||
-			(*dev_proc(dev, map_cmyk_color)) (dev, CV0, CV0, v, CV0) !=
+			(*dev_proc(dev, map_cmyk_color)) (dev, yellow) !=
 			i << ys ||
-			(*dev_proc(dev, map_cmyk_color)) (dev, CV0, CV0, CV0, v) !=
+			(*dev_proc(dev, map_cmyk_color)) (dev, black) !=
 			i	/*<< ks */
 			)
 			return 0;

Index: zfsample.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zfsample.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- zfsample.c	16 Jun 2002 03:43:51 -0000	1.7
+++ zfsample.c	22 Aug 2002 07:12:29 -0000	1.8
@@ -543,4 +543,3 @@
     {"1.buildsampledfunction", zbuildsampledfunction},
     op_def_end(0)
 };
-

Index: zgstate.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zgstate.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- zgstate.c	16 Jun 2002 03:43:51 -0000	1.5
+++ zgstate.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -26,6 +26,8 @@
 #include "igstate.h"
 #include "gsmatrix.h"
 #include "store.h"
+#include "gscspace.h"
+#include "iname.h"
 
 /* Structure descriptors */
 private_st_int_gstate();
@@ -75,10 +77,14 @@
 private void *gs_istate_alloc(gs_memory_t * mem);
 private int gs_istate_copy(void *to, const void *from);
 private void gs_istate_free(void *old, gs_memory_t * mem);
+private int gs_get_colorname_string(gs_separation_name colorname_index,
+			unsigned char **ppstr, unsigned int *pname_size);
 private const gs_state_client_procs istate_procs = {
     gs_istate_alloc,
     gs_istate_copy,
-    gs_istate_free
+    gs_istate_free,
+    0,			/* copy_for */
+    gs_get_colorname_string
 };
 
 /* Initialize the graphics stack. */
@@ -102,6 +108,7 @@
     make_real(proc0.value.refs + 1, 0.0);
     iigs->black_generation = proc0;
     iigs->undercolor_removal = proc0;
+    make_false(&iigs->use_cie_color);
     /*
      * Even though the gstate itself is allocated in local VM, the
      * container for the color remapping procedure must be allocated in
@@ -148,13 +155,11 @@
 private int
 zinitgraphics(i_ctx_t *i_ctx_p)
 {
-    /* gs_initgraphics does a setgray; we must clear the interpreter's */
-    /* cached copy of the color space object. */
-    int code = gs_initgraphics(igs);
-
-    if (code >= 0)
-	make_null(&istate->colorspace.array);
-    return code;
+    /*
+     * gs_initigraphics does not reset the colorspace;
+     * this is now handled in the PostScript code.
+     */
+    return gs_initgraphics(igs);
 }
 
 /* ------ Operations on graphics state elements ------ */
@@ -540,4 +545,22 @@
 gs_istate_free(void *old, gs_memory_t * mem)
 {
     gs_free_object(mem, old, "int_grestore");
+}
+
+/*
+ * This routine is used as an interpeter callback function for the
+ * graphics library.  This routine translates a colorname_index value,
+ * (which is how the separation and DeviceN colorant names are passed
+ * to the graphics library) into a character string pointer and a
+ * string length.
+ */
+int
+gs_get_colorname_string(gs_separation_name colorname_index,
+			unsigned char **ppstr, unsigned int *pname_size)
+{
+    ref nref;
+
+    name_index_ref(colorname_index, &nref);
+    name_string_ref(&nref, &nref);
+    return obj_string_data(&nref, (const unsigned char**) ppstr, pname_size);
 }

Index: zht.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zht.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- zht.c	16 Jun 2002 03:43:51 -0000	1.5
+++ zht.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -51,23 +51,37 @@
 	    push(4);
 	    make_real(op - 3, ht.params.screen.frequency);
 	    make_real(op - 2, ht.params.screen.angle);
-	    op[-1] = istate->screen_procs.colored.gray;
+	    op[-1] = istate->screen_procs.gray;
 	    make_int(op, 1);
 	    break;
 	case ht_type_colorscreen:
 	    push(13);
 	    {
-		int i;
+		os_ptr opc = op - 12;
+		gs_screen_halftone *pht = 
+		    &ht.params.colorscreen.screens.colored.red;
 
-		for (i = 0; i < 4; i++) {
-		    os_ptr opc = op - 12 + i * 3;
-		    gs_screen_halftone *pht =
-		    &ht.params.colorscreen.screens.indexed[i];
+		make_real(opc, pht->frequency);
+		make_real(opc + 1, pht->angle);
+		opc[2] = istate->screen_procs.red;
 
-		    make_real(opc, pht->frequency);
-		    make_real(opc + 1, pht->angle);
-		    opc[2] = istate->screen_procs.indexed[i];
-		}
+		opc = op - 9;
+		pht = &ht.params.colorscreen.screens.colored.green;
+		make_real(opc, pht->frequency);
+		make_real(opc + 1, pht->angle);
+		opc[2] = istate->screen_procs.green;
+
+		opc = op - 6;
+		pht = &ht.params.colorscreen.screens.colored.blue;
+		make_real(opc, pht->frequency);
+		make_real(opc + 1, pht->angle);
+		opc[2] = istate->screen_procs.blue;
+
+		opc = op - 3;
+		pht = &ht.params.colorscreen.screens.colored.gray;
+		make_real(opc, pht->frequency);
+		make_real(opc + 1, pht->angle);
+		opc[2] = istate->screen_procs.gray;
 	    }
 	    make_int(op, 2);
 	    break;
@@ -213,10 +227,10 @@
 setscreen_finish(i_ctx_t *i_ctx_p)
 {
     gs_screen_install(senum);
-    istate->screen_procs.colored.red = sproc;
-    istate->screen_procs.colored.green = sproc;
-    istate->screen_procs.colored.blue = sproc;
-    istate->screen_procs.colored.gray = sproc;
+    istate->screen_procs.red = sproc;
+    istate->screen_procs.green = sproc;
+    istate->screen_procs.blue = sproc;
+    istate->screen_procs.gray = sproc;
     make_null(&istate->halftone);
     return 0;
 }

Index: zht1.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zht1.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- zht1.c	16 Jun 2002 03:43:51 -0000	1.5
+++ zht1.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -118,7 +118,7 @@
     code = gx_ht_install(igs, r_ptr(esp - 1, gs_halftone), pdht);
     if (code < 0)
 	return code;
-    memcpy(istate->screen_procs.indexed, esp - 5, sizeof(ref) * 4);
+    memcpy(&istate->screen_procs.red, esp - 5, sizeof(ref) * 4);
     make_null(&istate->halftone);
     esp -= 7;
     setcolorscreen_cleanup(i_ctx_p);

Index: zht2.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zht2.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- zht2.c	16 Jun 2002 03:43:51 -0000	1.5
+++ zht2.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -29,6 +29,7 @@
 #include "icolor.h"
 #include "iht.h"
 #include "store.h"
+#include "iname.h"
 
 /* Forward references */
 private int dict_spot_params(const ref *, gs_spot_halftone *, ref *, ref *);
@@ -56,35 +57,78 @@
     gs_halftone_component *phtc;
     gs_halftone_component *pc;
     int code = 0;
-    int i, j;
+    int j;
     gs_halftone *pht;
     gx_device_halftone *pdht;
-    static const char *const color_names[] = {
-	gs_ht_separation_name_strings
-    };
-    ref sprocs[countof(color_names)];
-    ref tprocs[countof(color_names)];
+    ref sprocs[GS_CLIENT_COLOR_MAX_COMPONENTS + 1];
+    ref tprocs[GS_CLIENT_COLOR_MAX_COMPONENTS + 1];
     gs_memory_t *mem;
     uint edepth = ref_stack_count(&e_stack);
     int npop = 2;
+    int dict_enum = dict_first(op);
+    ref rvalue[2];
+    int cname, colorant_number;
+    int halftonetype, type = 0;
+    gs_state *pgs = igs;
 
     check_type(*op, t_dictionary);
     check_dict_read(*op);
     check_type(op[-1], t_dictionary);
     check_dict_read(op[-1]);
-    count = 0;
-    for (i = 0; i < countof(color_names); i++) {
-	ref *pvalue;
+ 
+    /*
+     * We think that Type 2 and Type 4 halftones, like
+     * screens set by setcolorscreen, adapt automatically to
+     * the device color space, so we need to mark them
+     * with a different internal halftone type.
+     */
+    dict_int_param(op - 1, "HalftoneType", 1, 5, 0, &type);
+    halftonetype = (type == 2 || type == 4)
+    			? ht_type_multiple_colorscreen
+			: ht_type_multiple;
 
-	if (dict_find_string(op, color_names[i], &pvalue) > 0)
-	    count++;
-	else if (i == gs_ht_separation_Default)
-	    return_error(e_typecheck);
+    /* Count how many components that we will actually use. */
+
+    for (count = 0; ;) {
+	bool have_default = false;
+
+	/* Move to next element in the dictionary */
+	if ((dict_enum = dict_next(op, dict_enum, rvalue)) == -1)
+	    break;
+	/*
+	 * Verify that we have a valid component.  We may have a
+	 * /HalfToneType entry.
+	 */
+  	if (!r_has_type(&rvalue[1], t_dictionary))
+	    continue;
+
+	/* Get the name of the component  verify that we will use it. */
+	cname = name_index(&rvalue[0]);
+	colorant_number = gs_cname_to_colorant_number(pgs, cname, halftonetype);
+	if (colorant_number < 0)
+	    continue;
+	else if (colorant_number == GX_DEVICE_COLOR_MAX_COMPONENTS) {
+	    /* If here then we have the "Default" component */
+	    if (have_default)
+		return_error(e_rangecheck);
+	    have_default = true;
+	}
+
+	count++;
+	/*
+	 * Check to see if we have already reached the legal number of
+	 * components.
+	 */
+	if (count > GS_CLIENT_COLOR_MAX_COMPONENTS + 1) {
+	    code = gs_note_error(e_rangecheck);
+	    break;
+        }
     }
+
     mem = (gs_memory_t *) idmemory->spaces_indexed[r_space_index(op - 1)];
     check_estack(5);		/* for sampling Type 1 screens */
-    refset_null(sprocs, countof(sprocs));
-    refset_null(tprocs, countof(tprocs));
+    refset_null(sprocs, count);
+    refset_null(tprocs, count);
     rc_alloc_struct_0(pht, gs_halftone, &st_halftone,
 		      imemory, pht = 0, ".sethalftone5");
     phtc = gs_alloc_struct_array(mem, count, gs_halftone_component,
@@ -94,77 +138,95 @@
 		      imemory, pdht = 0, ".sethalftone5");
     if (pht == 0 || phtc == 0 || pdht == 0)
 	code = gs_note_error(e_VMerror);
-    else
-	for (i = 0, j = 0, pc = phtc; i < countof(color_names); i++) {
+    else {
+        dict_enum = dict_first(op);
+	for (j = 0, pc = phtc; ;) {
 	    int type;
-	    ref *pvalue;
 
-	    if (dict_find_string(op, color_names[i], &pvalue) > 0) {
-		check_type_only(*pvalue, t_dictionary);
-		check_dict_read(*pvalue);
-		if (dict_int_param(pvalue, "HalftoneType", 1, 7, 0,
-				   &type) < 0
-		    ) {
-		    code = gs_note_error(e_typecheck);
+	    /* Move to next element in the dictionary */
+	    if ((dict_enum = dict_next(op, dict_enum, rvalue)) == -1)
+	        break;
+	    /*
+	     * Verify that we have a valid component.  We may have a
+	     * /HalfToneType entry.
+	     */
+  	    if (!r_has_type(&rvalue[1], t_dictionary))
+		continue;
+
+	    /* Get the name of the component */
+	    cname = name_index(&rvalue[0]);
+	    colorant_number = gs_cname_to_colorant_number(pgs, cname, halftonetype);
+	    if (colorant_number < 0)
+		continue;		/* Do not use this component */
+	    pc->comp_number = colorant_number;
+
+	    /* Now process the component dictionary */
+	    check_dict_read(rvalue[1]);
+	    if (dict_int_param(&rvalue[1], "HalftoneType", 1, 7, 0, &type) < 0) {
+		code = gs_note_error(e_typecheck);
+		break;
+	    }
+	    switch (type) {
+		default:
+		    code = gs_note_error(e_rangecheck);
 		    break;
-		}
-		switch (type) {
-		    default:
-			code = gs_note_error(e_rangecheck);
-			break;
-		    case 1:
-			code = dict_spot_params(pvalue,
-						&pc->params.spot, sprocs + j,
-						tprocs + j);
-			pc->params.spot.screen.spot_function = spot1_dummy;
-			pc->type = ht_type_spot;
-			break;
-		    case 3:
-			code = dict_threshold_params(pvalue,
-					 &pc->params.threshold, tprocs + j);
-			pc->type = ht_type_threshold;
-			break;
-		    case 7:
-			code = dict_threshold2_params(pvalue,
-					&pc->params.threshold2, tprocs + j,
-					imemory);
-			pc->type = ht_type_threshold2;
-			break;
-		}
-		if (code < 0)
+		case 1:
+		    code = dict_spot_params(&rvalue[1], &pc->params.spot,
+		    				sprocs + j, tprocs + j);
+		    pc->params.spot.screen.spot_function = spot1_dummy;
+		    pc->type = ht_type_spot;
+		    break;
+		case 3:
+		    code = dict_threshold_params(&rvalue[1], &pc->params.threshold,
+		    					tprocs + j);
+		    pc->type = ht_type_threshold;
+		    break;
+		case 7:
+		    code = dict_threshold2_params(&rvalue[1], &pc->params.threshold2,
+		    					tprocs + j, imemory);
+		    pc->type = ht_type_threshold2;
 		    break;
-		pc->cname = (gs_ht_separation_name) i;
-		pc++, j++;
 	    }
+	    if (code < 0)
+		break;
+	    pc++;
+	    j++;
 	}
+    }
     if (code >= 0) {
-	/*
-	 * We think that Type 2 and Type 4 halftones, like
-	 * screens set by setcolorscreen, adapt automatically to
-	 * the device color space, so we need to mark them
-	 * with a different internal halftone type.
-	 */
-	int type = 0;
-
-	dict_int_param(op - 1, "HalftoneType", 1, 5, 0, &type);
-	pht->type =
-	    (type == 2 || type == 4 ? ht_type_multiple_colorscreen :
-	     ht_type_multiple);
+	pht->type = halftonetype;
 	pht->params.multiple.components = phtc;
-	pht->params.multiple.num_comp = count;
+	pht->params.multiple.num_comp = j;
 	code = gs_sethalftone_prepare(igs, pht, pdht);
     }
-    if (code >= 0)
-	for (j = 0, pc = phtc; j < count; j++, pc++) {
-	    if (pc->type == ht_type_spot) {
-		ref *pvalue;
+    if (code >= 0) {
+	/*
+	 * Put the actual frequency and angle in the spot function component dictionaries.
+	 */
+	dict_enum = dict_first(op);
+	for (pc = phtc; ; ) {
+	    /* Move to next element in the dictionary */
+	    if ((dict_enum = dict_next(op, dict_enum, rvalue)) == -1)
+		break;
 
-		dict_find_string(op, color_names[pc->cname], &pvalue);
-		code = dict_spot_results(i_ctx_p, pvalue, &pc->params.spot);
+	    /* Verify that we have a valid component */
+	    if (!r_has_type(&rvalue[1], t_dictionary))
+		continue;
+
+	    /* Get the name of the component and verify that we will use it. */
+	    cname = name_index(&rvalue[0]);
+	    colorant_number = gs_cname_to_colorant_number(pgs, cname, halftonetype);
+	    if (colorant_number < 0)
+		continue;
+
+	    if (pc->type == ht_type_spot) {
+		code = dict_spot_results(i_ctx_p, &rvalue[1], &pc->params.spot);
 		if (code < 0)
 		    break;
 	    }
+	    pc++;
 	}
+    }
     if (code >= 0) {
 	/*
 	 * Schedule the sampling of any Type 1 screens,
@@ -186,32 +248,32 @@
 	make_op_estack(esp, sethalftone_finish);
 	for (j = 0; j < count; j++) {
 	    gx_ht_order *porder =
-	    (pdht->components == 0 ? &pdht->order :
-	     &pdht->components[j].corder);
+		(pdht->components == 0 ? &pdht->order :
+		 &pdht->components[j].corder);
 
 	    switch (phtc[j].type) {
-		case ht_type_spot:
-		    code = zscreen_enum_init(i_ctx_p, porder,
-					     &phtc[j].params.spot.screen,
-					     &sprocs[j], 0, 0, mem);
-		    if (code < 0)
-			break;
-		    /* falls through */
-		case ht_type_threshold:
-		    if (!r_has_type(tprocs + j, t__invalid)) {
-			/* Schedule TransferFunction sampling. */
-			/****** check_xstack IS WRONG ******/
-			check_ostack(zcolor_remap_one_ostack);
-			check_estack(zcolor_remap_one_estack);
-			code = zcolor_remap_one(i_ctx_p, tprocs + j,
-						porder->transfer, igs,
-						zcolor_remap_one_finish);
-			op = osp;
-		    }
+	    case ht_type_spot:
+		code = zscreen_enum_init(i_ctx_p, porder,
+					 &phtc[j].params.spot.screen,
+					 &sprocs[j], 0, 0, mem);
+		if (code < 0)
 		    break;
-		default:	/* not possible here, but to keep */
-		    /* the compilers happy.... */
-		    ;
+		/* falls through */
+	    case ht_type_threshold:
+		if (!r_has_type(tprocs + j, t__invalid)) {
+		    /* Schedule TransferFunction sampling. */
+		    /****** check_xstack IS WRONG ******/
+		    check_ostack(zcolor_remap_one_ostack);
+		    check_estack(zcolor_remap_one_estack);
+		    code = zcolor_remap_one(i_ctx_p, tprocs + j,
+					    porder->transfer, igs,
+					    zcolor_remap_one_finish);
+		    op = osp;
+		}
+		break;
+	    default:	/* not possible here, but to keep */
+				/* the compilers happy.... */
+		;
 	    }
 	    if (code < 0) {	/* Restore the stack. */
 		ref_stack_pop_to(&o_stack, odepth);
@@ -233,6 +295,7 @@
     pop(npop);
     return (ref_stack_count(&e_stack) > edepth ? o_push_estack : 0);
 }
+
 /* Install the halftone after sampling. */
 private int
 sethalftone_finish(i_ctx_t *i_ctx_p)

Index: zimage.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zimage.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- zimage.c	22 Jun 2002 11:16:12 -0000	1.9
+++ zimage.c	22 Aug 2002 07:12:29 -0000	1.10
@@ -16,130 +16,114 @@
 
 /* $Id$ */
 /* Image operators */
+#include "math_.h"
 #include "memory_.h"
 #include "ghost.h"
 #include "oper.h"
-#include "estack.h"		/* for image[mask] */
+#include "gscolor.h"
+#include "gscspace.h"
+#include "gscolor2.h"
+#include "gsmatrix.h"
+#include "gsimage.h"
+#include "gxfixed.h"
 #include "gsstruct.h"
+#include "gxiparam.h"
+#include "idict.h"
+#include "idparam.h"
+#include "estack.h"		/* for image[mask] */
 #include "ialloc.h"
 #include "igstate.h"
 #include "ilevel.h"
 #include "store.h"
-#include "gscspace.h"
-#include "gscssub.h"
-#include "gsmatrix.h"
-#include "gsimage.h"
-#include "gxiparam.h"
 #include "stream.h"
 #include "ifilter.h"		/* for stream exception handling */
 #include "iimage.h"
 
 /* Forward references */
-private int image_setup(i_ctx_t *i_ctx_p, os_ptr op, gs_image_t * pim,
-			const gs_color_space * pcs, int npop);
+private int zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
+				 gx_image_enum_common_t * pie,
+				 const ref * sources, int npop);
 private int image_proc_process(i_ctx_t *);
 private int image_file_continue(i_ctx_t *);
 private int image_string_continue(i_ctx_t *);
 private int image_cleanup(i_ctx_t *);
 
-/* <width> <height> <bits/sample> <matrix> <datasrc> image - */
-int
-zimage(i_ctx_t *i_ctx_p)
-{
-    return zimage_opaque_setup(i_ctx_p, osp, false, gs_image_alpha_none,
-			       gs_current_DeviceGray_space(igs), 5);
-}
-
-/* <width> <height> <paint_1s> <matrix> <datasrc> imagemask - */
-int
-zimagemask(i_ctx_t *i_ctx_p)
-{
-    os_ptr op = osp;
-    gs_image_t image;
 
-    check_type(op[-2], t_boolean);
-    gs_image_t_init_mask_adjust(&image, op[-2].value.boolval,
-				gs_incachedevice(igs) != CACHE_DEVICE_NONE);
-    return image_setup(i_ctx_p, op, &image, NULL, 5);
-}
 
-/* Setup for [color|alpha]image.  This code isn't used for Level 1, */
-/* but it's simpler to include it here. */
+/* Extract and check the parameters for a gs_data_image_t. */
 int
-zimage_multiple(i_ctx_t *i_ctx_p, bool has_alpha)
+data_image_params(const ref *op, gs_data_image_t *pim,
+		  image_params *pip, bool require_DataSource,
+		  int num_components, int max_bits_per_component,
+		  bool has_alpha)
 {
-    os_ptr op = osp;
-    int spp;			/* samples per pixel */
-    int npop = 7;
-    os_ptr procp = op - 2;
-    const gs_color_space *pcs;
-    bool multi = false;
+    int code;
+    int decode_size;
+    ref *pds;
 
-    check_int_leu(*op, 4);	/* ncolors */
-    check_type(op[-1], t_boolean);	/* multiproc */
-    switch ((spp = (int)(op->value.intval))) {
-	case 1:
-	    pcs = gs_current_DeviceGray_space(igs);
-	    break;
-	case 3:
-	    pcs = gs_current_DeviceRGB_space(igs);
-	    goto color;
-	case 4:
-	    pcs = gs_current_DeviceCMYK_space(igs);
-color:
-	    if (op[-1].value.boolval) {	/* planar format */
-		if (has_alpha)
-		    ++spp;
-		npop += spp - 1;
-		procp -= spp - 1;
-		multi = true;
-	    }
-	    break;
-	default:
-	    return_error(e_rangecheck);
+    check_type(*op, t_dictionary);
+    check_dict_read(*op);
+    if ((code = dict_int_param(op, "Width", 0, max_int_in_fixed / 2,
+			       -1, &pim->Width)) < 0 ||
+	(code = dict_int_param(op, "Height", 0, max_int_in_fixed / 2,
+			       -1, &pim->Height)) < 0 ||
+	(code = dict_matrix_param(op, "ImageMatrix",
+				  &pim->ImageMatrix)) < 0 ||
+	(code = dict_bool_param(op, "MultipleDataSources", false,
+				&pip->MultipleDataSources)) < 0 ||
+	(code = dict_int_param(op, "BitsPerComponent", 1,
+			       max_bits_per_component, -1,
+			       &pim->BitsPerComponent)) < 0 ||
+	(code = decode_size = dict_floats_param(op, "Decode",
+						num_components * 2,
+						&pim->Decode[0], NULL)) < 0 ||
+	(code = dict_bool_param(op, "Interpolate", false,
+				&pim->Interpolate)) < 0
+	)
+	return code;
+    pip->pDecode = &pim->Decode[0];
+    /* Extract and check the data sources. */
+    if ((code = dict_find_string(op, "DataSource", &pds)) <= 0) {
+	if (require_DataSource)
+	    return (code < 0 ? code : gs_note_error(e_rangecheck));
+	return 1;		/* no data source */
     }
-    return zimage_opaque_setup(i_ctx_p, procp, multi,
-		    (has_alpha ? gs_image_alpha_last : gs_image_alpha_none),
-			       pcs, npop);
+    if (pip->MultipleDataSources) {
+	long i, n = num_components + (has_alpha ? 1 : 0);
+        if (!r_is_array(pds))
+            return_error(e_typecheck);
+	if (r_size(pds) != n)
+	    return_error(e_rangecheck);
+	for (i = 0; i < n; ++i)
+            array_get(pds, i, &pip->DataSource[i]);
+    } else
+	pip->DataSource[0] = *pds;
+    return 0;
 }
 
-/* Common setup for [color|alpha]image. */
-/* Fills in format, BitsPerComponent, Alpha. */
+/* Extract and check the parameters for a gs_pixel_image_t. */
 int
-zimage_opaque_setup(i_ctx_t *i_ctx_p, os_ptr op, bool multi,
-		    gs_image_alpha_t alpha, const gs_color_space * pcs,
-		    int npop)
-{
-    gs_image_t image;
-
-    check_int_leu(op[-2], (level2_enabled ? 12 : 8));	/* bits/sample */
-    gs_image_t_init(&image, pcs);
-    image.BitsPerComponent = (int)op[-2].value.intval;
-    image.Alpha = alpha;
-    image.format =
-	(multi ? gs_image_format_component_planar : gs_image_format_chunky);
-    return image_setup(i_ctx_p, op, &image, pcs, npop);
-}
-
-/* Common setup for [color|alpha]image and imagemask. */
-/* Fills in Width, Height, ImageMatrix, ColorSpace. */
-private int
-image_setup(i_ctx_t *i_ctx_p, os_ptr op, gs_image_t * pim,
-	    const gs_color_space * pcs, int npop)
+pixel_image_params(i_ctx_t *i_ctx_p, const ref *op, gs_pixel_image_t *pim,
+		   image_params *pip, int max_bits_per_component,
+		   bool has_alpha)
 {
+    int num_components =
+	gs_color_space_num_components(gs_currentcolorspace(igs));
     int code;
 
-    check_type(op[-4], t_integer);	/* width */
-    check_type(op[-3], t_integer);	/* height */
-    if (op[-4].value.intval < 0 || op[-3].value.intval < 0)
-	return_error(e_rangecheck);
-    if ((code = read_matrix(op - 1, &pim->ImageMatrix)) < 0)
+    if (num_components < 1)
+	return_error(e_rangecheck);	/* Pattern space not allowed */
+    pim->ColorSpace = gs_currentcolorspace(igs);
+    code = data_image_params(op, (gs_data_image_t *) pim, pip, true,
+			     num_components, max_bits_per_component,
+			     has_alpha);
+    if (code < 0)
 	return code;
-    pim->ColorSpace = pcs;
-    pim->Width = (int)op[-4].value.intval;
-    pim->Height = (int)op[-3].value.intval;
-    return zimage_setup(i_ctx_p, (gs_pixel_image_t *) pim, op,
-			pim->ImageMask | pim->CombineWithColor, npop);
+    pim->format =
+	(pip->MultipleDataSources ? gs_image_format_component_planar :
+	 gs_image_format_chunky);
+    return dict_bool_param(op, "CombineWithColor", false,
+			   &pim->CombineWithColor);
 }
 
 /* Common setup for all Level 1 and 2 images, and ImageType 4 images. */
@@ -158,6 +142,62 @@
 			     sources, npop);
 }
 
+/* Common code for .image1 and .alphaimage operators */
+int
+image1_setup(i_ctx_t * i_ctx_p, bool has_alpha)
+{
+    os_ptr          op = osp;
+    gs_image_t      image;
+    image_params    ip;
+    int             code;
+
+    gs_image_t_init(&image, gs_currentcolorspace(igs));
+    code = pixel_image_params( i_ctx_p,
+                               op,
+                               (gs_pixel_image_t *)&image,
+                               &ip,
+			       (level2_enabled ? 12 : 8),
+                               has_alpha );
+    if (code < 0)
+	return code;
+
+    image.Alpha = (has_alpha ? gs_image_alpha_last : gs_image_alpha_none);
+    return zimage_setup( i_ctx_p,
+                         (gs_pixel_image_t *)&image,
+                         &ip.DataSource[0],
+			 image.CombineWithColor,
+                         1 );
+}
+
+/* <dict> .image1 - */
+private int
+zimage1(i_ctx_t *i_ctx_p)
+{
+    return image1_setup(i_ctx_p, false);
+}
+
+/* <dict> .imagemask1 - */
+private int
+zimagemask1(i_ctx_t *i_ctx_p)
+{
+    os_ptr op = osp;
+    gs_image_t image;
+    image_params ip;
+    int code;
+
+    gs_image_t_init_mask_adjust(&image, false,
+				gs_incachedevice(igs) != CACHE_DEVICE_NONE);
+    code = data_image_params(op, (gs_data_image_t *) & image,
+			     &ip, true, 1, 1, false);
+    if (code < 0)
+	return code;
+    if (ip.MultipleDataSources)
+	return_error(e_rangecheck);
+    return zimage_setup(i_ctx_p, (gs_pixel_image_t *)&image, &ip.DataSource[0],
+			true, 1);
+}
+
+
 /* Common setup for all Level 1 and 2 images, and ImageType 3 and 4 images. */
 /*
  * We push the following on the estack.
@@ -514,8 +554,8 @@
 
 const op_def zimage_op_defs[] =
 {
-    {"5image", zimage},
-    {"5imagemask", zimagemask},
+    {"1.image1", zimage1},
+    {"1.imagemask1", zimagemask1},
 		/* Internal operators */
     {"1%image_proc_continue", image_proc_continue},
     {"0%image_file_continue", image_file_continue},

Index: zimage2.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zimage2.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- zimage2.c	21 Feb 2002 22:24:54 -0000	1.6
+++ zimage2.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -16,133 +16,14 @@
 
 /* $Id$ */
 /* image operator extensions for Level 2 PostScript */
-#include "math_.h"
 #include "memory_.h"
 #include "ghost.h"
-#include "oper.h"
-#include "gscolor.h"
-#include "gscspace.h"
-#include "gscolor2.h"
-#include "gsmatrix.h"
 #include "gsimage.h"
-#include "gxfixed.h"
-#include "idict.h"
-#include "idparam.h"
-#include "iimage.h"
+#include "gxiparam.h"
+#include "icstate.h"
 #include "iimage2.h"
-#include "ilevel.h"
 #include "igstate.h"		/* for igs */
 
-/* Extract and check the parameters for a gs_data_image_t. */
-int
-data_image_params(const ref *op, gs_data_image_t *pim,
-		  image_params *pip, bool require_DataSource,
-		  int num_components, int max_bits_per_component)
-{
-    int code;
-    int decode_size;
-    ref *pds;
-
-    check_type(*op, t_dictionary);
-    check_dict_read(*op);
-    if ((code = dict_int_param(op, "Width", 0, max_int_in_fixed / 2,
-			       -1, &pim->Width)) < 0 ||
-	(code = dict_int_param(op, "Height", 0, max_int_in_fixed / 2,
-			       -1, &pim->Height)) < 0 ||
-	(code = dict_matrix_param(op, "ImageMatrix",
-				  &pim->ImageMatrix)) < 0 ||
-	(code = dict_bool_param(op, "MultipleDataSources", false,
-				&pip->MultipleDataSources)) < 0 ||
-	(code = dict_int_param(op, "BitsPerComponent", 1,
-			       max_bits_per_component, -1,
-			       &pim->BitsPerComponent)) < 0 ||
-	(code = decode_size = dict_floats_param(op, "Decode",
-						num_components * 2,
-						&pim->Decode[0], NULL)) < 0 ||
-	(code = dict_bool_param(op, "Interpolate", false,
-				&pim->Interpolate)) < 0
-	)
-	return code;
-    pip->pDecode = &pim->Decode[0];
-    /* Extract and check the data sources. */
-    if ((code = dict_find_string(op, "DataSource", &pds)) <= 0) {
-	if (require_DataSource)
-	    return (code < 0 ? code : gs_note_error(e_rangecheck));
-	return 1;		/* no data source */
-    }
-    if (pip->MultipleDataSources) {
-	long i;
-        if (!r_is_array(pds))
-            return_error(e_typecheck);
-	if (r_size(pds) != num_components)
-	    return_error(e_rangecheck);
-	for (i = 0; i < num_components; ++i)
-            array_get(pds, i, &pip->DataSource[i]);
-    } else
-	pip->DataSource[0] = *pds;
-    return 0;
-}
-
-/* Extract and check the parameters for a gs_pixel_image_t. */
-int
-pixel_image_params(i_ctx_t *i_ctx_p, const ref *op, gs_pixel_image_t *pim,
-		   image_params *pip, int max_bits_per_component)
-{
-    int num_components =
-	gs_color_space_num_components(gs_currentcolorspace(igs));
-    int code;
-
-    if (num_components < 1)
-	return_error(e_rangecheck);	/* Pattern space not allowed */
-    pim->ColorSpace = gs_currentcolorspace(igs);
-    code = data_image_params(op, (gs_data_image_t *) pim, pip, true,
-			     num_components, max_bits_per_component);
-    if (code < 0)
-	return code;
-    pim->format =
-	(pip->MultipleDataSources ? gs_image_format_component_planar :
-	 gs_image_format_chunky);
-    return dict_bool_param(op, "CombineWithColor", false,
-			   &pim->CombineWithColor);
-}
-
-/* <dict> .image1 - */
-private int
-zimage1(i_ctx_t *i_ctx_p)
-{
-    os_ptr op = osp;
-    gs_image_t image;
-    image_params ip;
-    int code;
-
-    gs_image_t_init(&image, gs_currentcolorspace(igs));
-    code = pixel_image_params(i_ctx_p, op, (gs_pixel_image_t *)&image, &ip,
-			      12);
-    if (code < 0)
-	return code;
-    return zimage_setup(i_ctx_p, (gs_pixel_image_t *)&image, &ip.DataSource[0],
-			image.CombineWithColor, 1);
-}
-
-/* <dict> .imagemask1 - */
-private int
-zimagemask1(i_ctx_t *i_ctx_p)
-{
-    os_ptr op = osp;
-    gs_image_t image;
-    image_params ip;
-    int code;
-
-    gs_image_t_init_mask_adjust(&image, false,
-				gs_incachedevice(igs) != CACHE_DEVICE_NONE);
-    code = data_image_params(op, (gs_data_image_t *) & image, &ip, true, 1, 1);
-    if (code < 0)
-	return code;
-    if (ip.MultipleDataSources)
-	return_error(e_rangecheck);
-    return zimage_setup(i_ctx_p, (gs_pixel_image_t *)&image, &ip.DataSource[0],
-			true, 1);
-}
 
 /*
  * Process an image that has no explicit source data.  This isn't used by
@@ -160,13 +41,3 @@
     /* We didn't pass any data, so there's nothing to clean up. */
     return code;
 }
-
-/* ------ Initialization procedure ------ */
-
-const op_def zimage2_l2_op_defs[] =
-{
-    op_def_begin_level2(),
-    {"1.image1", zimage1},
-    {"1.imagemask1", zimagemask1},
-    op_def_end(0)
-};

Index: zimage3.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zimage3.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- zimage3.c	21 Feb 2002 22:24:54 -0000	1.5
+++ zimage3.c	22 Aug 2002 07:12:29 -0000	1.6
@@ -28,7 +28,6 @@
 #include "idparam.h"
 #include "igstate.h"
 #include "iimage.h"
-#include "iimage2.h"
 
 /* <dict> .image3 - */
 private int
@@ -56,8 +55,9 @@
 	return_error(e_rangecheck);
     if ((code = pixel_image_params(i_ctx_p, pDataDict,
 				   (gs_pixel_image_t *)&image, &ip_data,
-				   12)) < 0 ||
-	(mcode = code = data_image_params(pMaskDict, &image.MaskDict, &ip_mask, false, 1, 12)) < 0 ||
+				   12, false)) < 0 ||
+	(mcode = code = data_image_params(pMaskDict, &image.MaskDict,
+				   &ip_mask, false, 1, 12, false)) < 0 ||
 	(code = dict_int_param(pDataDict, "ImageType", 1, 1, 0, &ignored)) < 0 ||
 	(code = dict_int_param(pMaskDict, "ImageType", 1, 1, 0, &ignored)) < 0
 	)
@@ -97,7 +97,7 @@
 
     gs_image4_t_init(&image, NULL);
     code = pixel_image_params(i_ctx_p, op, (gs_pixel_image_t *)&image, &ip,
-			      12);
+			      12, false);
     if (code < 0)
 	return code;
     code = dict_int_array_check_param(op, "MaskColor", num_components * 2,

Index: zmisc.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zmisc.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- zmisc.c	21 Feb 2002 22:24:54 -0000	1.4
+++ zmisc.c	22 Aug 2002 07:12:29 -0000	1.5
@@ -167,6 +167,16 @@
     return 0;
 }
 
+/* some FTS tests work better if realtime starts from 0 at boot time */
+private long    real_time_0[2];
+
+private int
+zmisc_init_realtime(i_ctx_t * i_ctx_p)
+{
+    gp_get_realtime(real_time_0);
+    return 0;
+}
+
 /* - realtime <int> */
 private int
 zrealtime(i_ctx_t *i_ctx_p)
@@ -175,6 +185,8 @@
     long secs_ns[2];
 
     gp_get_realtime(secs_ns);
+    secs_ns[1] -= real_time_0[1];
+    secs_ns[0] -= real_time_0[0];
     push(1);
     make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
     return 0;
@@ -359,5 +371,5 @@
     {"2.setdebug", zsetdebug},
     {"1.setoserrno", zsetoserrno},
     {"0usertime", zusertime},
-    op_def_end(0)
+    op_def_end(zmisc_init_realtime)
 };

Index: zmisc3.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zmisc3.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- zmisc3.c	21 Feb 2002 22:24:54 -0000	1.4
+++ zmisc3.c	22 Aug 2002 07:12:29 -0000	1.5
@@ -21,7 +21,6 @@
 #include "gsmatrix.h"		/* ditto */
 #include "gsclipsr.h"
 #include "gscolor2.h"
-#include "gscssub.h"
 #include "oper.h"
 #include "igstate.h"
 #include "store.h"
@@ -114,25 +113,6 @@
     return 0;
 }
 
-/* <index> <bool> .setsubstitutecolorspace - */
-private int
-zsetsubstitutecolorspace(i_ctx_t *i_ctx_p)
-{
-    os_ptr op = osp;
-    int index, code;
-
-    check_type(*op, t_boolean);
-    check_int_leu(op[-1], 2);
-    index = (int)op[-1].value.intval;
-    code = gs_setsubstitutecolorspace(igs, index,
-				      (op->value.boolval ?
-				       gs_currentcolorspace(igs) :
-				       NULL));
-    if (code >= 0)
-	pop(2);
-    return code;
-}
-
 /* ------ Initialization procedure ------ */
 
 const op_def zmisc3_op_defs[] =
@@ -141,6 +121,5 @@
     {"0cliprestore", zcliprestore},
     {"0clipsave", zclipsave},
     {"2.eqproc", zeqproc},
-    {"2.setsubstitutecolorspace", zsetsubstitutecolorspace},
     op_def_end(0)
 };

Index: zpcolor.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zpcolor.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- zpcolor.c	16 Jun 2002 03:43:51 -0000	1.6
+++ zpcolor.c	22 Aug 2002 07:12:29 -0000	1.7
@@ -131,7 +131,9 @@
     uint edepth = ref_stack_count(&e_stack);
     int code;
 
-    check_read_type(*op, t_array);
+    if (!r_is_array(op))
+        return_error(e_typecheck);
+    check_read(*op);
     switch (r_size(op)) {
 	case 1:		/* no base space */
 	    cs.params.pattern.has_base_space = false;
@@ -219,7 +221,8 @@
 	gs_grestore(pgs);
 	return code;
     }
-    gx_set_device_only(pgs, (gx_device *) pdev);
+    /* gx_set_device_only(pgs, (gx_device *) pdev); */
+    gs_setdevice_no_init(pgs, (gx_device *)pdev);
     push_mark_estack(es_other, pattern_paint_cleanup);
     ++esp;
     make_istruct(esp, 0, pdev);

Index: zshade.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zshade.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- zshade.c	16 Jun 2002 03:43:51 -0000	1.12
+++ zshade.c	22 Aug 2002 07:12:29 -0000	1.13
@@ -417,7 +417,7 @@
 					    "build_mesh_shading");
 	if (data == 0)
 	    return_error(e_VMerror);
-	code = float_params(pDataSource->value.refs + size - 1, size, data);
+	code = process_float_array(pDataSource, size, data);
 	if (code < 0) {
 	    gs_free_object(mem, data, "build_mesh_shading");
 	    return code;

Index: ztrans.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/ztrans.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- ztrans.c	16 Jun 2002 03:43:51 -0000	1.18
+++ ztrans.c	22 Aug 2002 07:12:29 -0000	1.19
@@ -30,7 +30,6 @@
 #include "ifunc.h"
 #include "igstate.h"
 #include "iimage.h"
-#include "iimage2.h"
 #include "iname.h"
 #include "store.h"
 #include "gsdfilt.h"
@@ -347,7 +346,7 @@
 	return_error(e_rangecheck);
     if ((code = pixel_image_params(i_ctx_p, pDataDict,
 				   (gs_pixel_image_t *)&image, &ip_data,
-				   12)) < 0 ||
+				   12, false)) < 0 ||
 	(code = dict_int_param(pDataDict, "ImageType", 1, 1, 0, &ignored)) < 0
 	)
 	return code;
@@ -378,7 +377,8 @@
 
     if (dict_find_string(op, dict_name, &pMaskDict) <= 0)
 	return 1;
-    if ((mcode = code = data_image_params(pMaskDict, &pixm->MaskDict, &ip_mask, false, 1, 12)) < 0 ||
+    if ((mcode = code = data_image_params(pMaskDict, &pixm->MaskDict,
+					  &ip_mask, false, 1, 12, false)) < 0 ||
 	(code = dict_int_param(pMaskDict, "ImageType", 1, 1, 0, &ignored)) < 0 ||
 	(code = dict_int_param(pMaskDict, "InterleaveType", 1, 3, -1,
 			       &pixm->InterleaveType)) < 0 ||

--- gscsepnm.h DELETED ---

--- gxdither.c DELETED ---




More information about the gs-cvs mailing list