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