/* Copyright (C) 1989, 1995, 1997, 1998, 1999 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: gxdevmem.h,v 1.2.6.1.2.1 2003/01/17 00:49:03 giles Exp $ */
/* Structure and procedures for memory devices */
/* Requires gxdevice.h */

#ifndef gxdevmem_INCLUDED
#  define gxdevmem_INCLUDED

#include "gxrplane.h"

/*
 * A 'memory' device is essentially a stored bitmap.
 * There are several different kinds: 1-bit black and white,
 * 2-, 4-, and 8-bit mapped color, 16- and 24-bit RGB color,
 * and 32-bit CMYK color.  (16-bit uses 5/6/5 bits per color.)
 * All use the same structure, since it's so awkward to get the effect of
 * subclasses in C.
 *
 * Memory devices come in two flavors: standard, which always stores bytes
 * big-endian, and word-oriented, which stores bytes in the machine order
 * within 32-bit "words".  The source data for copy_mono and
 * copy_color must be in big-endian order, and since memory devices
 * also are guaranteed to allocate the bitmap consecutively,
 * the bitmap of a standard memory device can serve directly as input
 * to copy_mono or copy_color operations.  This is not true of word-oriented
 * memory devices, which are provided only in response to a request by
 * a customer with their own image processing library that uses this format.
 *
 * In addition to the device structure itself, memory devices require two
 * other pieces of storage: the bitmap, and a table of pointers to the scan
 * lines of the bitmap.  Clients have several options for allocating these:
 *
 *	1) Set bitmap_memory to an allocator before opening the device.
 *	With this option, opening the device allocates the bitmap and the
 *	line pointer table (contiguously), and closing the device frees
 *	them.
 *
 *	2) Set line_pointer_memory to an allocator, base to the base address
 *	of the bitmap, and raster to the length of each scan line (distance
 *	from one scan line to the next) before opening the device.  With
 *	this option, opening the device allocates the line table, but not
 *	the bitmap; closing the device frees the table.
 *
 *	3) Set line_pointer_memory but not base or raster.  Opening /
 *	closing the device will allocate / free the line pointer table, but
 *	the client must set the pointers with a subsequent call of
 *	gdev_mem_set_line_ptrs.
 *
 *	4) Set neither _memory field.  In this case, it's up to the client
 *	to call gdev_mem_set_line_ptrs and to manage storage for the
 *	line pointers and the bitmap.
 *
 * In cases (2) through (4), it is the client's responsibility to set
 * foreign_bits (and foreign_line_pointers, if the line pointers are not
 * contiguous with the bits) to tell the GC whether to trace the pointers.
 * By default, anything allocated by bitmap_memory or line_pointer_memory is
 * assumed GC'able (i.e., case (1) assumes that the bits + line pointers are
 * GC'able, and cases (2) and (3) assume that the line pointers are GC'able,
 * but not the bits), but the client can change the foreign_* flag(s) after
 * opening the device if this is not the case.
 */
#ifndef gx_device_memory_DEFINED
#  define gx_device_memory_DEFINED
typedef struct gx_device_memory_s gx_device_memory;
#endif

struct gx_device_memory_s {
    gx_device_forward_common;	/* (see gxdevice.h) */
    /*
     * The following may be set by the client before or just after
     * opening the device.  See above.
     */
    uint raster;		/* bytes per scan line */
    byte *base;
#define scan_line_base(dev,y) ((dev)->line_ptrs[y])
    gs_memory_t *bitmap_memory;	/* allocator for bits + line pointers */
    bool foreign_bits;		/* if true, bits are not in GC-able space */
    gs_memory_t *line_pointer_memory;  /* allocate for line pointers */
    bool foreign_line_pointers;  /* if true, line_ptrs are not in GC-able space */
    /*
     * The following are only used for planar devices.  num_planes == 0
     * means this is a chunky device.  Note that for planar devices, we
     * require color_info.depth = the sum of the individual plane depths.
     */
    int num_planes;
    gx_render_plane_t planes[GX_DEVICE_COLOR_MAX_COMPONENTS];
    /*
     * End of client-initializable fields.
     */
    gs_matrix initial_matrix;	/* the initial transformation */
    byte **line_ptrs;		/* scan line pointers */
    /* Following is used for mapped color, */
    /* including 1-bit devices (to specify polarity). */
    gs_const_string palette;	/* RGB triples */
    /* Following is only used for 24-bit color. */
    struct _c24 {
	gx_color_index rgb;	/* cache key */
	bits32 rgbr, gbrg, brgb;	/* cache value */
    } color24;
    /* Following are only used for alpha buffers. */
    /* The client initializes those marked with $; */
    /* they don't change after initialization. */
    gs_log2_scale_point log2_scale;	/* $ oversampling scale factors */
    int log2_alpha_bits;	/* $ log2 of # of alpha bits being produced */
    int mapped_x;		/* $ X value mapped to buffer X=0 */
    int mapped_y;		/* lowest Y value mapped to buffer */
    int mapped_height;		/* # of Y values mapped to buffer */
    int mapped_start;		/* local Y value corresponding to mapped_y */
    gx_color_index save_color;	/* last (only) color displayed */
    /* Following are used only for planar devices. */
    int plane_depth;		/* if non-zero, depth of all planes */
};

extern_st(st_device_memory);
#define public_st_device_memory() /* in gdevmem.c */\
  gs_public_st_composite_use_final(st_device_memory, gx_device_memory,\
    "gx_device_memory", device_memory_enum_ptrs, device_memory_reloc_ptrs,\
    gx_device_finalize)
#define st_device_memory_max_ptrs (st_device_forward_max_ptrs + 2)
#define mem_device_init_private\
	0,			/* raster */\
	(byte *)0,		/* base */\
	0,			/* bitmap_memory */\
	true,			/* foreign_bits (default) */\
	0,			/* line_pointer_memory */\
	true,			/* foreign_line_pointers (default) */\
	0,			/* num_planes (default) */\
	{ { 0 } },		/* planes (only used for planar) */\
	{ identity_matrix_body },	/* initial matrix (filled in) */\
	(byte **)0,		/* line_ptrs (filled in by mem_open) */\
	{ (byte *)0, 0 },	/* palette (filled in for color) */\
	{ gx_no_color_index },	/* color24 */\
	{ 0, 0 }, 0,		/* scale, log2_alpha_bits */\
	0, 0, 0, 0,		/* mapped_* */\
	gx_no_color_index	/* save_color */

/*
 * Memory devices may have special setup requirements.  In particular, it
 * may not be obvious how much space to allocate for the bitmap.  Here is
 * the routine that computes this from the width and height.  Note that this
 * size includes both the bitmap and the line pointers.
 */
/* bits only */
ulong gdev_mem_bits_size(P3(const gx_device_memory *mdev, int width,
			    int height));
/* line pointers only */
ulong gdev_mem_line_ptrs_size(P3(const gx_device_memory *mdev, int width,
				 int height));
/* bits + line pointers */
ulong gdev_mem_data_size(P3(const gx_device_memory *mdev, int width,
			    int height));

#define gdev_mem_bitmap_size(mdev)\
  gdev_mem_data_size(mdev, (mdev)->width, (mdev)->height)

/*
 * Do the inverse computation: given the device width and a buffer size,
 * compute the maximum height.
 */
int gdev_mem_max_height(P3(const gx_device_memory *, int, ulong));

/*
 * Compute the standard raster (data bytes per line) similarly.
 */
#define gdev_mem_raster(mdev)\
  gx_device_raster((const gx_device *)(mdev), true)

/* Determine the appropriate memory device for a given */
/* number of bits per pixel (0 if none suitable). */
const gx_device_memory *gdev_mem_device_for_bits(P1(int));

/* Determine the word-oriented memory device for a given depth. */
const gx_device_memory *gdev_mem_word_device_for_bits(P1(int));

/* Make a memory device. */
/* mem is 0 if the device is temporary and local, */
/* or the allocator that was used to allocate it if it is a real object. */
/* page_device is 1 if the device should be a page device, */
/* 0 if it should propagate this property from its target, or */
/* -1 if it should not be a page device. */
void gs_make_mem_mono_device(P3(gx_device_memory * mdev, gs_memory_t * mem,
				gx_device * target));
void gs_make_mem_device(P5(gx_device_memory * mdev,
			   const gx_device_memory * mdproto,
			   gs_memory_t * mem, int page_device,
			   gx_device * target));
void gs_make_mem_abuf_device(P6(gx_device_memory * adev, gs_memory_t * mem,
				gx_device * target,
				const gs_log2_scale_point * pscale,
				int alpha_bits, int mapped_x));
void gs_make_mem_alpha_device(P4(gx_device_memory * adev, gs_memory_t * mem,
				 gx_device * target, int alpha_bits));

/*
 * Open a memory device, only setting line pointers to a subset of its
 * scan lines.  Banding devices use this (see gxclread.c).
 */
int gdev_mem_open_scan_lines(P2(gx_device_memory *mdev, int setup_height));

/*
 * Initialize the line pointers of a memory device.  base and/or line_ptrs
 * may be NULL, in which case the value already stored in the device is
 * used; if base is NULL, raster is also ignored and the existing value is
 * used.  Note that this takes raster and setup_height arguments.
 * If the base is not NULL and the device is planar, all planes must have
 * the same depth, since otherwise a single raster value is not sufficient.
 *
 * Note that setup_height may be less than height.  In this case, for
 * planar devices, only setup_height * num_planes line pointers are set,
 * in the expectation that the device's height will be reset to
 * setup_height.
 */
int gdev_mem_set_line_ptrs(P5(gx_device_memory *mdev,
			      byte *base, int raster, byte **line_ptrs,
			      int setup_height));

/* Define whether a monobit memory device is inverted (black=1). */
void gdev_mem_mono_set_inverted(P2(gx_device_memory * mdev, bool black_is_1));

/* Test whether a device is a memory device. */
bool gs_device_is_memory(P1(const gx_device *));

/* Test whether a device is an alpha-buffering device. */
bool gs_device_is_abuf(P1(const gx_device *));

#endif /* gxdevmem_INCLUDED */
