Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1991, 1992, 1994, 1996, 1997, 1998 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: gsdps1.c,v 1.10 2003/09/15 10:04:01 igor Exp $ */
18
/* Display PostScript graphics additions for Ghostscript library */
19
#include "math_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsmatrix.h"		/* for gscoord.h */
23
#include "gscoord.h"
24
#include "gspaint.h"
25
#include "gxdevice.h"
26
#include "gxfixed.h"
27
#include "gxmatrix.h"
28
#include "gxhldevc.h"
29
#include "gspath.h"
30
#include "gspath2.h"		/* defines interface */
31
#include "gzpath.h"
32
#include "gzcpath.h"
33
#include "gzstate.h"
34
 
35
/*
36
 * Define how much rounding slop setbbox should leave,
37
 * in device coordinates.  Because of rounding in transforming
38
 * path coordinates to fixed point, the minimum realistic value is:
39
 *
40
 *      #define box_rounding_slop_fixed (fixed_epsilon)
41
 *
42
 * But even this isn't enough to compensate for cumulative rounding error
43
 * in rmoveto or rcurveto.  Instead, we somewhat arbitrarily use:
44
 */
45
#define box_rounding_slop_fixed (fixed_epsilon * 3)
46
 
47
/* ------ Graphics state ------ */
48
 
49
/* Set the bounding box for the current path. */
50
int
51
gs_setbbox(gs_state * pgs, floatp llx, floatp lly, floatp urx, floatp ury)
52
{
53
    gs_rect ubox, dbox;
54
    gs_fixed_rect obox, bbox;
55
    gx_path *ppath = pgs->path;
56
    int code;
57
 
58
    if (llx > urx || lly > ury)
59
	return_error(gs_error_rangecheck);
60
    /* Transform box to device coordinates. */
61
    ubox.p.x = llx;
62
    ubox.p.y = lly;
63
    ubox.q.x = urx;
64
    ubox.q.y = ury;
65
    if ((code = gs_bbox_transform(&ubox, &ctm_only(pgs), &dbox)) < 0)
66
	return code;
67
    /* Round the corners in opposite directions. */
68
    /* Because we can't predict the magnitude of the dbox values, */
69
    /* we add/subtract the slop after fixing. */
70
    if (dbox.p.x < fixed2float(min_fixed + box_rounding_slop_fixed) ||
71
	dbox.p.y < fixed2float(min_fixed + box_rounding_slop_fixed) ||
72
	dbox.q.x >= fixed2float(max_fixed - box_rounding_slop_fixed + fixed_epsilon) ||
73
	dbox.q.y >= fixed2float(max_fixed - box_rounding_slop_fixed + fixed_epsilon)
74
	)
75
	return_error(gs_error_limitcheck);
76
    bbox.p.x =
77
	(fixed) floor(dbox.p.x * fixed_scale) - box_rounding_slop_fixed;
78
    bbox.p.y =
79
	(fixed) floor(dbox.p.y * fixed_scale) - box_rounding_slop_fixed;
80
    bbox.q.x =
81
	(fixed) ceil(dbox.q.x * fixed_scale) + box_rounding_slop_fixed;
82
    bbox.q.y =
83
	(fixed) ceil(dbox.q.y * fixed_scale) + box_rounding_slop_fixed;
84
    if (gx_path_bbox(ppath, &obox) >= 0) {	/* Take the union of the bboxes. */
85
	ppath->bbox.p.x = min(obox.p.x, bbox.p.x);
86
	ppath->bbox.p.y = min(obox.p.y, bbox.p.y);
87
	ppath->bbox.q.x = max(obox.q.x, bbox.q.x);
88
	ppath->bbox.q.y = max(obox.q.y, bbox.q.y);
89
    } else {			/* empty path *//* Just set the bbox. */
90
	ppath->bbox = bbox;
91
    }
92
    ppath->bbox_set = 1;
93
    return 0;
94
}
95
 
96
/* ------ Rectangles ------ */
97
 
98
/* Append a list of rectangles to a path. */
99
int
100
gs_rectappend(gs_state * pgs, const gs_rect * pr, uint count)
101
{
102
    for (; count != 0; count--, pr++) {
103
	floatp px = pr->p.x, py = pr->p.y, qx = pr->q.x, qy = pr->q.y;
104
	int code;
105
 
106
	/* Ensure counter-clockwise drawing. */
107
	if ((qx >= px) != (qy >= py))
108
	    qx = px, px = pr->q.x;	/* swap x values */
109
	if ((code = gs_moveto(pgs, px, py)) < 0 ||
110
	    (code = gs_lineto(pgs, qx, py)) < 0 ||
111
	    (code = gs_lineto(pgs, qx, qy)) < 0 ||
112
	    (code = gs_lineto(pgs, px, qy)) < 0 ||
113
	    (code = gs_closepath(pgs)) < 0
114
	    )
115
	    return code;
116
    }
117
    return 0;
118
}
119
 
120
/* Clip to a list of rectangles. */
121
int
122
gs_rectclip(gs_state * pgs, const gs_rect * pr, uint count)
123
{
124
    int code;
125
    gx_path save;
126
 
127
    gx_path_init_local(&save, pgs->memory);
128
    gx_path_assign_preserve(&save, pgs->path);
129
    gs_newpath(pgs);
130
    if ((code = gs_rectappend(pgs, pr, count)) < 0 ||
131
	(code = gs_clip(pgs)) < 0
132
	) {
133
	gx_path_assign_free(pgs->path, &save);
134
	return code;
135
    }
136
    gx_path_free(&save, "gs_rectclip");
137
    gs_newpath(pgs);
138
    return 0;
139
}
140
 
141
/* Fill a list of rectangles. */
142
/* We take the trouble to do this efficiently in the simple cases. */
143
int
144
gs_rectfill(gs_state * pgs, const gs_rect * pr, uint count)
145
{
146
    const gs_rect *rlist = pr;
147
    gx_clip_path *pcpath;
148
    uint rcount = count;
149
    int code;
150
    gx_device * pdev = pgs->device;
151
    gx_device_color *pdc = pgs->dev_color;
152
    const gs_imager_state *pis = (const gs_imager_state *)pgs;
153
    bool hl_color_available = gx_hld_is_hl_color_available(pis, pdc);
154
    gs_fixed_rect empty = {{0, 0}, {0, 0}};
155
    bool hl_color = (hl_color_available && 
156
		dev_proc(pdev, fill_rectangle_hl_color)(pdev, 
157
		    	    &empty, pis, pdc, NULL) == 0);
158
 
159
    gx_set_dev_color(pgs);
160
    if ((is_fzero2(pgs->ctm.xy, pgs->ctm.yx) ||
161
	 is_fzero2(pgs->ctm.xx, pgs->ctm.yy)) &&
162
	gx_effective_clip_path(pgs, &pcpath) >= 0 &&
163
	clip_list_is_rectangle(gx_cpath_list(pcpath)) &&
164
	(hl_color ||
165
	 pdc->type == gx_dc_type_pure ||
166
	 pdc->type == gx_dc_type_ht_binary ||
167
	 pdc->type == gx_dc_type_ht_colored
168
	 /* DeviceN todo: add wts case */) &&
169
	gs_state_color_load(pgs) >= 0 &&
170
	(*dev_proc(pdev, get_alpha_bits)) (pdev, go_graphics)
171
	<= 1 &&
172
        (!pgs->overprint || !pgs->effective_overprint_mode)
173
	) {
174
	uint i;
175
	gs_fixed_rect clip_rect;
176
 
177
	gx_cpath_inner_box(pcpath, &clip_rect);
178
	for (i = 0; i < count; ++i) {
179
	    gs_fixed_point p, q;
180
	    gs_fixed_rect draw_rect;
181
 
182
	    if (gs_point_transform2fixed(&pgs->ctm, pr[i].p.x, pr[i].p.y, &p) < 0 ||
183
		gs_point_transform2fixed(&pgs->ctm, pr[i].q.x, pr[i].q.y, &q) < 0
184
		) {		/* Switch to the slow algorithm. */
185
		goto slow;
186
	    }
187
	    draw_rect.p.x = min(p.x, q.x);
188
	    draw_rect.p.y = min(p.y, q.y);
189
	    draw_rect.q.x = max(p.x, q.x);
190
	    draw_rect.q.y = max(p.y, q.y);
191
	    if (hl_color) {
192
		rect_intersect(draw_rect, clip_rect);
193
		if (draw_rect.p.x < draw_rect.q.x &&
194
		    draw_rect.p.y < draw_rect.q.y) {
195
		    code = dev_proc(pdev, fill_rectangle_hl_color)(pdev,
196
			     &draw_rect, pis, pdc, pcpath);
197
		    if (code < 0)
198
			return code;
199
		}
200
	    } else {
201
		int x, y, w, h;
202
 
203
		draw_rect.p.x -= pgs->fill_adjust.x;
204
		draw_rect.p.y -= pgs->fill_adjust.x;
205
		draw_rect.q.x += pgs->fill_adjust.x;
206
		draw_rect.q.y += pgs->fill_adjust.x;
207
		rect_intersect(draw_rect, clip_rect);
208
		x = fixed2int_pixround(draw_rect.p.x);
209
		y = fixed2int_pixround(draw_rect.p.y);
210
		w = fixed2int_pixround(draw_rect.q.x) - x;
211
		h = fixed2int_pixround(draw_rect.q.y) - y;
212
		if (w > 0 && h > 0)
213
    		    if (gx_fill_rectangle(x, y, w, h, pdc, pgs) < 0)
214
			goto slow;
215
	    }
216
	}
217
	return 0;
218
      slow:rlist = pr + i;
219
	rcount = count - i;
220
    } {
221
	bool do_save = !gx_path_is_null(pgs->path);
222
 
223
	if (do_save) {
224
	    if ((code = gs_gsave(pgs)) < 0)
225
		return code;
226
	    gs_newpath(pgs);
227
	}
228
	if ((code = gs_rectappend(pgs, rlist, rcount)) < 0 ||
229
	    (code = gs_fill(pgs)) < 0
230
	    )
231
	    DO_NOTHING;
232
	if (do_save)
233
	    gs_grestore(pgs);
234
	else if (code < 0)
235
	    gs_newpath(pgs);
236
    }
237
    return code;
238
}
239
 
240
/* Stroke a list of rectangles. */
241
/* (We could do this a lot more efficiently.) */
242
int
243
gs_rectstroke(gs_state * pgs, const gs_rect * pr, uint count,
244
	      const gs_matrix * pmat)
245
{
246
    bool do_save = pmat != NULL || !gx_path_is_null(pgs->path);
247
    int code;
248
 
249
    if (do_save) {
250
	if ((code = gs_gsave(pgs)) < 0)
251
	    return code;
252
	gs_newpath(pgs);
253
    }
254
    if ((code = gs_rectappend(pgs, pr, count)) < 0 ||
255
	(pmat != NULL && (code = gs_concat(pgs, pmat)) < 0) ||
256
	(code = gs_stroke(pgs)) < 0
257
	)
258
	DO_NOTHING;
259
    if (do_save)
260
	gs_grestore(pgs);
261
    else if (code < 0)
262
	gs_newpath(pgs);
263
    return code;
264
}