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