xref: /plan9/sys/src/cmd/gs/src/gdevvec.h (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
1 /* Copyright (C) 1997, 1998, 1999, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This file is part of AFPL Ghostscript.
4 
5   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
6   distributor accepts any responsibility for the consequences of using it, or
7   for whether it serves any particular purpose or works at all, unless he or
8   she says so in writing.  Refer to the Aladdin Free Public License (the
9   "License") for full details.
10 
11   Every copy of AFPL Ghostscript must include a copy of the License, normally
12   in a plain ASCII text file named PUBLIC.  The License grants you the right
13   to copy, modify and redistribute AFPL Ghostscript, but only under certain
14   conditions described in the License.  Among other things, the License
15   requires that the copyright notice and this notice be preserved on all
16   copies.
17 */
18 
19 /*$Id: gdevvec.h,v 1.7 2001/07/12 03:28:02 lpd Exp $ */
20 /* Common definitions for "vector" devices */
21 
22 #ifndef gdevvec_INCLUDED
23 #  define gdevvec_INCLUDED
24 
25 #include "gp.h"			/* for gp_file_name_sizeof */
26 #include "gsropt.h"
27 #include "gxdevice.h"
28 #include "gdevbbox.h"
29 #include "gxiparam.h"
30 #include "gxistate.h"
31 #include "stream.h"
32 
33 /*
34  * "Vector" devices produce a stream of higher-level drawing commands rather
35  * than a raster image.  (We don't like the term "vector", since the command
36  * vocabulary typically includes text and raster images as well as actual
37  * vectors, but it's widely used in the industry, and we weren't able to
38  * find one that read better.)  Some examples of "vector" formats are PDF,
39  * PostScript, PCL XL, HP-GL/2 + RTL, CGM, Windows Metafile, and Macintosh
40  * PICT.
41  *
42  * This file extends the basic driver structure with elements likely to be
43  * useful to vector devices.  These include:
44  *
45  *      - Tracking whether any marks have been made on the page;
46  *
47  *      - Keeping track of the page bounding box;
48  *
49  *      - A copy of the most recently written current graphics state
50  *      parameters;
51  *
52  *      - An output stream (for drivers that compress or otherwise filter
53  *      their output);
54  *
55  *      - A vector of procedures for writing changes to the graphics state.
56  *
57  *      - The ability to work with scaled output coordinate systems.
58  *
59  * We expect to add more elements and procedures as we gain more experience
60  * with this kind of driver.
61  */
62 
63 /* ================ Types and structures ================ */
64 
65 /* Define the abstract type for a vector device. */
66 typedef struct gx_device_vector_s gx_device_vector;
67 
68 /* Define the maximum size of the output file name. */
69 #define fname_size (gp_file_name_sizeof - 1)
70 
71 /* Define the longest dash pattern we can remember. */
72 #define max_dash 11
73 
74 /*
75  * Define procedures for writing common output elements.  Not all devices
76  * will support all of these elements.  Note that these procedures normally
77  * only write out commands, and don't update the driver state itself.  All
78  * of them are optional, called only as indicated under the utility
79  * procedures below.
80  */
81 typedef enum {
82     gx_path_type_none = 0,
83     /*
84      * All combinations of flags are legal.  Multiple commands are
85      * executed in the order fill, stroke, clip.
86      */
87     gx_path_type_fill = 1,
88     gx_path_type_stroke = 2,
89     gx_path_type_clip = 4,
90     gx_path_type_winding_number = 0,
91     gx_path_type_even_odd = 8,
92     gx_path_type_optimize = 16,	/* OK to optimize paths by merging seg.s */
93     gx_path_type_always_close = 32, /* include final closepath even if not stroke */
94     gx_path_type_rule = gx_path_type_winding_number | gx_path_type_even_odd
95 } gx_path_type_t;
96 typedef enum {
97     gx_rect_x_first,
98     gx_rect_y_first
99 } gx_rect_direction_t;
100 typedef struct gx_device_vector_procs_s {
101     /* Page management */
102     int (*beginpage) (P1(gx_device_vector * vdev));
103     /* Imager state */
104     int (*setlinewidth) (P2(gx_device_vector * vdev, floatp width));
105     int (*setlinecap) (P2(gx_device_vector * vdev, gs_line_cap cap));
106     int (*setlinejoin) (P2(gx_device_vector * vdev, gs_line_join join));
107     int (*setmiterlimit) (P2(gx_device_vector * vdev, floatp limit));
108     int (*setdash) (P4(gx_device_vector * vdev, const float *pattern,
109 		       uint count, floatp offset));
110     int (*setflat) (P2(gx_device_vector * vdev, floatp flatness));
111     int (*setlogop) (P3(gx_device_vector * vdev, gs_logical_operation_t lop,
112 			gs_logical_operation_t diff));
113     /* Other state */
114     int (*setfillcolor) (P2(gx_device_vector * vdev, const gx_drawing_color * pdc));
115     int (*setstrokecolor) (P2(gx_device_vector * vdev, const gx_drawing_color * pdc));
116     /* Paths */
117     /* dopath and dorect are normally defaulted */
118     int (*dopath) (P4(gx_device_vector * vdev, const gx_path * ppath,
119 		      gx_path_type_t type, const gs_matrix *pmat));
120     int (*dorect) (P6(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1,
121 		      fixed y1, gx_path_type_t type));
122     int (*beginpath) (P2(gx_device_vector * vdev, gx_path_type_t type));
123     int (*moveto) (P6(gx_device_vector * vdev, floatp x0, floatp y0,
124 		      floatp x, floatp y, gx_path_type_t type));
125     int (*lineto) (P6(gx_device_vector * vdev, floatp x0, floatp y0,
126 		      floatp x, floatp y, gx_path_type_t type));
127     int (*curveto) (P10(gx_device_vector * vdev, floatp x0, floatp y0,
128 			floatp x1, floatp y1, floatp x2, floatp y2,
129 			floatp x3, floatp y3, gx_path_type_t type));
130     int (*closepath) (P6(gx_device_vector * vdev, floatp x0, floatp y0,
131 		      floatp x_start, floatp y_start, gx_path_type_t type));
132     int (*endpath) (P2(gx_device_vector * vdev, gx_path_type_t type));
133 } gx_device_vector_procs;
134 
135 /* Default implementations of procedures */
136 /* setflat does nothing */
137 int gdev_vector_setflat(P2(gx_device_vector * vdev, floatp flatness));
138 
139 /* dopath may call dorect, beginpath, moveto/lineto/curveto/closepath, */
140 /* endpath */
141 int gdev_vector_dopath(P4(gx_device_vector * vdev, const gx_path * ppath,
142 			  gx_path_type_t type, const gs_matrix *pmat));
143 
144 /* dorect may call beginpath, moveto, lineto, closepath */
145 int gdev_vector_dorect(P6(gx_device_vector * vdev, fixed x0, fixed y0,
146 			  fixed x1, fixed y1, gx_path_type_t type));
147 
148 /* Finally, define the extended device structure. */
149 #define gx_device_vector_common\
150 	gx_device_common;\
151 	gs_memory_t *v_memory;\
152 		/* Output element writing procedures */\
153 	const gx_device_vector_procs *vec_procs;\
154 		/* Output file */\
155 	char fname[fname_size + 1];\
156 	FILE *file;\
157 	stream *strm;\
158 	byte *strmbuf;\
159 	uint strmbuf_size;\
160 	int open_options;	/* see below */\
161 		/* Graphics state */\
162 	gs_imager_state state;\
163 	float dash_pattern[max_dash];\
164 	gx_drawing_color fill_color, stroke_color;\
165 	gs_id no_clip_path_id;	/* indicates no clipping */\
166 	gs_id clip_path_id;\
167 		/* Other state */\
168 	gx_path_type_t fill_options, stroke_options;  /* optimize */\
169 	gs_point scale;		/* device coords / scale => output coords */\
170 	bool in_page;		/* true if any marks on this page */\
171 	gx_device_bbox *bbox_device;	/* for tracking bounding box */\
172 		/* Cached values */\
173 	gx_color_index black, white
174 #define vdev_proc(vdev, p) ((vdev)->vec_procs->p)
175 
176 #define vector_initial_values\
177 	0,		/* v_memory */\
178 	0,		/* vec_procs */\
179 	 { 0 },		/* fname */\
180 	0,		/* file */\
181 	0,		/* strm */\
182 	0,		/* strmbuf */\
183 	0,		/* strmbuf_size */\
184 	0,		/* open_options */\
185 	 { 0 },		/* state */\
186 	 { 0 },		/* dash_pattern */\
187 	 { 0 },		/* fill_color ****** WRONG ****** */\
188 	 { 0 },		/* stroke_color ****** WRONG ****** */\
189 	gs_no_id,	/* clip_path_id */\
190 	gs_no_id,	/* no_clip_path_id */\
191 	0, 0,		/* fill/stroke_options */\
192 	 { X_DPI/72.0, Y_DPI/72.0 },	/* scale */\
193 	0/*false*/,	/* in_page */\
194 	0,		/* bbox_device */\
195 	gx_no_color_index,	/* black */\
196 	gx_no_color_index	/* white */
197 
198 struct gx_device_vector_s {
199     gx_device_vector_common;
200 };
201 
202 /* st_device_vector is never instantiated per se, but we still need to */
203 /* extern its descriptor for the sake of subclasses. */
204 extern_st(st_device_vector);
205 #define public_st_device_vector()	/* in gdevvec.c */\
206   gs_public_st_suffix_add3_final(st_device_vector, gx_device_vector,\
207     "gx_device_vector", device_vector_enum_ptrs,\
208     device_vector_reloc_ptrs, gx_device_finalize, st_device, strm, strmbuf,\
209     bbox_device)
210 #define st_device_vector_max_ptrs (st_device_max_ptrs + 3)
211 
212 /* ================ Utility procedures ================ */
213 
214 /* Initialize the state. */
215 void gdev_vector_init(P1(gx_device_vector * vdev));
216 
217 /* Reset the remembered graphics state. */
218 void gdev_vector_reset(P1(gx_device_vector * vdev));
219 
220 /*
221  * Open the output file and stream, with optional bbox tracking.
222  * The options must be defined so that 0 is always the default.
223  */
224 #define VECTOR_OPEN_FILE_ASCII 1	/* open file as text, not binary */
225 #define VECTOR_OPEN_FILE_SEQUENTIAL 2	/* open as non-seekable */
226 #define VECTOR_OPEN_FILE_SEQUENTIAL_OK 4  /* open as non-seekable if */
227 					/* open as seekable fails */
228 #define VECTOR_OPEN_FILE_BBOX 8		/* also open bbox device */
229 int gdev_vector_open_file_options(P3(gx_device_vector * vdev,
230 				     uint strmbuf_size, int open_options));
231 #define gdev_vector_open_file_bbox(vdev, bufsize, bbox)\
232   gdev_vector_open_file_options(vdev, bufsize,\
233 				(bbox ? VECTOR_OPEN_FILE_BBOX : 0))
234 #define gdev_vector_open_file(vdev, strmbuf_size)\
235   gdev_vector_open_file_bbox(vdev, strmbuf_size, false)
236 
237 /* Get the current stream, calling beginpage if in_page is false. */
238 stream *gdev_vector_stream(P1(gx_device_vector * vdev));
239 
240 /* Bring the logical operation up to date. */
241 /* May call setlogop. */
242 int gdev_vector_update_log_op(P2(gx_device_vector * vdev,
243 				 gs_logical_operation_t lop));
244 
245 /* Bring the fill color up to date. */
246 /* May call setfillcolor. */
247 int gdev_vector_update_fill_color(P2(gx_device_vector * vdev,
248 				     const gx_drawing_color * pdcolor));
249 
250 /* Bring state up to date for filling. */
251 /* May call setflat, setfillcolor, setlogop. */
252 int gdev_vector_prepare_fill(P4(gx_device_vector * vdev,
253 				const gs_imager_state * pis,
254 				const gx_fill_params * params,
255 				const gx_drawing_color * pdcolor));
256 
257 /* Bring state up to date for stroking.  Note that we pass the scale */
258 /* for the line width and dash offset explicitly. */
259 /* May call setlinewidth, setlinecap, setlinejoin, setmiterlimit, */
260 /* setdash, setflat, setstrokecolor, setlogop. */
261 /* Any of pis, params, and pdcolor may be NULL. */
262 int gdev_vector_prepare_stroke(P5(gx_device_vector * vdev,
263 				  const gs_imager_state * pis,
264 				  const gx_stroke_params * params,
265 				  const gx_drawing_color * pdcolor,
266 				  floatp scale));
267 
268 /*
269  * Compute the scale for transforming the line width and dash pattern for a
270  * stroke operation, and, if necessary to handle anisotropic scaling, a full
271  * transformation matrix to be inverse-applied to the path elements as well.
272  * Return 0 if only scaling, 1 if a full matrix is needed.
273  */
274 int gdev_vector_stroke_scaling(P4(const gx_device_vector *vdev,
275 				  const gs_imager_state *pis,
276 				  double *pscale, gs_matrix *pmat));
277 
278 /* Prepare to write a path using the default implementation. */
279 typedef struct gdev_vector_dopath_state_s {
280     /* Initialized by _init */
281     gx_device_vector *vdev;
282     gx_path_type_t type;
283     bool first;
284     gs_matrix scale_mat;
285     /* Change dynamically */
286     gs_point start;
287     gs_point prev;
288 } gdev_vector_dopath_state_t;
289 void gdev_vector_dopath_init(P4(gdev_vector_dopath_state_t *state,
290 				gx_device_vector *vdev,
291 				gx_path_type_t type, const gs_matrix *pmat));
292 
293 /* Write a segment of a path using the default implementation. */
294 int gdev_vector_dopath_segment(P3(gdev_vector_dopath_state_t *state, int pe_op,
295 				  gs_fixed_point vs[3]));
296 
297 /* Write a polygon as part of a path (type = gx_path_type_none) */
298 /* or as a path. */
299 /* May call moveto, lineto, closepath (if close); */
300 /* may call beginpath & endpath if type != none. */
301 int gdev_vector_write_polygon(P5(gx_device_vector * vdev,
302 				 const gs_fixed_point * points, uint count,
303 				 bool close, gx_path_type_t type));
304 
305 /* Write a rectangle.  This is just a special case of write_polygon. */
306 int gdev_vector_write_rectangle(P7(gx_device_vector * vdev,
307 				   fixed x0, fixed y0, fixed x1, fixed y1,
308 				   bool close, gx_rect_direction_t dir));
309 
310 /* Write a clipping path by calling the path procedures. */
311 /* May call the same procedures as writepath. */
312 int gdev_vector_write_clip_path(P2(gx_device_vector * vdev,
313 				   const gx_clip_path * pcpath));
314 
315 /* Bring the clipping state up to date. */
316 /* May call write_rectangle (q.v.), write_clip_path (q.v.). */
317 int gdev_vector_update_clip_path(P2(gx_device_vector * vdev,
318 				    const gx_clip_path * pcpath));
319 
320 /* Close the output file and stream. */
321 int gdev_vector_close_file(P1(gx_device_vector * vdev));
322 
323 /* ---------------- Image enumeration ---------------- */
324 
325 /* Define a common set of state parameters for enumerating images. */
326 #define gdev_vector_image_enum_common\
327 	gx_image_enum_common;\
328 		/* Set by begin_image */\
329 	gs_memory_t *memory;	/* from begin_image */\
330 	gx_image_enum_common_t *default_info;	/* non-0 iff using default implementation */\
331 	gx_image_enum_common_t *bbox_info;	/* non-0 iff passing image data to bbox dev */\
332 	int width, height;\
333 	int bits_per_pixel;	/* (per plane) */\
334 	uint bits_per_row;	/* (per plane) */\
335 		/* Updated dynamically by image_data */\
336 	int y			/* 0 <= y < height */
337 typedef struct gdev_vector_image_enum_s {
338     gdev_vector_image_enum_common;
339 } gdev_vector_image_enum_t;
340 
341 extern_st(st_vector_image_enum);
342 #define public_st_vector_image_enum()	/* in gdevvec.c */\
343   gs_public_st_ptrs2(st_vector_image_enum, gdev_vector_image_enum_t,\
344     "gdev_vector_image_enum_t", vector_image_enum_enum_ptrs,\
345     vector_image_enum_reloc_ptrs, default_info, bbox_info)
346 
347 /*
348  * Initialize for enumerating an image.  Note that the last argument is an
349  * already-allocated enumerator, not a pointer to the place to store the
350  * enumerator.
351  */
352 int gdev_vector_begin_image(P10(gx_device_vector * vdev,
353 			const gs_imager_state * pis, const gs_image_t * pim,
354 			gs_image_format_t format, const gs_int_rect * prect,
355 	      const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
356 		    gs_memory_t * mem, const gx_image_enum_procs_t * pprocs,
357 				gdev_vector_image_enum_t * pie));
358 
359 /* End an image, optionally supplying any necessary blank padding rows. */
360 /* Return 0 if we used the default implementation, 1 if not. */
361 int gdev_vector_end_image(P4(gx_device_vector * vdev,
362        gdev_vector_image_enum_t * pie, bool draw_last, gx_color_index pad));
363 
364 /* ================ Device procedures ================ */
365 
366 /* Redefine get/put_params to handle OutputFile. */
367 dev_proc_put_params(gdev_vector_put_params);
368 dev_proc_get_params(gdev_vector_get_params);
369 
370 /* ---------------- Defaults ---------------- */
371 
372 /* fill_rectangle may call setfillcolor, dorect. */
373 dev_proc_fill_rectangle(gdev_vector_fill_rectangle);
374 /* fill_path may call prepare_fill, writepath, write_clip_path. */
375 dev_proc_fill_path(gdev_vector_fill_path);
376 /* stroke_path may call prepare_stroke, write_path, write_clip_path. */
377 dev_proc_stroke_path(gdev_vector_stroke_path);
378 /* fill_trapezoid, fill_parallelogram, and fill_triangle may call */
379 /* setfillcolor, setlogop, beginpath, moveto, lineto, endpath. */
380 dev_proc_fill_trapezoid(gdev_vector_fill_trapezoid);
381 dev_proc_fill_parallelogram(gdev_vector_fill_parallelogram);
382 dev_proc_fill_triangle(gdev_vector_fill_triangle);
383 
384 #endif /* gdevvec_INCLUDED */
385