xref: /plan9/sys/src/cmd/gs/src/gdevvec.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /* Copyright (C) 1997, 2000 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gdevvec.c,v 1.27 2005/08/23 11:26:26 igor Exp $ */
187dd7cddfSDavid du Colombier /* Utilities for "vector" devices */
197dd7cddfSDavid du Colombier #include "math_.h"
207dd7cddfSDavid du Colombier #include "memory_.h"
217dd7cddfSDavid du Colombier #include "string_.h"
227dd7cddfSDavid du Colombier #include "gx.h"
237dd7cddfSDavid du Colombier #include "gp.h"
247dd7cddfSDavid du Colombier #include "gserrors.h"
257dd7cddfSDavid du Colombier #include "gsparam.h"
267dd7cddfSDavid du Colombier #include "gsutil.h"
277dd7cddfSDavid du Colombier #include "gxfixed.h"
287dd7cddfSDavid du Colombier #include "gdevvec.h"
297dd7cddfSDavid du Colombier #include "gscspace.h"
307dd7cddfSDavid du Colombier #include "gxdcolor.h"
317dd7cddfSDavid du Colombier #include "gxpaint.h"		/* requires gx_path, ... */
327dd7cddfSDavid du Colombier #include "gzpath.h"
337dd7cddfSDavid du Colombier #include "gzcpath.h"
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier /* Structure descriptors */
367dd7cddfSDavid du Colombier public_st_device_vector();
377dd7cddfSDavid du Colombier public_st_vector_image_enum();
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier /* ================ Default implementations of vector procs ================ */
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier int
gdev_vector_setflat(gx_device_vector * vdev,floatp flatness)427dd7cddfSDavid du Colombier gdev_vector_setflat(gx_device_vector * vdev, floatp flatness)
437dd7cddfSDavid du Colombier {
447dd7cddfSDavid du Colombier     return 0;
457dd7cddfSDavid du Colombier }
467dd7cddfSDavid du Colombier 
473ff48bf5SDavid du Colombier /* Put a path on the output file. */
483ff48bf5SDavid du Colombier private bool
coord_between(fixed start,fixed mid,fixed end)493ff48bf5SDavid du Colombier coord_between(fixed start, fixed mid, fixed end)
503ff48bf5SDavid du Colombier {
513ff48bf5SDavid du Colombier     return (start <= end ? start <= mid && mid <= end :
523ff48bf5SDavid du Colombier 	    start >= mid && mid >= end);
533ff48bf5SDavid du Colombier }
547dd7cddfSDavid du Colombier int
gdev_vector_dopath(gx_device_vector * vdev,const gx_path * ppath,gx_path_type_t type,const gs_matrix * pmat)557dd7cddfSDavid du Colombier gdev_vector_dopath(gx_device_vector *vdev, const gx_path * ppath,
567dd7cddfSDavid du Colombier 		   gx_path_type_t type, const gs_matrix *pmat)
577dd7cddfSDavid du Colombier {
583ff48bf5SDavid du Colombier     bool do_close =
593ff48bf5SDavid du Colombier 	(type & (gx_path_type_stroke | gx_path_type_always_close)) != 0;
607dd7cddfSDavid du Colombier     gs_fixed_rect rbox;
617dd7cddfSDavid du Colombier     gx_path_rectangular_type rtype = gx_path_is_rectangular(ppath, &rbox);
627dd7cddfSDavid du Colombier     gs_path_enum cenum;
637dd7cddfSDavid du Colombier     gdev_vector_dopath_state_t state;
643ff48bf5SDavid du Colombier     gs_fixed_point line_start, line_end;
653ff48bf5SDavid du Colombier     bool incomplete_line = false;
663ff48bf5SDavid du Colombier     bool need_moveto = false;
677dd7cddfSDavid du Colombier     int code;
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier     gdev_vector_dopath_init(&state, vdev, type, pmat);
707dd7cddfSDavid du Colombier     /*
717dd7cddfSDavid du Colombier      * if the path type is stroke, we only recognize closed
727dd7cddfSDavid du Colombier      * rectangles; otherwise, we recognize all rectangles.
733ff48bf5SDavid du Colombier      * Note that for stroking with a transformation, we can't use dorect,
743ff48bf5SDavid du Colombier      * which requires (untransformed) device coordinates.
757dd7cddfSDavid du Colombier      */
767dd7cddfSDavid du Colombier     if (rtype != prt_none &&
77*593dc095SDavid du Colombier 	(!(type & gx_path_type_stroke) || rtype == prt_closed) &&
783ff48bf5SDavid du Colombier 	(pmat == 0 || is_xxyy(pmat) || is_xyyx(pmat)) &&
793ff48bf5SDavid du Colombier 	(state.scale_mat.xx == 1.0 && state.scale_mat.yy == 1.0 &&
803ff48bf5SDavid du Colombier 	 is_xxyy(&state.scale_mat) &&
813ff48bf5SDavid du Colombier 	 is_fzero2(state.scale_mat.tx, state.scale_mat.ty))
827dd7cddfSDavid du Colombier 	) {
837dd7cddfSDavid du Colombier 	gs_point p, q;
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier 	gs_point_transform_inverse((floatp)rbox.p.x, (floatp)rbox.p.y,
867dd7cddfSDavid du Colombier 				   &state.scale_mat, &p);
877dd7cddfSDavid du Colombier 	gs_point_transform_inverse((floatp)rbox.q.x, (floatp)rbox.q.y,
887dd7cddfSDavid du Colombier 				   &state.scale_mat, &q);
897dd7cddfSDavid du Colombier 	code = vdev_proc(vdev, dorect)(vdev, (fixed)p.x, (fixed)p.y,
907dd7cddfSDavid du Colombier 				       (fixed)q.x, (fixed)q.y, type);
917dd7cddfSDavid du Colombier 	if (code >= 0)
927dd7cddfSDavid du Colombier 	    return code;
937dd7cddfSDavid du Colombier 	/* If the dorect proc failed, use a general path. */
947dd7cddfSDavid du Colombier     }
957dd7cddfSDavid du Colombier     code = vdev_proc(vdev, beginpath)(vdev, type);
967dd7cddfSDavid du Colombier     if (code < 0)
977dd7cddfSDavid du Colombier 	return code;
987dd7cddfSDavid du Colombier     gx_path_enum_init(&cenum, ppath);
997dd7cddfSDavid du Colombier     for (;;) {
1007dd7cddfSDavid du Colombier 	gs_fixed_point vs[3];
1017dd7cddfSDavid du Colombier 	int pe_op = gx_path_enum_next(&cenum, vs);
1027dd7cddfSDavid du Colombier 
1037dd7cddfSDavid du Colombier     sw:
1043ff48bf5SDavid du Colombier 	if (type & gx_path_type_optimize) {
1053ff48bf5SDavid du Colombier 	opt:
1063ff48bf5SDavid du Colombier 	    if (pe_op == gs_pe_lineto) {
1073ff48bf5SDavid du Colombier 		if (!incomplete_line) {
1083ff48bf5SDavid du Colombier 		    line_end = vs[0];
1093ff48bf5SDavid du Colombier 		    incomplete_line = true;
1103ff48bf5SDavid du Colombier 		    continue;
1113ff48bf5SDavid du Colombier 		}
1123ff48bf5SDavid du Colombier 		/*
1133ff48bf5SDavid du Colombier 		 * Merge collinear horizontal or vertical line segments
1143ff48bf5SDavid du Colombier 		 * going in the same direction.
1153ff48bf5SDavid du Colombier 		 */
1163ff48bf5SDavid du Colombier 		if (vs[0].x == line_end.x) {
1173ff48bf5SDavid du Colombier 		    if (vs[0].x == line_start.x &&
1183ff48bf5SDavid du Colombier 			coord_between(line_start.y, line_end.y, vs[0].y)
1193ff48bf5SDavid du Colombier 			) {
1203ff48bf5SDavid du Colombier 			line_end.y = vs[0].y;
1213ff48bf5SDavid du Colombier 			continue;
1223ff48bf5SDavid du Colombier 		    }
1233ff48bf5SDavid du Colombier 		} else if (vs[0].y == line_end.y) {
1243ff48bf5SDavid du Colombier 		    if (vs[0].y == line_start.y &&
1253ff48bf5SDavid du Colombier 			coord_between(line_start.x, line_end.x, vs[0].x)
1263ff48bf5SDavid du Colombier 			) {
1273ff48bf5SDavid du Colombier 			line_end.x = vs[0].x;
1283ff48bf5SDavid du Colombier 			continue;
1293ff48bf5SDavid du Colombier 		    }
1303ff48bf5SDavid du Colombier 		}
1313ff48bf5SDavid du Colombier 	    }
1323ff48bf5SDavid du Colombier 	    if (incomplete_line) {
1333ff48bf5SDavid du Colombier 		if (need_moveto) {	/* see gs_pe_moveto case */
1343ff48bf5SDavid du Colombier 		    code = gdev_vector_dopath_segment(&state, gs_pe_moveto,
1353ff48bf5SDavid du Colombier 						      &line_start);
1363ff48bf5SDavid du Colombier 		    if (code < 0)
1373ff48bf5SDavid du Colombier 			return code;
1383ff48bf5SDavid du Colombier 		    need_moveto = false;
1393ff48bf5SDavid du Colombier 		}
1403ff48bf5SDavid du Colombier 		code = gdev_vector_dopath_segment(&state, gs_pe_lineto,
1413ff48bf5SDavid du Colombier 						  &line_end);
1423ff48bf5SDavid du Colombier 		if (code < 0)
1433ff48bf5SDavid du Colombier 		    return code;
1443ff48bf5SDavid du Colombier 		line_start = line_end;
1453ff48bf5SDavid du Colombier 		incomplete_line = false;
1463ff48bf5SDavid du Colombier 		goto opt;
1473ff48bf5SDavid du Colombier 	    }
1483ff48bf5SDavid du Colombier 	}
1497dd7cddfSDavid du Colombier 	switch (pe_op) {
1507dd7cddfSDavid du Colombier 	case 0:		/* done */
1513ff48bf5SDavid du Colombier 	done:
1527dd7cddfSDavid du Colombier 	    code = vdev_proc(vdev, endpath)(vdev, type);
1537dd7cddfSDavid du Colombier 	    return (code < 0 ? code : 0);
1543ff48bf5SDavid du Colombier 	case gs_pe_curveto:
1553ff48bf5SDavid du Colombier 	    if (need_moveto) {	/* see gs_pe_moveto case */
1563ff48bf5SDavid du Colombier 		code = gdev_vector_dopath_segment(&state, gs_pe_moveto,
1573ff48bf5SDavid du Colombier 						  &line_start);
1583ff48bf5SDavid du Colombier 		if (code < 0)
1593ff48bf5SDavid du Colombier 		    return code;
1603ff48bf5SDavid du Colombier 		need_moveto = false;
1613ff48bf5SDavid du Colombier 	    }
1623ff48bf5SDavid du Colombier 	    line_start = vs[2];
1633ff48bf5SDavid du Colombier 	    goto draw;
1643ff48bf5SDavid du Colombier 	case gs_pe_moveto:
1653ff48bf5SDavid du Colombier 	    /*
1663ff48bf5SDavid du Colombier 	     * A bug in Acrobat Reader 4 causes it to draw a single pixel
1673ff48bf5SDavid du Colombier 	     * for a fill with an isolated moveto.  If we're doing a fill
1683ff48bf5SDavid du Colombier 	     * without a stroke, defer emitting a moveto until we know that
1693ff48bf5SDavid du Colombier 	     * the subpath has more elements.
1703ff48bf5SDavid du Colombier 	     */
1713ff48bf5SDavid du Colombier 	    line_start = vs[0];
1723ff48bf5SDavid du Colombier 	    if (!(type & gx_path_type_stroke) && (type & gx_path_type_fill)) {
1733ff48bf5SDavid du Colombier 		need_moveto = true;
1743ff48bf5SDavid du Colombier 		continue;
1753ff48bf5SDavid du Colombier 	    }
1763ff48bf5SDavid du Colombier 	    goto draw;
1773ff48bf5SDavid du Colombier 	case gs_pe_lineto:
1783ff48bf5SDavid du Colombier 	    if (need_moveto) {	/* see gs_pe_moveto case */
1793ff48bf5SDavid du Colombier 		code = gdev_vector_dopath_segment(&state, gs_pe_moveto,
1803ff48bf5SDavid du Colombier 						  &line_start);
1813ff48bf5SDavid du Colombier 		if (code < 0)
1823ff48bf5SDavid du Colombier 		    return code;
1833ff48bf5SDavid du Colombier 		need_moveto = false;
1843ff48bf5SDavid du Colombier 	    }
1853ff48bf5SDavid du Colombier 	    line_start = vs[0];
1863ff48bf5SDavid du Colombier 	    goto draw;
1877dd7cddfSDavid du Colombier 	case gs_pe_closepath:
1883ff48bf5SDavid du Colombier 	    if (need_moveto) {	/* see gs_pe_moveto case */
1893ff48bf5SDavid du Colombier 		need_moveto = false;
1903ff48bf5SDavid du Colombier 		continue;
1913ff48bf5SDavid du Colombier 	    }
1927dd7cddfSDavid du Colombier 	    if (!do_close) {
1937dd7cddfSDavid du Colombier 		pe_op = gx_path_enum_next(&cenum, vs);
1943ff48bf5SDavid du Colombier 		if (pe_op == 0)
1953ff48bf5SDavid du Colombier 		    goto done;
1963ff48bf5SDavid du Colombier 		code = gdev_vector_dopath_segment(&state, gs_pe_closepath, vs);
1977dd7cddfSDavid du Colombier 		if (code < 0)
1987dd7cddfSDavid du Colombier 		    return code;
1997dd7cddfSDavid du Colombier 		goto sw;
2007dd7cddfSDavid du Colombier 	    }
2017dd7cddfSDavid du Colombier 	    /* falls through */
2023ff48bf5SDavid du Colombier 	draw:
2037dd7cddfSDavid du Colombier 	    code = gdev_vector_dopath_segment(&state, pe_op, vs);
2047dd7cddfSDavid du Colombier 	    if (code < 0)
2057dd7cddfSDavid du Colombier 		return code;
2067dd7cddfSDavid du Colombier 	}
2073ff48bf5SDavid du Colombier 	incomplete_line = false; /* only needed if optimizing */
2087dd7cddfSDavid du Colombier     }
2097dd7cddfSDavid du Colombier }
2107dd7cddfSDavid du Colombier 
2117dd7cddfSDavid du Colombier int
gdev_vector_dorect(gx_device_vector * vdev,fixed x0,fixed y0,fixed x1,fixed y1,gx_path_type_t type)2127dd7cddfSDavid du Colombier gdev_vector_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1,
2137dd7cddfSDavid du Colombier 		   fixed y1, gx_path_type_t type)
2147dd7cddfSDavid du Colombier {
2157dd7cddfSDavid du Colombier     int code = (*vdev_proc(vdev, beginpath)) (vdev, type);
2167dd7cddfSDavid du Colombier 
2177dd7cddfSDavid du Colombier     if (code < 0)
2187dd7cddfSDavid du Colombier 	return code;
2197dd7cddfSDavid du Colombier     code = gdev_vector_write_rectangle(vdev, x0, y0, x1, y1,
2207dd7cddfSDavid du Colombier 				       (type & gx_path_type_stroke) != 0,
2217dd7cddfSDavid du Colombier 				       gx_rect_x_first);
2227dd7cddfSDavid du Colombier     if (code < 0)
2237dd7cddfSDavid du Colombier 	return code;
2247dd7cddfSDavid du Colombier     return (*vdev_proc(vdev, endpath)) (vdev, type);
2257dd7cddfSDavid du Colombier }
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier /* ================ Utility procedures ================ */
2287dd7cddfSDavid du Colombier 
2297dd7cddfSDavid du Colombier /* Recompute the cached color values. */
2307dd7cddfSDavid du Colombier private void
gdev_vector_load_cache(gx_device_vector * vdev)2317dd7cddfSDavid du Colombier gdev_vector_load_cache(gx_device_vector * vdev)
2327dd7cddfSDavid du Colombier {
2337dd7cddfSDavid du Colombier     vdev->black = gx_device_black((gx_device *)vdev);
2347dd7cddfSDavid du Colombier     vdev->white = gx_device_white((gx_device *)vdev);
2357dd7cddfSDavid du Colombier }
2367dd7cddfSDavid du Colombier 
2377dd7cddfSDavid du Colombier /* Initialize the state. */
2387dd7cddfSDavid du Colombier void
gdev_vector_init(gx_device_vector * vdev)2397dd7cddfSDavid du Colombier gdev_vector_init(gx_device_vector * vdev)
2407dd7cddfSDavid du Colombier {
2417dd7cddfSDavid du Colombier     gdev_vector_reset(vdev);
2427dd7cddfSDavid du Colombier     vdev->scale.x = vdev->scale.y = 1.0;
2437dd7cddfSDavid du Colombier     vdev->in_page = false;
2447dd7cddfSDavid du Colombier     gdev_vector_load_cache(vdev);
2457dd7cddfSDavid du Colombier }
2467dd7cddfSDavid du Colombier 
2477dd7cddfSDavid du Colombier /* Reset the remembered graphics state. */
2487dd7cddfSDavid du Colombier void
gdev_vector_reset(gx_device_vector * vdev)2497dd7cddfSDavid du Colombier gdev_vector_reset(gx_device_vector * vdev)
2507dd7cddfSDavid du Colombier {
2517dd7cddfSDavid du Colombier     static const gs_imager_state state_initial =
2527dd7cddfSDavid du Colombier     {gs_imager_state_initial(1)};
2537dd7cddfSDavid du Colombier 
2547dd7cddfSDavid du Colombier     vdev->state = state_initial;
255*593dc095SDavid du Colombier     gx_hld_saved_color_init(&vdev->saved_fill_color);
256*593dc095SDavid du Colombier     gx_hld_saved_color_init(&vdev->saved_stroke_color);
2577dd7cddfSDavid du Colombier     vdev->clip_path_id =
258*593dc095SDavid du Colombier 	vdev->no_clip_path_id = gs_next_ids(vdev->memory, 1);
2597dd7cddfSDavid du Colombier }
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier /* Open the output file and stream. */
2627dd7cddfSDavid du Colombier int
gdev_vector_open_file_options(gx_device_vector * vdev,uint strmbuf_size,int open_options)2633ff48bf5SDavid du Colombier gdev_vector_open_file_options(gx_device_vector * vdev, uint strmbuf_size,
2643ff48bf5SDavid du Colombier 			      int open_options)
2653ff48bf5SDavid du Colombier {
2663ff48bf5SDavid du Colombier     bool binary = !(open_options & VECTOR_OPEN_FILE_ASCII);
2673ff48bf5SDavid du Colombier     int code = -1;		/* (only for testing, never returned) */
2687dd7cddfSDavid du Colombier 
2693ff48bf5SDavid du Colombier     /* Open the file as seekable or sequential, as requested. */
2703ff48bf5SDavid du Colombier     if (!(open_options & VECTOR_OPEN_FILE_SEQUENTIAL)) {
2713ff48bf5SDavid du Colombier 	/* Try to open as seekable. */
2723ff48bf5SDavid du Colombier 	code =
2733ff48bf5SDavid du Colombier 	    gx_device_open_output_file((gx_device *)vdev, vdev->fname,
2743ff48bf5SDavid du Colombier 				       binary, true, &vdev->file);
2753ff48bf5SDavid du Colombier     }
2763ff48bf5SDavid du Colombier     if (code < 0 && (open_options & (VECTOR_OPEN_FILE_SEQUENTIAL |
2773ff48bf5SDavid du Colombier 				     VECTOR_OPEN_FILE_SEQUENTIAL_OK))) {
2783ff48bf5SDavid du Colombier 	/* Try to open as sequential. */
2793ff48bf5SDavid du Colombier 	code = gx_device_open_output_file((gx_device *)vdev, vdev->fname,
2803ff48bf5SDavid du Colombier 					  binary, false, &vdev->file);
2813ff48bf5SDavid du Colombier     }
2827dd7cddfSDavid du Colombier     if (code < 0)
2837dd7cddfSDavid du Colombier 	return code;
2847dd7cddfSDavid du Colombier     if ((vdev->strmbuf = gs_alloc_bytes(vdev->v_memory, strmbuf_size,
2857dd7cddfSDavid du Colombier 					"vector_open(strmbuf)")) == 0 ||
2867dd7cddfSDavid du Colombier 	(vdev->strm = s_alloc(vdev->v_memory,
2877dd7cddfSDavid du Colombier 			      "vector_open(strm)")) == 0 ||
2883ff48bf5SDavid du Colombier 	((open_options & VECTOR_OPEN_FILE_BBOX) &&
2897dd7cddfSDavid du Colombier 	 (vdev->bbox_device =
2907dd7cddfSDavid du Colombier 	  gs_alloc_struct_immovable(vdev->v_memory,
2917dd7cddfSDavid du Colombier 				    gx_device_bbox, &st_device_bbox,
2927dd7cddfSDavid du Colombier 				    "vector_open(bbox_device)")) == 0)
2937dd7cddfSDavid du Colombier 	) {
2947dd7cddfSDavid du Colombier 	if (vdev->bbox_device)
2957dd7cddfSDavid du Colombier 	    gs_free_object(vdev->v_memory, vdev->bbox_device,
2967dd7cddfSDavid du Colombier 			   "vector_open(bbox_device)");
2977dd7cddfSDavid du Colombier 	vdev->bbox_device = 0;
2987dd7cddfSDavid du Colombier 	if (vdev->strm)
2997dd7cddfSDavid du Colombier 	    gs_free_object(vdev->v_memory, vdev->strm,
3007dd7cddfSDavid du Colombier 			   "vector_open(strm)");
3017dd7cddfSDavid du Colombier 	vdev->strm = 0;
3027dd7cddfSDavid du Colombier 	if (vdev->strmbuf)
3037dd7cddfSDavid du Colombier 	    gs_free_object(vdev->v_memory, vdev->strmbuf,
3047dd7cddfSDavid du Colombier 			   "vector_open(strmbuf)");
3057dd7cddfSDavid du Colombier 	vdev->strmbuf = 0;
3067dd7cddfSDavid du Colombier 	fclose(vdev->file);
3077dd7cddfSDavid du Colombier 	vdev->file = 0;
3087dd7cddfSDavid du Colombier 	return_error(gs_error_VMerror);
3097dd7cddfSDavid du Colombier     }
3107dd7cddfSDavid du Colombier     vdev->strmbuf_size = strmbuf_size;
3117dd7cddfSDavid du Colombier     swrite_file(vdev->strm, vdev->file, vdev->strmbuf, strmbuf_size);
3123ff48bf5SDavid du Colombier     vdev->open_options = open_options;
3137dd7cddfSDavid du Colombier     /*
3147dd7cddfSDavid du Colombier      * We don't want finalization to close the file, but we do want it
3157dd7cddfSDavid du Colombier      * to flush the stream buffer.
3167dd7cddfSDavid du Colombier      */
3177dd7cddfSDavid du Colombier     vdev->strm->procs.close = vdev->strm->procs.flush;
3187dd7cddfSDavid du Colombier     if (vdev->bbox_device) {
319*593dc095SDavid du Colombier 	gx_device_bbox_init(vdev->bbox_device, NULL, vdev->v_memory);
320*593dc095SDavid du Colombier         rc_increment(vdev->bbox_device);
3217dd7cddfSDavid du Colombier 	gx_device_set_resolution((gx_device *) vdev->bbox_device,
3227dd7cddfSDavid du Colombier 				 vdev->HWResolution[0],
3237dd7cddfSDavid du Colombier 				 vdev->HWResolution[1]);
3247dd7cddfSDavid du Colombier 	/* Do the right thing about upright vs. inverted. */
3257dd7cddfSDavid du Colombier 	/* (This is dangerous in general, since the procedure */
3267dd7cddfSDavid du Colombier 	/* might reference non-standard elements.) */
3277dd7cddfSDavid du Colombier 	set_dev_proc(vdev->bbox_device, get_initial_matrix,
3287dd7cddfSDavid du Colombier 		     dev_proc(vdev, get_initial_matrix));
3297dd7cddfSDavid du Colombier 	(*dev_proc(vdev->bbox_device, open_device))
3307dd7cddfSDavid du Colombier 	    ((gx_device *) vdev->bbox_device);
3317dd7cddfSDavid du Colombier     }
3327dd7cddfSDavid du Colombier     return 0;
3337dd7cddfSDavid du Colombier }
3347dd7cddfSDavid du Colombier 
3357dd7cddfSDavid du Colombier /* Get the current stream, calling beginpage if in_page is false. */
3367dd7cddfSDavid du Colombier stream *
gdev_vector_stream(gx_device_vector * vdev)3377dd7cddfSDavid du Colombier gdev_vector_stream(gx_device_vector * vdev)
3387dd7cddfSDavid du Colombier {
3397dd7cddfSDavid du Colombier     if (!vdev->in_page) {
3407dd7cddfSDavid du Colombier 	(*vdev_proc(vdev, beginpage)) (vdev);
3417dd7cddfSDavid du Colombier 	vdev->in_page = true;
3427dd7cddfSDavid du Colombier     }
3437dd7cddfSDavid du Colombier     return vdev->strm;
3447dd7cddfSDavid du Colombier }
3457dd7cddfSDavid du Colombier 
3467dd7cddfSDavid du Colombier /* Update the logical operation. */
3477dd7cddfSDavid du Colombier int
gdev_vector_update_log_op(gx_device_vector * vdev,gs_logical_operation_t lop)3487dd7cddfSDavid du Colombier gdev_vector_update_log_op(gx_device_vector * vdev, gs_logical_operation_t lop)
3497dd7cddfSDavid du Colombier {
3507dd7cddfSDavid du Colombier     gs_logical_operation_t diff = lop ^ vdev->state.log_op;
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier     if (diff != 0) {
3537dd7cddfSDavid du Colombier 	int code = (*vdev_proc(vdev, setlogop)) (vdev, lop, diff);
3547dd7cddfSDavid du Colombier 
3557dd7cddfSDavid du Colombier 	if (code < 0)
3567dd7cddfSDavid du Colombier 	    return code;
3577dd7cddfSDavid du Colombier 	vdev->state.log_op = lop;
3587dd7cddfSDavid du Colombier     }
3597dd7cddfSDavid du Colombier     return 0;
3607dd7cddfSDavid du Colombier }
3617dd7cddfSDavid du Colombier 
362*593dc095SDavid du Colombier /* Update color (fill or stroke). */
363*593dc095SDavid du Colombier private int
gdev_vector_update_color(gx_device_vector * vdev,const gs_imager_state * pis,const gx_drawing_color * pdcolor,gx_hl_saved_color * sc,int (* setcolor)(gx_device_vector * vdev,const gs_imager_state * pis,const gx_drawing_color * pdc))364*593dc095SDavid du Colombier gdev_vector_update_color(gx_device_vector * vdev,
365*593dc095SDavid du Colombier 			      const gs_imager_state * pis,
366*593dc095SDavid du Colombier 			      const gx_drawing_color * pdcolor,
367*593dc095SDavid du Colombier 			      gx_hl_saved_color *sc,
368*593dc095SDavid du Colombier 			      int (*setcolor) (gx_device_vector * vdev,
369*593dc095SDavid du Colombier 			                       const gs_imager_state * pis,
370*593dc095SDavid du Colombier 					       const gx_drawing_color * pdc))
371*593dc095SDavid du Colombier {
372*593dc095SDavid du Colombier     gx_hl_saved_color temp;
373*593dc095SDavid du Colombier     int code;
374*593dc095SDavid du Colombier     bool hl_color = (*vdev_proc(vdev, can_handle_hl_color)) (vdev, pis, pdcolor);
375*593dc095SDavid du Colombier     const gs_imager_state *pis_for_hl_color = (hl_color ? pis : NULL);
376*593dc095SDavid du Colombier 
377*593dc095SDavid du Colombier     gx_hld_save_color(pis_for_hl_color, pdcolor, &temp);
378*593dc095SDavid du Colombier     if (gx_hld_saved_color_equal(&temp, sc))
379*593dc095SDavid du Colombier 	return 0;
380*593dc095SDavid du Colombier     code = (*setcolor) (vdev, pis_for_hl_color, pdcolor);
381*593dc095SDavid du Colombier     if (code < 0)
382*593dc095SDavid du Colombier 	return code;
383*593dc095SDavid du Colombier     *sc = temp;
384*593dc095SDavid du Colombier     return 0;
385*593dc095SDavid du Colombier }
386*593dc095SDavid du Colombier 
3877dd7cddfSDavid du Colombier /* Update the fill color. */
3887dd7cddfSDavid du Colombier int
gdev_vector_update_fill_color(gx_device_vector * vdev,const gs_imager_state * pis,const gx_drawing_color * pdcolor)3897dd7cddfSDavid du Colombier gdev_vector_update_fill_color(gx_device_vector * vdev,
390*593dc095SDavid du Colombier 			      const gs_imager_state * pis,
3917dd7cddfSDavid du Colombier 			      const gx_drawing_color * pdcolor)
3927dd7cddfSDavid du Colombier {
393*593dc095SDavid du Colombier     return gdev_vector_update_color(vdev, pis, pdcolor, &vdev->saved_fill_color,
394*593dc095SDavid du Colombier                                     vdev_proc(vdev, setfillcolor));
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier 
3977dd7cddfSDavid du Colombier /* Update the state for filling a region. */
3987dd7cddfSDavid du Colombier private int
update_fill(gx_device_vector * vdev,const gs_imager_state * pis,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)399*593dc095SDavid du Colombier update_fill(gx_device_vector * vdev, const gs_imager_state * pis,
400*593dc095SDavid du Colombier 	    const gx_drawing_color * pdcolor, gs_logical_operation_t lop)
4017dd7cddfSDavid du Colombier {
402*593dc095SDavid du Colombier     int code = gdev_vector_update_fill_color(vdev, pis, pdcolor);
4037dd7cddfSDavid du Colombier 
4047dd7cddfSDavid du Colombier     if (code < 0)
4057dd7cddfSDavid du Colombier 	return code;
4067dd7cddfSDavid du Colombier     return gdev_vector_update_log_op(vdev, lop);
4077dd7cddfSDavid du Colombier }
4087dd7cddfSDavid du Colombier 
4097dd7cddfSDavid du Colombier /* Bring state up to date for filling. */
4107dd7cddfSDavid du Colombier int
gdev_vector_prepare_fill(gx_device_vector * vdev,const gs_imager_state * pis,const gx_fill_params * params,const gx_drawing_color * pdcolor)4117dd7cddfSDavid du Colombier gdev_vector_prepare_fill(gx_device_vector * vdev, const gs_imager_state * pis,
4127dd7cddfSDavid du Colombier 	    const gx_fill_params * params, const gx_drawing_color * pdcolor)
4137dd7cddfSDavid du Colombier {
4147dd7cddfSDavid du Colombier     if (params->flatness != vdev->state.flatness) {
4157dd7cddfSDavid du Colombier 	int code = (*vdev_proc(vdev, setflat)) (vdev, params->flatness);
4167dd7cddfSDavid du Colombier 
4177dd7cddfSDavid du Colombier 	if (code < 0)
4187dd7cddfSDavid du Colombier 	    return code;
4197dd7cddfSDavid du Colombier 	vdev->state.flatness = params->flatness;
4207dd7cddfSDavid du Colombier     }
421*593dc095SDavid du Colombier     return update_fill(vdev, pis, pdcolor, pis->log_op);
4227dd7cddfSDavid du Colombier }
4237dd7cddfSDavid du Colombier 
4247dd7cddfSDavid du Colombier /* Compare two dash patterns. */
4257dd7cddfSDavid du Colombier private bool
dash_pattern_eq(const float * stored,const gx_dash_params * set,floatp scale)4267dd7cddfSDavid du Colombier dash_pattern_eq(const float *stored, const gx_dash_params * set, floatp scale)
4277dd7cddfSDavid du Colombier {
4287dd7cddfSDavid du Colombier     int i;
4297dd7cddfSDavid du Colombier 
4307dd7cddfSDavid du Colombier     for (i = 0; i < set->pattern_size; ++i)
4317dd7cddfSDavid du Colombier 	if (stored[i] != (float)(set->pattern[i] * scale))
4327dd7cddfSDavid du Colombier 	    return false;
4337dd7cddfSDavid du Colombier     return true;
4347dd7cddfSDavid du Colombier }
4357dd7cddfSDavid du Colombier 
4367dd7cddfSDavid du Colombier /* Bring state up to date for stroking. */
4377dd7cddfSDavid du Colombier int
gdev_vector_prepare_stroke(gx_device_vector * vdev,const gs_imager_state * pis,const gx_stroke_params * params,const gx_drawing_color * pdcolor,floatp scale)4383ff48bf5SDavid du Colombier gdev_vector_prepare_stroke(gx_device_vector * vdev,
4393ff48bf5SDavid du Colombier 			   const gs_imager_state * pis,	/* may be NULL */
4403ff48bf5SDavid du Colombier 			   const gx_stroke_params * params, /* may be NULL */
4413ff48bf5SDavid du Colombier 			   const gx_drawing_color * pdcolor, /* may be NULL */
4427dd7cddfSDavid du Colombier 			   floatp scale)
4437dd7cddfSDavid du Colombier {
4443ff48bf5SDavid du Colombier     if (pis) {
4457dd7cddfSDavid du Colombier 	int pattern_size = pis->line_params.dash.pattern_size;
4467dd7cddfSDavid du Colombier 	float dash_offset = pis->line_params.dash.offset * scale;
4477dd7cddfSDavid du Colombier 	float half_width = pis->line_params.half_width * scale;
4487dd7cddfSDavid du Colombier 
4497dd7cddfSDavid du Colombier 	if (pattern_size > max_dash)
4507dd7cddfSDavid du Colombier 	    return_error(gs_error_limitcheck);
4517dd7cddfSDavid du Colombier 	if (dash_offset != vdev->state.line_params.dash.offset ||
4527dd7cddfSDavid du Colombier 	    pattern_size != vdev->state.line_params.dash.pattern_size ||
4537dd7cddfSDavid du Colombier 	    (pattern_size != 0 &&
4547dd7cddfSDavid du Colombier 	     !dash_pattern_eq(vdev->dash_pattern, &pis->line_params.dash,
4557dd7cddfSDavid du Colombier 			      scale))
4567dd7cddfSDavid du Colombier 	    ) {
4577dd7cddfSDavid du Colombier 	    float pattern[max_dash];
4587dd7cddfSDavid du Colombier 	    int i, code;
4597dd7cddfSDavid du Colombier 
4607dd7cddfSDavid du Colombier 	    for (i = 0; i < pattern_size; ++i)
4617dd7cddfSDavid du Colombier 		pattern[i] = pis->line_params.dash.pattern[i] * scale;
4627dd7cddfSDavid du Colombier 	    code = (*vdev_proc(vdev, setdash))
4637dd7cddfSDavid du Colombier 		(vdev, pattern, pattern_size, dash_offset);
4647dd7cddfSDavid du Colombier 	    if (code < 0)
4657dd7cddfSDavid du Colombier 		return code;
4667dd7cddfSDavid du Colombier 	    memcpy(vdev->dash_pattern, pattern, pattern_size * sizeof(float));
4677dd7cddfSDavid du Colombier 
4687dd7cddfSDavid du Colombier 	    vdev->state.line_params.dash.pattern_size = pattern_size;
4697dd7cddfSDavid du Colombier 	    vdev->state.line_params.dash.offset = dash_offset;
4707dd7cddfSDavid du Colombier 	}
4717dd7cddfSDavid du Colombier 	if (half_width != vdev->state.line_params.half_width) {
4727dd7cddfSDavid du Colombier 	    int code = (*vdev_proc(vdev, setlinewidth))
4737dd7cddfSDavid du Colombier 		(vdev, half_width * 2);
4747dd7cddfSDavid du Colombier 
4757dd7cddfSDavid du Colombier 	    if (code < 0)
4767dd7cddfSDavid du Colombier 		return code;
4777dd7cddfSDavid du Colombier 	    vdev->state.line_params.half_width = half_width;
4787dd7cddfSDavid du Colombier 	}
4797dd7cddfSDavid du Colombier 	if (pis->line_params.miter_limit != vdev->state.line_params.miter_limit) {
4807dd7cddfSDavid du Colombier 	    int code = (*vdev_proc(vdev, setmiterlimit))
4817dd7cddfSDavid du Colombier 		(vdev, pis->line_params.miter_limit);
4827dd7cddfSDavid du Colombier 
4837dd7cddfSDavid du Colombier 	    if (code < 0)
4847dd7cddfSDavid du Colombier 		return code;
4857dd7cddfSDavid du Colombier 	    gx_set_miter_limit(&vdev->state.line_params,
4867dd7cddfSDavid du Colombier 			       pis->line_params.miter_limit);
4877dd7cddfSDavid du Colombier 	}
4887dd7cddfSDavid du Colombier 	if (pis->line_params.cap != vdev->state.line_params.cap) {
4897dd7cddfSDavid du Colombier 	    int code = (*vdev_proc(vdev, setlinecap))
4907dd7cddfSDavid du Colombier 		(vdev, pis->line_params.cap);
4917dd7cddfSDavid du Colombier 
4927dd7cddfSDavid du Colombier 	    if (code < 0)
4937dd7cddfSDavid du Colombier 		return code;
4947dd7cddfSDavid du Colombier 	    vdev->state.line_params.cap = pis->line_params.cap;
4957dd7cddfSDavid du Colombier 	}
4967dd7cddfSDavid du Colombier 	if (pis->line_params.join != vdev->state.line_params.join) {
4977dd7cddfSDavid du Colombier 	    int code = (*vdev_proc(vdev, setlinejoin))
4987dd7cddfSDavid du Colombier 		(vdev, pis->line_params.join);
4997dd7cddfSDavid du Colombier 
5007dd7cddfSDavid du Colombier 	    if (code < 0)
5017dd7cddfSDavid du Colombier 		return code;
5027dd7cddfSDavid du Colombier 	    vdev->state.line_params.join = pis->line_params.join;
5037dd7cddfSDavid du Colombier 	} {
5047dd7cddfSDavid du Colombier 	    int code = gdev_vector_update_log_op(vdev, pis->log_op);
5057dd7cddfSDavid du Colombier 
5067dd7cddfSDavid du Colombier 	    if (code < 0)
5077dd7cddfSDavid du Colombier 		return code;
5087dd7cddfSDavid du Colombier 	}
5093ff48bf5SDavid du Colombier     }
5103ff48bf5SDavid du Colombier     if (params) {
5113ff48bf5SDavid du Colombier 	if (params->flatness != vdev->state.flatness) {
5123ff48bf5SDavid du Colombier 	    int code = (*vdev_proc(vdev, setflat)) (vdev, params->flatness);
5133ff48bf5SDavid du Colombier 
5143ff48bf5SDavid du Colombier 	    if (code < 0)
5153ff48bf5SDavid du Colombier 		return code;
5163ff48bf5SDavid du Colombier 	    vdev->state.flatness = params->flatness;
5173ff48bf5SDavid du Colombier 	}
5183ff48bf5SDavid du Colombier     }
5193ff48bf5SDavid du Colombier     if (pdcolor) {
520*593dc095SDavid du Colombier 	int code = gdev_vector_update_color(vdev, pis, pdcolor,
521*593dc095SDavid du Colombier 		    &vdev->saved_stroke_color, vdev_proc(vdev, setstrokecolor));
5227dd7cddfSDavid du Colombier 
5237dd7cddfSDavid du Colombier 	if (code < 0)
5247dd7cddfSDavid du Colombier 	    return code;
5253ff48bf5SDavid du Colombier     }
5267dd7cddfSDavid du Colombier     return 0;
5277dd7cddfSDavid du Colombier }
5287dd7cddfSDavid du Colombier 
5297dd7cddfSDavid du Colombier /*
5303ff48bf5SDavid du Colombier  * Compute the scale for transforming the line width and dash pattern for a
5313ff48bf5SDavid du Colombier  * stroke operation, and, if necessary to handle anisotropic scaling, a full
5323ff48bf5SDavid du Colombier  * transformation matrix to be inverse-applied to the path elements as well.
5333ff48bf5SDavid du Colombier  * Return 0 if only scaling, 1 if a full matrix is needed.
5347dd7cddfSDavid du Colombier  */
5357dd7cddfSDavid du Colombier int
gdev_vector_stroke_scaling(const gx_device_vector * vdev,const gs_imager_state * pis,double * pscale,gs_matrix * pmat)5367dd7cddfSDavid du Colombier gdev_vector_stroke_scaling(const gx_device_vector *vdev,
5377dd7cddfSDavid du Colombier 			   const gs_imager_state *pis,
5387dd7cddfSDavid du Colombier 			   double *pscale, gs_matrix *pmat)
5397dd7cddfSDavid du Colombier {
5407dd7cddfSDavid du Colombier     bool set_ctm = true;
5417dd7cddfSDavid du Colombier     double scale = 1;
5427dd7cddfSDavid du Colombier 
5437dd7cddfSDavid du Colombier     /*
5447dd7cddfSDavid du Colombier      * If the CTM is not uniform, stroke width depends on angle.
5457dd7cddfSDavid du Colombier      * We'd like to avoid resetting the CTM, so we check for uniform
5467dd7cddfSDavid du Colombier      * CTMs explicitly.  Note that in PDF, unlike PostScript, it is
5477dd7cddfSDavid du Colombier      * the CTM at the time of the stroke operation, not the CTM at
5487dd7cddfSDavid du Colombier      * the time the path was constructed, that is used for transforming
5497dd7cddfSDavid du Colombier      * the points of the path; so if we have to reset the CTM, we must
5507dd7cddfSDavid du Colombier      * do it before constructing the path, and inverse-transform all
5517dd7cddfSDavid du Colombier      * the coordinates.
5527dd7cddfSDavid du Colombier      */
5537dd7cddfSDavid du Colombier     if (is_xxyy(&pis->ctm)) {
5547dd7cddfSDavid du Colombier 	scale = fabs(pis->ctm.xx);
5557dd7cddfSDavid du Colombier 	set_ctm = fabs(pis->ctm.yy) != scale;
5567dd7cddfSDavid du Colombier     } else if (is_xyyx(&pis->ctm)) {
5577dd7cddfSDavid du Colombier 	scale = fabs(pis->ctm.xy);
5587dd7cddfSDavid du Colombier 	set_ctm = fabs(pis->ctm.yx) != scale;
5597dd7cddfSDavid du Colombier     } else if ((pis->ctm.xx == pis->ctm.yy && pis->ctm.xy == -pis->ctm.yx) ||
5607dd7cddfSDavid du Colombier 	       (pis->ctm.xx == -pis->ctm.yy && pis->ctm.xy == pis->ctm.yx)
5617dd7cddfSDavid du Colombier 	) {
5627dd7cddfSDavid du Colombier 	scale = hypot(pis->ctm.xx, pis->ctm.xy);
5637dd7cddfSDavid du Colombier 	set_ctm = false;
5647dd7cddfSDavid du Colombier     }
5657dd7cddfSDavid du Colombier     if (set_ctm) {
5667dd7cddfSDavid du Colombier 	/*
5673ff48bf5SDavid du Colombier 	 * Adobe Acrobat Reader has limitations on the maximum user
5683ff48bf5SDavid du Colombier 	 * coordinate value.  If we scale the matrix down too far, the
5693ff48bf5SDavid du Colombier 	 * coordinates will get too big: limit the scale factor to prevent
5703ff48bf5SDavid du Colombier 	 * this from happening.  (This does no harm for other output
5713ff48bf5SDavid du Colombier 	 * formats.)
5727dd7cddfSDavid du Colombier 	 */
5737dd7cddfSDavid du Colombier 	double
5747dd7cddfSDavid du Colombier 	    mxx = pis->ctm.xx / vdev->scale.x,
5757dd7cddfSDavid du Colombier 	    mxy = pis->ctm.xy / vdev->scale.y,
5767dd7cddfSDavid du Colombier 	    myx = pis->ctm.yx / vdev->scale.x,
5777dd7cddfSDavid du Colombier 	    myy = pis->ctm.yy / vdev->scale.y;
5787dd7cddfSDavid du Colombier 
5797dd7cddfSDavid du Colombier 	scale = 0.5 * (fabs(mxx) + fabs(mxy) + fabs(myx) + fabs(myy));
5807dd7cddfSDavid du Colombier 	pmat->xx = mxx / scale, pmat->xy = mxy / scale;
5817dd7cddfSDavid du Colombier 	pmat->yx = myx / scale, pmat->yy = myy / scale;
5827dd7cddfSDavid du Colombier 	pmat->tx = pmat->ty = 0;
5837dd7cddfSDavid du Colombier     }
5847dd7cddfSDavid du Colombier     *pscale = scale;
5857dd7cddfSDavid du Colombier     return (int)set_ctm;
5867dd7cddfSDavid du Colombier }
5877dd7cddfSDavid du Colombier 
5887dd7cddfSDavid du Colombier /* Initialize for writing a path using the default implementation. */
5897dd7cddfSDavid du Colombier void
gdev_vector_dopath_init(gdev_vector_dopath_state_t * state,gx_device_vector * vdev,gx_path_type_t type,const gs_matrix * pmat)5907dd7cddfSDavid du Colombier gdev_vector_dopath_init(gdev_vector_dopath_state_t *state,
5917dd7cddfSDavid du Colombier 			gx_device_vector *vdev, gx_path_type_t type,
5927dd7cddfSDavid du Colombier 			const gs_matrix *pmat)
5937dd7cddfSDavid du Colombier {
5947dd7cddfSDavid du Colombier     state->vdev = vdev;
5957dd7cddfSDavid du Colombier     state->type = type;
5967dd7cddfSDavid du Colombier     if (pmat) {
5977dd7cddfSDavid du Colombier 	state->scale_mat = *pmat;
5987dd7cddfSDavid du Colombier 	/*
5997dd7cddfSDavid du Colombier 	 * The path element writing procedures all divide the coordinates
6007dd7cddfSDavid du Colombier 	 * by the scale, so we must compensate for that here.
6017dd7cddfSDavid du Colombier 	 */
6027dd7cddfSDavid du Colombier 	gs_matrix_scale(&state->scale_mat, 1.0 / vdev->scale.x,
6037dd7cddfSDavid du Colombier 			1.0 / vdev->scale.y, &state->scale_mat);
6047dd7cddfSDavid du Colombier     } else {
6057dd7cddfSDavid du Colombier 	gs_make_scaling(vdev->scale.x, vdev->scale.y, &state->scale_mat);
6067dd7cddfSDavid du Colombier     }
6077dd7cddfSDavid du Colombier     state->first = true;
6087dd7cddfSDavid du Colombier }
6097dd7cddfSDavid du Colombier 
6107dd7cddfSDavid du Colombier /*
6117dd7cddfSDavid du Colombier  * Put a segment of an enumerated path on the output file.
6127dd7cddfSDavid du Colombier  * pe_op is assumed to be valid and non-zero.
6137dd7cddfSDavid du Colombier  */
6147dd7cddfSDavid du Colombier int
gdev_vector_dopath_segment(gdev_vector_dopath_state_t * state,int pe_op,gs_fixed_point vs[3])6157dd7cddfSDavid du Colombier gdev_vector_dopath_segment(gdev_vector_dopath_state_t *state, int pe_op,
6167dd7cddfSDavid du Colombier 			   gs_fixed_point vs[3])
6177dd7cddfSDavid du Colombier {
6187dd7cddfSDavid du Colombier     gx_device_vector *vdev = state->vdev;
6197dd7cddfSDavid du Colombier     const gs_matrix *const pmat = &state->scale_mat;
6207dd7cddfSDavid du Colombier     gs_point vp[3];
6217dd7cddfSDavid du Colombier     int code;
6227dd7cddfSDavid du Colombier 
6237dd7cddfSDavid du Colombier     switch (pe_op) {
6247dd7cddfSDavid du Colombier 	case gs_pe_moveto:
625*593dc095SDavid du Colombier 	    code = gs_point_transform_inverse(fixed2float(vs[0].x),
6267dd7cddfSDavid du Colombier 				       fixed2float(vs[0].y), pmat, &vp[0]);
627*593dc095SDavid du Colombier 	    if (code < 0)
628*593dc095SDavid du Colombier 		return code;
6297dd7cddfSDavid du Colombier 	    if (state->first)
6307dd7cddfSDavid du Colombier 		state->start = vp[0], state->first = false;
6317dd7cddfSDavid du Colombier 	    code = vdev_proc(vdev, moveto)
632*593dc095SDavid du Colombier 		(vdev, 0/*unused*/, 0/*unused*/, vp[0].x, vp[0].y,
6337dd7cddfSDavid du Colombier 		 state->type);
6347dd7cddfSDavid du Colombier 	    state->prev = vp[0];
6357dd7cddfSDavid du Colombier 	    break;
6367dd7cddfSDavid du Colombier 	case gs_pe_lineto:
637*593dc095SDavid du Colombier 	    code = gs_point_transform_inverse(fixed2float(vs[0].x),
6387dd7cddfSDavid du Colombier 				       fixed2float(vs[0].y), pmat, &vp[0]);
639*593dc095SDavid du Colombier 	    if (code < 0)
640*593dc095SDavid du Colombier 		return code;
6417dd7cddfSDavid du Colombier 	    code = vdev_proc(vdev, lineto)
6427dd7cddfSDavid du Colombier 		(vdev, state->prev.x, state->prev.y, vp[0].x, vp[0].y,
6437dd7cddfSDavid du Colombier 		 state->type);
6447dd7cddfSDavid du Colombier 	    state->prev = vp[0];
6457dd7cddfSDavid du Colombier 	    break;
6467dd7cddfSDavid du Colombier 	case gs_pe_curveto:
647*593dc095SDavid du Colombier 	    code = gs_point_transform_inverse(fixed2float(vs[0].x),
6487dd7cddfSDavid du Colombier 				       fixed2float(vs[0].y), pmat, &vp[0]);
649*593dc095SDavid du Colombier 	    if (code < 0)
650*593dc095SDavid du Colombier 		return code;
651*593dc095SDavid du Colombier 	    code = gs_point_transform_inverse(fixed2float(vs[1].x),
6527dd7cddfSDavid du Colombier 				       fixed2float(vs[1].y), pmat, &vp[1]);
653*593dc095SDavid du Colombier 	    if (code < 0)
654*593dc095SDavid du Colombier 		return code;
6557dd7cddfSDavid du Colombier 	    gs_point_transform_inverse(fixed2float(vs[2].x),
6567dd7cddfSDavid du Colombier 				       fixed2float(vs[2].y), pmat, &vp[2]);
6577dd7cddfSDavid du Colombier 	    code = vdev_proc(vdev, curveto)
6587dd7cddfSDavid du Colombier 		(vdev, state->prev.x, state->prev.y, vp[0].x, vp[0].y,
6597dd7cddfSDavid du Colombier 		 vp[1].x, vp[1].y, vp[2].x, vp[2].y, state->type);
6607dd7cddfSDavid du Colombier 	    state->prev = vp[2];
6617dd7cddfSDavid du Colombier 	    break;
6627dd7cddfSDavid du Colombier 	case gs_pe_closepath:
6637dd7cddfSDavid du Colombier 	    code = vdev_proc(vdev, closepath)
6647dd7cddfSDavid du Colombier 		(vdev, state->prev.x, state->prev.y, state->start.x,
6657dd7cddfSDavid du Colombier 		 state->start.y, state->type);
6667dd7cddfSDavid du Colombier 	    state->prev = state->start;
6677dd7cddfSDavid du Colombier 	    break;
6687dd7cddfSDavid du Colombier 	default:		/* can't happen */
6697dd7cddfSDavid du Colombier 	    return -1;
6707dd7cddfSDavid du Colombier     }
6717dd7cddfSDavid du Colombier     return code;
6727dd7cddfSDavid du Colombier }
6737dd7cddfSDavid du Colombier 
6747dd7cddfSDavid du Colombier /* Write a polygon as part of a path. */
6757dd7cddfSDavid du Colombier /* May call beginpath, moveto, lineto, closepath, endpath. */
6767dd7cddfSDavid du Colombier int
gdev_vector_write_polygon(gx_device_vector * vdev,const gs_fixed_point * points,uint count,bool close,gx_path_type_t type)6777dd7cddfSDavid du Colombier gdev_vector_write_polygon(gx_device_vector * vdev, const gs_fixed_point * points,
6787dd7cddfSDavid du Colombier 			  uint count, bool close, gx_path_type_t type)
6797dd7cddfSDavid du Colombier {
6807dd7cddfSDavid du Colombier     int code = 0;
6817dd7cddfSDavid du Colombier 
6827dd7cddfSDavid du Colombier     if (type != gx_path_type_none &&
6837dd7cddfSDavid du Colombier 	(code = (*vdev_proc(vdev, beginpath)) (vdev, type)) < 0
6847dd7cddfSDavid du Colombier 	)
6857dd7cddfSDavid du Colombier 	return code;
6867dd7cddfSDavid du Colombier     if (count > 0) {
6877dd7cddfSDavid du Colombier 	double x = fixed2float(points[0].x) / vdev->scale.x, y = fixed2float(points[0].y) / vdev->scale.y;
6887dd7cddfSDavid du Colombier 	double x_start = x, y_start = y, x_prev, y_prev;
6897dd7cddfSDavid du Colombier 	uint i;
6907dd7cddfSDavid du Colombier 
6917dd7cddfSDavid du Colombier 	code = (*vdev_proc(vdev, moveto))
6927dd7cddfSDavid du Colombier 	    (vdev, 0.0, 0.0, x, y, type);
6937dd7cddfSDavid du Colombier 	if (code >= 0)
6947dd7cddfSDavid du Colombier 	    for (i = 1; i < count && code >= 0; ++i) {
6957dd7cddfSDavid du Colombier 		x_prev = x, y_prev = y;
6967dd7cddfSDavid du Colombier 		code = (*vdev_proc(vdev, lineto))
6977dd7cddfSDavid du Colombier 		    (vdev, x_prev, y_prev,
6987dd7cddfSDavid du Colombier 		     (x = fixed2float(points[i].x) / vdev->scale.x),
6997dd7cddfSDavid du Colombier 		     (y = fixed2float(points[i].y) / vdev->scale.y),
7007dd7cddfSDavid du Colombier 		     type);
7017dd7cddfSDavid du Colombier 	    }
7027dd7cddfSDavid du Colombier 	if (code >= 0 && close)
7037dd7cddfSDavid du Colombier 	    code = (*vdev_proc(vdev, closepath))
7047dd7cddfSDavid du Colombier 		(vdev, x, y, x_start, y_start, type);
7057dd7cddfSDavid du Colombier     }
7067dd7cddfSDavid du Colombier     return (code >= 0 && type != gx_path_type_none ?
7077dd7cddfSDavid du Colombier 	    (*vdev_proc(vdev, endpath)) (vdev, type) : code);
7087dd7cddfSDavid du Colombier }
7097dd7cddfSDavid du Colombier 
7107dd7cddfSDavid du Colombier /* Write a rectangle as part of a path. */
7117dd7cddfSDavid du Colombier /* May call moveto, lineto, closepath. */
7127dd7cddfSDavid du Colombier int
gdev_vector_write_rectangle(gx_device_vector * vdev,fixed x0,fixed y0,fixed x1,fixed y1,bool close,gx_rect_direction_t direction)7137dd7cddfSDavid du Colombier gdev_vector_write_rectangle(gx_device_vector * vdev, fixed x0, fixed y0,
7147dd7cddfSDavid du Colombier 	      fixed x1, fixed y1, bool close, gx_rect_direction_t direction)
7157dd7cddfSDavid du Colombier {
7167dd7cddfSDavid du Colombier     gs_fixed_point points[4];
7177dd7cddfSDavid du Colombier 
7187dd7cddfSDavid du Colombier     points[0].x = x0, points[0].y = y0;
7197dd7cddfSDavid du Colombier     points[2].x = x1, points[2].y = y1;
7207dd7cddfSDavid du Colombier     if (direction == gx_rect_x_first)
7217dd7cddfSDavid du Colombier 	points[1].x = x1, points[1].y = y0,
7227dd7cddfSDavid du Colombier 	    points[3].x = x0, points[3].y = y1;
7237dd7cddfSDavid du Colombier     else
7247dd7cddfSDavid du Colombier 	points[1].x = x0, points[1].y = y1,
7257dd7cddfSDavid du Colombier 	    points[3].x = x1, points[3].y = y0;
7267dd7cddfSDavid du Colombier     return gdev_vector_write_polygon(vdev, points, 4, close,
7277dd7cddfSDavid du Colombier 				     gx_path_type_none);
7287dd7cddfSDavid du Colombier }
7297dd7cddfSDavid du Colombier 
7307dd7cddfSDavid du Colombier /* Write a clipping path by calling the path procedures. */
7317dd7cddfSDavid du Colombier int
gdev_vector_write_clip_path(gx_device_vector * vdev,const gx_clip_path * pcpath)7327dd7cddfSDavid du Colombier gdev_vector_write_clip_path(gx_device_vector * vdev,
7337dd7cddfSDavid du Colombier 			    const gx_clip_path * pcpath)
7347dd7cddfSDavid du Colombier {
7357dd7cddfSDavid du Colombier     const gx_clip_rect *prect;
7367dd7cddfSDavid du Colombier     gx_clip_rect page_rect;
7377dd7cddfSDavid du Colombier     int code;
7387dd7cddfSDavid du Colombier 
7397dd7cddfSDavid du Colombier     if (pcpath == 0) {
7407dd7cddfSDavid du Colombier 	/* There's no special provision for initclip. */
7417dd7cddfSDavid du Colombier 	/* Write a rectangle that covers the entire page. */
7427dd7cddfSDavid du Colombier 	page_rect.xmin = page_rect.ymin = 0;
7437dd7cddfSDavid du Colombier 	page_rect.xmax = vdev->width;
7447dd7cddfSDavid du Colombier 	page_rect.ymax = vdev->height;
7457dd7cddfSDavid du Colombier 	page_rect.next = 0;
7467dd7cddfSDavid du Colombier 	prect = &page_rect;
7477dd7cddfSDavid du Colombier     } else if (pcpath->path_valid) {
7487dd7cddfSDavid du Colombier 	return (*vdev_proc(vdev, dopath))
7497dd7cddfSDavid du Colombier 	    (vdev, &pcpath->path,
7507dd7cddfSDavid du Colombier 	     (pcpath->rule <= 0 ?
7517dd7cddfSDavid du Colombier 	      gx_path_type_clip | gx_path_type_winding_number :
7527dd7cddfSDavid du Colombier 	      gx_path_type_clip | gx_path_type_even_odd),
7537dd7cddfSDavid du Colombier 	     NULL);
7547dd7cddfSDavid du Colombier     } else {
7557dd7cddfSDavid du Colombier 	const gx_clip_list *list = gx_cpath_list(pcpath);
7567dd7cddfSDavid du Colombier 
7577dd7cddfSDavid du Colombier 	prect = list->head;
7587dd7cddfSDavid du Colombier 	if (prect == 0)
7597dd7cddfSDavid du Colombier 	    prect = &list->single;
7607dd7cddfSDavid du Colombier     }
7617dd7cddfSDavid du Colombier     /* Write out the rectangles. */
7627dd7cddfSDavid du Colombier     code = (*vdev_proc(vdev, beginpath)) (vdev, gx_path_type_clip);
7637dd7cddfSDavid du Colombier     for (; code >= 0 && prect != 0; prect = prect->next)
7647dd7cddfSDavid du Colombier 	if (prect->xmax > prect->xmin && prect->ymax > prect->ymin)
7657dd7cddfSDavid du Colombier 	    code = gdev_vector_write_rectangle
7667dd7cddfSDavid du Colombier 		(vdev, int2fixed(prect->xmin), int2fixed(prect->ymin),
7677dd7cddfSDavid du Colombier 		 int2fixed(prect->xmax), int2fixed(prect->ymax),
7687dd7cddfSDavid du Colombier 		 false, gx_rect_x_first);
7697dd7cddfSDavid du Colombier     if (code >= 0)
7707dd7cddfSDavid du Colombier 	code = (*vdev_proc(vdev, endpath)) (vdev, gx_path_type_clip);
7717dd7cddfSDavid du Colombier     return code;
7727dd7cddfSDavid du Colombier }
7737dd7cddfSDavid du Colombier 
7747dd7cddfSDavid du Colombier /* Update the clipping path if needed. */
7757dd7cddfSDavid du Colombier int
gdev_vector_update_clip_path(gx_device_vector * vdev,const gx_clip_path * pcpath)7767dd7cddfSDavid du Colombier gdev_vector_update_clip_path(gx_device_vector * vdev,
7777dd7cddfSDavid du Colombier 			     const gx_clip_path * pcpath)
7787dd7cddfSDavid du Colombier {
7797dd7cddfSDavid du Colombier     if (pcpath) {
7807dd7cddfSDavid du Colombier 	if (pcpath->id != vdev->clip_path_id) {
7817dd7cddfSDavid du Colombier 	    int code = gdev_vector_write_clip_path(vdev, pcpath);
7827dd7cddfSDavid du Colombier 
7837dd7cddfSDavid du Colombier 	    if (code < 0)
7847dd7cddfSDavid du Colombier 		return code;
7857dd7cddfSDavid du Colombier 	    vdev->clip_path_id = pcpath->id;
7867dd7cddfSDavid du Colombier 	}
7877dd7cddfSDavid du Colombier     } else {
7887dd7cddfSDavid du Colombier 	if (vdev->clip_path_id != vdev->no_clip_path_id) {
7897dd7cddfSDavid du Colombier 	    int code = gdev_vector_write_clip_path(vdev, NULL);
7907dd7cddfSDavid du Colombier 
7917dd7cddfSDavid du Colombier 	    if (code < 0)
7927dd7cddfSDavid du Colombier 		return code;
7937dd7cddfSDavid du Colombier 	    vdev->clip_path_id = vdev->no_clip_path_id;
7947dd7cddfSDavid du Colombier 	}
7957dd7cddfSDavid du Colombier     }
7967dd7cddfSDavid du Colombier     return 0;
7977dd7cddfSDavid du Colombier }
7987dd7cddfSDavid du Colombier 
7997dd7cddfSDavid du Colombier /* Close the output file and stream. */
8007dd7cddfSDavid du Colombier int
gdev_vector_close_file(gx_device_vector * vdev)8017dd7cddfSDavid du Colombier gdev_vector_close_file(gx_device_vector * vdev)
8027dd7cddfSDavid du Colombier {
8037dd7cddfSDavid du Colombier     FILE *f = vdev->file;
8047dd7cddfSDavid du Colombier     int err;
8057dd7cddfSDavid du Colombier 
8067dd7cddfSDavid du Colombier     gs_free_object(vdev->v_memory, vdev->bbox_device,
8077dd7cddfSDavid du Colombier 		   "vector_close(bbox_device)");
8087dd7cddfSDavid du Colombier     vdev->bbox_device = 0;
8097dd7cddfSDavid du Colombier     sclose(vdev->strm);
8107dd7cddfSDavid du Colombier     gs_free_object(vdev->v_memory, vdev->strm, "vector_close(strm)");
8117dd7cddfSDavid du Colombier     vdev->strm = 0;
8127dd7cddfSDavid du Colombier     gs_free_object(vdev->v_memory, vdev->strmbuf, "vector_close(strmbuf)");
8137dd7cddfSDavid du Colombier     vdev->strmbuf = 0;
8147dd7cddfSDavid du Colombier     vdev->file = 0;
8157dd7cddfSDavid du Colombier     err = ferror(f);
8167dd7cddfSDavid du Colombier     /* We prevented sclose from closing the file. */
817*593dc095SDavid du Colombier     if (gx_device_close_output_file((gx_device *)vdev, vdev->fname, f) != 0
818*593dc095SDavid du Colombier 	|| err != 0)
8197dd7cddfSDavid du Colombier 	return_error(gs_error_ioerror);
8207dd7cddfSDavid du Colombier     return 0;
8217dd7cddfSDavid du Colombier }
8227dd7cddfSDavid du Colombier 
8237dd7cddfSDavid du Colombier /* ---------------- Image enumeration ---------------- */
8247dd7cddfSDavid du Colombier 
8257dd7cddfSDavid du Colombier /* Initialize for enumerating an image. */
8267dd7cddfSDavid du Colombier int
gdev_vector_begin_image(gx_device_vector * vdev,const gs_imager_state * pis,const gs_image_t * pim,gs_image_format_t format,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,const gx_image_enum_procs_t * pprocs,gdev_vector_image_enum_t * pie)8277dd7cddfSDavid du Colombier gdev_vector_begin_image(gx_device_vector * vdev,
8287dd7cddfSDavid du Colombier 			const gs_imager_state * pis, const gs_image_t * pim,
8297dd7cddfSDavid du Colombier 			gs_image_format_t format, const gs_int_rect * prect,
8307dd7cddfSDavid du Colombier 	      const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
8317dd7cddfSDavid du Colombier 		    gs_memory_t * mem, const gx_image_enum_procs_t * pprocs,
8327dd7cddfSDavid du Colombier 			gdev_vector_image_enum_t * pie)
8337dd7cddfSDavid du Colombier {
8347dd7cddfSDavid du Colombier     const gs_color_space *pcs = pim->ColorSpace;
8357dd7cddfSDavid du Colombier     int num_components;
8367dd7cddfSDavid du Colombier     int bits_per_pixel;
8377dd7cddfSDavid du Colombier     int code;
8387dd7cddfSDavid du Colombier 
8397dd7cddfSDavid du Colombier     if (pim->ImageMask)
8407dd7cddfSDavid du Colombier 	bits_per_pixel = num_components = 1;
8417dd7cddfSDavid du Colombier     else
8427dd7cddfSDavid du Colombier 	num_components = gs_color_space_num_components(pcs),
8437dd7cddfSDavid du Colombier 	    bits_per_pixel = pim->BitsPerComponent;
8447dd7cddfSDavid du Colombier     code = gx_image_enum_common_init((gx_image_enum_common_t *) pie,
8457dd7cddfSDavid du Colombier 				     (const gs_data_image_t *)pim,
8467dd7cddfSDavid du Colombier 				     pprocs, (gx_device *) vdev,
8477dd7cddfSDavid du Colombier 				     num_components, format);
8487dd7cddfSDavid du Colombier     if (code < 0)
8497dd7cddfSDavid du Colombier 	return code;
8507dd7cddfSDavid du Colombier     pie->bits_per_pixel = bits_per_pixel * num_components /
8517dd7cddfSDavid du Colombier 	pie->num_planes;
8527dd7cddfSDavid du Colombier     pie->default_info = 0;
8537dd7cddfSDavid du Colombier     pie->bbox_info = 0;
8547dd7cddfSDavid du Colombier     if ((code = gdev_vector_update_log_op(vdev, pis->log_op)) < 0 ||
8557dd7cddfSDavid du Colombier 	(code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 ||
8567dd7cddfSDavid du Colombier 	((pim->ImageMask ||
8577dd7cddfSDavid du Colombier 	  (pim->CombineWithColor && rop3_uses_T(pis->log_op))) &&
858*593dc095SDavid du Colombier 	 (code = gdev_vector_update_fill_color(vdev, pis, pdcolor)) < 0) ||
8597dd7cddfSDavid du Colombier 	(vdev->bbox_device &&
8607dd7cddfSDavid du Colombier 	 (code = (*dev_proc(vdev->bbox_device, begin_image))
8617dd7cddfSDavid du Colombier 	  ((gx_device *) vdev->bbox_device, pis, pim, format, prect,
8627dd7cddfSDavid du Colombier 	   pdcolor, pcpath, mem, &pie->bbox_info)) < 0)
8637dd7cddfSDavid du Colombier 	)
8647dd7cddfSDavid du Colombier 	return code;
8657dd7cddfSDavid du Colombier     pie->memory = mem;
8667dd7cddfSDavid du Colombier     if (prect)
8677dd7cddfSDavid du Colombier 	pie->width = prect->q.x - prect->p.x,
8687dd7cddfSDavid du Colombier 	    pie->height = prect->q.y - prect->p.y;
8697dd7cddfSDavid du Colombier     else
8707dd7cddfSDavid du Colombier 	pie->width = pim->Width, pie->height = pim->Height;
8717dd7cddfSDavid du Colombier     pie->bits_per_row = pie->width * pie->bits_per_pixel;
8727dd7cddfSDavid du Colombier     pie->y = 0;
8737dd7cddfSDavid du Colombier     return 0;
8747dd7cddfSDavid du Colombier }
8757dd7cddfSDavid du Colombier 
8767dd7cddfSDavid du Colombier /* End an image, optionally supplying any necessary blank padding rows. */
8777dd7cddfSDavid du Colombier /* Return 0 if we used the default implementation, 1 if not. */
8787dd7cddfSDavid du Colombier int
gdev_vector_end_image(gx_device_vector * vdev,gdev_vector_image_enum_t * pie,bool draw_last,gx_color_index pad)8797dd7cddfSDavid du Colombier gdev_vector_end_image(gx_device_vector * vdev,
8807dd7cddfSDavid du Colombier 	 gdev_vector_image_enum_t * pie, bool draw_last, gx_color_index pad)
8817dd7cddfSDavid du Colombier {
8827dd7cddfSDavid du Colombier     int code;
8837dd7cddfSDavid du Colombier 
8847dd7cddfSDavid du Colombier     if (pie->default_info) {
8857dd7cddfSDavid du Colombier 	code = gx_default_end_image((gx_device *) vdev, pie->default_info,
8867dd7cddfSDavid du Colombier 				    draw_last);
8877dd7cddfSDavid du Colombier 	if (code >= 0)
8887dd7cddfSDavid du Colombier 	    code = 0;
8897dd7cddfSDavid du Colombier     } else {			/* Fill out to the full image height. */
8907dd7cddfSDavid du Colombier 	if (pie->y < pie->height && pad != gx_no_color_index) {
8917dd7cddfSDavid du Colombier 	    uint bytes_per_row = (pie->bits_per_row + 7) >> 3;
8927dd7cddfSDavid du Colombier 	    byte *row = gs_alloc_bytes(pie->memory, bytes_per_row,
8937dd7cddfSDavid du Colombier 				       "gdev_vector_end_image(fill)");
8947dd7cddfSDavid du Colombier 
8957dd7cddfSDavid du Colombier 	    if (row == 0)
8967dd7cddfSDavid du Colombier 		return_error(gs_error_VMerror);
8977dd7cddfSDavid du Colombier /****** FILL VALUE IS WRONG ******/
8987dd7cddfSDavid du Colombier 	    memset(row, (byte) pad, bytes_per_row);
8997dd7cddfSDavid du Colombier 	    for (; pie->y < pie->height; pie->y++)
9007dd7cddfSDavid du Colombier 		gx_image_data((gx_image_enum_common_t *) pie,
9017dd7cddfSDavid du Colombier 			      (const byte **)&row, 0,
9027dd7cddfSDavid du Colombier 			      bytes_per_row, 1);
9037dd7cddfSDavid du Colombier 	    gs_free_object(pie->memory, row,
9047dd7cddfSDavid du Colombier 			   "gdev_vector_end_image(fill)");
9057dd7cddfSDavid du Colombier 	}
9067dd7cddfSDavid du Colombier 	code = 1;
9077dd7cddfSDavid du Colombier     }
9087dd7cddfSDavid du Colombier     if (vdev->bbox_device) {
9097dd7cddfSDavid du Colombier 	int bcode = gx_image_end(pie->bbox_info, draw_last);
9107dd7cddfSDavid du Colombier 
9117dd7cddfSDavid du Colombier 	if (bcode < 0)
9127dd7cddfSDavid du Colombier 	    code = bcode;
9137dd7cddfSDavid du Colombier     }
9147dd7cddfSDavid du Colombier     gs_free_object(pie->memory, pie, "gdev_vector_end_image");
9157dd7cddfSDavid du Colombier     return code;
9167dd7cddfSDavid du Colombier }
9177dd7cddfSDavid du Colombier 
9187dd7cddfSDavid du Colombier /* ================ Device procedures ================ */
9197dd7cddfSDavid du Colombier 
9207dd7cddfSDavid du Colombier #define vdev ((gx_device_vector *)dev)
9217dd7cddfSDavid du Colombier 
9227dd7cddfSDavid du Colombier /* Get parameters. */
9237dd7cddfSDavid du Colombier int
gdev_vector_get_params(gx_device * dev,gs_param_list * plist)9247dd7cddfSDavid du Colombier gdev_vector_get_params(gx_device * dev, gs_param_list * plist)
9257dd7cddfSDavid du Colombier {
9267dd7cddfSDavid du Colombier     int code = gx_default_get_params(dev, plist);
9277dd7cddfSDavid du Colombier     int ecode;
9287dd7cddfSDavid du Colombier     gs_param_string ofns;
9297dd7cddfSDavid du Colombier 
9307dd7cddfSDavid du Colombier     if (code < 0)
9317dd7cddfSDavid du Colombier 	return code;
9327dd7cddfSDavid du Colombier     ofns.data = (const byte *)vdev->fname,
9337dd7cddfSDavid du Colombier 	ofns.size = strlen(vdev->fname),
9347dd7cddfSDavid du Colombier 	ofns.persistent = false;
9357dd7cddfSDavid du Colombier     if ((ecode = param_write_string(plist, "OutputFile", &ofns)) < 0)
9367dd7cddfSDavid du Colombier 	return ecode;
9377dd7cddfSDavid du Colombier     return code;
9387dd7cddfSDavid du Colombier }
9397dd7cddfSDavid du Colombier 
9407dd7cddfSDavid du Colombier /* Put parameters. */
9417dd7cddfSDavid du Colombier int
gdev_vector_put_params(gx_device * dev,gs_param_list * plist)9427dd7cddfSDavid du Colombier gdev_vector_put_params(gx_device * dev, gs_param_list * plist)
9437dd7cddfSDavid du Colombier {
9447dd7cddfSDavid du Colombier     int ecode = 0;
9457dd7cddfSDavid du Colombier     int code;
9467dd7cddfSDavid du Colombier     gs_param_name param_name;
9477dd7cddfSDavid du Colombier     gs_param_string ofns;
9487dd7cddfSDavid du Colombier 
9497dd7cddfSDavid du Colombier     switch (code = param_read_string(plist, (param_name = "OutputFile"), &ofns)) {
9507dd7cddfSDavid du Colombier 	case 0:
9513ff48bf5SDavid du Colombier 	    /*
9523ff48bf5SDavid du Colombier 	     * Vector devices typically write header information at the
9533ff48bf5SDavid du Colombier 	     * beginning of the file: changing the file name after writing
9543ff48bf5SDavid du Colombier 	     * any pages should be an error.
9553ff48bf5SDavid du Colombier 	     */
9567dd7cddfSDavid du Colombier 	    if (ofns.size > fname_size)
9577dd7cddfSDavid du Colombier 		ecode = gs_error_limitcheck;
9583ff48bf5SDavid du Colombier 	    else if (!bytes_compare(ofns.data, ofns.size,
9593ff48bf5SDavid du Colombier 				    (const byte *)vdev->fname,
9603ff48bf5SDavid du Colombier 				    strlen(vdev->fname))
9613ff48bf5SDavid du Colombier 		     ) {
9623ff48bf5SDavid du Colombier 		/* The new name is the same as the old name.  Do nothing. */
9633ff48bf5SDavid du Colombier 		ofns.data = 0;
9643ff48bf5SDavid du Colombier 		break;
9653ff48bf5SDavid du Colombier 	    } else if (dev->LockSafetyParams ||
9663ff48bf5SDavid du Colombier 	    		(dev->is_open && vdev->strm != 0 &&
9673ff48bf5SDavid du Colombier 		       stell(vdev->strm) != 0)
9683ff48bf5SDavid du Colombier 		       )
9693ff48bf5SDavid du Colombier 		ecode = (dev->LockSafetyParams) ? gs_error_invalidaccess :
9703ff48bf5SDavid du Colombier 				gs_error_rangecheck;
9717dd7cddfSDavid du Colombier 	    else
9727dd7cddfSDavid du Colombier 		break;
9737dd7cddfSDavid du Colombier 	    goto ofe;
9747dd7cddfSDavid du Colombier 	default:
9757dd7cddfSDavid du Colombier 	    ecode = code;
9767dd7cddfSDavid du Colombier 	  ofe:param_signal_error(plist, param_name, ecode);
9777dd7cddfSDavid du Colombier 	case 1:
9787dd7cddfSDavid du Colombier 	    ofns.data = 0;
9797dd7cddfSDavid du Colombier 	    break;
9807dd7cddfSDavid du Colombier     }
9817dd7cddfSDavid du Colombier 
9827dd7cddfSDavid du Colombier     if (ecode < 0)
9837dd7cddfSDavid du Colombier 	return ecode;
9847dd7cddfSDavid du Colombier     {
9857dd7cddfSDavid du Colombier 	bool open = dev->is_open;
9867dd7cddfSDavid du Colombier 
9877dd7cddfSDavid du Colombier 	/* Don't let gx_default_put_params close the device. */
9887dd7cddfSDavid du Colombier 	dev->is_open = false;
9897dd7cddfSDavid du Colombier 	code = gx_default_put_params(dev, plist);
9907dd7cddfSDavid du Colombier 	dev->is_open = open;
9917dd7cddfSDavid du Colombier     }
9927dd7cddfSDavid du Colombier     if (code < 0)
9937dd7cddfSDavid du Colombier 	return code;
9947dd7cddfSDavid du Colombier 
9953ff48bf5SDavid du Colombier     if (ofns.data != 0) {
9967dd7cddfSDavid du Colombier 	memcpy(vdev->fname, ofns.data, ofns.size);
9977dd7cddfSDavid du Colombier 	vdev->fname[ofns.size] = 0;
9987dd7cddfSDavid du Colombier 	if (vdev->file != 0) {
9993ff48bf5SDavid du Colombier 	    gx_device_bbox *bbdev = vdev->bbox_device;
10003ff48bf5SDavid du Colombier 
10013ff48bf5SDavid du Colombier 	    vdev->bbox_device = 0; /* don't let it be freed */
10027dd7cddfSDavid du Colombier 	    code = gdev_vector_close_file(vdev);
10033ff48bf5SDavid du Colombier 	    vdev->bbox_device = bbdev;
10047dd7cddfSDavid du Colombier 	    if (code < 0)
10057dd7cddfSDavid du Colombier 		return code;
10063ff48bf5SDavid du Colombier 	    return gdev_vector_open_file_options(vdev, vdev->strmbuf_size,
10073ff48bf5SDavid du Colombier 						 vdev->open_options);
10087dd7cddfSDavid du Colombier 	}
10097dd7cddfSDavid du Colombier     }
10107dd7cddfSDavid du Colombier     return 0;
10117dd7cddfSDavid du Colombier }
10127dd7cddfSDavid du Colombier 
10137dd7cddfSDavid du Colombier /* ---------------- Defaults ---------------- */
10147dd7cddfSDavid du Colombier 
10157dd7cddfSDavid du Colombier int
gdev_vector_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)10167dd7cddfSDavid du Colombier gdev_vector_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
10177dd7cddfSDavid du Colombier 			   gx_color_index color)
10187dd7cddfSDavid du Colombier {
10197dd7cddfSDavid du Colombier     gx_drawing_color dcolor;
10207dd7cddfSDavid du Colombier 
10217dd7cddfSDavid du Colombier     /* Ignore the initial fill with white. */
10227dd7cddfSDavid du Colombier     if (!vdev->in_page && color == vdev->white)
10237dd7cddfSDavid du Colombier 	return 0;
1024*593dc095SDavid du Colombier     /*
1025*593dc095SDavid du Colombier      * The original colorspace and client color are unknown so use
1026*593dc095SDavid du Colombier      * set_nonclient_dev_color instead of color_set_pure.
1027*593dc095SDavid du Colombier      */
1028*593dc095SDavid du Colombier     set_nonclient_dev_color(&dcolor, color);
10297dd7cddfSDavid du Colombier     {
1030*593dc095SDavid du Colombier 	/* Make sure we aren't being clipped. */
1031*593dc095SDavid du Colombier 	int code = gdev_vector_update_clip_path(vdev, NULL);
10327dd7cddfSDavid du Colombier 
10337dd7cddfSDavid du Colombier 	if (code < 0)
10347dd7cddfSDavid du Colombier 	    return code;
1035*593dc095SDavid du Colombier 	if ((code = update_fill(vdev, NULL, &dcolor, rop3_T)) < 0)
10367dd7cddfSDavid du Colombier 	    return code;
10377dd7cddfSDavid du Colombier     }
10387dd7cddfSDavid du Colombier     if (vdev->bbox_device) {
10397dd7cddfSDavid du Colombier 	int code = (*dev_proc(vdev->bbox_device, fill_rectangle))
10407dd7cddfSDavid du Colombier 	((gx_device *) vdev->bbox_device, x, y, w, h, color);
10417dd7cddfSDavid du Colombier 
10427dd7cddfSDavid du Colombier 	if (code < 0)
10437dd7cddfSDavid du Colombier 	    return code;
10447dd7cddfSDavid du Colombier     }
10457dd7cddfSDavid du Colombier     return (*vdev_proc(vdev, dorect)) (vdev, int2fixed(x), int2fixed(y),
10467dd7cddfSDavid du Colombier 				       int2fixed(x + w), int2fixed(y + h),
10477dd7cddfSDavid du Colombier 				       gx_path_type_fill);
10487dd7cddfSDavid du Colombier }
10497dd7cddfSDavid du Colombier 
10507dd7cddfSDavid du Colombier int
gdev_vector_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_device_color * pdevc,const gx_clip_path * pcpath)10517dd7cddfSDavid du Colombier gdev_vector_fill_path(gx_device * dev, const gs_imager_state * pis,
10527dd7cddfSDavid du Colombier 		      gx_path * ppath, const gx_fill_params * params,
10537dd7cddfSDavid du Colombier 		 const gx_device_color * pdevc, const gx_clip_path * pcpath)
10547dd7cddfSDavid du Colombier {
10557dd7cddfSDavid du Colombier     int code;
10567dd7cddfSDavid du Colombier 
10577dd7cddfSDavid du Colombier     if ((code = gdev_vector_prepare_fill(vdev, pis, params, pdevc)) < 0 ||
10587dd7cddfSDavid du Colombier 	(code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 ||
10597dd7cddfSDavid du Colombier 	(vdev->bbox_device &&
10607dd7cddfSDavid du Colombier 	 (code = (*dev_proc(vdev->bbox_device, fill_path))
10617dd7cddfSDavid du Colombier 	  ((gx_device *) vdev->bbox_device, pis, ppath, params,
10627dd7cddfSDavid du Colombier 	   pdevc, pcpath)) < 0) ||
10637dd7cddfSDavid du Colombier 	(code = (*vdev_proc(vdev, dopath))
10647dd7cddfSDavid du Colombier 	 (vdev, ppath,
10657dd7cddfSDavid du Colombier 	  (params->rule > 0 ? gx_path_type_even_odd :
10663ff48bf5SDavid du Colombier 	   gx_path_type_winding_number) | gx_path_type_fill |
10673ff48bf5SDavid du Colombier 	   vdev->fill_options,
10687dd7cddfSDavid du Colombier 	 NULL)) < 0
10697dd7cddfSDavid du Colombier 	)
10707dd7cddfSDavid du Colombier 	return gx_default_fill_path(dev, pis, ppath, params, pdevc, pcpath);
10717dd7cddfSDavid du Colombier     return code;
10727dd7cddfSDavid du Colombier }
10737dd7cddfSDavid du Colombier 
10747dd7cddfSDavid du Colombier int
gdev_vector_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)10757dd7cddfSDavid du Colombier gdev_vector_stroke_path(gx_device * dev, const gs_imager_state * pis,
10767dd7cddfSDavid du Colombier 			gx_path * ppath, const gx_stroke_params * params,
10777dd7cddfSDavid du Colombier 	      const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
10787dd7cddfSDavid du Colombier {
10797dd7cddfSDavid du Colombier     int code;
10807dd7cddfSDavid du Colombier     double scale;
10817dd7cddfSDavid du Colombier     int set_ctm;
10827dd7cddfSDavid du Colombier     gs_matrix mat;
10837dd7cddfSDavid du Colombier 
10847dd7cddfSDavid du Colombier     if ((set_ctm = gdev_vector_stroke_scaling(vdev, pis, &scale, &mat)) != 0 ||
10857dd7cddfSDavid du Colombier 	(code = gdev_vector_prepare_stroke(vdev, pis, params, pdcolor, scale)) < 0 ||
10867dd7cddfSDavid du Colombier 	(code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 ||
10877dd7cddfSDavid du Colombier 	(vdev->bbox_device &&
10887dd7cddfSDavid du Colombier 	 (code = (*dev_proc(vdev->bbox_device, stroke_path))
10897dd7cddfSDavid du Colombier 	  ((gx_device *) vdev->bbox_device, pis, ppath, params,
10907dd7cddfSDavid du Colombier 	   pdcolor, pcpath)) < 0) ||
10917dd7cddfSDavid du Colombier 	(code = (*vdev_proc(vdev, dopath))
10923ff48bf5SDavid du Colombier 	 (vdev, ppath, gx_path_type_stroke | vdev->stroke_options, NULL)) < 0
10937dd7cddfSDavid du Colombier 	)
10947dd7cddfSDavid du Colombier 	return gx_default_stroke_path(dev, pis, ppath, params, pdcolor, pcpath);
10957dd7cddfSDavid du Colombier     return code;
10967dd7cddfSDavid du Colombier }
10977dd7cddfSDavid du Colombier 
10987dd7cddfSDavid du Colombier int
gdev_vector_fill_trapezoid(gx_device * dev,const gs_fixed_edge * left,const gs_fixed_edge * right,fixed ybot,fixed ytop,bool swap_axes,const gx_device_color * pdevc,gs_logical_operation_t lop)10997dd7cddfSDavid du Colombier gdev_vector_fill_trapezoid(gx_device * dev, const gs_fixed_edge * left,
11007dd7cddfSDavid du Colombier 	const gs_fixed_edge * right, fixed ybot, fixed ytop, bool swap_axes,
11017dd7cddfSDavid du Colombier 		  const gx_device_color * pdevc, gs_logical_operation_t lop)
11027dd7cddfSDavid du Colombier {
11037dd7cddfSDavid du Colombier     fixed xl = left->start.x;
11047dd7cddfSDavid du Colombier     fixed wl = left->end.x - xl;
11057dd7cddfSDavid du Colombier     fixed yl = left->start.y;
11067dd7cddfSDavid du Colombier     fixed hl = left->end.y - yl;
11077dd7cddfSDavid du Colombier     fixed xr = right->start.x;
11087dd7cddfSDavid du Colombier     fixed wr = right->end.x - xr;
11097dd7cddfSDavid du Colombier     fixed yr = right->start.y;
11107dd7cddfSDavid du Colombier     fixed hr = right->end.y - yr;
11117dd7cddfSDavid du Colombier     fixed x0l = xl + fixed_mult_quo(wl, ybot - yl, hl);
11127dd7cddfSDavid du Colombier     fixed x1l = xl + fixed_mult_quo(wl, ytop - yl, hl);
11137dd7cddfSDavid du Colombier     fixed x0r = xr + fixed_mult_quo(wr, ybot - yr, hr);
11147dd7cddfSDavid du Colombier     fixed x1r = xr + fixed_mult_quo(wr, ytop - yr, hr);
11157dd7cddfSDavid du Colombier 
11167dd7cddfSDavid du Colombier #define y0 ybot
11177dd7cddfSDavid du Colombier #define y1 ytop
1118*593dc095SDavid du Colombier     int code = update_fill(vdev, NULL, pdevc, lop);
11197dd7cddfSDavid du Colombier     gs_fixed_point points[4];
11207dd7cddfSDavid du Colombier 
11217dd7cddfSDavid du Colombier     if (code < 0)
11227dd7cddfSDavid du Colombier 	return gx_default_fill_trapezoid(dev, left, right, ybot, ytop,
11237dd7cddfSDavid du Colombier 					 swap_axes, pdevc, lop);
11247dd7cddfSDavid du Colombier     /* Make sure we aren't being clipped. */
11257dd7cddfSDavid du Colombier     code = gdev_vector_update_clip_path(vdev, NULL);
11267dd7cddfSDavid du Colombier     if (code < 0)
11277dd7cddfSDavid du Colombier 	return code;
11287dd7cddfSDavid du Colombier     if (swap_axes)
11297dd7cddfSDavid du Colombier 	points[0].y = x0l, points[1].y = x0r,
11307dd7cddfSDavid du Colombier 	    points[0].x = points[1].x = y0,
11317dd7cddfSDavid du Colombier 	    points[2].y = x1r, points[3].y = x1l,
11327dd7cddfSDavid du Colombier 	    points[2].x = points[3].x = y1;
11337dd7cddfSDavid du Colombier     else
11347dd7cddfSDavid du Colombier 	points[0].x = x0l, points[1].x = x0r,
11357dd7cddfSDavid du Colombier 	    points[0].y = points[1].y = y0,
11367dd7cddfSDavid du Colombier 	    points[2].x = x1r, points[3].x = x1l,
11377dd7cddfSDavid du Colombier 	    points[2].y = points[3].y = y1;
11387dd7cddfSDavid du Colombier #undef y0
11397dd7cddfSDavid du Colombier #undef y1
11407dd7cddfSDavid du Colombier     if (vdev->bbox_device) {
11417dd7cddfSDavid du Colombier 	int code = (*dev_proc(vdev->bbox_device, fill_trapezoid))
11427dd7cddfSDavid du Colombier 	((gx_device *) vdev->bbox_device, left, right, ybot, ytop,
11437dd7cddfSDavid du Colombier 	 swap_axes, pdevc, lop);
11447dd7cddfSDavid du Colombier 
11457dd7cddfSDavid du Colombier 	if (code < 0)
11467dd7cddfSDavid du Colombier 	    return code;
11477dd7cddfSDavid du Colombier     }
11487dd7cddfSDavid du Colombier     return gdev_vector_write_polygon(vdev, points, 4, true,
11497dd7cddfSDavid du Colombier 				     gx_path_type_fill);
11507dd7cddfSDavid du Colombier }
11517dd7cddfSDavid du Colombier 
11527dd7cddfSDavid du Colombier int
gdev_vector_fill_parallelogram(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_device_color * pdevc,gs_logical_operation_t lop)11537dd7cddfSDavid du Colombier gdev_vector_fill_parallelogram(gx_device * dev,
11547dd7cddfSDavid du Colombier 		 fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
11557dd7cddfSDavid du Colombier 		  const gx_device_color * pdevc, gs_logical_operation_t lop)
11567dd7cddfSDavid du Colombier {
11577dd7cddfSDavid du Colombier     fixed pax = px + ax, pay = py + ay;
1158*593dc095SDavid du Colombier     int code = update_fill(vdev, NULL, pdevc, lop);
11597dd7cddfSDavid du Colombier     gs_fixed_point points[4];
11607dd7cddfSDavid du Colombier 
11617dd7cddfSDavid du Colombier     if (code < 0)
11627dd7cddfSDavid du Colombier 	return gx_default_fill_parallelogram(dev, px, py, ax, ay, bx, by,
11637dd7cddfSDavid du Colombier 					     pdevc, lop);
11647dd7cddfSDavid du Colombier     /* Make sure we aren't being clipped. */
11657dd7cddfSDavid du Colombier     code = gdev_vector_update_clip_path(vdev, NULL);
11667dd7cddfSDavid du Colombier     if (code < 0)
11677dd7cddfSDavid du Colombier 	return code;
11687dd7cddfSDavid du Colombier     if (vdev->bbox_device) {
11697dd7cddfSDavid du Colombier 	code = (*dev_proc(vdev->bbox_device, fill_parallelogram))
11707dd7cddfSDavid du Colombier 	    ((gx_device *) vdev->bbox_device, px, py, ax, ay, bx, by,
11717dd7cddfSDavid du Colombier 	     pdevc, lop);
11727dd7cddfSDavid du Colombier 	if (code < 0)
11737dd7cddfSDavid du Colombier 	    return code;
11747dd7cddfSDavid du Colombier     }
11757dd7cddfSDavid du Colombier     points[0].x = px, points[0].y = py;
11767dd7cddfSDavid du Colombier     points[1].x = pax, points[1].y = pay;
11777dd7cddfSDavid du Colombier     points[2].x = pax + bx, points[2].y = pay + by;
11787dd7cddfSDavid du Colombier     points[3].x = px + bx, points[3].y = py + by;
11797dd7cddfSDavid du Colombier     return gdev_vector_write_polygon(vdev, points, 4, true,
11807dd7cddfSDavid du Colombier 				     gx_path_type_fill);
11817dd7cddfSDavid du Colombier }
11827dd7cddfSDavid du Colombier 
11837dd7cddfSDavid du Colombier int
gdev_vector_fill_triangle(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_device_color * pdevc,gs_logical_operation_t lop)11847dd7cddfSDavid du Colombier gdev_vector_fill_triangle(gx_device * dev,
11857dd7cddfSDavid du Colombier 		 fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
11867dd7cddfSDavid du Colombier 		  const gx_device_color * pdevc, gs_logical_operation_t lop)
11877dd7cddfSDavid du Colombier {
1188*593dc095SDavid du Colombier     int code = update_fill(vdev, NULL, pdevc, lop);
11897dd7cddfSDavid du Colombier     gs_fixed_point points[3];
11907dd7cddfSDavid du Colombier 
11917dd7cddfSDavid du Colombier     if (code < 0)
11927dd7cddfSDavid du Colombier 	return gx_default_fill_triangle(dev, px, py, ax, ay, bx, by,
11937dd7cddfSDavid du Colombier 					pdevc, lop);
11947dd7cddfSDavid du Colombier     /* Make sure we aren't being clipped. */
11957dd7cddfSDavid du Colombier     code = gdev_vector_update_clip_path(vdev, NULL);
11967dd7cddfSDavid du Colombier     if (code < 0)
11977dd7cddfSDavid du Colombier 	return code;
11987dd7cddfSDavid du Colombier     if (vdev->bbox_device) {
11997dd7cddfSDavid du Colombier 	code = (*dev_proc(vdev->bbox_device, fill_triangle))
12007dd7cddfSDavid du Colombier 	    ((gx_device *) vdev->bbox_device, px, py, ax, ay, bx, by,
12017dd7cddfSDavid du Colombier 	     pdevc, lop);
12027dd7cddfSDavid du Colombier 	if (code < 0)
12037dd7cddfSDavid du Colombier 	    return code;
12047dd7cddfSDavid du Colombier     }
12057dd7cddfSDavid du Colombier     points[0].x = px, points[0].y = py;
12067dd7cddfSDavid du Colombier     points[1].x = px + ax, points[1].y = py + ay;
12077dd7cddfSDavid du Colombier     points[2].x = px + bx, points[2].y = py + by;
12087dd7cddfSDavid du Colombier     return gdev_vector_write_polygon(vdev, points, 3, true,
12097dd7cddfSDavid du Colombier 				     gx_path_type_fill);
12107dd7cddfSDavid du Colombier }
12117dd7cddfSDavid du Colombier 
12127dd7cddfSDavid du Colombier #undef vdev
1213