xref: /plan9/sys/src/cmd/gs/src/gxpath.h (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gxpath.h,v 1.16 2005/08/22 14:29:18 igor Exp $ */
18 /* Fixed-point path procedures */
19 /* Requires gxfixed.h */
20 
21 #ifndef gxpath_INCLUDED
22 #  define gxpath_INCLUDED
23 
24 #include "gscpm.h"
25 #include "gslparam.h"
26 #include "gspenum.h"
27 #include "gsrect.h"
28 
29 /* The routines and types in this interface use */
30 /* device, rather than user, coordinates, and fixed-point, */
31 /* rather than floating, representation. */
32 
33 /* Opaque type for a path */
34 #ifndef gx_path_DEFINED
35 #  define gx_path_DEFINED
36 typedef struct gx_path_s gx_path;
37 #endif
38 
39 /* Define the two insideness rules */
40 #define gx_rule_winding_number (-1)
41 #define gx_rule_even_odd 1
42 
43 /* Define 'notes' that describe the role of a path segment. */
44 /* These are only for internal use; a normal segment's notes are 0. */
45 typedef enum {
46     sn_none = 0,
47     sn_not_first = 1,		/* segment is in curve/arc and not first */
48     sn_from_arc = 2		/* segment is part of an arc */
49 } segment_notes;
50 
51 /* Debugging routines */
52 #ifdef DEBUG
53 void gx_dump_path(const gx_path *, const char *);
54 void gx_path_print(const gx_path *);
55 #endif
56 
57 /* Path memory management */
58 
59 /*
60  * Path memory management is unfortunately a little tricky.  The
61  * implementation details are in gzpath.h: we only present the API here.
62  *
63  * Path objects per se may be allocated in 3 different ways: on the
64  * C stack, as separate objects in the heap, or (for the graphics state
65  * only) contained in a larger heap-allocated object.
66  *
67  * Any number of paths may share segments.  The segments are stored in
68  * their own, reference-counted object, and are freed when there are no
69  * more references to that object.
70  */
71 
72 /*
73  * Allocate a path on the heap, and initialize it.  If shared is NULL,
74  * allocate a segments object; if shared is an existing path, share its
75  * segments.
76  */
77 gx_path *gx_path_alloc_shared(const gx_path * shared, gs_memory_t * mem,
78 			      client_name_t cname);
79 
80 #define gx_path_alloc(mem, cname)\
81   gx_path_alloc_shared(NULL, mem, cname)
82 /*
83  * Initialize a path contained in an already-heap-allocated object,
84  * optionally allocating its segments.
85  */
86 int gx_path_init_contained_shared(gx_path * ppath, const gx_path * shared,
87 				  gs_memory_t * mem, client_name_t cname);
88 
89 #define gx_path_alloc_contained(ppath, mem, cname)\
90   gx_path_init_contained_shared(ppath, NULL, mem, cname)
91 /*
92  * Initialize a stack-allocated path.  This doesn't allocate anything,
93  * but may still share the segments.  Note that it returns an error if
94  * asked to share the segments of another local path.
95  */
96 int gx_path_init_local_shared(gx_path * ppath, const gx_path * shared,
97 			      gs_memory_t * mem);
98 
99 #define gx_path_init_local(ppath, mem)\
100   (void)gx_path_init_local_shared(ppath, NULL, mem)	/* can't fail */
101 
102 /*
103  * Initialize a stack-allocated pseudo-path for computing a bbox
104  * for a dynamic path.
105  */
106 void gx_path_init_bbox_accumulator(gx_path * ppath);
107 
108 /*
109  * Ensure that a path owns its segments, by copying the segments if
110  * they currently have multiple references.
111  */
112 int gx_path_unshare(gx_path * ppath);
113 
114 /*
115  * Free a path by releasing its segments if they have no more references.
116  * This also frees the path object iff it was allocated by gx_path_alloc.
117  */
118 void gx_path_free(gx_path * ppath, client_name_t cname);
119 
120 /*
121  * Assign one path to another, adjusting reference counts appropriately.
122  * Note that this requires that segments of the two paths (but not the path
123  * objects themselves) were allocated with the same allocator.  Note also
124  * that if ppfrom is stack-allocated, ppto is not, and ppto's segments are
125  * currently shared, gx_path_assign must do the equivalent of a
126  * gx_path_new(ppto), which allocates a new segments object for ppto.
127  */
128 int gx_path_assign_preserve(gx_path * ppto, gx_path * ppfrom);
129 
130 /*
131  * Assign one path to another and free the first path at the same time.
132  * (This may do less work than assign_preserve + free.)
133  */
134 int gx_path_assign_free(gx_path * ppto, gx_path * ppfrom);
135 
136 /* Path constructors */
137 /* Note that all path constructors have an implicit initial gx_path_unshare. */
138 
139 int gx_path_new(gx_path *),
140     gx_path_add_point(gx_path *, fixed, fixed),
141     gx_path_add_relative_point(gx_path *, fixed, fixed),
142     gx_path_add_line_notes(gx_path *, fixed, fixed, segment_notes),
143     gx_path_add_lines_notes(gx_path *, const gs_fixed_point *, int, segment_notes),
144     gx_path_add_rectangle(gx_path *, fixed, fixed, fixed, fixed),
145     gx_path_add_char_path(gx_path *, gx_path *, gs_char_path_mode),
146     gx_path_add_curve_notes(gx_path *, fixed, fixed, fixed, fixed, fixed, fixed, segment_notes),
147     gx_path_add_partial_arc_notes(gx_path *, fixed, fixed, fixed, fixed, floatp, segment_notes),
148     gx_path_add_path(gx_path *, gx_path *),
149     gx_path_close_subpath_notes(gx_path *, segment_notes),
150 	  /* We have to remove the 'subpath' from the following name */
151 	  /* to keep it unique in the first 23 characters. */
152     gx_path_pop_close_notes(gx_path *, segment_notes);
153 
154 /* Access path state flags */
155 byte gx_path_get_state_flags(gx_path *ppath);
156 void gx_path_set_state_flags(gx_path *ppath, byte flags);
157 bool gx_path_is_drawing(gx_path *ppath);
158 
159 /*
160  * The last argument to gx_path_add_partial_arc is a fraction for computing
161  * the curve parameters.  Here is the correct value for quarter-circles.
162  * (stroke uses this to draw round caps and joins.)
163  */
164 #define quarter_arc_fraction 0.55228474983079334
165 /*
166  * Backward-compatible constructors that don't take a notes argument.
167  */
168 #define gx_path_add_line(ppath, x, y)\
169   gx_path_add_line_notes(ppath, x, y, sn_none)
170 #define gx_path_add_lines(ppath, pts, count)\
171   gx_path_add_lines_notes(ppath, pts, count, sn_none)
172 #define gx_path_add_curve(ppath, x1, y1, x2, y2, x3, y3)\
173   gx_path_add_curve_notes(ppath, x1, y1, x2, y2, x3, y3, sn_none)
174 #define gx_path_add_partial_arc(ppath, x3, y3, xt, yt, fraction)\
175   gx_path_add_partial_arc_notes(ppath, x3, y3, xt, yt, fraction, sn_none)
176 #define gx_path_close_subpath(ppath)\
177   gx_path_close_subpath_notes(ppath, sn_none)
178 #define gx_path_pop_close_subpath(ppath)\
179   gx_path_pop_close_notes(ppath, sn_none)
180 
181 typedef enum {
182     pco_none = 0,
183     pco_monotonize = 1,		/* make curves monotonic */
184     pco_accurate = 2,		/* flatten with accurate tangents at ends */
185     pco_for_stroke = 4,		/* flatten taking line width into account */
186     pco_small_curves = 8	/* make curves small */
187 } gx_path_copy_options;
188 
189 /* Path accessors */
190 
191 gx_path *gx_current_path(const gs_state *);
192 int gx_path_current_point(const gx_path *, gs_fixed_point *),
193     gx_path_bbox(gx_path *, gs_fixed_rect *),
194     gx_path_bbox_set(gx_path *, gs_fixed_rect *);
195 int gx_path_subpath_start_point(const gx_path *, gs_fixed_point *);
196 bool gx_path_has_curves(const gx_path *),
197     gx_path_is_void(const gx_path *),	/* no segments */
198     gx_path_is_null(const gx_path *),	/* nothing at all */
199     gx_path__check_curves(const gx_path * ppath, gx_path_copy_options options, fixed fixed_flat);
200 typedef enum {
201     prt_none = 0,
202     prt_open = 1,		/* only 3 sides */
203     prt_fake_closed = 2,	/* 4 lines, no closepath */
204     prt_closed = 3		/* 3 or 4 lines + closepath */
205 } gx_path_rectangular_type;
206 
207 gx_path_rectangular_type
208 gx_path_is_rectangular(const gx_path *, gs_fixed_rect *);
209 
210 #define gx_path_is_rectangle(ppath, pbox)\
211   (gx_path_is_rectangular(ppath, pbox) != prt_none)
212 /* Inline versions of the above */
213 #define gx_path_is_null_inline(ppath)\
214   (gx_path_is_void(ppath) && !path_position_valid(ppath))
215 
216 /* Path transformers */
217 
218 /* The imager state is only needed when flattening for stroke. */
219 #ifndef gs_imager_state_DEFINED
220 #  define gs_imager_state_DEFINED
221 typedef struct gs_imager_state_s gs_imager_state;
222 #endif
223 int gx_path_copy_reducing(const gx_path * ppath_old, gx_path * ppath_new,
224 			  fixed fixed_flatness, const gs_imager_state *pis,
225 			  gx_path_copy_options options);
226 
227 #define gx_path_copy(old, new)\
228   gx_path_copy_reducing(old, new, max_fixed, NULL, pco_none)
229 #define gx_path_add_flattened(old, new, flatness)\
230   gx_path_copy_reducing(old, new, float2fixed(flatness), NULL, pco_none)
231 #define gx_path_add_flattened_accurate(old, new, flatness, accurate)\
232   gx_path_copy_reducing(old, new, float2fixed(flatness), NULL,\
233 			(accurate ? pco_accurate : pco_none))
234 #define gx_path_add_flattened_for_stroke(old, new, flatness, pis)\
235   gx_path_copy_reducing(old, new, float2fixed(flatness), pis,\
236 			(pis->accurate_curves ?\
237 			 pco_accurate | pco_for_stroke : pco_for_stroke))
238 #define gx_path_add_monotonized(old, new)\
239   gx_path_copy_reducing(old, new, max_fixed, NULL, pco_monotonize)
240 int gx_path_add_dash_expansion(const gx_path * /*old*/, gx_path * /*new*/,
241 				  const gs_imager_state *),
242       gx_path_copy_reversed(const gx_path * /*old*/, gx_path * /*new*/),
243       gx_path_translate(gx_path *, fixed, fixed),
244       gx_path_scale_exp2_shared(gx_path *ppath, int log2_scale_x,
245 				   int log2_scale_y, bool segments_shared);
246 void gx_point_scale_exp2(gs_fixed_point *, int, int),
247       gx_rect_scale_exp2(gs_fixed_rect *, int, int);
248 
249 /* Path enumerator */
250 
251 /* This interface does not make a copy of the path. */
252 /* Do not use gs_path_enum_cleanup with this interface! */
253 int gx_path_enum_init(gs_path_enum *, const gx_path *);
254 int gx_path_enum_next(gs_path_enum *, gs_fixed_point[3]);	/* 0 when done */
255 
256 segment_notes
257 gx_path_enum_notes(const gs_path_enum *);
258 bool gx_path_enum_backup(gs_path_enum *);
259 
260 /* An auxiliary function to add a path point with a specified transformation. */
261 int gs_moveto_aux(gs_imager_state *pis, gx_path *ppath, floatp x, floatp y);
262 int gx_setcurrentpoint_from_path(gs_imager_state *pis, gx_path *path);
263 
264 /* Path optimization for the filling algorithm. */
265 
266 int gx_path_merge_contacting_contours(gx_path *ppath);
267 
268 /* ------ Clipping paths ------ */
269 
270 /* Opaque type for a clipping path */
271 #ifndef gx_clip_path_DEFINED
272 #  define gx_clip_path_DEFINED
273 typedef struct gx_clip_path_s gx_clip_path;
274 #endif
275 
276 /* Graphics state clipping */
277 int gx_clip_to_rectangle(gs_state *, gs_fixed_rect *);
278 int gx_clip_to_path(gs_state *);
279 int gx_default_clip_box(const gs_state *, gs_fixed_rect *);
280 int gx_effective_clip_path(gs_state *, gx_clip_path **);
281 
282 /* Opaque type for a clip list. */
283 #ifndef gx_clip_list_DEFINED
284 #  define gx_clip_list_DEFINED
285 typedef struct gx_clip_list_s gx_clip_list;
286 #endif
287 
288 /* Opaque type for a clipping path enumerator. */
289 typedef struct gs_cpath_enum_s gs_cpath_enum;
290 
291 /*
292  * Provide similar memory management for clip paths to what we have for
293  * paths (see above for details).
294  */
295 gx_clip_path *gx_cpath_alloc_shared(const gx_clip_path * shared,
296 				    gs_memory_t * mem, client_name_t cname);
297 
298 #define gx_cpath_alloc(mem, cname)\
299   gx_cpath_alloc_shared(NULL, mem, cname)
300 int gx_cpath_init_contained_shared(gx_clip_path * pcpath,
301 				   const gx_clip_path * shared,
302 				   gs_memory_t * mem,
303 				   client_name_t cname);
304 
305 #define gx_cpath_alloc_contained(pcpath, mem, cname)\
306   gx_cpath_init_contained_shared(pcpath, NULL, mem, cname)
307 int gx_cpath_init_local_shared(gx_clip_path * pcpath,
308 			       const gx_clip_path * shared,
309 			       gs_memory_t * mem);
310 
311 #define gx_cpath_init_local(pcpath, mem)\
312   (void)gx_cpath_init_local_shared(pcpath, NULL, mem)	/* can't fail */
313 int gx_cpath_unshare(gx_clip_path * pcpath);
314 void gx_cpath_free(gx_clip_path * pcpath, client_name_t cname);
315 int gx_cpath_assign_preserve(gx_clip_path * pcpto, gx_clip_path * pcpfrom);
316 int gx_cpath_assign_free(gx_clip_path * pcpto, gx_clip_path * pcpfrom);
317 
318 /* Clip path constructors and accessors */
319 
320 int
321     gx_cpath_reset(gx_clip_path *),		/* from_rectangle ((0,0),(0,0)) */
322     gx_cpath_from_rectangle(gx_clip_path *, gs_fixed_rect *),
323     gx_cpath_clip(gs_state *, gx_clip_path *, /*const*/ gx_path *, int),
324     gx_cpath_intersect(gx_clip_path *, /*const*/ gx_path *, int,
325 		       gs_imager_state *),
326     gx_cpath_scale_exp2_shared(gx_clip_path *pcpath, int log2_scale_x,
327 			       int log2_scale_y, bool list_shared,
328 			       bool segments_shared),
329     gx_cpath_to_path(gx_clip_path *, gx_path *);
330 bool
331     gx_cpath_inner_box(const gx_clip_path *, gs_fixed_rect *),
332     gx_cpath_outer_box(const gx_clip_path *, gs_fixed_rect *),
333     gx_cpath_includes_rectangle(const gx_clip_path *, fixed, fixed,
334 				fixed, fixed);
335 const gs_fixed_rect *cpath_is_rectangle(const gx_clip_path * pcpath);
336 
337 /* Enumerate a clipping path.  This interface does not copy the path. */
338 /* However, it does write into the path's "visited" flags. */
339 int gx_cpath_enum_init(gs_cpath_enum *, gx_clip_path *);
340 int gx_cpath_enum_next(gs_cpath_enum *, gs_fixed_point[3]);		/* 0 when done */
341 
342 segment_notes
343 gx_cpath_enum_notes(const gs_cpath_enum *);
344 
345 #ifdef DEBUG
346 void gx_cpath_print(const gx_clip_path *);
347 #endif
348 
349 
350 #endif /* gxpath_INCLUDED */
351