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 |
}
|