Coverage Report

Created: 2026-02-14 07:09

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