/* Copyright (C) 1991, 1995, 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: gxcpath.h,v 1.2.6.1.2.1 2003/01/17 00:49:03 giles Exp $ */
/* Definitions for clipping lists and devices */
/* Requires gxdevice.h */

#ifndef gxcpath_INCLUDED
#  define gxcpath_INCLUDED

/* We expose the implementation of clipping lists so that clients */
/* can allocate clipping lists or devices on the stack. */

/*
 * For clipping, a path is represented as a list of rectangles.
 * Normally, a path is created as a list of segments;
 * installing it as a clipping path creates the rectangle list.
 * However, when the clipping path originates in some other way
 * (e.g., from initclip, or for clipping a cached character),
 * or if it is a non-trivial intersection of two paths,
 * the resulting clipping path exists only as a rectangle list;
 * clippath constructs the segment representation if needed.
 * Note that even if the path only exists as a rectangle list,
 * its bounding box (path.bbox) is still correct.
 */

/*
 * Rectangle list structure.
 * Consecutive gx_clip_rect entries either have the same Y values,
 * or ymin of this entry >= ymax of the previous entry.
 */
typedef struct gx_clip_rect_s gx_clip_rect;
struct gx_clip_rect_s {
    gx_clip_rect *next, *prev;
    int ymin, ymax;		/* ymax > ymin */
    int xmin, xmax;		/* xmax > xmin */
    byte to_visit;		/* bookkeeping for gs_clippath */
};

/* The descriptor is public only for gxacpath.c. */
extern_st(st_clip_rect);
#define public_st_clip_rect()	/* in gxcpath.c */\
  gs_public_st_ptrs2(st_clip_rect, gx_clip_rect, "clip_rect",\
    clip_rect_enum_ptrs, clip_rect_reloc_ptrs, next, prev)
#define st_clip_rect_max_ptrs 2

/*
 * A clip list may consist either of a single rectangle,
 * with null head and tail, or a list of rectangles.  In the latter case,
 * there is a dummy head entry with p.x = q.x to cover Y values
 * starting at min_int, and a dummy tail entry to cover Y values
 * ending at max_int.  This eliminates the need for end tests.
 */
#ifndef gx_clip_list_DEFINED
#  define gx_clip_list_DEFINED
typedef struct gx_clip_list_s gx_clip_list;
#endif
struct gx_clip_list_s {
    gx_clip_rect single;	/* (has next = prev = 0) */
    gx_clip_rect *head;
    gx_clip_rect *tail;
    int xmin, xmax;		/* min and max X over all but head/tail */
    int count;			/* # of rectangles not counting */
				/* head or tail */
};

#define private_st_clip_list()	/* in gxcpath.c */\
  gs_private_st_ptrs2(st_clip_list, gx_clip_list, "clip_list",\
    clip_list_enum_ptrs, clip_list_reloc_ptrs, head, tail)
#define st_clip_list_max_ptrs 2	/* head, tail */
#define clip_list_is_rectangle(clp) ((clp)->count <= 1)

/*
 * Clipping devices provide for translation before clipping.
 * This ability, a late addition, currently is used only in a few
 * situations that require breaking up a transfer into pieces,
 * but we suspect it could be used more widely.
 *
 * Note that clipping devices cache their clipping box, so the target's
 * clipping box and the clip list must be const after the clipping device
 * is opened.
 */
#ifndef gx_device_clip_DEFINED
#  define gx_device_clip_DEFINED
typedef struct gx_device_clip_s gx_device_clip;
#endif
struct gx_device_clip_s {
    gx_device_forward_common;	/* target is set by client */
    gx_clip_list list;		/* set by client */
    gx_clip_rect *current;	/* cursor in list */
    gs_int_point translation;
    gs_fixed_rect clipping_box;
    bool clipping_box_set;
};

extern_st(st_device_clip);
#define public_st_device_clip()	/* in gxcpath.c */\
  gs_public_st_composite_use_final(st_device_clip, gx_device_clip,\
    "gx_device_clip", device_clip_enum_ptrs, device_clip_reloc_ptrs,\
    gx_device_finalize)
void gx_make_clip_translate_device(P5(gx_device_clip * dev,
				      const gx_clip_list * list,
				      int tx, int ty, gs_memory_t *mem));

#define gx_make_clip_device(dev, list)\
  gx_make_clip_translate_device(dev, list, 0, 0, NULL)
void gx_make_clip_path_device(P2(gx_device_clip *, const gx_clip_path *));

#define clip_rect_print(ch, str, ar)\
  if_debug7(ch, "[%c]%s 0x%lx: (%d,%d),(%d,%d)\n", ch, str, (ulong)ar,\
	    (ar)->xmin, (ar)->ymin, (ar)->xmax, (ar)->ymax)

/* Exported by gxcpath.c for gxacpath.c */

/* Initialize a clip list. */
void gx_clip_list_init(P1(gx_clip_list *));

/* Free a clip list. */
void gx_clip_list_free(P2(gx_clip_list *, gs_memory_t *));

/* Set the outer box for a clipping path from its bounding box. */
void gx_cpath_set_outer_box(P1(gx_clip_path *));

/* Exported by gxcpath.c for gxclip.c */

/* Return the rectangle list of a clipping path (for local use only). */
const gx_clip_list *gx_cpath_list(P1(const gx_clip_path *pcpath));

#endif /* gxcpath_INCLUDED */
