/src/ghostpdl/pcl/pcl/pcrect.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* pcrect.c - PCL5 rectangular area fill commands */ |
18 | | #include "math_.h" |
19 | | #include "pcommand.h" |
20 | | #include "pcstate.h" |
21 | | #include "pcdraw.h" |
22 | | #include "pcpatrn.h" |
23 | | #include "pcbiptrn.h" |
24 | | #include "pcuptrn.h" |
25 | | #include "gspath.h" |
26 | | #include "gspath2.h" |
27 | | #include "gsmatrix.h" |
28 | | #include "gscoord.h" |
29 | | #include "gspaint.h" |
30 | | #include "gsrop.h" |
31 | | |
32 | | /* |
33 | | * The graphic library is, unfortunately, not equipped to produce accurate |
34 | | * PCL rectangles on its own. These rectangles must always be rendered with |
35 | | * the same pixel dimensions, regardless of location (ignoring clipping), |
36 | | * in the "grid intersection" pixel placement mode, must always add one |
37 | | * additional pixel in the "right" and "down" directions, relative to print |
38 | | * direction 0. |
39 | | * |
40 | | * To accomplish these tasks, it is necessary to properly adjust the rectangle |
41 | | * dimensions provided to the graphic layer. That task is accomplished by |
42 | | * this routine. |
43 | | * |
44 | | * Note that this code is designed to work with no fill adjustment in the |
45 | | * graphic library. |
46 | | */ |
47 | | static int |
48 | | adjust_render_rectangle(pcl_state_t * pcs) |
49 | 3.41k | { |
50 | 3.41k | gs_gstate *pgs = pcs->pgs; |
51 | 3.41k | const pcl_xfm_state_t *pxfmst = &(pcs->xfm_state); |
52 | 3.41k | coord w = pcs->rectangle.x; |
53 | 3.41k | coord h = pcs->rectangle.y; |
54 | 3.41k | gs_point dims; |
55 | 3.41k | gs_rect rect; |
56 | 3.41k | gs_matrix save_mtx, ident_mtx; |
57 | 3.41k | int code = 0; |
58 | | |
59 | | /* adjust the width and height to reflect the logical page boundaries */ |
60 | 3.41k | if (pcs->cap.x + w > pxfmst->pd_size.x) |
61 | 183 | w = pxfmst->pd_size.x - pcs->cap.x; |
62 | 3.41k | if (pcs->cap.y + h > pxfmst->pd_size.y) |
63 | 84 | h = pxfmst->pd_size.y - pcs->cap.y; |
64 | | |
65 | | /* move the current point to an integral pixel location */ |
66 | 3.41k | gs_transform(pgs, (double) pcs->cap.x, (double) pcs->cap.y, &(rect.p)); |
67 | 3.41k | rect.p.x = floor(rect.p.x + 0.5); |
68 | 3.41k | rect.p.y = floor(rect.p.y + 0.5); |
69 | | |
70 | | /* set the dimensions to be a multiple of pixels */ |
71 | 3.41k | gs_dtransform(pgs, (double) w, (double) h, &dims); |
72 | 3.41k | if (dims.x >= 0) |
73 | 3.24k | rect.q.x = rect.p.x + ceil(dims.x); |
74 | 162 | else { |
75 | 162 | rect.q.x = rect.p.x; |
76 | 162 | rect.p.x += floor(dims.x); |
77 | 162 | } |
78 | 3.41k | if (dims.y >= 0) |
79 | 3.12k | rect.q.y = rect.p.y + ceil(dims.y); |
80 | 282 | else { |
81 | 282 | rect.q.y = rect.p.y; |
82 | 282 | rect.p.y += floor(dims.y); |
83 | 282 | } |
84 | | |
85 | | /* |
86 | | * If the pixel-placement mode is 1, decrease the size of the rectangle |
87 | | * by one pixel. Note that this occurs only if the rectangle dimension is |
88 | | * not 0; rectangles with a zero dimension are never rendered, irrespective |
89 | | * of pixle placement mode. |
90 | | * |
91 | | * This trickiest part of this increase in dimension concerns correction |
92 | | * for the device orientation relative to print direction 0. The output |
93 | | * produced needs to be the same for pages produced with either long-edge |
94 | | * -feed or short-edge-feed printers, so it is not possible to add one |
95 | | * pixel in each direction in device space. |
96 | | */ |
97 | 3.41k | if ((pcs->pp_mode == 1) && (dims.x != 0.0) && (dims.y != 0.0)) { |
98 | 0 | gs_matrix dflt_mtx; |
99 | 0 | gs_point disp; |
100 | |
|
101 | 0 | gs_defaultmatrix(pgs, &dflt_mtx); |
102 | 0 | gs_distance_transform(1.0, 1.0, &dflt_mtx, &disp); |
103 | 0 | if (disp.x < 0.0) |
104 | 0 | rect.p.x += 1.0; |
105 | 0 | else |
106 | 0 | rect.q.x -= 1.0; |
107 | 0 | if (disp.y < 0.0) |
108 | 0 | rect.p.y += 1.0; |
109 | 0 | else |
110 | 0 | rect.q.y -= 1.0; |
111 | 0 | } |
112 | | |
113 | | /* rectangles with 0-dimensions are never printed */ |
114 | 3.41k | if ((rect.p.x == rect.q.x) || (rect.p.y == rect.q.y)) |
115 | 465 | return 0; |
116 | | |
117 | | /* transform back into pseudo-print-direction space */ |
118 | 2.94k | gs_currentmatrix(pgs, &save_mtx); |
119 | 2.94k | gs_make_identity(&ident_mtx); |
120 | 2.94k | gs_setmatrix(pgs, &ident_mtx); |
121 | 2.94k | code = gs_rectfill(pgs, &rect, 1); |
122 | 2.94k | pcs->page_marked = true; |
123 | 2.94k | gs_setmatrix(pgs, &save_mtx); |
124 | 2.94k | return code; |
125 | 3.41k | } |
126 | | |
127 | | /* |
128 | | * ESC * c <dp> H |
129 | | */ |
130 | | static int |
131 | | pcl_horiz_rect_size_decipoints(pcl_args_t * pargs, pcl_state_t * pcs) |
132 | 926 | { |
133 | 926 | pcs->rectangle.x = (coord) (any_abs(float_arg(pargs)) * 10); |
134 | 926 | return 0; |
135 | 926 | } |
136 | | |
137 | | /* |
138 | | * ESC * c <units> A |
139 | | */ |
140 | | static int |
141 | | pcl_horiz_rect_size_units(pcl_args_t * pargs, pcl_state_t * pcs) |
142 | 2.88k | { |
143 | 2.88k | pcs->rectangle.x = (coord) (any_abs(int_arg(pargs)) * pcs->uom_cp); |
144 | 2.88k | return 0; |
145 | 2.88k | } |
146 | | |
147 | | /* |
148 | | * ESC * c <dp> V |
149 | | */ |
150 | | static int |
151 | | pcl_vert_rect_size_decipoints(pcl_args_t * pargs, pcl_state_t * pcs) |
152 | 2.22k | { |
153 | 2.22k | pcs->rectangle.y = (coord) any_abs(float_arg(pargs)) * 10; |
154 | 2.22k | return 0; |
155 | 2.22k | } |
156 | | |
157 | | /* |
158 | | * ESC * c B |
159 | | */ |
160 | | static int |
161 | | pcl_vert_rect_size_units(pcl_args_t * pargs, pcl_state_t * pcs) |
162 | 3.11k | { |
163 | 3.11k | pcs->rectangle.y = any_abs(int_arg(pargs)) * pcs->uom_cp; |
164 | 3.11k | return 0; |
165 | 3.11k | } |
166 | | |
167 | | /* |
168 | | * ESC * c <fill_enum> P |
169 | | */ |
170 | | static int |
171 | | pcl_fill_rect_area(pcl_args_t * pargs, pcl_state_t * pcs) |
172 | 4.56k | { |
173 | 4.56k | pcl_pattern_source_t type = (pcl_pattern_source_t) int_arg(pargs); |
174 | 4.56k | int id = pcs->pattern_id; |
175 | 4.56k | int code = 0; |
176 | | |
177 | | /* |
178 | | * Rectangles have a special property with respect to patterns: |
179 | | * |
180 | | * a non-zero, non-existent pattern specification causes the command |
181 | | * to be ignored, UNLESS this is the current pattern. This only |
182 | | * applies to cross-hatch and user-defined patterns, as the |
183 | | * pattern id. is interpreted as an intensity level for shade |
184 | | * patterns, and patterns >= 100% are considered white. |
185 | | */ |
186 | 4.56k | if (type == pcl_pattern_cross_hatch) { |
187 | 1.63k | if (pcl_pattern_get_cross(pcs, id) == 0) |
188 | 1.00k | return 0; |
189 | 2.92k | } else if (type == pcl_pattern_user_defined) { |
190 | 72 | if (pcl_pattern_get_pcl_uptrn(pcs, id) == 0) |
191 | 72 | return 0; |
192 | 2.85k | } else if (type == pcl_pattern_current_pattern) { |
193 | 12 | type = pcs->pattern_type; |
194 | 12 | id = pcs->current_pattern_id; |
195 | 2.84k | } else if (type > pcl_pattern_shading) |
196 | 74 | return 0; |
197 | | |
198 | | /* set up the graphic state; render the rectangle */ |
199 | 3.41k | if (((code = pcl_set_drawing_color(pcs, type, id, false)) >= 0) && |
200 | 3.41k | ((code = pcl_set_graphics_state(pcs)) >= 0)) |
201 | 3.41k | code = adjust_render_rectangle(pcs); |
202 | 3.41k | return code; |
203 | 4.56k | } |
204 | | |
205 | | /* |
206 | | * Initialization |
207 | | */ |
208 | | static int |
209 | | pcrect_do_registration(pcl_parser_state_t * pcl_parser_state, |
210 | | gs_memory_t * mem) |
211 | 16.1k | { |
212 | | /* Register commands */ |
213 | 16.1k | DEFINE_CLASS('*') { |
214 | 16.1k | 'c', 'H', |
215 | 16.1k | PCL_COMMAND("Horizontal Rectangle Size Decipoints", |
216 | 16.1k | pcl_horiz_rect_size_decipoints, |
217 | 16.1k | pca_neg_error | pca_big_error | pca_in_rtl) |
218 | 16.1k | }, { |
219 | 16.1k | 'c', 'A', |
220 | 16.1k | PCL_COMMAND("Horizontal Rectangle Size Units", |
221 | 16.1k | pcl_horiz_rect_size_units, |
222 | 16.1k | pca_neg_error | pca_big_error | pca_in_rtl) |
223 | 16.1k | }, { |
224 | 16.1k | 'c', 'V', |
225 | 16.1k | PCL_COMMAND("Vertical Rectangle Size Decipoint", |
226 | 16.1k | pcl_vert_rect_size_decipoints, |
227 | 16.1k | pca_neg_error | pca_big_error | pca_in_rtl) |
228 | 16.1k | }, { |
229 | 16.1k | 'c', 'B', |
230 | 16.1k | PCL_COMMAND("Vertical Rectangle Size Units", |
231 | 16.1k | pcl_vert_rect_size_units, |
232 | 16.1k | pca_neg_error | pca_big_error | pca_in_rtl) |
233 | 16.1k | }, { |
234 | 16.1k | 'c', 'P', |
235 | 16.1k | PCL_COMMAND("Fill Rectangular Area", |
236 | 16.1k | pcl_fill_rect_area, |
237 | 16.1k | pca_neg_ignore | pca_big_ignore | pca_in_rtl) |
238 | 16.1k | }, END_CLASS return 0; |
239 | 16.1k | } |
240 | | |
241 | | static int |
242 | | pcrect_do_reset(pcl_state_t * pcs, pcl_reset_type_t type) |
243 | 49.4k | { |
244 | 49.4k | static const uint mask = (pcl_reset_initial |
245 | 49.4k | | pcl_reset_printer | pcl_reset_overlay); |
246 | 49.4k | if ((type & mask) != 0) { |
247 | 49.4k | pcs->rectangle.x = 0; |
248 | 49.4k | pcs->rectangle.y = 0; |
249 | 49.4k | } |
250 | | |
251 | 49.4k | return 0; |
252 | 49.4k | } |
253 | | |
254 | | const pcl_init_t pcrect_init = { pcrect_do_registration, pcrect_do_reset, 0 }; |