/* Copyright (C) 1989, 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: gzht.h,v 1.4.4.1.2.1 2003/01/17 00:49:04 giles Exp $ */
/* Internal procedures for halftones */
/* Requires gxdevice.h, gxdcolor.h */

#ifndef gzht_INCLUDED
#  define gzht_INCLUDED

#include "gscsel.h"
#include "gxht.h"
#include "gxfmap.h"
#include "gxdht.h"
#include "gxhttile.h"

/* Sort a sampled halftone order by sample value. */
void gx_sort_ht_order(P2(gx_ht_bit *, uint));

/* (Internal) procedures for constructing halftone orders. */
int gx_ht_alloc_ht_order(P8(gx_ht_order * porder, uint width, uint height,
			    uint num_levels, uint num_bits, uint strip_shift,
			    const gx_ht_order_procs_t *procs,
			    gs_memory_t * mem));
int gx_ht_alloc_order(P6(gx_ht_order * porder, uint width, uint height,
			 uint strip_shift, uint num_levels, gs_memory_t *mem));
int gx_ht_alloc_threshold_order(P5(gx_ht_order * porder, uint width,
				   uint height, uint num_levels,
				   gs_memory_t * mem));
int gx_ht_alloc_client_order(P6(gx_ht_order * porder, uint width, uint height,
			uint num_levels, uint num_bits, gs_memory_t * mem));
void gx_ht_construct_spot_order(P1(gx_ht_order *));
int gx_ht_construct_threshold_order(P2(gx_ht_order *, const byte *));
void gx_ht_construct_bit(P3(gx_ht_bit * bit, int width, int bit_num));
void gx_ht_construct_bits(P1(gx_ht_order *));

/* Halftone enumeration structure */
struct gs_screen_enum_s {
    gs_halftone halftone;	/* supplied by client */
    gx_ht_order order;
    gs_matrix mat;		/* for mapping device x,y to rotated cell */
    gs_matrix mat_inv;		/* the inversion of mat */
    int x, y;
    int strip, shift;
    gs_state *pgs;
};

#define private_st_gs_screen_enum() /* in gshtscr.c */\
  gs_private_st_composite(st_gs_screen_enum, gs_screen_enum,\
    "gs_screen_enum", screen_enum_enum_ptrs, screen_enum_reloc_ptrs)
/*    order.levels, order.bits, pgs) */

/* Prepare a device halftone for installation, but don't install it. */
int gs_sethalftone_prepare(P3(gs_state *, gs_halftone *,
			      gx_device_halftone *));

/* Allocate and initialize a spot screen. */
/* This is the first half of gs_screen_init_accurate/memory. */
int gs_screen_order_alloc(P2(gx_ht_order *, gs_memory_t *));
int gs_screen_order_init_memory(P5(gx_ht_order *, const gs_state *,
				   gs_screen_halftone *, bool, gs_memory_t *));

#define gs_screen_order_init(porder, pgs, phsp, accurate)\
  gs_screen_order_init_memory(porder, pgs, phsp, accurate, pgs->memory)

/* Prepare to sample a spot screen. */
/* This is the second half of gs_screen_init_accurate/memory. */
int gs_screen_enum_init_memory(P5(gs_screen_enum *, const gx_ht_order *,
				  gs_state *, const gs_screen_halftone *,
				  gs_memory_t *));

#define gs_screen_enum_init(penum, porder, pgs, phsp)\
  gs_screen_enum_init_memory(penum, porder, pgs, phsp, pgs->memory)

/* Process an entire screen plane. */
int gx_ht_process_screen_memory(P5(gs_screen_enum * penum, gs_state * pgs,
				   gs_screen_halftone * phsp, bool accurate,
				   gs_memory_t * mem));

#define gx_ht_process_screen(penum, pgs, phsp, accurate)\
  gx_ht_process_screen_memory(penum, pgs, phsp, accurate, pgs->memory)

/*
 * We don't want to remember all the values of the halftone screen,
 * because they would take up space proportional to P^3, where P is
 * the number of pixels in a cell.  Instead, we pick some number N of
 * patterns to cache.  Each cache slot covers a range of (P+1)/N
 * different gray levels: we "slide" the contents of the slot back and
 * forth within this range by incrementally adding and dropping 1-bits.
 * N>=0 (obviously); N<=P+1 (likewise); also, so that we can simplify things
 * by preallocating the bookkeeping information for the cache, we define
 * a constant max_cached_tiles which is an a priori maximum value for N.
 *
 * Note that the raster for each tile must be a multiple of bitmap_align_mod,
 * to satisfy the copy_mono device routine, even though a multiple of
 * sizeof(ht_mask_t) would otherwise be sufficient.
 */

struct gx_ht_cache_s {
    /* The following are set when the cache is created. */
    byte *bits;			/* the base of the bits */
    uint bits_size;		/* the space available for bits */
    gx_ht_tile *ht_tiles;	/* the base of the tiles */
    uint num_tiles;		/* the number of tiles allocated */
    /* The following are reset each time the cache is initialized */
    /* for a new screen. */
    gx_ht_order order;		/* the cached order vector */
    int num_cached;		/* actual # of cached tiles */
    int levels_per_tile;	/* # of levels per cached tile */
    int tiles_fit;		/* -1 if not determined, 0 if no fit, */
				/* 1 if fit */
    gx_bitmap_id base_id;	/* the base id, to which */
				/* we add the halftone level */
    gx_ht_tile *(*render_ht)(P2(gx_ht_cache *, int)); /* rendering procedure */
};

/* 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",\
    ht_tiles_enum_ptrs, ht_tiles_reloc_ptrs)
#define private_st_ht_cache()	/* in gxht.c */\
  gs_private_st_ptrs_add2(st_ht_cache, gx_ht_cache, "ht cache",\
    ht_cache_enum_ptrs, ht_cache_reloc_ptrs,\
    st_ht_order, order, bits, ht_tiles)

/* Compute a fractional color for dithering, the correctly rounded */
/* quotient f * max_gx_color_value / maxv. */
#define frac_color_(f, maxv)\
  (gx_color_value)(((f) * (0xffffL * 2) + maxv) / (maxv * 2))
extern const gx_color_value *const fc_color_quo[8];

#define fractional_color(f, maxv)\
  ((maxv) <= 7 ? fc_color_quo[maxv][f] : frac_color_(f, maxv))

/* ------ Halftone cache procedures ------ */

/* Allocate/free a halftone cache. */
uint gx_ht_cache_default_tiles(P0());
uint gx_ht_cache_default_bits(P0());
gx_ht_cache *gx_ht_alloc_cache(P3(gs_memory_t *, uint, uint));
void gx_ht_free_cache(P2(gs_memory_t *, gx_ht_cache *));

/* Clear a halftone cache. */
#define gx_ht_clear_cache(pcache)\
  ((pcache)->order.levels = 0, (pcache)->order.bit_data = 0,\
   (pcache)->ht_tiles[0].tiles.data = 0)

/* Initialize a halftone cache with a given order. */
void gx_ht_init_cache(P2(gx_ht_cache *, const gx_ht_order *));

/* Make the cache order current, and return whether */
/* there is room for all possible tiles in the cache. */
bool gx_check_tile_cache(P1(const gs_imager_state *));

/* Determine whether a given (width, y, height) might fit into a */
/* single tile. If so, return the byte offset of the appropriate row */
/* from the beginning of the tile, and set *ppx to the x phase offset */
/* within the tile; if not, return -1. */
int gx_check_tile_size(P6(const gs_imager_state * pis, int w, int y, int h,
			  gs_color_select_t select, int *ppx));

/* Make a given level current in a halftone cache. */
#define gx_render_ht(pcache, b_level)\
  ((pcache)->render_ht(pcache, b_level))

/* ------ Device halftone management ------ */

/* Release a gx_ht_order by freeing its components. */
/* (Don't free the gx_device_halftone itself.) */
void gx_ht_order_release(P3(gx_ht_order * porder, gs_memory_t * mem, bool free_cache));

/*
 * 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.
 */
int gx_imager_dev_ht_install(P4(gs_imager_state * pis,
				const gx_device_halftone * pdht,
				gs_halftone_type type,
				const gx_device * dev));

/*
 * Install a new halftone in the graphics state.  Note that we copy the top
 * level of the gs_halftone and the gx_device_halftone, and take ownership
 * of any substructures.
 */
int gx_ht_install(P3(gs_state *, const gs_halftone *,
		     const gx_device_halftone *));

/* Reestablish the effective transfer functions, taking into account */
/* any overrides from halftone dictionaries. */
/* Some compilers object to names longer than 31 characters.... */
void gx_imager_set_effective_xfer(P1(gs_imager_state * pis));
void gx_set_effective_transfer(P1(gs_state * pgs));


#endif /* gzht_INCLUDED */
