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