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