/* Copyright (C) 1991, 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: gscspace.h,v 1.8.2.1.2.1 2003/01/17 00:49:02 giles Exp $ */
/* Client interface to color spaces */

#ifndef gscspace_INCLUDED
#  define gscspace_INCLUDED

#include "gsmemory.h"

/*
 * The handling of color spaces in the graphic library is somewhat
 * awkward because of historical artifacts.
 *
 * The PostScript Level 1 (DeviceGray/RGB) color spaces, and the "Level
 * 1 1/2" DeviceCMYK space, have no associated parameters.  Therefore,
 * they can be represented as simple objects (just a pointer to a type
 * vector containing procedures and parameters).  This was the original
 * design.
 *
 * PostScript Level 2 and LanguageLevel 3 add two new kinds of color spaces:
 * color spaces with parameters (CIEBased and DevicePixel spaces),  and
 * compound color spaces (Indexed, Separation, Pattern, and DeviceN spaces),
 * with parameters that include a specification of an alternative or
 * underlying color space.  To handle these spaces, we extended the original
 * design to store in-line certain scalar parameters (i.e., parameters other
 * than the complex color transformation data for CIEBased spaces, the lookup
 * table for Indexed spaces, and the list of component names for DeviceN
 * spaces) in the color space object.  For compound spaces, this requires
 * storing a color space in-line inside another color space, which is clearly
 * impossible.  Therefore, we defined a generality hierarchy for color spaces:
 *
 *      - Base spaces (DeviceGray/RGB/CMYK/Pixel, CIEBased), whose
 *      whose parameters (if any) don't include other color spaces.
 *
 *	- Direct spaces (base spaces + Separation and DeviceN), which
 *      may have a base space as an alternative space.
 *
 *      - Paint spaces (direct spaces + Indexed), which may have a direct
 *      space as the underlying space
 *
 *      - General spaces (paint spaces + Pattern), which may have a
 *      paint space as the underlying space.
 *
 * With this approach, a general space can include a paint space stored
 * in-line; a paint space (either in its own right or as the underlying
 * space of a Pattern space) can include a direct space in-line; and a
 * direct space can include a base space in-line.
 *
 * The introduction of ICCBased color spaces in PDF 1.3 wrecked havoc on
 * this hierarchy. ICCBased color spaces contain alternative color spaces,
 * which may be paint spaces. On the other hand, ICCBased spaces may be
 * use as alternative or underlying color spaces in direct and paint
 * spaces.
 *
 * The proper solution to this problem would be to reference alternative and
 * underlying color spaces via a pointer. The cost and risk of that approach
 * is, however, larger than is warranted just by the addition of ICCBased
 * color spaces. Another alternative is to allow just base color spaces to 
 * include an alternative color space via a pointer. That would require two
 * separate mechanisms for dealing with alternative color spaces, which
 * seems messy and may well cause problems in the future.
 *
 * Examination of some PDF files indicates that ICCBased color spaces are
 * routinely used as alternative spaces for Separation or Device color
 * spaces, but essentially never make use of alternative color spaces other
 * than the device-specific spaces. To support this usage, the approach
 * taken here splits previous base color space class into "small"  and
 * "regular" base color spaces. Small base color spaces include all of
 * those color spaces that previously were considered base spaces. Regular
 * base spaces add the ICCBased color spaces to this set. To maintain
 * compatibility with the existing code base, regular base spaces make use
 * of the gs_base_color_space type name.
 *
 * Note that because general, paint, direct, regular base, and small base
 * spaces are (necessarily) of different sizes, assigning (copying the top
 * object of) color spaces must take into account the actual size of the
 * color space being assigned.  In principle, this also requires checking
 * that the source object will actually fit into the destination.  Currently
 * we rely on the caller to ensure that this is the case; in fact, the
 * current API (gs_cspace_init and gs_cspace_assign) doesn't even provide
 * enough information to make the check.
 *
 * In retrospect, we might have gotten a simpler design without significant
 * performance loss by always referencing underlying and alternate spaces
 * through a pointer; however, at this point, the cost and risk of changing
 * to such a design are too high.
 *
 * There are two aspects to memory management for color spaces: managing
 * the color space objects themselves, and managing the non-scalar
 * parameters that they reference (if any).
 *
 *      - Color space objects per se have no special management properties:
 *      they can be allocated on the stack or on the heap, and freed by
 *      scope exit, explicit deallocation, or garbage collection.
 *
 *      - Separately allocated (non-scalar) color space parameters are
 *      managed by reference counting.  Currently we do this for the
 *      CIEBased spaces, and for the first-level parameters of Indexed and
 *      Separation spaces: clients must deal with deallocating the other
 *      parameter structures mentioned above, including the Indexed lookup
 *      table if any. This is clearly not a good situation, but we don't
 *      envision fixing it any time soon.
 *
 * Here is the information associated with the various color space
 * structures.  Note that DevicePixel, DeviceN, and the ability to use
 * Separation or DeviceN spaces as the base space of an Indexed space
 * are LanguageLevel 3 additions.  Unfortunately, the terminology for the
 * different levels of generality is confusing and inconsistent for
 * historical reasons.
 *
 * For base spaces:
 *
 * Space        Space parameters                Color parameters
 * -----        ----------------                ----------------
 * DeviceGray   (none)                          1 real [0-1]
 * DeviceRGB    (none)                          3 reals [0-1]
 * DeviceCMYK   (none)                          4 reals [0-1]
 * DevicePixel  depth                           1 int [up to depth bits]
 * CIEBasedDEFG dictionary                      4 reals
 * CIEBasedDEF  dictionary                      3 reals
 * CIEBasedABC  dictionary                      3 reals
 * CIEBasedA    dictionary                      1 real
 *
 * For non-base direct spaces:
 *
 * Space        Space parameters                Color parameters
 * -----        ----------------                ----------------
 *
 * Separation   name, alt_space, tint_xform     1 real [0-1]
 * DeviceN      names, alt_space, tint_xform    N reals
 *
 * For non-direct paint spaces:
 *
 * Space        Space parameters                Color parameters
 * -----        ----------------                ----------------
 * Indexed      base_space, hival, lookup       1 int [0-hival]
 * ICCBased     dictionary, alt_space           1, 3, or 4 reals
 *
 * For non-paint spaces:
 *
 * Space        Space parameters                Color parameters
 * -----        ----------------                ----------------
 * Pattern      colored: (none)                 dictionary
 *              uncolored: base_space dictionary + base space params
 */

/*
 * Define color space type indices.  NOTE: PostScript code (gs_res.ps,
 * gs_ll3.ps) and the color space substitution code (gscssub.[hc] and its
 * clients) assumes values 0-2 for DeviceGray/RGB/CMYK respectively.
 */
typedef enum {

    /* Supported in all configurations */
    gs_color_space_index_DeviceGray = 0,
    gs_color_space_index_DeviceRGB,

    /* Supported in extended Level 1, and in Level 2 and above */
    gs_color_space_index_DeviceCMYK,

    /* Supported in LanguageLevel 3 only */
    gs_color_space_index_DevicePixel,
    gs_color_space_index_DeviceN,

    /* Supported in Level 2 and above only */
    /* DEC C truncates identifiers at 32 characters, so.... */
    gs_color_space_index_CIEDEFG,
    gs_color_space_index_CIEDEF,
    gs_color_space_index_CIEABC,
    gs_color_space_index_CIEA,
    gs_color_space_index_Separation,
    gs_color_space_index_Indexed,
    gs_color_space_index_Pattern,

    /* Supported in PDF 1.3 and later only */
    gs_color_space_index_CIEICC

} gs_color_space_index;

/* We define the names only for debugging printout. */
#define GS_COLOR_SPACE_TYPE_NAMES\
  "DeviceGray", "DeviceRGB", "DeviceCMYK", "DevicePixel", "DeviceN",\
  "ICCBased", "CIEBasedDEFG", "CIEBasedDEF", "CIEBasedABC", "CIEBasedA",\
  "Separation", "Indexed", "Pattern"

/* Define an abstract type for color space types (method structures). */
typedef struct gs_color_space_type_s gs_color_space_type;

/*
 * The common part of all color spaces. This structure now includes a memory
 * structure pointer, so that it may be released without providing this
 * information separately. (type is a pointer to the structure of methods.)
 *
 * Note that all color space structures consist of the basic information and
 * a union containing some additional information. The macro operand is that
 * union.
 */
#define gs_cspace_common(param_union)   \
    const gs_color_space_type * type;   \
    gs_memory_t *               pmem;   \
    gs_id                       id;     \
    union {                             \
	param_union;                    \
    }                           params

/*
 * Parameters for "small" base color spaces. Of the small base color spaces,
 * only DevicePixel and CIE spaces have parameters: see gscie.h for the
 * structure definitions for CIE space parameters.
 */
typedef struct gs_device_pixel_params_s {
    int depth;
} gs_device_pixel_params;
typedef struct gs_cie_a_s gs_cie_a;
typedef struct gs_cie_abc_s gs_cie_abc;
typedef struct gs_cie_def_s gs_cie_def;
typedef struct gs_cie_defg_s gs_cie_defg;

#define gs_small_base_cspace_params     \
    gs_device_pixel_params   pixel;     \
    gs_cie_defg *            defg;      \
    gs_cie_def *             def;       \
    gs_cie_abc *             abc;       \
    gs_cie_a *               a

typedef struct gs_small_base_color_space_s {
    gs_cspace_common(gs_small_base_cspace_params);
} gs_small_base_color_space;

#define gs_small_base_color_space_size sizeof(gs_small_base_color_space)

/*
 * "Regular" base color spaces include all of the small base color space and
 * the ICCBased color space, which includes a small base color space as an
 * alternative color space. See gsicc.h for the structure definition of
 * gs_cie_icc_s.
 */
typedef struct gs_cie_icc_s gs_cie_icc;

typedef struct gs_cieicc_params_s {
    gs_cie_icc *                picc_info;
    gs_small_base_color_space   alt_space;
} gs_icc_params;

#define gs_base_cspace_params   \
    gs_small_base_cspace_params;\
    gs_icc_params   icc

typedef struct gs_base_color_space_s {
    gs_cspace_common(gs_base_cspace_params);
} gs_base_color_space;

#define gs_base_color_space_size sizeof(gs_base_color_space)


/*
 * 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_base_color_space alt_space;
    gs_indexed_map *map;
    separation_type sep_type;
} 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
 * component names.  This is used for comparison of component
 * names with similar objects like ProcessColorModel colorant
 * names.
 */
typedef int (gs_callback_func_get_colorname_string)
    (P3(gs_separation_name colorname, unsigned char **ppstr, unsigned int *plen));

typedef struct gs_device_n_params_s {
    gs_separation_name *names;
    uint num_components;
    gs_base_color_space alt_space;
    gs_device_n_map *map;
    gs_callback_func_get_colorname_string *get_colorname_string;
} gs_device_n_params;

#define gs_direct_cspace_params         \
    gs_base_cspace_params;              \
    gs_separation_params separation;    \
    gs_device_n_params device_n

typedef struct gs_direct_color_space_s {
    gs_cspace_common(gs_direct_cspace_params);
} gs_direct_color_space;

#define gs_direct_color_space_size sizeof(gs_direct_color_space)

/*
 * Non-direct paint space: Indexed space.
 *
 * Note that for indexed color spaces, hival is the highest support index,
 * which is one less than the number of entries in the palette (as defined
 * in PostScript).
 */

typedef struct gs_indexed_params_s {
    gs_direct_color_space base_space;
    int hival;			/* num_entries - 1 */
    union {
	gs_const_string table;	/* size is implicit */
	gs_indexed_map *map;
    } lookup;
    bool use_proc;		/* 0 = use table, 1 = use proc & map */
} gs_indexed_params;

#define gs_paint_cspace_params          \
    gs_direct_cspace_params;            \
    gs_indexed_params indexed

typedef struct gs_paint_color_space_s {
    gs_cspace_common(gs_paint_cspace_params);
} gs_paint_color_space;

#define gs_paint_color_space_size sizeof(gs_paint_color_space)

/*
 * Pattern parameter set. This may contain an instances of a paintable
 * color space. The boolean indicates if this is the case.
 */
typedef struct gs_pattern_params_s {
    bool has_base_space;
    gs_paint_color_space base_space;
} gs_pattern_params;

/*
 * Fully general color spaces.
 */
struct gs_color_space_s {
    gs_cspace_common(
	gs_paint_cspace_params;
	gs_pattern_params pattern
    );
};

#define gs_pattern_color_space_size sizeof(gs_color_space)

/*
 * Define the abstract type for color space objects.
 */
#ifndef gs_color_space_DEFINED
#  define gs_color_space_DEFINED
typedef struct gs_color_space_s gs_color_space;
#endif

					/*extern_st(st_color_space); *//* in gxcspace.h */
#define public_st_color_space()	/* in gscspace.c */  \
    gs_public_st_composite( st_color_space,         \
                            gs_color_space,         \
                            "gs_color_space",       \
                            color_space_enum_ptrs,  \
                            color_space_reloc_ptrs  \
                            )

#define st_color_space_max_ptrs 2	/* 1 base + 1 indexed */

/* ---------------- Procedures ---------------- */

/* ------ Create/copy/destroy ------ */

/*
 * Note that many of the constructors take no parameters, and the
 * remainder take only a few (CIE color spaces constructures take a
 * client data pointer as an operand, the composite color space (Separation,
 * Indexed, and Pattern) constructurs take the base space as an operand,
 * and the Indexed color space constructors have a few additiona operands).
 * This is done to conserve memory. If initialization values for all the
 * color space parameters were provided to the constructors, these values
 * would need to have some fairly generic format. Different clients gather
 * this data in different forms, so they would need to allocate memory to
 * convert it to the generic form, only to immediately release this memory
 * once the construction is complete.
 *
 * The alternative approach employed here is to provide a number of access
 * methods (macros) that return pointers to individual fields of the
 * various color space structures. This requires exporting only fairly simple
 * data structures, and so does not violate modularity too severely.
 *
 * NB: Of necessity, the macros provide access to modifiable structures. If
 *     these structures are modified after the color space object is first
 *     initialized, unpredictable and, most likely, undesirable results will
 *     occur.
 *
 * The constructors return an integer, 0 on success and an
 * error code on failure (gs_error_VMerror or gs_error_rangecheck).
 *
 * In parallel with the constructors, we provide initializers that assume
 * the client has allocated the color space object (perhaps on the stack)
 * and takes responsibility for freeing it.
 */

extern int
    gs_cspace_init_DeviceGray(P1(gs_color_space *pcs)),
    gs_cspace_build_DeviceGray(P2(gs_color_space ** ppcspace,
				  gs_memory_t * pmem)),
    gs_cspace_init_DeviceRGB(P1(gs_color_space *pcs)),
    gs_cspace_build_DeviceRGB(P2(gs_color_space ** ppcspace,
				 gs_memory_t * pmem)),
    gs_cspace_init_DeviceCMYK(P1(gs_color_space *pcs)),
    gs_cspace_build_DeviceCMYK(P2(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(P1(const gs_imager_state * pis));
const gs_color_space * gs_cspace_DeviceRGB(P1(const gs_imager_state * pis));
const gs_color_space * gs_cspace_DeviceCMYK(P1(const gs_imager_state * pis));

/* Copy a color space into one newly allocated by the caller. */
void gs_cspace_init_from(P2(gs_color_space * pcsto,
			    const gs_color_space * pcsfrom));

/* Assign a color space into a previously initialized one. */
void gs_cspace_assign(P2(gs_color_space * pdest, const gs_color_space * psrc));

/* Prepare to free a color space. */
void gs_cspace_release(P1(gs_color_space * pcs));

/* ------ Accessors ------ */

/* Get the index of a color space. */
gs_color_space_index gs_color_space_get_index(P1(const gs_color_space *));

/* Get the number of components in a color space. */
int gs_color_space_num_components(P1(const gs_color_space *));

/*
 * Test whether two color spaces are equal.  Note that this test is
 * conservative: if it returns true, the color spaces are definitely
 * equal, while if it returns false, they might still be equivalent.
 */
bool gs_color_space_equal(P2(const gs_color_space *pcs1,
			     const gs_color_space *pcs2));

/* Restrict a color to its legal range. */
#ifndef gs_client_color_DEFINED
#  define gs_client_color_DEFINED
typedef struct gs_client_color_s gs_client_color;
#endif
void gs_color_space_restrict_color(P2(gs_client_color *,
				      const gs_color_space *));

/*
 * Get the base space of an Indexed or uncolored Pattern color space, or the
 * alternate space of a Separation or DeviceN space.  Return NULL if the
 * color space does not have a base/alternative color space.
 */
const gs_color_space *gs_cspace_base_space(P1(const gs_color_space * pcspace));

/* backwards compatibility */
#define gs_color_space_indexed_base_space(pcspace)\
    gs_cspace_base_space(pcspace)

#endif /* gscspace_INCLUDED */
