/src/ghostpdl/base/gxclpath.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2026 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 | | /* Higher-level path operations for band lists */ |
18 | | #include "math_.h" |
19 | | #include "memory_.h" |
20 | | #include "gx.h" |
21 | | #include "gpcheck.h" |
22 | | #include "gserrors.h" |
23 | | #include "gsptype2.h" |
24 | | #include "gsptype1.h" |
25 | | #include "gxdevice.h" |
26 | | #include "gxdevmem.h" /* must precede gxcldev.h */ |
27 | | #include "gxcldev.h" |
28 | | #include "gxclpath.h" |
29 | | #include "gxcolor2.h" |
30 | | #include "gxdcolor.h" |
31 | | #include "gxpcolor.h" |
32 | | #include "gxpaint.h" /* for gx_fill/stroke_params */ |
33 | | #include "gzpath.h" |
34 | | #include "gzcpath.h" |
35 | | #include "stream.h" |
36 | | #include "gsserial.h" |
37 | | #include "gxdevsop.h" |
38 | | |
39 | | /* Statistics */ |
40 | | #ifdef COLLECT_STATS_CLIST |
41 | | ulong stats_cmd_diffs[5]; |
42 | | #endif |
43 | | |
44 | | /* Forward declarations */ |
45 | | static int cmd_put_path(gx_device_clist_writer * cldev, |
46 | | gx_clist_state * pcls, const gx_path * ppath, |
47 | | fixed ymin, fixed ymax, byte op, |
48 | | bool implicit_close, segment_notes keep_notes); |
49 | | |
50 | | /* ------ Utilities ------ */ |
51 | | |
52 | | /* Compute the colors used by a colored halftone. */ |
53 | | static gx_color_index |
54 | | colored_halftone_color_usage(gx_device_clist_writer *cldev, |
55 | | const gx_drawing_color *pdcolor) |
56 | 1.96M | { |
57 | | /* |
58 | | * We only know how to compute an accurate color set for the |
59 | | * standard CMYK color mapping function. |
60 | | */ |
61 | 1.96M | if (dev_proc(cldev, dev_spec_op)((gx_device *)cldev, |
62 | 1.96M | gxdso_is_std_cmyk_1bit, NULL, 0) <= 0) |
63 | 1.96M | return ((gx_color_index)1 << cldev->color_info.depth) - 1; /* What about transparency? Need to check this */ |
64 | | /* |
65 | | * Note that c_base[0], and the low-order bit of plane_mask, |
66 | | * correspond to cyan: this requires reversing the bit order of |
67 | | * the plane mask. |
68 | | */ |
69 | 0 | return |
70 | 0 | ((pdcolor->colors.colored.c_base[0] << 3) | |
71 | 0 | (pdcolor->colors.colored.c_base[1] << 2) | |
72 | 0 | (pdcolor->colors.colored.c_base[2] << 1) | |
73 | 0 | (pdcolor->colors.colored.c_base[3]) | |
74 | 0 | (byte_reverse_bits[pdcolor->colors.colored.plane_mask] >> 4)); |
75 | 1.96M | } |
76 | | |
77 | | /* |
78 | | * Compute whether a drawing operation will require the slow (full-pixel) |
79 | | * RasterOp implementation. If pdcolor is not NULL, it is the texture for |
80 | | * the RasterOp. |
81 | | */ |
82 | | bool |
83 | | cmd_slow_rop(gx_device *dev, gs_logical_operation_t lop, |
84 | | const gx_drawing_color *pdcolor) |
85 | 53.9M | { |
86 | 53.9M | gs_rop3_t rop = lop_rop(lop); |
87 | | |
88 | 53.9M | if (pdcolor != 0 && gx_dc_is_pure(pdcolor)) { |
89 | 40.5M | gx_color_index color = gx_dc_pure_color(pdcolor); |
90 | | |
91 | 40.5M | if (color == gx_device_black(dev)) |
92 | 34.0M | rop = rop3_know_T_0(rop); |
93 | 6.52M | else if (color == gx_device_white(dev)) |
94 | 3.96M | rop = rop3_know_T_1(rop); |
95 | 40.5M | } |
96 | 53.9M | return !(rop == rop3_0 || rop == rop3_1 || |
97 | 10.2M | rop == rop3_S || rop == rop3_T); |
98 | 53.9M | } |
99 | | |
100 | | /* Write out the color for filling, stroking, or masking. */ |
101 | | /* We should be able to share this with clist_tile_rectangle, */ |
102 | | /* but I don't see how to do it without adding a level of procedure. */ |
103 | | /* If the pattern color is big, it can write to "all" bands. */ |
104 | | int |
105 | | cmd_put_drawing_color(gx_device_clist_writer * cldev, gx_clist_state * pcls, |
106 | | const gx_drawing_color * pdcolor, cmd_rects_enum_t *pre, |
107 | | dc_devn_cl_type devn_type) |
108 | 255M | { |
109 | 255M | const gx_device_halftone * pdht = pdcolor->type->get_dev_halftone(pdcolor); |
110 | 255M | int code, di; |
111 | 255M | uint dc_size = 0, req_size; |
112 | 255M | gx_device_color_saved * psdc = &pcls->sdc; |
113 | 255M | byte * dp; |
114 | 255M | byte * dp0; |
115 | 255M | gs_int_point color_phase; |
116 | 255M | int buffer_space; |
117 | 255M | int offset = 0; |
118 | 255M | int left; |
119 | 255M | uint portion_size, prefix_size; |
120 | 255M | int req_size_final; |
121 | 255M | bool is_pattern; |
122 | 255M | gs_id pattern_id = gs_no_id; |
123 | 255M | bool all_bands = (pre == NULL); |
124 | | |
125 | | /* see if the halftone must be inserted in the command list */ |
126 | 255M | if ( pdht != NULL && |
127 | 184M | pdht->id != cldev->device_halftone_id ) { |
128 | 25.3k | if ((code = cmd_put_halftone(cldev, pdht)) < 0) |
129 | 0 | return code; |
130 | 25.3k | psdc->type = gx_dc_type_none; /* force writing */ |
131 | 25.3k | } |
132 | | |
133 | 255M | if (psdc->devn_type != devn_type) { |
134 | 1.62M | psdc->type = gx_dc_type_none; /* force writing if fill/stroke mismatch. */ |
135 | 1.62M | psdc->devn_type = devn_type; |
136 | 1.62M | } |
137 | | /* |
138 | | * Get the device color type index and the required size. |
139 | | * |
140 | | * The complete cmd_opv_ext_put_drawing_color consists of: |
141 | | * command code (2 bytes) |
142 | | * tile index value or non tile color (1) |
143 | | * device color type index (1) |
144 | | * length of serialized device color (enc_u_sizew(dc_size)) |
145 | | * the serialized device color itself (dc_size) |
146 | | */ |
147 | 255M | di = gx_get_dc_type_index(pdcolor); |
148 | 255M | code = pdcolor->type->write( pdcolor, |
149 | 255M | psdc, |
150 | 255M | (gx_device *)cldev, |
151 | 255M | 0, |
152 | 255M | 0, |
153 | 255M | &dc_size ); |
154 | | |
155 | | /* if the returned value is > 0, no change in the color is necessary */ |
156 | 255M | if (code > 0 && ((devn_type == devn_not_tile_fill) || (devn_type == devn_not_tile_stroke))) |
157 | 221M | return 0; |
158 | 33.2M | else if (code < 0 && code != gs_error_rangecheck) |
159 | 872 | return code; |
160 | 33.2M | if (!all_bands && dc_size * pre->rect_nbands > 1024*1024 /* arbitrary */) |
161 | 3.43k | all_bands = true; |
162 | 33.2M | is_pattern = gx_dc_is_pattern1_color(pdcolor); |
163 | 33.2M | if (is_pattern) |
164 | 862k | pattern_id = gs_dc_get_pattern_id(pdcolor); |
165 | 33.2M | if (all_bands) { |
166 | 656k | gx_clist_state * pcls1; |
167 | | |
168 | 769k | for (pcls1 = cldev->states; pcls1 < cldev->states + cldev->nbands; pcls1++) { |
169 | 766k | if (pcls1->pattern_id == pattern_id) { |
170 | 653k | pcls->pattern_id = gs_no_id; /* Force writing entire pattern. */ |
171 | 653k | break; |
172 | 653k | } |
173 | 766k | } |
174 | 656k | } |
175 | 33.2M | left = dc_size; |
176 | | |
177 | 33.2M | CMD_CHECK_LAST_OP_BLOCK_DEFINED(cldev); |
178 | | /* see if phase information must be inserted in the command list */ |
179 | 33.2M | if (pdcolor->type->get_phase(pdcolor, &color_phase) && |
180 | 5.43M | (color_phase.x != pcls->screen_phase[gs_color_select_texture].x || |
181 | 5.43M | color_phase.y != pcls->screen_phase[gs_color_select_texture].y || all_bands)) { |
182 | | /* Devc phase is the reverse of screen phase! */ |
183 | 3.43k | code = cmd_set_screen_phase_generic(cldev, pcls, |
184 | 3.43k | -color_phase.x, -color_phase.y, |
185 | 3.43k | gs_color_select_texture, all_bands); |
186 | 3.43k | if (code < 0) |
187 | 0 | return code; |
188 | 3.43k | } |
189 | | |
190 | 33.2M | CMD_CHECK_LAST_OP_BLOCK_DEFINED(cldev); |
191 | 33.2M | if (is_pattern) { |
192 | 862k | pattern_id = gs_dc_get_pattern_id(pdcolor); |
193 | | |
194 | 862k | if (pattern_id != gs_no_id && pcls->pattern_id == pattern_id) { |
195 | 476 | if (pcls->step_phase.x == pdcolor->colors.pattern.p_tile->step_matrix.tx && |
196 | 476 | pcls->step_phase.y == pdcolor->colors.pattern.p_tile->step_matrix.ty) { |
197 | | /* The pattern is known, write its id only. |
198 | | Note that gx_dc_pattern_write must process this case especially. */ |
199 | | /* Note that id is gs_no_id when the pattern supplies an empty tile. |
200 | | In this case the full serialized pattern is shorter (left == 0), |
201 | | so go with it. */ |
202 | 476 | left = sizeof(pattern_id); |
203 | 476 | } |
204 | 476 | } |
205 | 862k | } |
206 | | |
207 | 33.2M | do { |
208 | 33.2M | int extop; |
209 | 33.2M | prefix_size = 2 + 1 + (offset > 0 ? enc_u_sizew(offset) : 0); |
210 | 33.2M | req_size = left + prefix_size + enc_u_sizew(left); |
211 | 33.2M | CMD_CHECK_LAST_OP_BLOCK_DEFINED(cldev); |
212 | 33.2M | code = cmd_get_buffer_space(cldev, pcls, req_size); |
213 | 33.2M | if (code < 0) |
214 | 0 | return code; |
215 | 33.2M | buffer_space = min(code, req_size); |
216 | 33.2M | portion_size = buffer_space - prefix_size - enc_u_sizew(left); |
217 | 33.2M | req_size_final = portion_size + prefix_size + enc_u_sizew(portion_size); |
218 | 33.2M | if (req_size_final > buffer_space) |
219 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
220 | 33.2M | CMD_CHECK_LAST_OP_BLOCK_DEFINED(cldev); |
221 | 33.2M | switch (devn_type) { |
222 | 31.5M | case devn_not_tile_fill: |
223 | 31.5M | extop = cmd_opv_ext_put_fill_dcolor; |
224 | 31.5M | break; |
225 | 1.75M | case devn_not_tile_stroke: |
226 | 1.75M | extop = cmd_opv_ext_put_stroke_dcolor; |
227 | 1.75M | break; |
228 | 6.49k | case devn_tile0: |
229 | 6.49k | extop = cmd_opv_ext_put_tile_devn_color0; |
230 | 6.49k | break; |
231 | 6.49k | case devn_tile1: |
232 | 6.49k | extop = cmd_opv_ext_put_tile_devn_color1; |
233 | 6.49k | break; |
234 | 0 | default: |
235 | 0 | extop = cmd_opv_ext_put_fill_dcolor; |
236 | 33.2M | } |
237 | 33.2M | if (all_bands) |
238 | 687k | code = set_cmd_put_all_extended_op(&dp, cldev, extop, req_size_final); |
239 | 32.5M | else |
240 | 32.5M | code = set_cmd_put_extended_op(&dp, cldev, pcls, extop, req_size_final); |
241 | 33.2M | if (code < 0) |
242 | 0 | return code; |
243 | 33.2M | dp0 = dp; |
244 | 33.2M | dp += 2; |
245 | 33.2M | *dp++ = di | (offset > 0 ? 0x80 : 0); |
246 | 33.2M | if (offset > 0) |
247 | 33.2M | enc_u_putw(offset, dp); |
248 | 33.2M | enc_u_putw(portion_size, dp); |
249 | 33.2M | code = pdcolor->type->write( pdcolor, |
250 | 33.2M | &pcls->sdc, |
251 | 33.2M | (gx_device *)cldev, |
252 | 33.2M | offset, |
253 | 33.2M | dp, |
254 | 33.2M | &portion_size); |
255 | 33.2M | CMD_CHECK_LAST_OP_BLOCK_DEFINED(cldev); |
256 | 33.2M | if (code < 0) { |
257 | 0 | if (offset == 0) |
258 | 0 | cldev->cnext = dp0; |
259 | 0 | return code; |
260 | 0 | } |
261 | 33.2M | offset += portion_size; |
262 | 33.2M | left -= portion_size; |
263 | 33.2M | } while (left); |
264 | | |
265 | | /* attempt to properly calculate color_usage */ |
266 | 33.2M | pcls->color_usage.or |= cmd_drawing_color_usage(cldev, pdcolor); |
267 | | |
268 | | /* record the color we have just serialized color */ |
269 | 33.2M | pdcolor->type->save_dc(pdcolor, &pcls->sdc); |
270 | 33.2M | if (pattern_id != gs_no_id) { |
271 | | /* Don't record empty tiles because they're not cached. */ |
272 | 200k | pcls->pattern_id = pattern_id; |
273 | 200k | } |
274 | 33.2M | if (is_pattern) { |
275 | | /* HACK: since gx_dc_pattern_write identifies pattern by tile id, |
276 | | replace the client's pattern id with tile id in the saved color. */ |
277 | 862k | pcls->sdc.colors.pattern.id = pattern_id; |
278 | 862k | if (pdcolor->colors.pattern.p_tile) { |
279 | 200k | pcls->sdc.colors.pattern.step_matrix = pdcolor->colors.pattern.p_tile->step_matrix; |
280 | 200k | pcls->step_phase.x = pdcolor->colors.pattern.p_tile->step_matrix.tx; |
281 | 200k | pcls->step_phase.y = pdcolor->colors.pattern.p_tile->step_matrix.ty; |
282 | 661k | } else { |
283 | 661k | memset(&pcls->sdc.colors.pattern.step_matrix, 0, sizeof(pcls->sdc.colors.pattern.step_matrix)); |
284 | 661k | pcls->step_phase.x = 0; |
285 | 661k | pcls->step_phase.y = 0; |
286 | 661k | } |
287 | 862k | if (pattern_id && |
288 | 200k | (gx_pattern1_get_transptr(pdcolor) != NULL || |
289 | 189k | gx_pattern1_clist_has_trans(pdcolor))) { |
290 | | /* update either this band or all bands with the trans_bbox */ |
291 | 72.3k | if (all_bands) { |
292 | 323 | pcls->color_usage.trans_bbox.p.x = 0; |
293 | 323 | pcls->color_usage.trans_bbox.q.x = cldev->width; /* no other information available */ |
294 | 323 | pcls->color_usage.trans_bbox.p.y = 0; |
295 | 323 | pcls->color_usage.trans_bbox.q.y = cldev->height; |
296 | 323 | clist_update_trans_bbox(cldev, &(pcls->color_usage.trans_bbox)); |
297 | 72.0k | } else { |
298 | 72.0k | pcls->color_usage.trans_bbox.p.x = 0; |
299 | 72.0k | pcls->color_usage.trans_bbox.q.x = cldev->width; /* no other information available */ |
300 | 72.0k | pcls->color_usage.trans_bbox.p.y = pre->y; |
301 | 72.0k | pcls->color_usage.trans_bbox.q.y = pre->yend; |
302 | 72.0k | } |
303 | 72.3k | } |
304 | 862k | } |
305 | 33.2M | if (is_pattern && all_bands) { |
306 | | /* Distribute the written pattern params to all bands. |
307 | | We know it is big, so it is not empty, so it has pattern_id and tile_phase. |
308 | | */ |
309 | 3.43k | gx_clist_state * pcls1; |
310 | | |
311 | 160k | for (pcls1 = cldev->states; pcls1 < cldev->states + cldev->nbands; pcls1++) { |
312 | 157k | pcls1->sdc = pcls->sdc; |
313 | 157k | pcls1->pattern_id = pcls->pattern_id; |
314 | 157k | pcls1->tile_phase.x = pcls->tile_phase.x; |
315 | 157k | pcls1->tile_phase.y = pcls->tile_phase.y; |
316 | 157k | pcls1->color_usage.or = pcls->color_usage.or; |
317 | 157k | } |
318 | 3.43k | } |
319 | 33.2M | return code; |
320 | 33.2M | } |
321 | | |
322 | | /* Compute the colors used by a drawing color. */ |
323 | | /* If the device is using transparency, the pdf14 compositor may have */ |
324 | | /* altered the colorspace. If so, just flag all components used. */ |
325 | | gx_color_usage_bits |
326 | | cmd_drawing_color_usage(gx_device_clist_writer *cldev, |
327 | | const gx_drawing_color * pdcolor) |
328 | 50.5M | { |
329 | 50.5M | if (cldev->page_uses_transparency && |
330 | 32.6M | (cldev->color_info.polarity != cldev->clist_color_info.polarity || |
331 | 18.8M | (cldev->color_info.num_components != cldev->clist_color_info.num_components))) { |
332 | | /* we would have to transform the color which would impact performance */ |
333 | 14.4M | return gx_color_usage_all(cldev); |
334 | 14.4M | } |
335 | | |
336 | 36.1M | if (gx_dc_is_pure(pdcolor)) |
337 | 3.41M | return gx_color_index2usage((gx_device *)cldev, gx_dc_pure_color(pdcolor)); |
338 | 32.7M | else if (gx_dc_is_binary_halftone(pdcolor)) |
339 | 2.82M | return gx_color_index2usage((gx_device *)cldev, |
340 | 2.82M | gx_color_index2usage((gx_device *)cldev, gx_dc_binary_color0(pdcolor)) | |
341 | 2.82M | gx_color_index2usage((gx_device *)cldev, gx_dc_binary_color1(pdcolor))); |
342 | 29.9M | else if (gx_dc_is_colored_halftone(pdcolor)) |
343 | 1.96M | return gx_color_index2usage((gx_device *)cldev, colored_halftone_color_usage(cldev, pdcolor)); |
344 | 27.9M | else if (gx_dc_is_devn(pdcolor)) { |
345 | 27.4M | gx_color_usage_bits bits = 0; |
346 | | |
347 | 27.4M | gx_dc_devn_get_nonzero_comps(pdcolor, (gx_device *)cldev, &bits); |
348 | 27.4M | return bits; |
349 | 27.4M | } |
350 | 538k | else |
351 | 538k | return gx_color_usage_all(cldev); |
352 | 36.1M | } |
353 | | |
354 | | /* Clear (a) specific 'known' flag(s) for all bands. */ |
355 | | /* We must do this whenever the value of a 'known' parameter changes. */ |
356 | | void |
357 | | cmd_clear_known(gx_device_clist_writer * cldev, uint known) |
358 | 1.56M | { |
359 | 1.56M | uint unknown = ~known; |
360 | 1.56M | gx_clist_state *pcls = cldev->states; |
361 | 1.56M | int i; |
362 | | |
363 | 207M | for (i = cldev->nbands; --i >= 0; ++pcls) |
364 | 205M | pcls->known &= unknown; |
365 | 1.56M | } |
366 | | |
367 | | /* Check whether we need to change the clipping path in the device. */ |
368 | | bool |
369 | | cmd_check_clip_path(gx_device_clist_writer * cldev, const gx_clip_path * pcpath) |
370 | 25.4M | { |
371 | 25.4M | if (pcpath == NULL) |
372 | 0 | return false; |
373 | | /* The clip path might have moved in memory, so even if the */ |
374 | | /* ids match, update the pointer. */ |
375 | 25.4M | cldev->clip_path = pcpath; |
376 | 25.4M | if (pcpath->id == cldev->clip_path_id) |
377 | 24.6M | return false; |
378 | 790k | cldev->clip_path_id = pcpath->id; |
379 | 790k | return true; |
380 | 25.4M | } |
381 | | |
382 | | /* |
383 | | * Check the graphics state elements that need to be up to date for filling |
384 | | * or stroking. |
385 | | */ |
386 | | #define FILL_KNOWN\ |
387 | | (cj_ac_sa_known | flatness_known | op_bm_tk_known | ais_known |\ |
388 | | fill_alpha_known | fill_adjust_known | stroke_alpha_known | clip_path_known) |
389 | | static void |
390 | | cmd_check_fill_known(gx_device_clist_writer* cdev, const gs_gstate* pgs, |
391 | | double flatness, const gs_fixed_point* padjust, |
392 | | const gx_clip_path* pcpath, uint* punknown) |
393 | 4.73M | { |
394 | | /* |
395 | | * stroke_adjust is not needed for fills, and none of these are needed |
396 | | * if the path has no curves, but it's easier to update them all. |
397 | | */ |
398 | 4.73M | if (state_neq(line_params.curve_join) || state_neq(accurate_curves) || |
399 | 4.73M | state_neq(stroke_adjust) |
400 | 4.73M | ) { |
401 | 10.6k | *punknown |= cj_ac_sa_known; |
402 | 10.6k | state_update(line_params.curve_join); |
403 | 10.6k | state_update(accurate_curves); |
404 | 10.6k | state_update(stroke_adjust); |
405 | 10.6k | } |
406 | 4.73M | if (cdev->gs_gstate.flatness != flatness) { |
407 | 43.6k | *punknown |= flatness_known; |
408 | 43.6k | cdev->gs_gstate.flatness = flatness; |
409 | 43.6k | } |
410 | | /* |
411 | | * Note: overprint and overprint_mode are implemented via a compositor |
412 | | * device, which is passed separately through the command list. Hence, |
413 | | * though both parameters are passed in the state as well, this usually |
414 | | * has no effect. |
415 | | */ |
416 | 4.73M | if (state_neq(overprint) || state_neq(overprint_mode) || |
417 | 4.71M | state_neq(blend_mode) || state_neq(text_knockout) || |
418 | 4.64M | state_neq(stroke_overprint) || state_neq(renderingintent)) { |
419 | 94.0k | *punknown |= op_bm_tk_known; |
420 | 94.0k | state_update(overprint); |
421 | 94.0k | state_update(overprint_mode); |
422 | 94.0k | state_update(blend_mode); |
423 | 94.0k | state_update(text_knockout); |
424 | 94.0k | state_update(stroke_overprint); |
425 | 94.0k | state_update(renderingintent); |
426 | 94.0k | } |
427 | 4.73M | if (state_neq(alphaisshape)) { |
428 | 1.34k | *punknown |= ais_known; |
429 | 1.34k | state_update(alphaisshape); |
430 | 1.34k | } |
431 | 4.73M | if (state_neq(strokeconstantalpha)) { |
432 | 3.58k | *punknown |= stroke_alpha_known; |
433 | 3.58k | state_update(strokeconstantalpha); |
434 | 3.58k | } |
435 | 4.73M | if (cdev->gs_gstate.fillconstantalpha != pgs->fillconstantalpha) { |
436 | 6.20k | *punknown |= fill_alpha_known; |
437 | 6.20k | state_update(fillconstantalpha); |
438 | 6.20k | } |
439 | 4.73M | if (cdev->gs_gstate.fill_adjust.x != padjust->x || |
440 | 4.70M | cdev->gs_gstate.fill_adjust.y != padjust->y |
441 | 4.73M | ) { |
442 | 24.3k | *punknown |= fill_adjust_known; |
443 | 24.3k | cdev->gs_gstate.fill_adjust = *padjust; |
444 | 24.3k | } |
445 | 4.73M | if (cmd_check_clip_path(cdev, pcpath)) |
446 | 274k | *punknown |= clip_path_known; |
447 | 4.73M | } |
448 | | |
449 | | /* Compute the written CTM length. */ |
450 | | int |
451 | | cmd_write_ctm_return_length(gx_device_clist_writer * cldev, const gs_matrix *m) |
452 | 2.28M | { |
453 | 2.28M | stream s; |
454 | | |
455 | 2.28M | s_init(&s, cldev->memory); |
456 | 2.28M | swrite_position_only(&s); |
457 | 2.28M | sput_matrix(&s, m); |
458 | 2.28M | return (uint)stell(&s); |
459 | 2.28M | } |
460 | | |
461 | | /* Compute the written CTM length. */ |
462 | | int |
463 | | cmd_write_ctm_return_length_nodevice(const gs_matrix *m) |
464 | 903k | { |
465 | 903k | stream s; |
466 | | |
467 | 903k | s_init(&s, NULL); |
468 | 903k | swrite_position_only(&s); |
469 | 903k | sput_matrix(&s, m); |
470 | 903k | return (uint)stell(&s); |
471 | 903k | } |
472 | | |
473 | | /* Write out CTM. */ |
474 | | int |
475 | | cmd_write_ctm(const gs_matrix *m, byte *dp, int len) |
476 | 3.18M | { |
477 | 3.18M | stream s; |
478 | | |
479 | 3.18M | s_init(&s, NULL); |
480 | 3.18M | swrite_string(&s, dp + 1, len); |
481 | 3.18M | sput_matrix(&s, m); |
482 | 3.18M | return 0; |
483 | 3.18M | } |
484 | | |
485 | | /* Write out values of any unknown parameters. */ |
486 | | int |
487 | | cmd_write_unknown(gx_device_clist_writer * cldev, gx_clist_state * pcls, |
488 | | uint must_know) |
489 | 5.03M | { |
490 | 5.03M | uint unknown = ~pcls->known & must_know; |
491 | 5.03M | uint misc2_unknown = unknown & misc2_all_known; |
492 | 5.03M | byte *dp; |
493 | 5.03M | int code; |
494 | | |
495 | 5.03M | if (misc2_unknown) { |
496 | 1.90M | byte buf[ |
497 | 1.90M | 1 + /* cap_join: start_cap|join */ |
498 | 1.90M | 1 + /* end_cap|dash_cap */ |
499 | 1.90M | 1 + /* cj_ac_sa */ |
500 | 1.90M | sizeof(float) + /* flatness */ |
501 | 1.90M | sizeof(float) + /* line width */ |
502 | 1.90M | sizeof(float) + /* miter limit */ |
503 | 1.90M | 3 + /* bm_tk, op, and rend intent */ |
504 | 1.90M | sizeof(cldev->gs_gstate.alphaisshape) + |
505 | 1.90M | sizeof(float) * 2 /* ca CA */ |
506 | 1.90M | ]; |
507 | 1.90M | byte *bp = buf; |
508 | 1.90M | if (unknown & cap_join_known) { |
509 | 264k | *bp++ = (cldev->gs_gstate.line_params.start_cap << 3) + |
510 | 264k | cldev->gs_gstate.line_params.join; |
511 | 264k | *bp++ = (cldev->gs_gstate.line_params.end_cap << 3) + |
512 | 264k | cldev->gs_gstate.line_params.dash_cap; |
513 | 264k | } |
514 | 1.90M | if (unknown & cj_ac_sa_known) { |
515 | 137k | *bp++ = |
516 | 137k | ((cldev->gs_gstate.line_params.curve_join + 1) << 2) + |
517 | 137k | (cldev->gs_gstate.accurate_curves ? 2 : 0) + |
518 | 137k | (cldev->gs_gstate.stroke_adjust ? 1 : 0); |
519 | 137k | } |
520 | 1.90M | if (unknown & flatness_known) { |
521 | 262k | memcpy(bp, &cldev->gs_gstate.flatness, sizeof(float)); |
522 | 262k | bp += sizeof(float); |
523 | 262k | } |
524 | 1.90M | if (unknown & line_width_known) { |
525 | 705k | float width = |
526 | 705k | gx_current_line_width(&cldev->gs_gstate.line_params); |
527 | | |
528 | 705k | memcpy(bp, &width, sizeof(width)); |
529 | 705k | bp += sizeof(width); |
530 | 705k | } |
531 | 1.90M | if (unknown & miter_limit_known) { |
532 | 28.1k | memcpy(bp, &cldev->gs_gstate.line_params.miter_limit, |
533 | 28.1k | sizeof(float)); |
534 | 28.1k | bp += sizeof(float); |
535 | 28.1k | } |
536 | 1.90M | if (unknown & op_bm_tk_known) { |
537 | 1.20M | *bp++ = |
538 | 1.20M | ((int)cldev->gs_gstate.blend_mode << 3) + |
539 | 1.20M | cldev->gs_gstate.text_knockout; |
540 | 1.20M | *bp++ = |
541 | 1.20M | (cldev->gs_gstate.overprint_mode << 2) + |
542 | 1.20M | (cldev->gs_gstate.stroke_overprint << 1) + |
543 | 1.20M | cldev->gs_gstate.overprint; |
544 | 1.20M | *bp++ = cldev->gs_gstate.renderingintent; |
545 | 1.20M | } |
546 | 1.90M | if (unknown & ais_known) { |
547 | 65.0k | memcpy(bp, &cldev->gs_gstate.alphaisshape, |
548 | 65.0k | sizeof(cldev->gs_gstate.alphaisshape)); |
549 | 65.0k | bp += sizeof(cldev->gs_gstate.alphaisshape); |
550 | 65.0k | } |
551 | 1.90M | if (unknown & stroke_alpha_known) { |
552 | 204k | memcpy(bp, &cldev->gs_gstate.strokeconstantalpha, sizeof(float)); |
553 | 204k | bp += sizeof(float); |
554 | 204k | } |
555 | 1.90M | if (unknown & fill_alpha_known) { |
556 | 265k | memcpy(bp, &cldev->gs_gstate.fillconstantalpha, sizeof(float)); |
557 | 265k | bp += sizeof(float); |
558 | 265k | } |
559 | 1.90M | code = set_cmd_put_op(&dp, cldev, pcls, cmd_opv_set_misc2, |
560 | 1.90M | 1 + cmd_sizew(misc2_unknown) + (bp - buf)); |
561 | 1.90M | if (code < 0) |
562 | 0 | return 0; |
563 | 1.90M | memcpy(cmd_put_w(misc2_unknown, dp + 1), buf, bp - buf); |
564 | 1.90M | pcls->known |= misc2_unknown; |
565 | 1.90M | } |
566 | 5.03M | if (unknown & fill_adjust_known) { |
567 | 255k | code = set_cmd_put_op(&dp, cldev, pcls, cmd_opv_set_fill_adjust, |
568 | 255k | 1 + sizeof(fixed) * 2); |
569 | 255k | if (code < 0) |
570 | 0 | return code; |
571 | 255k | memcpy(dp + 1, &cldev->gs_gstate.fill_adjust.x, sizeof(fixed)); |
572 | 255k | memcpy(dp + 1 + sizeof(fixed), &cldev->gs_gstate.fill_adjust.y, sizeof(fixed)); |
573 | 255k | pcls->known |= fill_adjust_known; |
574 | 255k | } |
575 | 5.03M | if (unknown & ctm_known) { |
576 | 2.28M | int len = cmd_write_ctm_return_length(cldev, &ctm_only(&cldev->gs_gstate)); |
577 | | |
578 | 2.28M | code = set_cmd_put_op(&dp, cldev, pcls, cmd_opv_set_ctm, len + 1); |
579 | 2.28M | if (code < 0) |
580 | 0 | return code; |
581 | 2.28M | code = cmd_write_ctm(&ctm_only(&cldev->gs_gstate), dp, len); |
582 | 2.28M | if (code < 0) |
583 | 0 | return code; |
584 | 2.28M | pcls->known |= ctm_known; |
585 | 2.28M | } |
586 | 5.03M | if (unknown & dash_known) { |
587 | 175k | int n = cldev->gs_gstate.line_params.dash.pattern_size; |
588 | | |
589 | 175k | code = set_cmd_put_op(&dp, cldev, pcls, cmd_opv_set_dash, |
590 | 175k | 2 + (n + 2) * sizeof(float)); |
591 | 175k | if (code < 0) |
592 | 0 | return code; |
593 | 175k | dp[1] = n + (cldev->gs_gstate.line_params.dash.adapt ? 0x80 : 0) + |
594 | 175k | (cldev->gs_gstate.line_params.dot_length_absolute ? 0x40 : 0); |
595 | 175k | memcpy(dp + 2, &cldev->gs_gstate.line_params.dot_length, |
596 | 175k | sizeof(float)); |
597 | 175k | memcpy(dp + 2 + sizeof(float), |
598 | 175k | &cldev->gs_gstate.line_params.dash.offset, |
599 | 175k | sizeof(float)); |
600 | 175k | if (n != 0) |
601 | 133k | memcpy(dp + 2 + sizeof(float) * 2, |
602 | 133k | cldev->dash_pattern, n * sizeof(float)); |
603 | 175k | pcls->known |= dash_known; |
604 | 175k | } |
605 | 5.03M | if (unknown & clip_path_known) { |
606 | | /* |
607 | | * We can write out the clipping path either as rectangles |
608 | | * or as a real (filled) path. |
609 | | */ |
610 | 3.65M | const gx_clip_path *pcpath = cldev->clip_path; |
611 | 3.65M | int band_height = cldev->page_info.band_params.BandHeight; |
612 | 3.65M | int ymin = (pcls - cldev->states) * band_height; |
613 | 3.65M | int ymax = min(ymin + band_height, cldev->height); |
614 | 3.65M | gs_fixed_rect box; |
615 | 3.65M | int code; |
616 | 3.65M | int fill_adjust_size; |
617 | 3.65M | enum { |
618 | 3.65M | write_path_as_rect = 0, |
619 | 3.65M | write_path_as_rects = 1, |
620 | 3.65M | write_path_as_outer_box = 2, |
621 | 3.65M | write_path_as_path = 3 |
622 | 3.65M | } method; |
623 | | |
624 | | /* We are going to begin_clip followed by the fill_adjust to use. |
625 | | * In order to know what fill_adjust to use, we need to know whether |
626 | | * we are going to send the clip through based upon its actual |
627 | | * 'path' entry, or whether we are going to send it based upon its |
628 | | * rectangle list representation. Accordingly, we have to do the |
629 | | * logic to figure out how we are going to send it now. */ |
630 | 3.65M | if (pcpath->path_valid) { |
631 | 1.45M | if (gx_path_is_rectangle(&pcpath->path, &box) && |
632 | 1.25M | fixed_is_int(box.p.x | box.p.y | box.q.x | box.q.y)) |
633 | 97.4k | method = write_path_as_rect; |
634 | 1.35M | else if ( !(cldev->disable_mask & clist_disable_complex_clip) ) |
635 | 1.35M | method = write_path_as_path; |
636 | 0 | else |
637 | 0 | method = write_path_as_outer_box; |
638 | 2.20M | } else { |
639 | 2.20M | const gx_clip_list *list = gx_cpath_list(pcpath); |
640 | 2.20M | const gx_clip_rect *prect = list->head; |
641 | | |
642 | 2.20M | if (prect != NULL && |
643 | 83.0k | cldev->disable_mask & clist_disable_complex_clip) |
644 | 0 | method = write_path_as_outer_box; |
645 | 2.20M | else |
646 | 2.20M | method = write_path_as_rects; |
647 | 2.20M | } |
648 | | |
649 | | /* And thus how large the fill_adjust values will be. */ |
650 | 3.65M | if (method == write_path_as_path) |
651 | 1.35M | fill_adjust_size = cmd_size2w(pcpath->path_fill_adjust.x, |
652 | 3.65M | pcpath->path_fill_adjust.y); |
653 | 2.30M | else |
654 | 2.30M | fill_adjust_size = cmd_size2w(0, 0); |
655 | | |
656 | | /* Send the 'begin_clip' with the fill_adjust values. */ |
657 | 3.65M | code = set_cmd_put_op(&dp, cldev, pcls, cmd_opv_begin_clip, 1+fill_adjust_size); |
658 | 3.65M | if (code < 0) |
659 | 0 | return code; |
660 | 3.65M | dp++; |
661 | 3.65M | if (method == write_path_as_path) |
662 | 1.35M | cmd_put2w(pcpath->path_fill_adjust.x, |
663 | 3.65M | pcpath->path_fill_adjust.y, &dp); |
664 | 2.30M | else |
665 | 2.30M | cmd_put2w(0, 0, &dp); |
666 | | |
667 | | /* Then send the actual clip path representation. */ |
668 | 3.65M | switch (method) |
669 | 3.65M | { |
670 | 97.4k | case write_path_as_rect: |
671 | | /* Write the path as a rectangle. */ |
672 | 97.4k | code = cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect, |
673 | 97.4k | fixed2int_var(box.p.x), |
674 | 97.4k | fixed2int_var(box.p.y), |
675 | 97.4k | fixed2int(box.q.x - box.p.x), |
676 | 97.4k | fixed2int(box.q.y - box.p.y)); |
677 | 97.4k | break; |
678 | 1.35M | case write_path_as_path: |
679 | | /* Write the path. */ |
680 | 1.35M | code = cmd_put_path(cldev, pcls, &pcpath->path, |
681 | 1.35M | int2fixed(ymin - 1), |
682 | 1.35M | int2fixed(ymax + 1), |
683 | 1.35M | (byte)(pcpath->rule == gx_rule_even_odd ? |
684 | 1.31M | cmd_opv_eofill : cmd_opv_fill), |
685 | 1.35M | true, sn_not_first); |
686 | 1.35M | break; |
687 | 2.20M | case write_path_as_rects: |
688 | 2.20M | { |
689 | | /* Write out the rectangles. */ |
690 | 2.20M | const gx_clip_list *list = gx_cpath_list(pcpath); |
691 | 2.20M | const gx_clip_rect *prect = list->head; |
692 | | |
693 | 2.20M | if (prect == 0) |
694 | 2.12M | prect = &list->single; |
695 | 26.7M | for (; prect != 0 && code >= 0; prect = prect->next) { |
696 | 24.5M | if (prect->xmax > prect->xmin && |
697 | 24.0M | prect->ymin < ymax && prect->ymax > ymin) { |
698 | 3.31M | code = cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect, |
699 | 3.31M | prect->xmin, prect->ymin, |
700 | 3.31M | prect->xmax - prect->xmin, |
701 | 3.31M | prect->ymax - prect->ymin); |
702 | 3.31M | } |
703 | 24.5M | } |
704 | 2.20M | break; |
705 | 0 | } |
706 | 0 | default: |
707 | 0 | { |
708 | | /* Clip is complex, but disabled. Write out the outer box */ |
709 | 0 | gs_fixed_rect box; |
710 | |
|
711 | 0 | gx_cpath_outer_box(pcpath, &box); |
712 | 0 | box.p.x = fixed_floor(box.p.x); |
713 | 0 | box.p.y = fixed_floor(box.p.y); |
714 | 0 | code = cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect, |
715 | 0 | fixed2int_var(box.p.x), |
716 | 0 | fixed2int_var(box.p.y), |
717 | 0 | fixed2int_ceiling(box.q.x - box.p.x), |
718 | 0 | fixed2int_ceiling(box.q.y - box.p.y)); |
719 | 0 | } |
720 | 3.65M | } |
721 | | |
722 | | /* And now we can send 'end_clip' so the reader can finalise everything. */ |
723 | 3.65M | { |
724 | 3.65M | int end_code = |
725 | 3.65M | set_cmd_put_op(&dp, cldev, pcls, cmd_opv_end_clip, 1); |
726 | | |
727 | 3.65M | if (code >= 0) |
728 | 3.65M | code = end_code; /* take the first failure seen */ |
729 | 3.65M | if (end_code < 0) { |
730 | | /* |
731 | | * end_clip has to work despite lo-mem to maintain consistency. |
732 | | * This isn't error recovery, but just to prevent dangling |
733 | | * cmd_opv_begin_clip's. |
734 | | */ |
735 | 0 | ++cldev->ignore_lo_mem_warnings; |
736 | 0 | end_code = |
737 | 0 | set_cmd_put_op(&dp, cldev, pcls, cmd_opv_end_clip, 1); |
738 | 0 | --cldev->ignore_lo_mem_warnings; |
739 | 0 | } |
740 | 3.65M | } |
741 | 3.65M | if (code < 0) |
742 | 0 | return code; |
743 | 3.65M | pcls->clip_enabled = 1; |
744 | 3.65M | pcls->known |= clip_path_known; |
745 | 3.65M | } |
746 | 5.03M | if (unknown & color_space_known) { |
747 | 460k | byte *dp; |
748 | | |
749 | 460k | if (cldev->color_space.byte1 & 8) { /* indexed */ |
750 | 20.5k | const gs_color_space *pcs = cldev->color_space.space; |
751 | 20.5k | int hival = pcs->params.indexed.hival; |
752 | 20.5k | uint num_values = (hival + 1) * |
753 | 20.5k | gs_color_space_num_components(pcs->base_space); |
754 | 20.5k | bool use_proc = cldev->color_space.byte1 & 4; |
755 | 20.5k | const void *map_data; |
756 | 20.5k | uint map_size; |
757 | | |
758 | 20.5k | if (use_proc) { |
759 | 0 | map_data = pcs->params.indexed.lookup.map->values; |
760 | 0 | map_size = num_values * |
761 | 0 | sizeof(pcs->params.indexed.lookup.map->values[0]); |
762 | 20.5k | } else { |
763 | 20.5k | map_data = pcs->params.indexed.lookup.table.data; |
764 | 20.5k | map_size = num_values; |
765 | 20.5k | } |
766 | 20.5k | code = set_cmd_put_op(&dp, cldev, pcls, cmd_opv_set_color_space, |
767 | 20.5k | 2 + cmd_sizew(hival) + map_size + |
768 | 20.5k | sizeof(clist_icc_color_t)); |
769 | 20.5k | if (code < 0) |
770 | 0 | return code; |
771 | | /* Save the ICC information */ |
772 | 20.5k | memcpy(dp + 2, &(cldev->color_space.icc_info), |
773 | 20.5k | sizeof(clist_icc_color_t)); |
774 | 20.5k | memcpy(cmd_put_w(hival, dp + 2 + |
775 | 20.5k | sizeof(clist_icc_color_t)), map_data, map_size); |
776 | 440k | } else { |
777 | 440k | code = set_cmd_put_op(&dp, cldev, pcls, cmd_opv_set_color_space, |
778 | 440k | 2 + sizeof(clist_icc_color_t)); |
779 | 440k | if (code < 0) |
780 | 0 | return code; |
781 | 440k | memcpy(dp + 2, &(cldev->color_space.icc_info), |
782 | 440k | sizeof(clist_icc_color_t)); |
783 | 440k | } |
784 | 460k | dp[1] = cldev->color_space.byte1; |
785 | 460k | pcls->known |= color_space_known; |
786 | 460k | } |
787 | | /****** HANDLE masks ******/ |
788 | 5.03M | return 0; |
789 | 5.03M | } |
790 | | |
791 | | /* ------ Driver procedures ------ */ |
792 | | |
793 | | int |
794 | | clist_fill_path(gx_device * dev, const gs_gstate * pgs, gx_path * ppath, |
795 | | const gx_fill_params * params, const gx_drawing_color * pdcolor, |
796 | | const gx_clip_path * pcpath) |
797 | 3.42M | { |
798 | 3.42M | gx_device_clist_writer * const cdev = |
799 | 3.42M | &((gx_device_clist *)dev)->writer; |
800 | 3.42M | uint unknown = 0; |
801 | 3.42M | int ry, rheight, rx, rwidth, y0, y1; |
802 | 3.42M | gs_logical_operation_t lop = pgs->log_op; |
803 | 3.42M | byte op = (byte) |
804 | 3.42M | (params->rule == gx_rule_even_odd ? |
805 | 3.14M | cmd_opv_eofill : cmd_opv_fill); |
806 | 3.42M | gs_fixed_point adjust; |
807 | 3.42M | bool slow_rop = cmd_slow_rop(dev, lop_know_S_0(lop), pdcolor); |
808 | 3.42M | cmd_rects_enum_t re; |
809 | 3.42M | int code; |
810 | | |
811 | 3.42M | adjust = params->adjust; |
812 | 3.42M | { |
813 | 3.42M | gs_fixed_rect bbox; |
814 | | |
815 | 3.42M | if (ppath != NULL) |
816 | 3.42M | gx_path_bbox(ppath, &bbox); |
817 | 1.37k | else { |
818 | | /* gx_default_fill_path passes the clip path for shfill. */ |
819 | 1.37k | gx_cpath_outer_box(pcpath, &bbox); |
820 | 1.37k | } |
821 | 3.42M | ry = fixed2int(bbox.p.y) - 1; |
822 | 3.42M | rheight = fixed2int_ceiling(bbox.q.y) - ry + 1; |
823 | 3.42M | crop_fill_y(cdev, ry, rheight); |
824 | 3.42M | if (rheight <= 0) |
825 | 311k | return 0; |
826 | 3.11M | if (rheight > cdev->height) |
827 | 0 | return gs_error_limitcheck; |
828 | 3.11M | rx = fixed2int(bbox.p.x) - 1; |
829 | 3.11M | rwidth = fixed2int_ceiling(bbox.q.x) - rx + 1; |
830 | 3.11M | fit_fill_w(cdev, rx, rwidth); |
831 | 3.11M | } |
832 | 3.11M | if ( (cdev->disable_mask & clist_disable_fill_path) || |
833 | 3.11M | gs_debug_c(',') |
834 | 3.11M | ) { |
835 | | /* Disable path-based banding. */ |
836 | 0 | return gx_default_fill_path(dev, pgs, ppath, params, pdcolor, |
837 | 0 | pcpath); |
838 | 0 | } |
839 | 3.11M | if (pdcolor != NULL && gx_dc_is_pattern2_color(pdcolor)) { |
840 | | /* Here we need to intersect *ppath, *pcpath and shading bbox. |
841 | | Call the default implementation, which has a special |
842 | | branch for processing a shading fill with the clip writer device. |
843 | | It will call us back with pdcolor=NULL for passing |
844 | | the intersected clipping path, |
845 | | and then will decompose the shading into trapezoids. |
846 | | See comment below about pdcolor == NULL. |
847 | | */ |
848 | 1.30k | cdev->cropping_saved = false; |
849 | 1.30k | code = gx_default_fill_path(dev, pgs, ppath, params, pdcolor, pcpath); |
850 | 1.30k | if (cdev->cropping_saved) { |
851 | 1.30k | cdev->cropping_min = cdev->save_cropping_min; |
852 | 1.30k | cdev->cropping_max = cdev->save_cropping_max; |
853 | 1.30k | if_debug2m('v', cdev->memory, |
854 | 1.30k | "[v] clist_fill_path: restore cropping_min=%d croping_max=%d\n", |
855 | 1.30k | cdev->save_cropping_min, cdev->save_cropping_max); |
856 | 1.30k | } |
857 | 1.30k | return code; |
858 | 1.30k | } |
859 | 3.11M | y0 = ry; |
860 | 3.11M | y1 = ry + rheight; |
861 | 3.11M | cmd_check_fill_known(cdev, pgs, params->flatness, &adjust, pcpath, |
862 | 3.11M | &unknown); |
863 | 3.11M | if (unknown) |
864 | 195k | cmd_clear_known(cdev, unknown); |
865 | 3.11M | if (cdev->permanent_error < 0) |
866 | 0 | return (cdev->permanent_error); |
867 | 3.11M | if (pdcolor == NULL) { |
868 | | /* See comment above about pattern2_color. |
869 | | Put the clipping path only. |
870 | | The graphics library will call us again with subdividing |
871 | | the shading into trapezoids and rectangles. |
872 | | Narrow cropping_min, croping_max for such calls. */ |
873 | 1.30k | cdev->cropping_saved = true; |
874 | 1.30k | cdev->save_cropping_min = cdev->cropping_min; |
875 | 1.30k | cdev->save_cropping_max = cdev->cropping_max; |
876 | 1.30k | cdev->cropping_min = max(ry, cdev->cropping_min); |
877 | 1.30k | cdev->cropping_max = min(ry + rheight, cdev->cropping_max); |
878 | 1.30k | if_debug2m('v', cdev->memory, |
879 | 1.30k | "[v] clist_fill_path: narrow cropping_min=%d croping_max=%d\n", |
880 | 1.30k | cdev->save_cropping_min, cdev->save_cropping_max); |
881 | 1.30k | RECT_ENUM_INIT(re, ry, rheight); |
882 | 5.94k | do { |
883 | 5.94k | RECT_STEP_INIT(re); |
884 | 5.94k | if (pcpath != NULL) { |
885 | 5.94k | code = cmd_do_write_unknown(cdev, re.pcls, clip_path_known); |
886 | 5.94k | if (code < 0) |
887 | 0 | return code; |
888 | 5.94k | } |
889 | 5.94k | code = cmd_do_enable_clip(cdev, re.pcls, pcpath != NULL); |
890 | 5.94k | if (code < 0) |
891 | 0 | return code; |
892 | 5.94k | re.y += re.height; |
893 | 5.94k | } while (re.y < re.yend); |
894 | 3.11M | } else { |
895 | | /* We should not reach here with ppath==NULL (pdcolor != NULL, so not a shading fill */ |
896 | 3.11M | if (ppath == NULL) |
897 | 0 | return_error(gs_error_unregistered); |
898 | | |
899 | | /* If needed, update the trans_bbox */ |
900 | 3.11M | if (cdev->pdf14_needed) { |
901 | 959k | gs_int_rect bbox; |
902 | | |
903 | 959k | bbox.p.x = rx; |
904 | 959k | bbox.q.x = rx + rwidth - 1; |
905 | 959k | bbox.p.y = ry; |
906 | 959k | bbox.q.y = ry + rheight - 1; |
907 | | |
908 | 959k | clist_update_trans_bbox(cdev, &bbox); |
909 | 959k | } |
910 | | |
911 | 3.11M | RECT_ENUM_INIT(re, ry, rheight); |
912 | 8.06M | do { |
913 | 8.06M | RECT_STEP_INIT(re); |
914 | 8.06M | code = cmd_do_write_unknown(cdev, re.pcls, FILL_KNOWN); |
915 | 8.06M | if (code < 0) |
916 | 0 | return code; |
917 | 8.06M | if ((code = cmd_do_enable_clip(cdev, re.pcls, pcpath != NULL)) < 0 || |
918 | 8.06M | (code = cmd_update_lop(cdev, re.pcls, lop)) < 0 |
919 | 8.06M | ) |
920 | 0 | return code; |
921 | 8.06M | code = cmd_put_drawing_color(cdev, re.pcls, pdcolor, &re, |
922 | 8.06M | devn_not_tile_fill); |
923 | 8.06M | if (code == gs_error_unregistered) |
924 | 0 | return code; |
925 | 8.06M | if (code < 0) { |
926 | | /* Something went wrong, use the default implementation. */ |
927 | 169 | return gx_default_fill_path(dev, pgs, ppath, params, pdcolor, |
928 | 169 | pcpath); |
929 | 169 | } |
930 | 8.06M | re.pcls->color_usage.slow_rop |= slow_rop; |
931 | 8.06M | code = cmd_put_path(cdev, re.pcls, ppath, |
932 | 8.06M | int2fixed(max(re.y - 1, y0)), |
933 | 8.06M | int2fixed(min(re.y + re.height + 1, y1)), |
934 | 8.06M | op, |
935 | 8.06M | true, sn_none /* fill doesn't need the notes */ ); |
936 | 8.06M | if (code < 0) |
937 | 0 | return code; |
938 | 8.06M | re.y += re.height; |
939 | 8.06M | } while (re.y < re.yend); |
940 | 3.11M | } |
941 | 3.11M | return 0; |
942 | 3.11M | } |
943 | | |
944 | | int clist_lock_pattern(gx_device * pdev, gs_gstate * pgs, gs_id pattern, int lock) |
945 | 414 | { |
946 | 414 | gx_device_clist_writer * const cdev = |
947 | 414 | &((gx_device_clist *)pdev)->writer; |
948 | 414 | byte *dp; |
949 | 414 | int code; |
950 | | |
951 | | /* We need to both lock now, and ensure that we lock on reading this back. */ |
952 | 414 | code = gx_pattern_cache_entry_set_lock(pgs, pattern, lock); |
953 | 414 | if (code < 0) |
954 | 0 | return code; |
955 | | |
956 | 414 | code = set_cmd_put_all_op(&dp, cdev, cmd_opv_lock_pattern, |
957 | 414 | 1 + 1 + sizeof(pattern)); |
958 | | |
959 | 414 | if (code < 0) |
960 | 0 | return code; |
961 | 414 | dp[1] = lock; |
962 | 414 | memcpy(dp+2, &pattern, sizeof(pattern)); |
963 | 414 | return 0; |
964 | 414 | } |
965 | | |
966 | | int |
967 | | clist_fill_stroke_path(gx_device * pdev, const gs_gstate * pgs, |
968 | | gx_path * ppath, |
969 | | const gx_fill_params * params_fill, |
970 | | const gx_device_color * pdevc_fill, |
971 | | const gx_stroke_params * params_stroke, |
972 | | const gx_device_color * pdevc_stroke, |
973 | | const gx_clip_path * pcpath) |
974 | 41.4k | { |
975 | 41.4k | gx_device_clist_writer * const cdev = |
976 | 41.4k | &((gx_device_clist *)pdev)->writer; |
977 | 41.4k | int pattern_size = pgs->line_params.dash.pattern_size; |
978 | 41.4k | byte op = (byte) (params_fill->rule == gx_rule_even_odd ? |
979 | 39.7k | cmd_opv_eofill_stroke : cmd_opv_fill_stroke); |
980 | 41.4k | uint unknown = 0; |
981 | 41.4k | gs_fixed_rect bbox; |
982 | 41.4k | gs_fixed_point expansion; |
983 | 41.4k | int adjust_y, expansion_code; |
984 | 41.4k | int ry, rheight; |
985 | 41.4k | gs_logical_operation_t lop = pgs->log_op; |
986 | 41.4k | bool slow_rop = cmd_slow_rop(pdev, lop_know_S_0(lop), pdevc_fill); |
987 | 41.4k | cmd_rects_enum_t re; |
988 | | |
989 | 41.4k | if (pdevc_stroke == NULL || pdevc_fill == NULL) |
990 | 0 | return_error(gs_error_unknownerror); /* shouldn't happen */ |
991 | | |
992 | 41.4k | if ((cdev->disable_mask & (clist_disable_fill_path | clist_disable_stroke_path)) || |
993 | 41.4k | gs_debug_c(',') |
994 | 41.4k | ) { |
995 | | /* Disable path-based banding. */ |
996 | 0 | return gx_default_fill_stroke_path(pdev, pgs, ppath, params_fill, pdevc_fill, |
997 | 0 | params_stroke, pdevc_stroke, pcpath); |
998 | 0 | } |
999 | | /* TODO: For now punt to default if we have shaded color (pattern2) */ |
1000 | 41.4k | if (gx_dc_is_pattern2_color(pdevc_fill) || gx_dc_is_pattern2_color(pdevc_stroke)) { |
1001 | 0 | return gx_default_fill_stroke_path(pdev, pgs, ppath, params_fill, pdevc_fill, |
1002 | 0 | params_stroke, pdevc_stroke, pcpath); |
1003 | 0 | } |
1004 | 41.4k | gx_path_bbox(ppath, &bbox); |
1005 | | /* We must use the supplied gs_gstate, not our saved one, */ |
1006 | | /* for computing the stroke expansion. */ |
1007 | 41.4k | expansion_code = gx_stroke_path_expansion(pgs, ppath, &expansion); |
1008 | 41.4k | if (expansion_code < 0) { |
1009 | | /* Expansion is too large: use the entire page. */ |
1010 | 714 | adjust_y = 0; |
1011 | 714 | ry = 0; |
1012 | 714 | rheight = pdev->height; |
1013 | 40.7k | } else { |
1014 | 40.7k | adjust_y = fixed2int_ceiling(expansion.y) + 1; |
1015 | 40.7k | ry = fixed2int(bbox.p.y) - adjust_y; |
1016 | 40.7k | rheight = fixed2int_ceiling(bbox.q.y) - ry + adjust_y; |
1017 | 40.7k | fit_fill_y(pdev, ry, rheight); |
1018 | 40.7k | fit_fill_h(pdev, ry, rheight); |
1019 | 40.7k | if (rheight <= 0) |
1020 | 661 | return 0; |
1021 | 40.7k | } |
1022 | | /* Check the dash pattern, since we bail out if */ |
1023 | | /* the pattern is too large. */ |
1024 | 40.8k | if (cdev->gs_gstate.line_params.dash.pattern_size != pattern_size || |
1025 | 40.7k | (pattern_size != 0 && |
1026 | 67 | memcmp(cdev->dash_pattern, pgs->line_params.dash.pattern, |
1027 | 67 | pattern_size * sizeof(float))) || |
1028 | 40.7k | cdev->gs_gstate.line_params.dash.offset != |
1029 | 40.7k | pgs->line_params.dash.offset || |
1030 | 40.7k | cdev->gs_gstate.line_params.dash.adapt != |
1031 | 40.7k | pgs->line_params.dash.adapt || |
1032 | 40.7k | cdev->gs_gstate.line_params.dot_length != |
1033 | 40.7k | pgs->line_params.dot_length || |
1034 | 40.7k | cdev->gs_gstate.line_params.dot_length_absolute != |
1035 | 40.7k | pgs->line_params.dot_length_absolute |
1036 | 40.8k | ) { |
1037 | | /* Bail out if the dash pattern is too long. */ |
1038 | 51 | if (pattern_size > cmd_max_dash) |
1039 | 0 | return gx_default_fill_stroke_path(pdev, pgs, ppath, params_fill, pdevc_fill, |
1040 | 0 | params_stroke, pdevc_stroke, pcpath); |
1041 | 51 | unknown |= dash_known; |
1042 | | /* |
1043 | | * Temporarily reset the dash pattern pointer for gx_set_dash, |
1044 | | * but don't leave it set, since that would confuse the GC. |
1045 | | */ |
1046 | 51 | cdev->gs_gstate.line_params.dash.pattern = cdev->dash_pattern; |
1047 | 51 | gx_set_dash(&cdev->gs_gstate.line_params.dash, |
1048 | 51 | pgs->line_params.dash.pattern, |
1049 | 51 | pgs->line_params.dash.pattern_size, |
1050 | 51 | pgs->line_params.dash.offset, NULL); |
1051 | 51 | cdev->gs_gstate.line_params.dash.pattern = 0; |
1052 | 51 | gx_set_dash_adapt(&cdev->gs_gstate.line_params.dash, |
1053 | 51 | pgs->line_params.dash.adapt); |
1054 | 51 | gx_set_dot_length(&cdev->gs_gstate.line_params, |
1055 | 51 | pgs->line_params.dot_length, |
1056 | 51 | pgs->line_params.dot_length_absolute); |
1057 | 51 | } |
1058 | | |
1059 | 40.8k | if (state_neq(line_params.start_cap) || state_neq(line_params.join) || |
1060 | 38.1k | state_neq(line_params.end_cap) || state_neq(line_params.dash_cap)) { |
1061 | 2.60k | unknown |= cap_join_known; |
1062 | 2.60k | state_update(line_params.start_cap); |
1063 | 2.60k | state_update(line_params.end_cap); |
1064 | 2.60k | state_update(line_params.dash_cap); |
1065 | 2.60k | state_update(line_params.join); |
1066 | 2.60k | } |
1067 | 40.8k | cmd_check_fill_known(cdev, pgs, params_fill->flatness, &pgs->fill_adjust, |
1068 | 40.8k | pcpath, &unknown); |
1069 | 40.8k | if (state_neq(line_params.half_width)) { |
1070 | 7.98k | unknown |= line_width_known; |
1071 | 7.98k | state_update(line_params.half_width); |
1072 | 7.98k | } |
1073 | 40.8k | if (state_neq(line_params.miter_limit)) { |
1074 | 1.51k | unknown |= miter_limit_known; |
1075 | 1.51k | gx_set_miter_limit(&cdev->gs_gstate.line_params, |
1076 | 1.51k | pgs->line_params.miter_limit); |
1077 | 1.51k | } |
1078 | 40.8k | if (state_neq(ctm.xx) || state_neq(ctm.xy) || |
1079 | 32.7k | state_neq(ctm.yx) || state_neq(ctm.yy) || |
1080 | | /* We don't actually need tx or ty, but we don't want to bother */ |
1081 | | /* tracking them separately from the other coefficients. */ |
1082 | 32.7k | state_neq(ctm.tx) || state_neq(ctm.ty) |
1083 | 40.8k | ) { |
1084 | 9.94k | unknown |= ctm_known; |
1085 | 9.94k | state_update(ctm); |
1086 | 9.94k | } |
1087 | 40.8k | if (unknown) |
1088 | 11.7k | cmd_clear_known(cdev, unknown); |
1089 | 40.8k | if (cdev->permanent_error < 0) |
1090 | 0 | return (cdev->permanent_error); |
1091 | | /* If needed, update the trans_bbox */ |
1092 | 40.8k | if (cdev->pdf14_needed) { |
1093 | 8.59k | gs_int_rect trans_bbox; |
1094 | 8.59k | int rx = fixed2int(bbox.p.x) - 1; |
1095 | 8.59k | int rwidth = fixed2int_ceiling(bbox.q.x) - rx + 1; |
1096 | 8.59k | unknown |= STROKE_ALL_KNOWN; |
1097 | | |
1098 | 8.59k | fit_fill_w(cdev, rx, rwidth); |
1099 | 8.59k | trans_bbox.p.x = rx; |
1100 | 8.59k | trans_bbox.q.x = rx + rwidth - 1; |
1101 | 8.59k | trans_bbox.p.y = ry; |
1102 | 8.59k | trans_bbox.q.y = ry + rheight - 1; |
1103 | | |
1104 | 8.59k | clist_update_trans_bbox(cdev, &trans_bbox); |
1105 | 8.59k | } |
1106 | | /* If either fill or stroke uses overprint, or overprint_mode != 0, then we */ |
1107 | | /* need to write out the overprint drawn_comps and retain_* */ |
1108 | 40.8k | if (((pgs->overprint_mode || pgs->overprint || pgs->stroke_overprint))) { |
1109 | 8.74k | unknown |= op_bm_tk_known; |
1110 | 8.74k | } |
1111 | 40.8k | RECT_ENUM_INIT(re, ry, rheight); |
1112 | 253k | do { |
1113 | 253k | int code; |
1114 | | |
1115 | 253k | RECT_STEP_INIT(re); |
1116 | 253k | if ((code = cmd_do_write_unknown(cdev, re.pcls, STROKE_ALL_KNOWN | FILL_KNOWN)) < 0) |
1117 | 0 | return code; |
1118 | 253k | if ((code = cmd_do_enable_clip(cdev, re.pcls, pcpath != NULL)) < 0) |
1119 | 0 | return code; |
1120 | 253k | if ((code = cmd_update_lop(cdev, re.pcls, lop)) < 0) |
1121 | 0 | return code; |
1122 | | /* Write the stroke first since do_fill_stroke will have locked the pattern */ |
1123 | | /* tile if needed, and we want it locked after reading the stroke color. */ |
1124 | 253k | code = cmd_put_drawing_color(cdev, re.pcls, pdevc_stroke, &re, devn_not_tile_stroke); |
1125 | 253k | if (code < 0) { |
1126 | | /* Something went wrong, use the default implementation. */ |
1127 | 0 | return gx_default_fill_stroke_path(pdev, pgs, ppath, params_fill, pdevc_fill, |
1128 | 0 | params_stroke, pdevc_stroke, pcpath); |
1129 | 0 | } |
1130 | 253k | code = cmd_put_drawing_color(cdev, re.pcls, pdevc_fill, &re, devn_not_tile_fill); |
1131 | 253k | if (code < 0) { |
1132 | | /* Something went wrong, use the default implementation. */ |
1133 | 100 | return gx_default_fill_stroke_path(pdev, pgs, ppath, params_fill, pdevc_fill, |
1134 | 100 | params_stroke, pdevc_stroke, pcpath); |
1135 | 100 | } |
1136 | 253k | re.pcls->color_usage.slow_rop |= slow_rop; |
1137 | | |
1138 | | /* Don't skip segments when expansion is unknown. */ |
1139 | | |
1140 | 253k | code = cmd_put_path(cdev, re.pcls, ppath, min_fixed, max_fixed, |
1141 | 253k | op, false, (segment_notes)~0); |
1142 | 253k | if (code < 0) |
1143 | 0 | return code; |
1144 | 253k | re.y += re.height; |
1145 | 253k | } while (re.y < re.yend); |
1146 | 40.7k | return 0; |
1147 | 40.8k | } |
1148 | | |
1149 | | int |
1150 | | clist_stroke_path(gx_device * dev, const gs_gstate * pgs, gx_path * ppath, |
1151 | | const gx_stroke_params * params, |
1152 | | const gx_drawing_color * pdcolor, const gx_clip_path * pcpath) |
1153 | 1.66M | { |
1154 | 1.66M | gx_device_clist_writer * const cdev = |
1155 | 1.66M | &((gx_device_clist *)dev)->writer; |
1156 | 1.66M | int pattern_size = pgs->line_params.dash.pattern_size; |
1157 | 1.66M | uint unknown = 0; |
1158 | 1.66M | gs_fixed_rect bbox; |
1159 | 1.66M | gs_fixed_point expansion; |
1160 | 1.66M | int adjust_y, expansion_code; |
1161 | 1.66M | int ry, rheight; |
1162 | 1.66M | gs_logical_operation_t lop = pgs->log_op; |
1163 | 1.66M | bool slow_rop = cmd_slow_rop(dev, lop_know_S_0(lop), pdcolor); |
1164 | 1.66M | cmd_rects_enum_t re; |
1165 | | |
1166 | 1.66M | CMD_CHECK_LAST_OP_BLOCK_DEFINED(cdev); |
1167 | 1.66M | if ((cdev->disable_mask & clist_disable_stroke_path) || |
1168 | 1.66M | gs_debug_c(',') |
1169 | 1.66M | ) { |
1170 | | /* Disable path-based banding. */ |
1171 | 0 | return gx_default_stroke_path(dev, pgs, ppath, params, pdcolor, |
1172 | 0 | pcpath); |
1173 | 0 | } |
1174 | 1.66M | gx_path_bbox(ppath, &bbox); |
1175 | | /* We must use the supplied gs_gstate, not our saved one, */ |
1176 | | /* for computing the stroke expansion. */ |
1177 | 1.66M | expansion_code = gx_stroke_path_expansion(pgs, ppath, &expansion); |
1178 | 1.66M | if (expansion_code < 0) { |
1179 | | /* Expansion is too large: use the entire page. */ |
1180 | 24.1k | adjust_y = 0; |
1181 | 24.1k | ry = 0; |
1182 | 24.1k | rheight = dev->height; |
1183 | 1.64M | } else { |
1184 | 1.64M | adjust_y = fixed2int_ceiling(expansion.y) + 1; |
1185 | 1.64M | ry = fixed2int(bbox.p.y) - adjust_y; |
1186 | 1.64M | rheight = fixed2int_ceiling(bbox.q.y) - ry + adjust_y; |
1187 | 1.64M | fit_fill_y(dev, ry, rheight); |
1188 | 1.64M | fit_fill_h(dev, ry, rheight); |
1189 | 1.64M | if (rheight <= 0) |
1190 | 90.6k | return 0; |
1191 | 1.64M | } |
1192 | | /* Check the dash pattern, since we bail out if */ |
1193 | | /* the pattern is too large. */ |
1194 | 1.57M | if (cdev->gs_gstate.line_params.dash.pattern_size != pattern_size || |
1195 | 1.56M | (pattern_size != 0 && |
1196 | 6.84k | memcmp(cdev->dash_pattern, pgs->line_params.dash.pattern, |
1197 | 6.84k | pattern_size * sizeof(float))) || |
1198 | 1.56M | cdev->gs_gstate.line_params.dash.offset != |
1199 | 1.56M | pgs->line_params.dash.offset || |
1200 | 1.56M | cdev->gs_gstate.line_params.dash.adapt != |
1201 | 1.56M | pgs->line_params.dash.adapt || |
1202 | 1.56M | cdev->gs_gstate.line_params.dot_length != |
1203 | 1.56M | pgs->line_params.dot_length || |
1204 | 1.56M | cdev->gs_gstate.line_params.dot_length_absolute != |
1205 | 1.56M | pgs->line_params.dot_length_absolute |
1206 | 1.57M | ) { |
1207 | | /* Bail out if the dash pattern is too long. */ |
1208 | 12.8k | if (pattern_size > cmd_max_dash) |
1209 | 0 | return gx_default_stroke_path(dev, pgs, ppath, params, |
1210 | 0 | pdcolor, pcpath); |
1211 | 12.8k | unknown |= dash_known; |
1212 | | /* |
1213 | | * Temporarily reset the dash pattern pointer for gx_set_dash, |
1214 | | * but don't leave it set, since that would confuse the GC. |
1215 | | */ |
1216 | 12.8k | cdev->gs_gstate.line_params.dash.pattern = cdev->dash_pattern; |
1217 | 12.8k | gx_set_dash(&cdev->gs_gstate.line_params.dash, |
1218 | 12.8k | pgs->line_params.dash.pattern, |
1219 | 12.8k | pgs->line_params.dash.pattern_size, |
1220 | 12.8k | pgs->line_params.dash.offset, NULL); |
1221 | 12.8k | cdev->gs_gstate.line_params.dash.pattern = 0; |
1222 | 12.8k | gx_set_dash_adapt(&cdev->gs_gstate.line_params.dash, |
1223 | 12.8k | pgs->line_params.dash.adapt); |
1224 | 12.8k | gx_set_dot_length(&cdev->gs_gstate.line_params, |
1225 | 12.8k | pgs->line_params.dot_length, |
1226 | 12.8k | pgs->line_params.dot_length_absolute); |
1227 | 12.8k | } |
1228 | | |
1229 | 1.57M | if (state_neq(line_params.start_cap) || state_neq(line_params.join) || |
1230 | 1.55M | state_neq(line_params.end_cap) || state_neq(line_params.dash_cap)) { |
1231 | 23.8k | unknown |= cap_join_known; |
1232 | 23.8k | state_update(line_params.start_cap); |
1233 | 23.8k | state_update(line_params.end_cap); |
1234 | 23.8k | state_update(line_params.dash_cap); |
1235 | 23.8k | state_update(line_params.join); |
1236 | 23.8k | } |
1237 | 1.57M | cmd_check_fill_known(cdev, pgs, params->flatness, &pgs->fill_adjust, |
1238 | 1.57M | pcpath, &unknown); |
1239 | 1.57M | if (state_neq(line_params.half_width)) { |
1240 | 87.0k | unknown |= line_width_known; |
1241 | 87.0k | state_update(line_params.half_width); |
1242 | 87.0k | } |
1243 | 1.57M | if (state_neq(line_params.miter_limit)) { |
1244 | 2.72k | unknown |= miter_limit_known; |
1245 | 2.72k | gx_set_miter_limit(&cdev->gs_gstate.line_params, |
1246 | 2.72k | pgs->line_params.miter_limit); |
1247 | 2.72k | } |
1248 | 1.57M | if (state_neq(ctm.xx) || state_neq(ctm.xy) || |
1249 | 1.48M | state_neq(ctm.yx) || state_neq(ctm.yy) || |
1250 | | /* We don't actually need tx or ty, but we don't want to bother */ |
1251 | | /* tracking them separately from the other coefficients. */ |
1252 | 1.48M | state_neq(ctm.tx) || state_neq(ctm.ty) |
1253 | 1.57M | ) { |
1254 | 493k | unknown |= ctm_known; |
1255 | 493k | state_update(ctm); |
1256 | 493k | } |
1257 | 1.57M | if (unknown) |
1258 | 551k | cmd_clear_known(cdev, unknown); |
1259 | 1.57M | if (cdev->permanent_error < 0) |
1260 | 0 | return (cdev->permanent_error); |
1261 | | /* If needed, update the trans_bbox */ |
1262 | 1.57M | if (cdev->pdf14_needed) { |
1263 | 277k | gs_int_rect trans_bbox; |
1264 | 277k | int rx = fixed2int(bbox.p.x) - 1; |
1265 | 277k | int rwidth = fixed2int_ceiling(bbox.q.x) - rx + 1; |
1266 | | |
1267 | 277k | fit_fill_w(cdev, rx, rwidth); |
1268 | 277k | trans_bbox.p.x = rx; |
1269 | 277k | trans_bbox.q.x = rx + rwidth - 1; |
1270 | 277k | trans_bbox.p.y = ry; |
1271 | 277k | trans_bbox.q.y = ry + rheight - 1; |
1272 | | |
1273 | 277k | clist_update_trans_bbox(cdev, &trans_bbox); |
1274 | 277k | } |
1275 | 1.57M | RECT_ENUM_INIT(re, ry, rheight); |
1276 | 3.87M | do { |
1277 | 3.87M | int code; |
1278 | | |
1279 | 3.87M | RECT_STEP_INIT(re); |
1280 | 3.87M | CMD_CHECK_LAST_OP_BLOCK_DEFINED(cdev); |
1281 | 3.87M | if ((code = cmd_do_write_unknown(cdev, re.pcls, STROKE_ALL_KNOWN)) < 0 || |
1282 | 3.87M | (code = cmd_do_enable_clip(cdev, re.pcls, pcpath != NULL)) < 0 || |
1283 | 3.87M | (code = cmd_update_lop(cdev, re.pcls, lop)) < 0 |
1284 | 3.87M | ) |
1285 | 0 | return code; |
1286 | 3.87M | CMD_CHECK_LAST_OP_BLOCK_DEFINED(cdev); |
1287 | 3.87M | code = cmd_put_drawing_color(cdev, re.pcls, pdcolor, &re, devn_not_tile_stroke); |
1288 | 3.87M | if (code == gs_error_unregistered) |
1289 | 0 | return code; |
1290 | 3.87M | if (code < 0) { |
1291 | | /* Something went wrong, use the default implementation. */ |
1292 | 135 | cdev->cropping_saved = false; |
1293 | 135 | code = gx_default_stroke_path(dev, pgs, ppath, params, pdcolor, |
1294 | 135 | pcpath); |
1295 | 135 | if (cdev->cropping_saved) { |
1296 | 0 | cdev->cropping_min = cdev->save_cropping_min; |
1297 | 0 | cdev->cropping_max = cdev->save_cropping_max; |
1298 | 0 | if_debug2m('v', cdev->memory, |
1299 | 0 | "[v] clist_stroke_path: restore cropping_min=%d croping_max=%d\n", |
1300 | 0 | cdev->save_cropping_min, cdev->save_cropping_max); |
1301 | 0 | } |
1302 | 135 | return code; |
1303 | 135 | } |
1304 | 3.87M | re.pcls->color_usage.slow_rop |= slow_rop; |
1305 | 3.87M | CMD_CHECK_LAST_OP_BLOCK_DEFINED(cdev); |
1306 | 3.87M | { |
1307 | 3.87M | fixed ymin, ymax; |
1308 | | |
1309 | | /* |
1310 | | * If a dash pattern is active, we can't skip segments |
1311 | | * outside the clipping region, because that would throw off |
1312 | | * the pattern. |
1313 | | * Don't skip segments when expansion is unknown. |
1314 | | */ |
1315 | | |
1316 | 3.87M | if (pattern_size || expansion_code < 0 ) { |
1317 | 888k | ymin = min_fixed; |
1318 | 888k | ymax = max_fixed; |
1319 | 2.98M | } else { |
1320 | 2.98M | ymin = int2fixed(re.y - adjust_y); |
1321 | 2.98M | ymax = int2fixed(re.y + re.height + adjust_y); |
1322 | 2.98M | } |
1323 | 3.87M | code = cmd_put_path(cdev, re.pcls, ppath, ymin, ymax, |
1324 | 3.87M | cmd_opv_stroke, |
1325 | 3.87M | false, (segment_notes)~0); |
1326 | 3.87M | if (code < 0) |
1327 | 0 | return code; |
1328 | 3.87M | } |
1329 | 3.87M | re.y += re.height; |
1330 | 3.87M | } while (re.y < re.yend); |
1331 | 1.57M | return 0; |
1332 | 1.57M | } |
1333 | | |
1334 | | /* |
1335 | | * Fill_parallelogram and fill_triangle aren't very efficient. This isn't |
1336 | | * important right now, since the non-degenerate case is only used for |
1337 | | * smooth shading. However, the rectangular case of fill_parallelogram is |
1338 | | * sometimes used for images, so its performance does matter. |
1339 | | */ |
1340 | | |
1341 | | static int |
1342 | | clist_put_polyfill(gx_device *dev, fixed px, fixed py, |
1343 | | const gs_fixed_point *points, int num_points, |
1344 | | const gx_drawing_color *pdcolor, gs_logical_operation_t lop) |
1345 | 1.51M | { |
1346 | 1.51M | gx_path path; |
1347 | 1.51M | gs_memory_t *mem = dev->memory; |
1348 | 1.51M | int code; |
1349 | 1.51M | gx_device_clist_writer * const cdev = |
1350 | 1.51M | &((gx_device_clist *)dev)->writer; |
1351 | 1.51M | gs_fixed_rect bbox; |
1352 | 1.51M | int ry, rheight, y0, y1; |
1353 | 1.51M | bool slow_rop = cmd_slow_rop(dev, lop_know_S_0(lop), pdcolor); |
1354 | 1.51M | cmd_rects_enum_t re; |
1355 | | |
1356 | 1.51M | if (gs_debug_c(',')) |
1357 | 0 | return -1; /* path-based banding is disabled */ |
1358 | 1.51M | gx_path_init_local(&path, mem); |
1359 | 1.51M | if ((code = gx_path_add_point(&path, px, py)) < 0 || |
1360 | 1.51M | (code = gx_path_add_lines(&path, points, num_points)) < 0 |
1361 | 1.51M | ) |
1362 | 0 | goto out; |
1363 | 1.51M | gx_path_bbox(&path, &bbox); |
1364 | 1.51M | ry = fixed2int(bbox.p.y) - 1; |
1365 | 1.51M | rheight = fixed2int_ceiling(bbox.q.y) - ry + 1; |
1366 | 1.51M | fit_fill_y(dev, ry, rheight); |
1367 | 1.51M | fit_fill_h(dev, ry, rheight); |
1368 | 1.51M | if (rheight <= 0) |
1369 | 1.04M | return 0; |
1370 | 471k | y0 = ry; |
1371 | 471k | y1 = ry + rheight; |
1372 | 471k | if (cdev->permanent_error < 0) |
1373 | 0 | return (cdev->permanent_error); |
1374 | | /* If needed, update the trans_bbox */ |
1375 | 471k | if (cdev->pdf14_needed) { |
1376 | 62.0k | gs_int_rect trans_bbox; |
1377 | 62.0k | int rx = fixed2int(bbox.p.x) - 1; |
1378 | 62.0k | int rwidth = fixed2int_ceiling(bbox.q.x) - rx + 1; |
1379 | | |
1380 | 62.0k | fit_fill_w(cdev, rx, rwidth); |
1381 | 62.0k | trans_bbox.p.x = rx; |
1382 | 62.0k | trans_bbox.q.x = rx + rwidth - 1; |
1383 | 62.0k | trans_bbox.p.y = ry; |
1384 | 62.0k | trans_bbox.q.y = ry + rheight - 1; |
1385 | | |
1386 | 62.0k | clist_update_trans_bbox(cdev, &trans_bbox); |
1387 | 62.0k | } |
1388 | 471k | RECT_ENUM_INIT(re, ry, rheight); |
1389 | 509k | do { |
1390 | 509k | RECT_STEP_INIT(re); |
1391 | 509k | if ((code = cmd_update_lop(cdev, re.pcls, lop)) < 0 || |
1392 | 509k | (code = cmd_put_drawing_color(cdev, re.pcls, pdcolor, &re, devn_not_tile_fill)) < 0) |
1393 | 0 | goto out; |
1394 | 509k | re.pcls->color_usage.slow_rop |= slow_rop; |
1395 | 509k | code = cmd_put_path(cdev, re.pcls, &path, |
1396 | 509k | int2fixed(max(re.y - 1, y0)), |
1397 | 509k | int2fixed(min(re.y + re.height + 1, y1)), |
1398 | 509k | cmd_opv_polyfill, |
1399 | 509k | true, sn_none /* fill doesn't need the notes */ ); |
1400 | 509k | if (code < 0) |
1401 | 0 | goto out; |
1402 | 509k | re.y += re.height; |
1403 | 509k | } while (re.y < re.yend); |
1404 | 471k | out: |
1405 | 471k | gx_path_free(&path, "clist_put_polyfill"); |
1406 | 471k | return code; |
1407 | 471k | } |
1408 | | |
1409 | | int |
1410 | | clist_fill_parallelogram(gx_device *dev, fixed px, fixed py, |
1411 | | fixed ax, fixed ay, fixed bx, fixed by, |
1412 | | const gx_drawing_color *pdcolor, |
1413 | | gs_logical_operation_t lop) |
1414 | 5.56M | { |
1415 | 5.56M | gs_fixed_point pts[3]; |
1416 | 5.56M | int code; |
1417 | | |
1418 | 5.56M | if (PARALLELOGRAM_IS_RECT(ax, ay, bx, by)) { |
1419 | 4.05M | gs_int_rect r; |
1420 | | |
1421 | 4.05M | INT_RECT_FROM_PARALLELOGRAM(&r, px, py, ax, ay, bx, by); |
1422 | 4.05M | return gx_fill_rectangle_device_rop(r.p.x, r.p.y, r.q.x - r.p.x, |
1423 | 4.05M | r.q.y - r.p.y, pdcolor, dev, lop); |
1424 | 4.05M | } |
1425 | 1.51M | pts[0].x = px + ax, pts[0].y = py + ay; |
1426 | 1.51M | pts[1].x = pts[0].x + bx, pts[1].y = pts[0].y + by; |
1427 | 1.51M | pts[2].x = px + bx, pts[2].y = py + by; |
1428 | 1.51M | code = clist_put_polyfill(dev, px, py, pts, 3, pdcolor, lop); |
1429 | 1.51M | return (code >= 0 ? code : |
1430 | 1.51M | gx_default_fill_parallelogram(dev, px, py, ax, ay, bx, by, |
1431 | 0 | pdcolor, lop)); |
1432 | 5.56M | } |
1433 | | |
1434 | | int |
1435 | | clist_fill_triangle(gx_device *dev, fixed px, fixed py, |
1436 | | fixed ax, fixed ay, fixed bx, fixed by, |
1437 | | const gx_drawing_color *pdcolor, |
1438 | | gs_logical_operation_t lop) |
1439 | 0 | { |
1440 | 0 | gs_fixed_point pts[2]; |
1441 | 0 | int code; |
1442 | |
|
1443 | 0 | pts[0].x = px + ax, pts[0].y = py + ay; |
1444 | 0 | pts[1].x = px + bx, pts[1].y = py + by; |
1445 | 0 | code = clist_put_polyfill(dev, px, py, pts, 2, pdcolor, lop); |
1446 | 0 | return (code >= 0 ? code : |
1447 | 0 | gx_default_fill_triangle(dev, px, py, ax, ay, bx, by, |
1448 | 0 | pdcolor, lop)); |
1449 | 0 | } |
1450 | | |
1451 | | /* ------ Path utilities ------ */ |
1452 | | |
1453 | | /* Define the state bookkeeping for writing path segments. */ |
1454 | | typedef struct cmd_segment_writer_s { |
1455 | | /* Set at initialization */ |
1456 | | gx_device_clist_writer *cldev; |
1457 | | gx_clist_state *pcls; |
1458 | | /* Updated dynamically */ |
1459 | | segment_notes notes; |
1460 | | byte *dp; |
1461 | | int len; |
1462 | | gs_fixed_point delta_first; |
1463 | | byte cmd[6 * (1 + sizeof(fixed))]; |
1464 | | } |
1465 | | cmd_segment_writer; |
1466 | | |
1467 | | /* Put out a path segment command. */ |
1468 | | static int |
1469 | | cmd_put_segment(cmd_segment_writer * psw, byte op, |
1470 | | const fixed * operands, segment_notes notes) |
1471 | 77.4M | { |
1472 | 77.4M | const fixed *optr = operands; |
1473 | | /* Fetch num_operands before possible command merging. */ |
1474 | 77.4M | static const byte op_num_operands[] = { |
1475 | 77.4M | cmd_segment_op_num_operands_values |
1476 | 77.4M | }; |
1477 | 77.4M | int i = op_num_operands[op & 0xf]; |
1478 | | /* One picky compiler complains if we initialize to psw->cmd - 1. */ |
1479 | 77.4M | byte *q = psw->cmd; |
1480 | | |
1481 | 77.4M | --q; |
1482 | | |
1483 | | #ifdef DEBUG |
1484 | | if (gs_debug_c('L')) { |
1485 | | int j; |
1486 | | |
1487 | | dmlprintf2(psw->cldev->memory, "[L] %s:%d:", cmd_sub_op_names[op >> 4][op & 0xf], |
1488 | | (int)notes); |
1489 | | for (j = 0; j < i; ++j) |
1490 | | dmprintf1(psw->cldev->memory, " %g", fixed2float(operands[j])); |
1491 | | dmputs(psw->cldev->memory, "\n"); |
1492 | | } |
1493 | | #endif |
1494 | | |
1495 | | /* Merge or shorten commands if possible. */ |
1496 | 77.4M | if (op == cmd_opv_rlineto) { |
1497 | 38.7M | if (operands[0] == 0) |
1498 | 15.5M | op = cmd_opv_vlineto, optr = ++operands, i = 1; |
1499 | 23.1M | else if (operands[1] == 0) |
1500 | 10.7M | op = cmd_opv_hlineto, i = 1; |
1501 | 12.3M | else |
1502 | 12.3M | switch (*psw->dp) { |
1503 | 3.30M | case cmd_opv_rmoveto: |
1504 | 3.30M | psw->delta_first.x = operands[0]; |
1505 | 3.30M | psw->delta_first.y = operands[1]; |
1506 | 3.30M | op = cmd_opv_rmlineto; |
1507 | 5.01M | merge:cmd_uncount_op(*psw->dp, psw->len); |
1508 | 5.01M | cmd_shorten_op(psw->cldev, psw->pcls, psw->len); /* delete it */ |
1509 | 5.01M | q += psw->len - 1; |
1510 | 5.01M | break; |
1511 | 1.71M | case cmd_opv_rmlineto: |
1512 | 1.71M | if (notes != psw->notes) |
1513 | 95 | break; |
1514 | 1.71M | op = cmd_opv_rm2lineto; |
1515 | 1.71M | goto merge; |
1516 | 784k | case cmd_opv_rm2lineto: |
1517 | 784k | if (notes != psw->notes) |
1518 | 48 | break; |
1519 | 784k | if (operands[0] == -psw->delta_first.x && |
1520 | 471k | operands[1] == -psw->delta_first.y |
1521 | 784k | ) { |
1522 | 433k | cmd_uncount_op(cmd_opv_rm2lineto, psw->len); |
1523 | 433k | *psw->dp = cmd_count_op(cmd_opv_rm3lineto, psw->len, psw->cldev->memory); |
1524 | 433k | return 0; |
1525 | 433k | } |
1526 | 350k | break; |
1527 | 6.57M | default: |
1528 | 6.57M | ; |
1529 | 12.3M | } |
1530 | 38.7M | } |
1531 | 201M | for (; --i >= 0; ++optr) { |
1532 | 124M | fixed d = *optr, d2; |
1533 | | |
1534 | 124M | if (is_bits(d, _fixed_shift + 11) && |
1535 | 99.4M | !(d & (float2fixed(0.25) - 1)) |
1536 | 124M | ) { |
1537 | 14.5M | cmd_count_add1(stats_cmd_diffs[3]); |
1538 | 14.5M | d = ((d >> (_fixed_shift - 2)) & 0x1fff) + 0xc000; |
1539 | 14.5M | q += 2; |
1540 | 109M | } else if (is_bits(d, 19) && i > 0 && is_bits(d2 = optr[1], 19)) { |
1541 | 59.6M | cmd_count_add1(stats_cmd_diffs[0]); |
1542 | 59.6M | q[1] = (byte) ((d >> 13) & 0x3f); |
1543 | 59.6M | q[2] = (byte) (d >> 5); |
1544 | 59.6M | q[3] = (byte) ((d << 3) + ((d2 >> 16) & 7)); |
1545 | 59.6M | q[4] = (byte) (d2 >> 8); |
1546 | 59.6M | q[5] = (byte) d2; |
1547 | 59.6M | q += 5; |
1548 | 59.6M | --i, ++optr; |
1549 | 59.6M | continue; |
1550 | 59.6M | } else if (is_bits(d, 22)) { |
1551 | 38.7M | cmd_count_add1(stats_cmd_diffs[1]); |
1552 | 38.7M | q[1] = (byte) (((d >> 16) & 0x3f) + 0x40); |
1553 | 38.7M | q += 3; |
1554 | 38.7M | } else if (is_bits(d, 30)) { |
1555 | 8.66M | cmd_count_add1(stats_cmd_diffs[2]); |
1556 | 8.66M | q[1] = (byte) (((d >> 24) & 0x3f) + 0x80); |
1557 | 8.66M | q[2] = (byte) (d >> 16); |
1558 | 8.66M | q += 4; |
1559 | 8.66M | } else { |
1560 | 2.62M | int b; |
1561 | | |
1562 | 2.62M | cmd_count_add1(stats_cmd_diffs[4]); |
1563 | 2.62M | *++q = 0xe0; |
1564 | 7.87M | for (b = sizeof(fixed) - 1; b > 1; --b) |
1565 | 5.24M | *++q = (byte) (d >> (b * 8)); |
1566 | 2.62M | q += 2; |
1567 | 2.62M | } |
1568 | 64.5M | q[-1] = (byte) (d >> 8); |
1569 | 64.5M | *q = (byte) d; |
1570 | 64.5M | } |
1571 | 77.0M | if (notes != psw->notes) { |
1572 | 5.29k | byte *dp; |
1573 | 5.29k | int code = |
1574 | 5.29k | set_cmd_put_op(&dp, psw->cldev, psw->pcls, cmd_opv_set_misc2, 3); |
1575 | | |
1576 | 5.29k | if (code < 0) |
1577 | 0 | return code; |
1578 | 5.29k | dp[1] = segment_notes_known; |
1579 | 5.29k | dp[2] = notes; |
1580 | 5.29k | psw->notes = notes; |
1581 | 77.0M | } { |
1582 | 77.0M | int len = q + 2 - psw->cmd; |
1583 | 77.0M | byte *dp; |
1584 | 77.0M | int code = set_cmd_put_op(&dp, psw->cldev, psw->pcls, op, len); |
1585 | | |
1586 | 77.0M | if (code < 0) |
1587 | 0 | return code; |
1588 | 77.0M | memcpy(dp + 1, psw->cmd, len - 1); |
1589 | 77.0M | psw->len = len; |
1590 | 77.0M | psw->dp = dp; |
1591 | 77.0M | } |
1592 | 0 | return 0; |
1593 | 77.0M | } |
1594 | | /* Put out a line segment command. */ |
1595 | | #define cmd_put_rmoveto(psw, operands)\ |
1596 | 14.2M | cmd_put_segment(psw, cmd_opv_rmoveto, operands, sn_none) |
1597 | | #define cmd_put_rgapto(psw, operands, notes)\ |
1598 | 0 | cmd_put_segment(psw, cmd_opv_rgapto, operands, notes) |
1599 | | #define cmd_put_rlineto(psw, operands, notes)\ |
1600 | 38.7M | cmd_put_segment(psw, cmd_opv_rlineto, operands, notes) |
1601 | | |
1602 | | |
1603 | | /* Bug 693235 shows a problem with a 'large' stroke, that |
1604 | | * extends from almost the minimum extent permissible |
1605 | | * to almost the positive extent permissible. When we band |
1606 | | * that, and play it back, we subtract the y offset of the band |
1607 | | * from it, and that causes a very negative number to tip over |
1608 | | * to being a very positive number. |
1609 | | * |
1610 | | * To avoid this, we spot 'far out' entries in the path, and |
1611 | | * reduce them to being 'less far out'. |
1612 | | * |
1613 | | * We pick 'far out' as being outside the central 1/4 of our |
1614 | | * 2d plane. This is far larger than is ever going to be used |
1615 | | * by a real device (famous last words!). |
1616 | | * |
1617 | | * We reduce the lines by moving to 1/4 of the way along them. |
1618 | | * |
1619 | | * If we only ever actually want to render the central 1/16 of |
1620 | | * the plane (which is still far more generous than we'd expect), |
1621 | | * the reduced lines should be suitably small not to overflow, |
1622 | | * and yet not be reduced so much that the reduction is ever visible. |
1623 | | * |
1624 | | * In practice this gives us a 4 million x 4 million maximum |
1625 | | * resolution. |
1626 | | */ |
1627 | | |
1628 | | static int |
1629 | | far_out(gs_fixed_point out) |
1630 | 10.3M | { |
1631 | 10.3M | return (out.y >= max_fixed/2 || out.y <= -(max_fixed/2) || out.x >= max_fixed/2 || out.x <= -(max_fixed/2)); |
1632 | 10.3M | } |
1633 | | |
1634 | | static void |
1635 | | reduce_line(fixed *m0, fixed *m1, fixed x0, fixed y0, fixed x1, fixed y1) |
1636 | 810k | { |
1637 | | /* We want to find m0, m1, 1/4 of the way from x0, y0 to x1, y1. */ |
1638 | | /* Sacrifice 2 bits of accuracy to avoid overflow. */ |
1639 | 810k | *m0 = (x0/4) + 3*(x1/4); |
1640 | 810k | *m1 = (y0/4) + 3*(y1/4); |
1641 | 810k | } |
1642 | | |
1643 | | /* |
1644 | | * Write a path. We go to a lot of trouble to omit segments that are |
1645 | | * entirely outside the band. |
1646 | | */ |
1647 | | static int |
1648 | | cmd_put_path(gx_device_clist_writer * cldev, gx_clist_state * pcls, |
1649 | | const gx_path * ppath, fixed ymin, fixed ymax, byte path_op, |
1650 | | bool implicit_close, segment_notes keep_notes) |
1651 | 14.0M | { |
1652 | 14.0M | gs_path_enum cenum; |
1653 | 14.0M | cmd_segment_writer writer; |
1654 | | |
1655 | | /* |
1656 | | * initial_op is logically const. We would like to declare it as |
1657 | | * static const, since some systems really dislike non-const statics, |
1658 | | * but this would entail a cast in set_first_point() that provokes a |
1659 | | * warning message from gcc. Instead, we pay the (tiny) cost of an |
1660 | | * unnecessary dynamic initialization. |
1661 | | */ |
1662 | 14.0M | byte initial_op = cmd_opv_end_run; |
1663 | | |
1664 | | /* |
1665 | | * We define the 'side' of a point according to its Y value as |
1666 | | * follows: |
1667 | | */ |
1668 | 163M | #define which_side(y) ((y) < ymin ? -1 : (y) >= ymax ? 1 : 0) |
1669 | | |
1670 | | /* |
1671 | | * While writing a subpath, we need to keep track of any segments |
1672 | | * skipped at the beginning of the subpath and any segments skipped |
1673 | | * just before the current segment. We do this with two sets of |
1674 | | * state variables, one that tracks the actual path segments and one |
1675 | | * that tracks the emitted segments. |
1676 | | * |
1677 | | * The following track the actual segments: |
1678 | | */ |
1679 | | |
1680 | | /* |
1681 | | * The point and side of the last moveto (skipped if |
1682 | | * start_side != 0): |
1683 | | */ |
1684 | 14.0M | gs_fixed_point start; |
1685 | 14.0M | int start_side = 0x7badf00d; /* Initialize against indeterminizm. */ |
1686 | | |
1687 | | /* |
1688 | | * Whether any lines or curves were skipped immediately |
1689 | | * following the moveto: |
1690 | | */ |
1691 | 14.0M | bool start_skip = 0x7badf00d; /* Initialize against indeterminizm. */ |
1692 | | |
1693 | | /* The side of the last point: */ |
1694 | 14.0M | int side = 0x7badf00d; /* Initialize against indeterminizm. */ |
1695 | | |
1696 | | /* The last point with side != 0: */ |
1697 | 14.0M | gs_fixed_point out; |
1698 | | |
1699 | | /* If the last out-going segment was a lineto, */ |
1700 | | /* its notes: */ |
1701 | 14.0M | segment_notes out_notes = 0x7badf00d; /* Initialize against indeterminizm. */ |
1702 | | |
1703 | | /* |
1704 | | * The following track the emitted segments: |
1705 | | */ |
1706 | | |
1707 | | /* The last point emitted: */ |
1708 | 14.0M | fixed px = int2fixed(pcls->rect.x); |
1709 | 14.0M | fixed py = int2fixed(pcls->rect.y); |
1710 | | |
1711 | | /* The point of the last emitted moveto: */ |
1712 | 14.0M | gs_fixed_point first; |
1713 | | |
1714 | | /* Information about the last emitted operation: */ |
1715 | 14.0M | int open = 0; /* -1 if last was moveto, 1 if line/curveto, */ |
1716 | | /* 0 if newpath/closepath */ |
1717 | 14.0M | struct { fixed vs[6]; } prev = { { 0 } }; |
1718 | | |
1719 | 14.0M | first.x = first.y = out.x = out.y = start.x = start.y = 0; /* Quiet gcc warning. */ |
1720 | 14.0M | if_debug4m('p', cldev->memory, "[p]initial (%g,%g), clip [%g..%g)\n", |
1721 | 14.0M | fixed2float(px), fixed2float(py), |
1722 | 14.0M | fixed2float(ymin), fixed2float(ymax)); |
1723 | 14.0M | gx_path_enum_init(&cenum, ppath); |
1724 | 14.0M | writer.cldev = cldev; |
1725 | 14.0M | writer.pcls = pcls; |
1726 | 14.0M | writer.notes = sn_none; |
1727 | 26.3M | #define set_first_point() (writer.dp = &initial_op) |
1728 | 14.0M | #define first_point() (writer.dp == &initial_op) |
1729 | 14.0M | set_first_point(); |
1730 | 208M | for (;;) { |
1731 | 208M | fixed vs[6]; |
1732 | | |
1733 | 386M | #define A vs[0] |
1734 | 381M | #define B vs[1] |
1735 | 208M | #define C vs[2] |
1736 | 208M | #define D vs[3] |
1737 | 208M | #define E vs[4] |
1738 | 208M | #define F vs[5] |
1739 | 208M | int pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *) vs); |
1740 | 208M | byte *dp; |
1741 | 208M | int code; |
1742 | | |
1743 | 208M | switch (pe_op) { |
1744 | 15.0M | case 0: |
1745 | | /* If the path is open and needs an implicit close, */ |
1746 | | /* do the close and then come here again. */ |
1747 | 15.0M | if (open > 0 && implicit_close) |
1748 | 988k | goto close; |
1749 | | /* All done. */ |
1750 | 14.0M | pcls->rect.x = fixed2int_var(px); |
1751 | 14.0M | pcls->rect.y = fixed2int_var(py); |
1752 | 14.0M | if_debug2m('p', cldev->memory, "[p]final (%d,%d)\n", |
1753 | 14.0M | pcls->rect.x, pcls->rect.y); |
1754 | 14.0M | return set_cmd_put_op(&dp, cldev, pcls, path_op, 1); |
1755 | 53.9M | case gs_pe_moveto: |
1756 | | /* If the path is open and needs an implicit close, */ |
1757 | | /* do a closepath and then redo the moveto. */ |
1758 | 53.9M | if (open > 0 && implicit_close) { |
1759 | 276k | gx_path_enum_backup(&cenum); |
1760 | 276k | goto close; |
1761 | 276k | } |
1762 | 53.6M | open = -1; |
1763 | 53.6M | start.x = A, start.y = B; |
1764 | 53.6M | start_skip = false; |
1765 | 53.6M | if ((start_side = side = which_side(B)) != 0) { |
1766 | 46.4M | out.x = A, out.y = B; |
1767 | 46.4M | if_debug3m('p', cldev->memory, "[p]skip moveto (%g,%g) side %d\n", |
1768 | 46.4M | fixed2float(out.x), fixed2float(out.y), |
1769 | 46.4M | side); |
1770 | 46.4M | continue; |
1771 | 46.4M | } |
1772 | 7.17M | C = A - px, D = B - py; |
1773 | 7.17M | first.x = px = A, first.y = py = B; |
1774 | 7.17M | code = cmd_put_rmoveto(&writer, &C); |
1775 | 7.17M | if_debug2m('p', cldev->memory, "[p]moveto (%g,%g)\n", |
1776 | 7.17M | fixed2float(px), fixed2float(py)); |
1777 | 7.17M | break; |
1778 | 0 | case gs_pe_gapto: |
1779 | 0 | { |
1780 | 0 | int next_side = which_side(B); |
1781 | 0 | segment_notes notes = |
1782 | 0 | gx_path_enum_notes(&cenum) & keep_notes; |
1783 | |
|
1784 | 0 | if (next_side == side && side != 0) { /* Skip a line completely outside the clip region. */ |
1785 | 0 | if (open < 0) |
1786 | 0 | start_skip = true; |
1787 | 0 | out.x = A, out.y = B; |
1788 | 0 | out_notes = notes; |
1789 | 0 | if_debug3m('p', cldev->memory, "[p]skip gapto (%g,%g) side %d\n", |
1790 | 0 | fixed2float(out.x), fixed2float(out.y), |
1791 | 0 | side); |
1792 | 0 | continue; |
1793 | 0 | } |
1794 | | /* If we skipped any segments, put out a moveto/lineto. */ |
1795 | 0 | if (side && ((open < 0) || (px != out.x || py != out.y || first_point()))) { |
1796 | 0 | if (far_out(out)) { |
1797 | | /* out is far enough out that we have to worry about wrapping on playback. Reduce the extent. */ |
1798 | 0 | if (open >= 0) { |
1799 | 0 | fixed mid[2]; |
1800 | 0 | fixed m0, m1; |
1801 | 0 | reduce_line(&m0, &m1, out.x, out.y, px, py); |
1802 | 0 | mid[0] = m0 - px, mid[1] = m1 - py; |
1803 | 0 | code = cmd_put_rlineto(&writer, mid, out_notes); |
1804 | 0 | if (code < 0) |
1805 | 0 | return code; |
1806 | 0 | px = m0, py = m1; |
1807 | 0 | } |
1808 | 0 | reduce_line(&out.x, &out.y, out.x, out.y, A, B); |
1809 | 0 | } |
1810 | 0 | C = out.x - px, D = out.y - py; |
1811 | 0 | if (open < 0) { |
1812 | 0 | first = out; |
1813 | 0 | code = cmd_put_rmoveto(&writer, &C); |
1814 | 0 | } else |
1815 | 0 | code = cmd_put_rlineto(&writer, &C, out_notes); |
1816 | 0 | if (code < 0) |
1817 | 0 | return code; |
1818 | 0 | px = out.x, py = out.y; |
1819 | 0 | if_debug3m('p', cldev->memory, "[p]catchup %s (%g,%g) for line\n", |
1820 | 0 | (open < 0 ? "moveto" : "lineto"), |
1821 | 0 | fixed2float(px), fixed2float(py)); |
1822 | 0 | } |
1823 | 0 | if ((side = next_side) != 0) { /* Note a vertex going outside the clip region. */ |
1824 | 0 | out.x = A, out.y = B; |
1825 | 0 | } |
1826 | 0 | C = A - px, D = B - py; |
1827 | 0 | px = A, py = B; |
1828 | 0 | open = 1; |
1829 | 0 | code = cmd_put_rgapto(&writer, &C, notes); |
1830 | 0 | } |
1831 | 0 | if_debug3m('p', cldev->memory, "[p]gapto (%g,%g) side %d\n", |
1832 | 0 | fixed2float(px), fixed2float(py), side); |
1833 | 0 | break; |
1834 | 90.9M | case gs_pe_lineto: |
1835 | 90.9M | { |
1836 | 90.9M | int next_side = which_side(B); |
1837 | 90.9M | segment_notes notes = |
1838 | 90.9M | gx_path_enum_notes(&cenum) & keep_notes; |
1839 | | |
1840 | 90.9M | if (next_side == side && side != 0) { /* Skip a line completely outside the clip region. */ |
1841 | 61.0M | if (open < 0) |
1842 | 49.4M | start_skip = true; |
1843 | 61.0M | out.x = A, out.y = B; |
1844 | 61.0M | out_notes = notes; |
1845 | 61.0M | if_debug3m('p', cldev->memory, "[p]skip lineto (%g,%g) side %d\n", |
1846 | 61.0M | fixed2float(out.x), fixed2float(out.y), |
1847 | 61.0M | side); |
1848 | 61.0M | continue; |
1849 | 61.0M | } |
1850 | | /* If we skipped any segments, put out a moveto/lineto. */ |
1851 | 29.9M | if (side && ((open < 0) || (px != out.x || py != out.y || first_point()))) { |
1852 | 7.68M | if (far_out(out)) { |
1853 | | /* out is far enough out that we have to worry about wrapping on playback. Reduce the extent. */ |
1854 | 607k | if (open >= 0) { |
1855 | 135k | fixed mid[2]; |
1856 | 135k | fixed m0, m1; |
1857 | 135k | reduce_line(&m0, &m1, out.x, out.y, px, py); |
1858 | 135k | mid[0] = m0 - px, mid[1] = m1 - py; |
1859 | 135k | code = cmd_put_rlineto(&writer, mid, out_notes); |
1860 | 135k | if (code < 0) |
1861 | 0 | return code; |
1862 | 135k | px = m0, py = m1; |
1863 | 135k | } |
1864 | 607k | reduce_line(&out.x, &out.y, out.x, out.y, A, B); |
1865 | 607k | } |
1866 | 7.68M | C = out.x - px, D = out.y - py; |
1867 | 7.68M | if (open < 0) { |
1868 | 5.59M | first = out; |
1869 | 5.59M | code = cmd_put_rmoveto(&writer, &C); |
1870 | 5.59M | } else |
1871 | 2.09M | code = cmd_put_rlineto(&writer, &C, out_notes); |
1872 | 7.68M | if (code < 0) |
1873 | 0 | return code; |
1874 | 7.68M | px = out.x, py = out.y; |
1875 | 7.68M | if_debug3m('p', cldev->memory, "[p]catchup %s (%g,%g) for line\n", |
1876 | 7.68M | (open < 0 ? "moveto" : "lineto"), |
1877 | 7.68M | fixed2float(px), fixed2float(py)); |
1878 | 7.68M | } |
1879 | 29.9M | if ((side = next_side) != 0) { /* Note a vertex going outside the clip region. */ |
1880 | 8.38M | out.x = A, out.y = B; |
1881 | 8.38M | } |
1882 | 29.9M | C = A - px, D = B - py; |
1883 | 29.9M | px = A, py = B; |
1884 | 29.9M | open = 1; |
1885 | 29.9M | code = cmd_put_rlineto(&writer, &C, notes); |
1886 | 29.9M | } |
1887 | 29.9M | if_debug3m('p', cldev->memory, "[p]lineto (%g,%g) side %d\n", |
1888 | 29.9M | fixed2float(px), fixed2float(py), side); |
1889 | 29.9M | break; |
1890 | 12.4M | case gs_pe_closepath: |
1891 | | #ifdef DEBUG |
1892 | | { |
1893 | | gs_path_enum cpenum; |
1894 | | gs_fixed_point cvs[3]; |
1895 | | int op; |
1896 | | |
1897 | | cpenum = cenum; |
1898 | | switch (op = gx_path_enum_next(&cpenum, cvs)) { |
1899 | | case 0: |
1900 | | case gs_pe_moveto: |
1901 | | break; |
1902 | | default: |
1903 | | mlprintf1(cldev->memory, |
1904 | | "closepath followed by %d, not end/moveto!\n", |
1905 | | op); |
1906 | | } |
1907 | | } |
1908 | | #endif |
1909 | | /* A closepath may require drawing an explicit line if */ |
1910 | | /* we skipped any segments at the beginning of the path. */ |
1911 | 13.6M | close:if (side != start_side) { /* If we skipped any segments, put out a moveto/lineto. */ |
1912 | 3.54M | if (side && (px != out.x || py != out.y || first_point())) { |
1913 | 2.70M | if (far_out(out)) { |
1914 | | /* out is far enough out that we have to worry about wrapping on playback. Reduce the extent. */ |
1915 | 33.7k | if (open >= 0) { |
1916 | 33.7k | fixed mid[2]; |
1917 | 33.7k | fixed m0, m1; |
1918 | 33.7k | reduce_line(&m0, &m1, out.x, out.y, px, py); |
1919 | 33.7k | mid[0] = m0 - px, mid[1] = m1 - py; |
1920 | 33.7k | code = cmd_put_rlineto(&writer, mid, out_notes); |
1921 | 33.7k | if (code < 0) |
1922 | 0 | return code; |
1923 | 33.7k | px = m0, py = m1; |
1924 | 33.7k | } |
1925 | 33.7k | reduce_line(&out.x, &out.y, out.x, out.y, A, B); |
1926 | 33.7k | } |
1927 | 2.70M | C = out.x - px, D = out.y - py; |
1928 | 2.70M | code = cmd_put_rlineto(&writer, &C, out_notes); |
1929 | 2.70M | if (code < 0) |
1930 | 0 | return code; |
1931 | 2.70M | px = out.x, py = out.y; |
1932 | 2.70M | if_debug2m('p', cldev->memory, "[p]catchup line (%g,%g) for close\n", |
1933 | 2.70M | fixed2float(px), fixed2float(py)); |
1934 | 2.70M | } |
1935 | 3.54M | if (open > 0 && start_skip) { /* Draw the closing line back to the start. */ |
1936 | 2.68M | C = start.x - px, D = start.y - py; |
1937 | 2.68M | code = cmd_put_rlineto(&writer, &C, sn_none); |
1938 | 2.68M | if (code < 0) |
1939 | 0 | return code; |
1940 | 2.68M | px = start.x, py = start.y; |
1941 | 2.68M | if_debug2m('p', cldev->memory, "[p]draw close to (%g,%g)\n", |
1942 | 2.68M | fixed2float(px), fixed2float(py)); |
1943 | 2.68M | } |
1944 | 3.54M | } |
1945 | | /* |
1946 | | * We don't bother to update side because we know that the |
1947 | | * next element after a closepath, if any, must be a moveto. |
1948 | | * We must handle explicitly the possibility that the entire |
1949 | | * subpath was skipped. |
1950 | | */ |
1951 | 13.6M | if (implicit_close || open <= 0) { |
1952 | | /* |
1953 | | * Force writing an explicit moveto if the next subpath |
1954 | | * starts with a moveto to the same point where this one |
1955 | | * ends. |
1956 | | */ |
1957 | 12.2M | set_first_point(); |
1958 | | /* |
1959 | | * If implicit_close == true, we don't need an explicit closepath, |
1960 | | * because the filling algorithm will close subpath automatically. |
1961 | | * Otherwise, if open < 0, we have an empty closed path. |
1962 | | * If side != 0, it is outside the band, so we can |
1963 | | * safely skip it, because the band has been expanded |
1964 | | * with line width. |
1965 | | */ |
1966 | 12.2M | if (side != 0) { |
1967 | 8.55M | open = 0; |
1968 | 8.55M | continue; |
1969 | 8.55M | } |
1970 | 12.2M | } |
1971 | 5.12M | open = 0; |
1972 | 5.12M | px = first.x, py = first.y; |
1973 | 5.12M | code = cmd_put_segment(&writer, cmd_opv_closepath, &A, sn_none); |
1974 | 5.12M | if_debug0m('p', cldev->memory, "[p]close\n"); |
1975 | 5.12M | break; |
1976 | 36.1M | case gs_pe_curveto: |
1977 | 36.1M | { |
1978 | 36.1M | segment_notes notes = |
1979 | 36.1M | gx_path_enum_notes(&cenum) & keep_notes; |
1980 | | |
1981 | 36.1M | { |
1982 | 36.1M | fixed bpy, bqy; |
1983 | 36.1M | int all_side, out_side; |
1984 | | |
1985 | | /* Compute the Y bounds for the clipping check. */ |
1986 | 36.1M | if (B < D) |
1987 | 16.3M | bpy = B, bqy = D; |
1988 | 19.7M | else |
1989 | 19.7M | bpy = D, bqy = B; |
1990 | 36.1M | if (F < bpy) |
1991 | 12.5M | bpy = F; |
1992 | 23.6M | else if (F > bqy) |
1993 | 12.1M | bqy = F; |
1994 | 36.1M | all_side = (bqy < ymin ? -1 : bpy > ymax ? 1 : 0); |
1995 | 36.1M | if (all_side != 0) { |
1996 | 17.7M | if (all_side == side) { /* Skip a curve entirely outside the clip region. */ |
1997 | 16.7M | if (open < 0) |
1998 | 7.69M | start_skip = true; |
1999 | 16.7M | out.x = E, out.y = F; |
2000 | 16.7M | out_notes = notes; |
2001 | 16.7M | if_debug3m('p', cldev->memory, |
2002 | 16.7M | "[p]skip curveto (%g,%g) side %d\n", |
2003 | 16.7M | fixed2float(out.x), fixed2float(out.y), |
2004 | 16.7M | side); |
2005 | 16.7M | continue; |
2006 | 16.7M | } |
2007 | 1.01M | out_side = all_side; |
2008 | 1.01M | } else |
2009 | 18.3M | out_side = which_side(F); |
2010 | | /* If we skipped any segments, put out a moveto/lineto. */ |
2011 | 19.3M | if (side && ((open < 0) || (px != out.x || py != out.y || first_point()))) { |
2012 | 2.56M | fixed diff[2]; |
2013 | | |
2014 | 2.56M | diff[0] = out.x - px, diff[1] = out.y - py; |
2015 | 2.56M | if (open < 0) { |
2016 | 1.49M | first = out; |
2017 | 1.49M | code = cmd_put_rmoveto(&writer, diff); |
2018 | 1.49M | } else |
2019 | 1.07M | code = cmd_put_rlineto(&writer, diff, out_notes); |
2020 | 2.56M | if (code < 0) |
2021 | 0 | return code; |
2022 | 2.56M | px = out.x, py = out.y; |
2023 | 2.56M | if_debug3m('p', cldev->memory, |
2024 | 2.56M | "[p]catchup %s (%g,%g) for curve\n", |
2025 | 2.56M | (open < 0 ? "moveto" : "lineto"), |
2026 | 2.56M | fixed2float(px), fixed2float(py)); |
2027 | 2.56M | } |
2028 | 19.3M | if ((side = out_side) != 0) { /* Note a vertex going outside the clip region. */ |
2029 | 3.72M | out.x = E, out.y = F; |
2030 | 3.72M | } |
2031 | 19.3M | } |
2032 | 0 | { |
2033 | 19.3M | fixed nx = E, ny = F; |
2034 | 19.3M | const fixed *optr = vs; |
2035 | 19.3M | byte op; |
2036 | | |
2037 | 19.3M | if_debug7m('p', cldev->memory, |
2038 | 19.3M | "[p]curveto (%g,%g; %g,%g; %g,%g) side %d\n", |
2039 | 19.3M | fixed2float(A), fixed2float(B), |
2040 | 19.3M | fixed2float(C), fixed2float(D), |
2041 | 19.3M | fixed2float(E), fixed2float(F), side); |
2042 | 19.3M | E -= C, F -= D; |
2043 | 19.3M | C -= A, D -= B; |
2044 | 19.3M | A -= px, B -= py; |
2045 | 19.3M | if (*writer.dp >= cmd_opv_min_curveto && |
2046 | 12.4M | *writer.dp <= cmd_opv_max_curveto && |
2047 | 12.4M | ((prev.A == 0 && |
2048 | 2.25M | A == prev.E && C == prev.C && E == prev.A && |
2049 | 81.0k | B == -prev.F && D == -prev.D && F == -prev.B) || |
2050 | 12.3M | (prev.A != 0 && |
2051 | 10.1M | A == -prev.E && C == -prev.C && E == -prev.A && |
2052 | 42.3k | B == prev.F && D == prev.D && F == prev.B)) |
2053 | 19.3M | ) |
2054 | 69.6k | op = cmd_opv_scurveto; |
2055 | 19.3M | else if (A == 0 && F == 0) { |
2056 | 2.54M | optr++, op = cmd_opv_vhcurveto; |
2057 | 2.54M | if ((B ^ C) >= 0) { |
2058 | 1.60M | if (D == C && E == B) |
2059 | 446k | op = cmd_opv_vqcurveto; |
2060 | 1.60M | } else if (D == -C && E == -B) |
2061 | 23.8k | op = cmd_opv_vqcurveto; |
2062 | 16.7M | } else if (B == 0 && E == 0) { |
2063 | 2.10M | B = A, E = F, optr++, op = cmd_opv_hvcurveto; |
2064 | 2.10M | if ((B ^ D) >= 0) { |
2065 | 1.17M | if (C == D && E == B) |
2066 | 29.2k | op = cmd_opv_hqcurveto; |
2067 | 1.17M | } else if (C == -D && E == -B) |
2068 | 10.2k | C = D, op = cmd_opv_hqcurveto; |
2069 | 2.10M | } |
2070 | 14.6M | else if (A == 0 && B == 0) |
2071 | 77.2k | optr += 2, op = cmd_opv_nrcurveto; |
2072 | 14.5M | else if (E == 0 && F == 0) |
2073 | 98.5k | op = cmd_opv_rncurveto; |
2074 | 14.4M | else |
2075 | 14.4M | op = cmd_opv_rrcurveto; |
2076 | 19.3M | memcpy(prev.vs, vs, sizeof(prev.vs)); |
2077 | 19.3M | px = nx, py = ny; |
2078 | 19.3M | open = 1; |
2079 | 19.3M | code = cmd_put_segment(&writer, op, optr, notes); |
2080 | 19.3M | } |
2081 | 19.3M | } |
2082 | 0 | break; |
2083 | 0 | default: |
2084 | 0 | return_error(gs_error_rangecheck); |
2085 | 208M | } |
2086 | 61.6M | if (code < 0) |
2087 | 0 | return code; |
2088 | 61.6M | #undef A |
2089 | 61.6M | #undef B |
2090 | 61.6M | #undef C |
2091 | 61.6M | #undef D |
2092 | 61.6M | #undef E |
2093 | 61.6M | #undef F |
2094 | 61.6M | } |
2095 | 14.0M | } |