Coverage Report

Created: 2025-08-28 07:06

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