/* Copyright (C) 1996, 2000 artofcode LLC.  All rights reserved.
  
  This program is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version.

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  59 Temple Place, Suite 330, Boston, MA, 02111-1307.

*/

/*$Id: gsdcolor.h,v 1.3.6.1.2.1 2003/01/17 00:49:02 giles Exp $ */
/* Device color representation for drivers */

#ifndef gsdcolor_INCLUDED
#  define gsdcolor_INCLUDED

#include "gsccolor.h"
#include "gxarith.h"		/* for imod */
#include "gxbitmap.h"
#include "gxhttile.h"
#include "gxcindex.h"

#ifndef gx_device_color_DEFINED
#  define gx_device_color_DEFINED
typedef struct gx_device_color_s gx_device_color;
#endif

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

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * The definitions in the following section of the file are the only
 * ones that should be used by read-only clients such as implementors
 * of high-level driver functions.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
 * A device color consists of a base color and an optional (tiled) mask.
 * The base color may be a pure color, a binary halftone, or a colored
 * bitmap (color halftone or colored Pattern).  The mask is used for
 * both colored and uncolored Patterns.
 */

/* Accessing a pure color. */
#define gx_dc_is_pure(pdc)\
  ((pdc)->type == gx_dc_type_pure)
#define gx_dc_writes_pure(pdc, lop)\
  (gx_dc_is_pure(pdc) && lop_no_S_is_T(lop))
#define gx_dc_pure_color(pdc)\
  ((pdc)->colors.pure)

/* Accessing the phase of a halftone. */
#define gx_dc_phase(pdc)\
  ((pdc)->phase)

/* Accessing a binary halftone. */
#define gx_dc_is_binary_halftone(pdc)\
  ((pdc)->type == gx_dc_type_ht_binary)
#define gx_dc_binary_tile(pdc)\
  (&(pdc)->colors.binary.b_tile->tiles)
#define gx_dc_binary_color0(pdc)\
  ((pdc)->colors.binary.color[0])
#define gx_dc_binary_color1(pdc)\
  ((pdc)->colors.binary.color[1])

/* Accessing a colored halftone. */
#define gx_dc_is_colored_halftone(pdc)\
  ((pdc)->type == gx_dc_type_ht_colored)

/* Test device colors for equality. */
bool gx_device_color_equal(P2(const gx_device_color *pdevc1,
			      const gx_device_color *pdevc2));

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * The definitions in the following section of the file, plus the ones
 * just above, are the only ones that should be used by clients that
 * set as well as read device colors.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#define color_is_set(pdc)\
  ((pdc)->type != gx_dc_type_none)
#define color_unset(pdc)\
  ((pdc)->type = gx_dc_type_none)

#define gx_dc_is_null(pdc)\
  ((pdc)->type == gx_dc_type_null)
#define color_is_null(pdc) gx_dc_is_null(pdc)
#define color_set_null(pdc)\
  ((pdc)->type = gx_dc_type_null)

#define color_is_pure(pdc) gx_dc_is_pure(pdc)
#define color_writes_pure(pdc, lop) gx_dc_writes_pure(pdc, lop)
#define color_set_pure(pdc, color)\
  ((pdc)->colors.pure = (color),\
   (pdc)->type = gx_dc_type_pure)

/* Set the phase to an offset from the tile origin. */
#define color_set_phase(pdc, px, py)\
  ((pdc)->phase.x = (px),\
   (pdc)->phase.y = (py))
/* Set the phase from the halftone phase in a graphics state. */
#define color_set_phase_mod(pdc, px, py, tw, th)\
  color_set_phase(pdc, imod(-(px), tw), imod(-(py), th))

#define color_is_binary_halftone(pdc) gx_dc_is_binary_halftone(pdc)
#define color_set_binary_halftone_component(pdc, ht, index, color0, color1, level)\
  ((pdc)->colors.binary.b_ht = (ht),\
   (pdc)->colors.binary.b_index = (index),\
   (pdc)->colors.binary.color[0] = (color0),\
   (pdc)->colors.binary.color[1] = (color1),\
   (pdc)->colors.binary.b_level = (level),\
   (pdc)->type = gx_dc_type_ht_binary)
#define color_set_binary_halftone(pdc, ht, color0, color1, level)\
  color_set_binary_halftone_component(pdc, ht, -1, color0, color1, level)
#define color_set_binary_tile(pdc, color0, color1, tile)\
  ((pdc)->colors.binary.b_ht = 0,\
   (pdc)->colors.binary.color[0] = (color0),\
   (pdc)->colors.binary.color[1] = (color1),\
   (pdc)->colors.binary.b_index = -1, /* irrelevant */\
   (pdc)->colors.binary.b_tile = (tile),\
   (pdc)->type = gx_dc_type_ht_binary)

#define color_is_colored_halftone(pdc) gx_dc_is_colored_halftone(pdc)
#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(P2(gx_device_color *pdevc,
				 gx_device_halftone *pdht));
#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),\
   gx_complete_rgb_halftone(pdc, ht))
/* Some special clients set the individual components separately. */
void gx_complete_cmyk_halftone(P2(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))

/* Note that color_set_null_pattern doesn't set mask.ccolor. */
#define color_set_null_pattern(pdc)\
 ((pdc)->mask.id = gx_no_bitmap_id,\
  (pdc)->mask.m_tile = 0,\
  (pdc)->colors.pattern.p_tile = 0,\
  (pdc)->type = gx_dc_type_pattern)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * The remaining definitions are internal ones that are included in this
 * file only because C's abstraction mechanisms aren't strong enough to
 * allow us to keep them separate and still have in-line access to the
 * commonly used members.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* Define opaque types for objects referenced by device colors. */

#ifndef gx_ht_tile_DEFINED
#  define gx_ht_tile_DEFINED
typedef struct gx_ht_tile_s gx_ht_tile;
#endif

#ifndef gx_color_tile_DEFINED
#  define gx_color_tile_DEFINED
typedef struct gx_color_tile_s gx_color_tile;
#endif

/*
 * The device color in the graphics state is computed from client color
 * specifications, and kept current through changes in transfer function,
 * device, and (if relevant) halftone phase.
 * (gx_set_dev_color sets the device color if needed.)
 * For binary halftones (and eventually colored halftones as well),
 * the bitmaps are only cached, so internal clients (the painting operators)
 * must call gx_color_load to ensure that the bitmap is available.
 * Device color elements set by gx_color_load are marked with @ below.
 *
 * Base colors are represented as follows:
 *
 *      Pure color (gx_dc_pure):
 *              colors.pure = the color;
 *      Binary halftone (gx_dc_ht_binary):
 *              colors.binary.b_ht = the device halftone;
 *		colors.binary.b_index = -1 if b_ht is the halftone,
 *		  otherwise an index in b_ht.components
 *              colors.binary.color[0] = the color for 0s (darker);
 *              colors.binary.color[1] = the color for 1s (lighter);
 *              colors.binary.b_level = the number of pixels to lighten,
 *                0 < halftone_level < P, the number of pixels in the tile;
 *      @       colors.binary.b_tile points to an entry in the binary
 *                tile cache.
 *      Colored halftone (gx_dc_ht_colored):
 *              colors.colored.c_ht = the device halftone;
 *              colors.colored.c_level[0..N-1] = the halftone levels,
 *                like b_level;
 *              colors.colored.c_base[0..N-1] = the base colors;
 *                N = the device color_info.num_components
 *		    (3 for RGB devices, 4 for CMYK devices, ? for DeviceN);
 *                0 <= c_level[i] < P;
 *                0 <= c_base[i] <= dither_rgb;
 *              colors.colored.alpha = the opacity.
 *		colors.colored.plane_mask: bit 2^i = 1 iff c_level[i] != 0
 *      Colored PatternType 1 pattern (gx_dc_pattern):
 *              (mask is also set, see below)
 *      @       colors.pattern.p_tile points to a gx_color_tile in
 *                the pattern cache, or is NULL for a null pattern.
 *
 * The phase element is used for all colors except pure ones.  It holds the
 * negative of the graphics state halftone phase, modulo the halftone tile
 * size.
 *
 * The ccolor element is used for all kinds of patterns.  It is needed for
 * rendering the pattern.
 *
 * The mask elements of a device color are only used for PatternType 1
 * patterns:
 *      Non-pattern:
 *              mask is unused.
 *      Pattern:
 *              mask.id gives the ID of the pattern (and its mask);
 *              mask.m_phase holds the negative of the graphics state
 *                halftone phase;
 *      @       mask.m_tile points to a gx_color_tile in the pattern cache,
 *                or is NULL for a pattern that doesn't require a mask.
 *                (The 'bits' of the tile are not accessed.)
 *                For colored patterns requiring a mask, p_tile and
 *                mask.m_tile point to the same cache entry.
 * For masked colors, gx_set_dev_color replaces the type with a different
 * type that applies the mask when painting.  These types are not defined
 * here, because they are only used in Level 2.
 */

/* Define the (opaque) type for device color types. */
/* The name is an unfortunate anachronism. */
typedef struct gx_device_color_type_s gx_device_color_type_t;
typedef const gx_device_color_type_t *gx_device_color_type;

struct gx_device_color_s {
    /*
     * Since some compilers don't allow static initialization of a
     * union, we put the type first.
     */
    gx_device_color_type type;
    /*
     * See the comment above for descriptions of the members.  We use
     * b_, c_, and p_ member names because some old compilers don't
     * allow the same name to be used for two different structure
     * members even when it's unambiguous.
     */
    union _c {
	gx_color_index pure;
	struct _bin {
	    const gx_device_halftone *b_ht;
	    gx_color_index color[2];
	    uint b_level;
	    int b_index;
	    gx_ht_tile *b_tile;
	} binary;
	struct _col {
	    gx_device_halftone *c_ht; /* non-const for setting cache ptr */
	    byte c_base[GX_DEVICE_COLOR_MAX_COMPONENTS];
	    uint c_level[GX_DEVICE_COLOR_MAX_COMPONENTS];
	    ushort /*gx_color_value */ alpha;
#if GX_DEVICE_COLOR_MAX_COMPONENTS <= ARCH_SIZEOF_SHORT * 8
	    ushort plane_mask;
#else
#if GX_DEVICE_COLOR_MAX_COMPONENTS <= ARCH_SIZEOF_INT * 8
	    uint plane_mask;
#else
	    gx_color_index plane_mask;
#endif
#endif
	} colored;
	struct _pat {
	    gx_color_tile *p_tile;
	} /*(colored) */ pattern;
    } colors;
    gs_int_point phase;
    gs_client_color ccolor;	/* needed for remapping patterns, */
				/* not set for non-pattern colors */
    struct _mask {
	struct mp_ {
	    short x, y;
	} m_phase;
	gx_bitmap_id id;
	gx_color_tile *m_tile;
    } mask;
};

/*extern_st(st_device_color); *//* in gxdcolor.h */
#define public_st_device_color() /* in gxcmap.c */\
  gs_public_st_composite(st_device_color, gx_device_color, "gx_device_color",\
    device_color_enum_ptrs, device_color_reloc_ptrs)
#define st_device_color_max_ptrs (st_client_color_max_ptrs + 2)

/*
 * 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;
 * we redefine them as macros in gxdcolor.h where the concrete type for
 * gx_device_color_procs is available.
 * We spell out the definition of gx_device_color type because some
 * C compilers can't handle the typedef correctly.
 */
#ifndef gx_dc_type_none
extern const gx_device_color_type_t *const gx_dc_type_none;	/* gxdcolor.c */
#endif
#ifndef gx_dc_type_null
extern const gx_device_color_type_t *const gx_dc_type_null;	/* gxdcolor.c */
#endif
#ifndef gx_dc_type_pure
extern const gx_device_color_type_t *const gx_dc_type_pure;	/* gxdcolor.c */
#endif
		/*
		 * We don't declare gx_dc_pattern here, so as not to create
		 * a spurious external reference in Level 1 systems.
		 */
#ifndef gx_dc_type_pattern
								    /*extern const gx_device_color_type_t * const gx_dc_type_pattern; *//* gspcolor.c */
#endif
#ifndef gx_dc_type_ht_binary
extern const gx_device_color_type_t *const gx_dc_type_ht_binary;	/* gxht.c */
#endif
#ifndef gx_dc_type_ht_colored
extern const gx_device_color_type_t *const gx_dc_type_ht_colored;	/* gxcht.c */
#endif

#endif /* gsdcolor_INCLUDED */
