Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gdevvec.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2024 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
/* Utilities for "vector" devices */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "string_.h"
21
#include "gx.h"
22
#include "gp.h"
23
#include "gserrors.h"
24
#include "gsparam.h"
25
#include "gsutil.h"
26
#include "gxfixed.h"
27
#include "gdevvec.h"
28
#include "gscspace.h"
29
#include "gxiparam.h"
30
#include "gxdcolor.h"
31
#include "gxpaint.h"    /* requires gx_path, ... */
32
#include "gzpath.h"
33
#include "gzcpath.h"
34
#include "gxdevsop.h"
35
36
#include "gdevkrnlsclass.h" /* 'standard' built in subclasses, currently First/Last Page and obejct filter */
37
38
/* Structure descriptors */
39
public_st_device_vector();
40
public_st_vector_image_enum();
41
42
/* ================ Default implementations of vector procs ================ */
43
44
int
45
gdev_vector_setflat(gx_device_vector * vdev, double flatness)
46
228k
{
47
228k
    return 0;
48
228k
}
49
50
/* Put a path on the output file. */
51
static bool
52
coord_between(fixed start, fixed mid, fixed end)
53
0
{
54
0
    return (start <= end ? start <= mid && mid <= end :
55
0
            start >= mid && mid >= end);
56
0
}
57
int
58
gdev_vector_dopath(gx_device_vector *vdev, const gx_path * ppath,
59
                   gx_path_type_t type, const gs_matrix *pmat)
60
7.32M
{
61
7.32M
    bool do_close =
62
7.32M
        (type & (gx_path_type_stroke | gx_path_type_always_close)) != 0;
63
7.32M
    gs_fixed_rect rbox;
64
7.32M
    gx_path_rectangular_type rtype = gx_path_is_rectangular(ppath, &rbox);
65
7.32M
    gs_path_enum cenum;
66
7.32M
    gdev_vector_dopath_state_t state;
67
7.32M
    gs_fixed_point line_start, line_end;
68
7.32M
    bool incomplete_line = false;
69
7.32M
    bool need_moveto = false;
70
7.32M
    int code;
71
72
7.32M
    gdev_vector_dopath_init(&state, vdev, type, pmat);
73
    /*
74
     * if the path type is stroke, we only recognize closed
75
     * rectangles; otherwise, we recognize all rectangles.
76
     * Note that for stroking with a transformation, we can't use dorect,
77
     * which requires (untransformed) device coordinates.
78
     */
79
7.32M
    if (rtype != prt_none &&
80
7.32M
        (!(type & gx_path_type_stroke) || rtype == prt_closed) &&
81
7.32M
        (pmat == 0 || is_xxyy(pmat) || is_xyyx(pmat)) &&
82
7.32M
        (state.scale_mat.xx == 1.0 && state.scale_mat.yy == 1.0 &&
83
741k
         is_xxyy(&state.scale_mat) &&
84
741k
         is_fzero2(state.scale_mat.tx, state.scale_mat.ty))
85
7.32M
        ) {
86
741k
        gs_point p, q;
87
88
741k
        gs_point_transform_inverse((double)rbox.p.x, (double)rbox.p.y,
89
741k
                                   &state.scale_mat, &p);
90
741k
        gs_point_transform_inverse((double)rbox.q.x, (double)rbox.q.y,
91
741k
                                   &state.scale_mat, &q);
92
741k
        code = vdev_proc(vdev, dorect)(vdev, (fixed)p.x, (fixed)p.y,
93
741k
                                       (fixed)q.x, (fixed)q.y, type);
94
741k
        if (code >= 0)
95
631k
            return code;
96
        /* If the dorect proc failed, use a general path. */
97
741k
    }
98
6.69M
    code = vdev_proc(vdev, beginpath)(vdev, type);
99
6.69M
    if (code < 0)
100
434
        return code;
101
6.69M
    gx_path_enum_init(&cenum, ppath);
102
75.9M
    for (;;) {
103
75.9M
        gs_fixed_point vs[3];
104
75.9M
        int pe_op = gx_path_enum_next(&cenum, vs);
105
106
77.6M
    sw:
107
77.6M
        if (type & gx_path_type_optimize) {
108
0
        opt:
109
            /* RJW: We fail to optimize gaptos */
110
0
            if (pe_op == gs_pe_lineto) {
111
0
                if (!incomplete_line) {
112
0
                    line_end = vs[0];
113
0
                    incomplete_line = true;
114
0
                    continue;
115
0
                }
116
                /*
117
                 * Merge collinear horizontal or vertical line segments
118
                 * going in the same direction.
119
                 */
120
0
                if (vs[0].x == line_end.x) {
121
0
                    if (vs[0].x == line_start.x &&
122
0
                        coord_between(line_start.y, line_end.y, vs[0].y)
123
0
                        ) {
124
0
                        line_end.y = vs[0].y;
125
0
                        continue;
126
0
                    }
127
0
                } else if (vs[0].y == line_end.y) {
128
0
                    if (vs[0].y == line_start.y &&
129
0
                        coord_between(line_start.x, line_end.x, vs[0].x)
130
0
                        ) {
131
0
                        line_end.x = vs[0].x;
132
0
                        continue;
133
0
                    }
134
0
                }
135
0
            }
136
0
            if (incomplete_line) {
137
0
                if (need_moveto) { /* see gs_pe_moveto case */
138
0
                    code = gdev_vector_dopath_segment(&state, gs_pe_moveto,
139
0
                                                      &line_start);
140
0
                    if (code < 0)
141
0
                        return code;
142
0
                    need_moveto = false;
143
0
                }
144
0
                code = gdev_vector_dopath_segment(&state, gs_pe_lineto,
145
0
                                                  &line_end);
146
0
                if (code < 0)
147
0
                    return code;
148
0
                line_start = line_end;
149
0
                incomplete_line = false;
150
0
                goto opt;
151
0
            }
152
0
        }
153
77.6M
        switch (pe_op) {
154
1.87M
        case 0:   /* done */
155
6.69M
        done:
156
6.69M
            code = vdev_proc(vdev, endpath)(vdev, type);
157
6.69M
            return (code < 0 ? code : 0);
158
33.8M
        case gs_pe_curveto:
159
33.8M
            if (need_moveto) { /* see gs_pe_moveto case */
160
2.58M
                code = gdev_vector_dopath_segment(&state, gs_pe_moveto,
161
2.58M
                                                  &line_start);
162
2.58M
                if (code < 0)
163
0
                    return code;
164
2.58M
                need_moveto = false;
165
2.58M
            }
166
33.8M
            line_start = vs[2];
167
33.8M
            goto draw;
168
7.03M
        case gs_pe_moveto:
169
            /*
170
             * A bug in Acrobat Reader 4 causes it to draw a single pixel
171
             * for a fill with an isolated moveto.  If we're doing a fill
172
             * without a stroke, defer emitting a moveto until we know that
173
             * the subpath has more elements.
174
             */
175
7.03M
            line_start = vs[0];
176
7.03M
            if (!(type & gx_path_type_stroke) && (type & gx_path_type_fill)) {
177
6.67M
                need_moveto = true;
178
6.67M
                continue;
179
6.67M
            }
180
362k
            goto draw;
181
28.4M
        case gs_pe_lineto:
182
28.4M
        case gs_pe_gapto:
183
28.4M
            if (need_moveto) { /* see gs_pe_moveto case */
184
4.05M
                code = gdev_vector_dopath_segment(&state, gs_pe_moveto,
185
4.05M
                                                  &line_start);
186
4.05M
                if (code < 0)
187
0
                    return code;
188
4.05M
                need_moveto = false;
189
4.05M
            }
190
28.4M
            line_start = vs[0];
191
28.4M
            goto draw;
192
6.47M
        case gs_pe_closepath:
193
6.47M
            if (need_moveto) { /* see gs_pe_moveto case */
194
851
                need_moveto = false;
195
851
                continue;
196
851
            }
197
6.47M
            if (!do_close) {
198
6.44M
                pe_op = gx_path_enum_next(&cenum, vs);
199
6.44M
                if (pe_op == 0)
200
4.81M
                    goto done;
201
1.63M
                code = gdev_vector_dopath_segment(&state, gs_pe_closepath, vs);
202
1.63M
                if (code < 0)
203
0
                    return code;
204
1.63M
                goto sw;
205
1.63M
            }
206
            /* falls through */
207
62.6M
        draw:
208
62.6M
            code = gdev_vector_dopath_segment(&state, pe_op, vs);
209
62.6M
            if (code < 0)
210
0
                return code;
211
77.6M
        }
212
62.6M
        incomplete_line = false; /* only needed if optimizing */
213
62.6M
    }
214
6.69M
}
215
216
int
217
gdev_vector_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1,
218
                   fixed y1, gx_path_type_t type)
219
0
{
220
0
    int code = (*vdev_proc(vdev, beginpath)) (vdev, type);
221
222
0
    if (code < 0)
223
0
        return code;
224
0
    code = gdev_vector_write_rectangle(vdev, x0, y0, x1, y1,
225
0
                                       (type & gx_path_type_stroke) != 0,
226
0
                                       gx_rect_x_first);
227
0
    if (code < 0)
228
0
        return code;
229
0
    return (*vdev_proc(vdev, endpath)) (vdev, type);
230
0
}
231
232
/* ================ Utility procedures ================ */
233
234
/* Recompute the cached color values. */
235
static void
236
gdev_vector_load_cache(gx_device_vector * vdev)
237
84.8k
{
238
84.8k
    vdev->black = gx_device_black((gx_device *)vdev);
239
84.8k
    vdev->white = gx_device_white((gx_device *)vdev);
240
84.8k
}
241
242
/* Initialize the state. */
243
void
244
gdev_vector_init(gx_device_vector * vdev)
245
84.8k
{
246
84.8k
    gdev_vector_reset(vdev);
247
84.8k
    if (dev_proc(vdev, dev_spec_op) == gx_default_dev_spec_op)
248
31.6k
        set_dev_proc(vdev, dev_spec_op, gdev_vector_dev_spec_op);
249
250
84.8k
    vdev->scale.x = vdev->scale.y = 1.0;
251
84.8k
    vdev->in_page = false;
252
84.8k
    gdev_vector_load_cache(vdev);
253
84.8k
}
254
255
/* Reset the remembered graphics state. */
256
void
257
gdev_vector_reset(gx_device_vector * vdev)
258
84.8k
{
259
84.8k
    static const gs_gstate state_initial =
260
84.8k
    {gs_gstate_initial(1.0)};
261
262
84.8k
    vdev->state = state_initial;
263
84.8k
    gx_hld_saved_color_init(&vdev->saved_fill_color);
264
84.8k
    gx_hld_saved_color_init(&vdev->saved_stroke_color);
265
84.8k
    vdev->clip_path_id =
266
84.8k
        vdev->no_clip_path_id = gs_next_ids(vdev->memory, 1);
267
84.8k
}
268
269
/* Open the output file and stream. */
270
int
271
gdev_vector_open_file_options(gx_device_vector * vdev, uint strmbuf_size,
272
                              int open_options)
273
65.6k
{
274
65.6k
    bool binary = !(open_options & VECTOR_OPEN_FILE_ASCII);
275
65.6k
    int code = -1;    /* (only for testing, never returned) */
276
65.6k
    cmm_dev_profile_t *icc_struct = 0;
277
278
    /* Open the file as seekable or sequential, as requested. */
279
65.6k
    if (!(open_options & VECTOR_OPEN_FILE_SEQUENTIAL)) {
280
        /* Try to open as seekable. */
281
34.0k
        code =
282
34.0k
            gx_device_open_output_file((gx_device *)vdev, vdev->fname,
283
34.0k
                                       binary, true, &vdev->file);
284
34.0k
    }
285
65.6k
    if (code < 0 && (open_options & (VECTOR_OPEN_FILE_SEQUENTIAL |
286
31.6k
                                     VECTOR_OPEN_FILE_SEQUENTIAL_OK))) {
287
        /* Try to open as sequential. */
288
31.6k
        code = gx_device_open_output_file((gx_device *)vdev, vdev->fname,
289
31.6k
                                          binary, false, &vdev->file);
290
31.6k
    }
291
65.6k
    if ((code >= 0) && (dev_proc(vdev, get_profile) != NULL)) {
292
65.6k
        code = dev_proc(vdev, get_profile)((gx_device *)vdev, &icc_struct);
293
65.6k
    }
294
295
65.6k
    if (code < 0)
296
0
        return code;
297
65.6k
    if ((vdev->strmbuf = gs_alloc_bytes(vdev->v_memory, strmbuf_size,
298
65.6k
                                        "vector_open(strmbuf)")) == 0 ||
299
65.6k
        (vdev->strm = s_alloc(vdev->v_memory,
300
65.6k
                              "vector_open(strm)")) == 0 ||
301
65.6k
        ((open_options & VECTOR_OPEN_FILE_BBOX) &&
302
65.6k
         (vdev->bbox_device =
303
0
          gs_alloc_struct_immovable(vdev->v_memory,
304
0
                                    gx_device_bbox, &st_device_bbox,
305
0
                                    "vector_open(bbox_device)")) == 0)
306
65.6k
        ) {
307
0
        if (vdev->bbox_device)
308
0
            gs_free_object(vdev->v_memory, vdev->bbox_device,
309
0
                           "vector_open(bbox_device)");
310
0
        vdev->bbox_device = 0;
311
0
        if (vdev->strm)
312
0
            gs_free_object(vdev->v_memory, vdev->strm,
313
0
                           "vector_open(strm)");
314
0
        vdev->strm = 0;
315
0
        if (vdev->strmbuf)
316
0
            gs_free_object(vdev->v_memory, vdev->strmbuf,
317
0
                           "vector_open(strmbuf)");
318
0
        vdev->strmbuf = 0;
319
0
        gx_device_close_output_file((gx_device *)vdev, vdev->fname, vdev->file);
320
0
        vdev->file = 0;
321
0
        return_error(gs_error_VMerror);
322
0
    }
323
65.6k
    vdev->strmbuf_size = strmbuf_size;
324
65.6k
    swrite_file(vdev->strm, vdev->file, vdev->strmbuf, strmbuf_size);
325
65.6k
    vdev->open_options = open_options;
326
    /*
327
     * We don't want finalization to close the file, but we do want it
328
     * to flush the stream buffer.
329
     */
330
65.6k
    vdev->strm->procs.close = vdev->strm->procs.flush;
331
65.6k
    if (vdev->bbox_device) {
332
0
        gx_device_bbox_init(vdev->bbox_device, NULL, vdev->v_memory);
333
0
        rc_increment(vdev->bbox_device);
334
335
0
        vdev->bbox_device->icc_struct = icc_struct;
336
0
        rc_increment(vdev->bbox_device->icc_struct);
337
338
0
        gx_device_set_resolution((gx_device *) vdev->bbox_device,
339
0
                                 vdev->HWResolution[0],
340
0
                                 vdev->HWResolution[1]);
341
        /* Do the right thing about upright vs. inverted. */
342
        /* (This is dangerous in general, since the procedure */
343
        /* might reference non-standard elements.) */
344
0
        set_dev_proc(vdev->bbox_device, get_initial_matrix,
345
0
                     dev_proc(vdev, get_initial_matrix));
346
0
        (*dev_proc(vdev->bbox_device, open_device))
347
0
            ((gx_device *) vdev->bbox_device);
348
0
    }
349
350
65.6k
    code = install_internal_subclass_devices((gx_device **)&vdev, NULL);
351
65.6k
    if (code < 0)
352
0
        return code;
353
354
65.6k
    return 0;
355
65.6k
}
356
357
/* Get the current stream, calling beginpage if in_page is false. */
358
stream *
359
gdev_vector_stream(gx_device_vector * vdev)
360
340M
{
361
340M
    if (!vdev->in_page) {
362
25.0k
        (*vdev_proc(vdev, beginpage)) (vdev);
363
25.0k
        vdev->in_page = true;
364
25.0k
    }
365
340M
    return vdev->strm;
366
340M
}
367
368
/* Update the logical operation. */
369
int
370
gdev_vector_update_log_op(gx_device_vector * vdev, gs_logical_operation_t lop)
371
74.8M
{
372
74.8M
    gs_logical_operation_t diff = lop ^ vdev->state.log_op;
373
374
74.8M
    if (diff != 0) {
375
494k
        int code = (*vdev_proc(vdev, setlogop)) (vdev, lop, diff);
376
377
494k
        if (code < 0)
378
0
            return code;
379
494k
        vdev->state.log_op = lop;
380
494k
    }
381
74.8M
    return 0;
382
74.8M
}
383
384
/* Update color (fill or stroke). */
385
static int
386
gdev_vector_update_color(gx_device_vector * vdev,
387
                              const gs_gstate * pgs,
388
                              const gx_drawing_color * pdcolor,
389
                              gx_hl_saved_color *sc,
390
                              int (*setcolor) (gx_device_vector * vdev,
391
                                               const gs_gstate * pgs,
392
                                               const gx_drawing_color * pdc))
393
74.7M
{
394
74.7M
    gx_hl_saved_color temp;
395
74.7M
    int code;
396
74.7M
    bool hl_color = (*vdev_proc(vdev, can_handle_hl_color)) (vdev, pgs, pdcolor);
397
74.7M
    const gs_gstate *pgs_for_hl_color = (hl_color ? pgs : NULL);
398
399
74.7M
    gx_hld_save_color(pgs_for_hl_color, pdcolor, &temp);
400
74.7M
    if (gx_hld_saved_color_equal(&temp, sc))
401
42.4M
        return 0;
402
32.3M
    code = (*setcolor) (vdev, pgs_for_hl_color, pdcolor);
403
32.3M
    if (code < 0)
404
18.2k
        return code;
405
32.3M
    *sc = temp;
406
32.3M
    return 0;
407
32.3M
}
408
409
/* Update the fill color. */
410
int
411
gdev_vector_update_fill_color(gx_device_vector * vdev,
412
                              const gs_gstate * pgs,
413
                              const gx_drawing_color * pdcolor)
414
73.7M
{
415
73.7M
    return gdev_vector_update_color(vdev, pgs, pdcolor, &vdev->saved_fill_color,
416
73.7M
                                    vdev_proc(vdev, setfillcolor));
417
73.7M
}
418
419
/* Update the state for filling a region. */
420
static int
421
update_fill(gx_device_vector * vdev, const gs_gstate * pgs,
422
            const gx_drawing_color * pdcolor, gs_logical_operation_t lop)
423
72.3M
{
424
72.3M
    int code = gdev_vector_update_fill_color(vdev, pgs, pdcolor);
425
426
72.3M
    if (code < 0)
427
17.8k
        return code;
428
72.2M
    return gdev_vector_update_log_op(vdev, lop);
429
72.3M
}
430
431
/* Bring state up to date for filling. */
432
int
433
gdev_vector_prepare_fill(gx_device_vector * vdev, const gs_gstate * pgs,
434
            const gx_fill_params * params, const gx_drawing_color * pdcolor)
435
6.66M
{
436
6.66M
    if (params->flatness != vdev->state.flatness) {
437
137k
        int code = (*vdev_proc(vdev, setflat)) (vdev, params->flatness);
438
439
137k
        if (code < 0)
440
0
            return code;
441
137k
        vdev->state.flatness = params->flatness;
442
137k
    }
443
6.66M
    return update_fill(vdev, pgs, pdcolor, pgs->log_op);
444
6.66M
}
445
446
/* Compare two dash patterns. */
447
static bool
448
dash_pattern_eq(const float *stored, const gx_dash_params * set, double scale)
449
3.54k
{
450
3.54k
    int i;
451
452
9.32k
    for (i = 0; i < set->pattern_size; ++i)
453
6.66k
        if (stored[i] != (float)(set->pattern[i] * scale))
454
878
            return false;
455
2.66k
    return true;
456
3.54k
}
457
458
/* Bring state up to date for stroking. */
459
int
460
gdev_vector_prepare_stroke(gx_device_vector * vdev,
461
                           const gs_gstate * pgs, /* may be NULL */
462
                           const gx_stroke_params * params, /* may be NULL */
463
                           const gx_drawing_color * pdcolor, /* may be NULL */
464
                           double scale)
465
1.03M
{
466
1.03M
    if (pgs) {
467
1.03M
        int pattern_size = pgs->line_params.dash.pattern_size;
468
1.03M
        float dash_offset = pgs->line_params.dash.offset * scale;
469
1.03M
        float half_width = pgs->line_params.half_width * scale;
470
471
1.03M
        if (dash_offset != vdev->state.line_params.dash.offset ||
472
1.03M
            pattern_size != vdev->state.line_params.dash.pattern_size ||
473
1.03M
            (pattern_size != 0 &&
474
1.02M
             !dash_pattern_eq(vdev->dash_pattern, &pgs->line_params.dash,
475
3.54k
                              scale))
476
1.03M
            ) {
477
9.25k
            float *pattern;
478
9.25k
            int i, code;
479
480
9.25k
            pattern = (float *)gs_alloc_bytes(vdev->memory->stable_memory, pattern_size * sizeof(float), "vector allocate dash pattern");
481
9.25k
            if (pattern == NULL)
482
0
                return_error(gs_error_VMerror);
483
18.7k
            for (i = 0; i < pattern_size; ++i)
484
9.44k
                pattern[i] = pgs->line_params.dash.pattern[i] * scale;
485
9.25k
            code = (*vdev_proc(vdev, setdash))
486
9.25k
                (vdev, pattern, pattern_size, dash_offset);
487
9.25k
            if (code < 0) {
488
0
                gs_free_object(vdev->memory->stable_memory, pattern, "vector free new dash pattern on error");
489
0
                return code;
490
0
            }
491
9.25k
            if (vdev->dash_pattern)
492
6.87k
                gs_free_object(vdev->memory->stable_memory, vdev->dash_pattern, "vector free old dash pattern");
493
9.25k
            vdev->dash_pattern = pattern;
494
9.25k
            vdev->dash_pattern_size = pattern_size;
495
496
9.25k
            vdev->state.line_params.dash.pattern_size = pattern_size;
497
9.25k
            vdev->state.line_params.dash.offset = dash_offset;
498
9.25k
        }
499
1.03M
        if (half_width != vdev->state.line_params.half_width) {
500
88.1k
            int code = (*vdev_proc(vdev, setlinewidth))
501
88.1k
                (vdev, half_width * 2);
502
503
88.1k
            if (code < 0)
504
0
                return code;
505
88.1k
            vdev->state.line_params.half_width = half_width;
506
88.1k
        }
507
1.03M
        if (pgs->line_params.miter_limit != vdev->state.line_params.miter_limit) {
508
2.62k
            int code = (*vdev_proc(vdev, setmiterlimit))
509
2.62k
                (vdev, pgs->line_params.miter_limit);
510
511
2.62k
            if (code < 0)
512
0
                return code;
513
2.62k
            gx_set_miter_limit(&vdev->state.line_params,
514
2.62k
                               pgs->line_params.miter_limit);
515
2.62k
        }
516
        /* FIXME: Should cope with end_cap and dash_cap too */
517
1.03M
        if (pgs->line_params.start_cap != vdev->state.line_params.start_cap) {
518
43.0k
            int code = (*vdev_proc(vdev, setlinecap))
519
43.0k
                (vdev, pgs->line_params.start_cap);
520
521
43.0k
            if (code < 0)
522
0
                return code;
523
43.0k
            vdev->state.line_params.start_cap = pgs->line_params.start_cap;
524
43.0k
        }
525
1.03M
        if (pgs->line_params.join != vdev->state.line_params.join) {
526
43.5k
            int code = (*vdev_proc(vdev, setlinejoin))
527
43.5k
                (vdev, pgs->line_params.join);
528
529
43.5k
            if (code < 0)
530
0
                return code;
531
43.5k
            vdev->state.line_params.join = pgs->line_params.join;
532
1.03M
        } {
533
1.03M
            int code = gdev_vector_update_log_op(vdev, pgs->log_op);
534
535
1.03M
            if (code < 0)
536
0
                return code;
537
1.03M
        }
538
1.03M
    }
539
1.03M
    if (params) {
540
1.03M
        if (params->flatness != vdev->state.flatness) {
541
105k
            int code = (*vdev_proc(vdev, setflat)) (vdev, params->flatness);
542
543
105k
            if (code < 0)
544
0
                return code;
545
105k
            vdev->state.flatness = params->flatness;
546
105k
        }
547
1.03M
    }
548
1.03M
    if (pdcolor) {
549
1.03M
        int code = gdev_vector_update_color(vdev, pgs, pdcolor,
550
1.03M
                    &vdev->saved_stroke_color, vdev_proc(vdev, setstrokecolor));
551
552
1.03M
        if (code < 0)
553
345
            return code;
554
1.03M
    }
555
1.03M
    return 0;
556
1.03M
}
557
558
/*
559
 * Compute the scale for transforming the line width and dash pattern for a
560
 * stroke operation, and, if necessary to handle anisotropic scaling, a full
561
 * transformation matrix to be inverse-applied to the path elements as well.
562
 * Return 0 if only scaling, 1 if a full matrix is needed.
563
 */
564
int
565
gdev_vector_stroke_scaling(const gx_device_vector *vdev,
566
                           const gs_gstate *pgs,
567
                           double *pscale, gs_matrix *pmat)
568
1.44M
{
569
1.44M
    bool set_ctm = true;
570
1.44M
    double scale = 1;
571
572
    /*
573
     * If the CTM is not uniform, stroke width depends on angle.
574
     * We'd like to avoid resetting the CTM, so we check for uniform
575
     * CTMs explicitly.  Note that in PDF, unlike PostScript, it is
576
     * the CTM at the time of the stroke operation, not the CTM at
577
     * the time the path was constructed, that is used for transforming
578
     * the points of the path; so if we have to reset the CTM, we must
579
     * do it before constructing the path, and inverse-transform all
580
     * the coordinates.
581
     */
582
1.44M
    if (is_xxyy(&pgs->ctm)) {
583
1.39M
        scale = fabs(pgs->ctm.xx);
584
1.39M
        set_ctm = fabs(pgs->ctm.yy) != scale;
585
1.39M
    } else if (is_xyyx(&pgs->ctm)) {
586
1.59k
        scale = fabs(pgs->ctm.xy);
587
1.59k
        set_ctm = fabs(pgs->ctm.yx) != scale;
588
47.5k
    } else if ((pgs->ctm.xx == pgs->ctm.yy && pgs->ctm.xy == -pgs->ctm.yx) ||
589
47.5k
               (pgs->ctm.xx == -pgs->ctm.yy && pgs->ctm.xy == pgs->ctm.yx)
590
47.5k
        ) {
591
29.6k
        scale = hypot(pgs->ctm.xx, pgs->ctm.xy);
592
29.6k
        set_ctm = false;
593
29.6k
    }
594
1.44M
    if (set_ctm) {
595
        /*
596
         * Adobe Acrobat Reader has limitations on the maximum user
597
         * coordinate value.  If we scale the matrix down too far, the
598
         * coordinates will get too big: limit the scale factor to prevent
599
         * this from happening.  (This does no harm for other output
600
         * formats.)
601
         */
602
545k
        double
603
545k
            mxx = pgs->ctm.xx / vdev->scale.x,
604
545k
            mxy = pgs->ctm.xy / vdev->scale.y,
605
545k
            myx = pgs->ctm.yx / vdev->scale.x,
606
545k
            myy = pgs->ctm.yy / vdev->scale.y;
607
608
545k
        scale = 0.5 * (fabs(mxx) + fabs(mxy) + fabs(myx) + fabs(myy));
609
545k
        pmat->xx = mxx / scale, pmat->xy = mxy / scale;
610
545k
        pmat->yx = myx / scale, pmat->yy = myy / scale;
611
545k
        pmat->tx = pmat->ty = 0;
612
545k
    }
613
1.44M
    *pscale = scale;
614
1.44M
    return (int)set_ctm;
615
1.44M
}
616
617
/* Initialize for writing a path using the default implementation. */
618
void
619
gdev_vector_dopath_init(gdev_vector_dopath_state_t *state,
620
                        gx_device_vector *vdev, gx_path_type_t type,
621
                        const gs_matrix *pmat)
622
8.69M
{
623
8.69M
    state->vdev = vdev;
624
8.69M
    state->type = type;
625
8.69M
    if (pmat) {
626
166k
        state->scale_mat = *pmat;
627
        /*
628
         * The path element writing procedures all divide the coordinates
629
         * by the scale, so we must compensate for that here.
630
         */
631
166k
        gs_matrix_scale(&state->scale_mat, 1.0 / vdev->scale.x,
632
166k
                        1.0 / vdev->scale.y, &state->scale_mat);
633
8.53M
    } else {
634
8.53M
        gs_make_scaling(vdev->scale.x, vdev->scale.y, &state->scale_mat);
635
8.53M
    }
636
8.69M
    state->first = true;
637
638
    /* This is purely to prevent Coverity from thinking gdev_vector_dopath()
639
    could use uninitialised state->start.x. */
640
8.69M
    state->start.x = 0;
641
8.69M
    state->start.y = 0;
642
8.69M
}
643
644
/*
645
 * Put a segment of an enumerated path on the output file.
646
 * pe_op is assumed to be valid and non-zero.
647
 */
648
int
649
gdev_vector_dopath_segment(gdev_vector_dopath_state_t *state, int pe_op,
650
                           gs_fixed_point *vs)
651
77.6M
{
652
77.6M
    gx_device_vector *vdev = state->vdev;
653
77.6M
    const gs_matrix *const pmat = &state->scale_mat;
654
77.6M
    gs_point vp[3];
655
77.6M
    int code;
656
657
77.6M
    switch (pe_op) {
658
8.16M
        case gs_pe_moveto:
659
8.16M
            code = gs_point_transform_inverse(fixed2float(vs[0].x),
660
8.16M
                                       fixed2float(vs[0].y), pmat, &vp[0]);
661
8.16M
            if (code < 0)
662
22
                return code;
663
8.16M
            if (state->first)
664
6.05M
                state->start = vp[0], state->first = false;
665
8.16M
            code = vdev_proc(vdev, moveto)
666
8.16M
                (vdev, 0/*unused*/, 0/*unused*/, vp[0].x, vp[0].y,
667
8.16M
                 state->type);
668
8.16M
            state->prev = vp[0];
669
8.16M
            break;
670
31.1M
        case gs_pe_lineto:
671
31.1M
        case gs_pe_gapto: /* FIXME */
672
31.1M
            code = gs_point_transform_inverse(fixed2float(vs[0].x),
673
31.1M
                                       fixed2float(vs[0].y), pmat, &vp[0]);
674
31.1M
            if (code < 0)
675
11
                return code;
676
31.1M
            code = vdev_proc(vdev, lineto)
677
31.1M
                (vdev, state->prev.x, state->prev.y, vp[0].x, vp[0].y,
678
31.1M
                 state->type);
679
31.1M
            state->prev = vp[0];
680
31.1M
            break;
681
36.3M
        case gs_pe_curveto:
682
36.3M
            code = gs_point_transform_inverse(fixed2float(vs[0].x),
683
36.3M
                                       fixed2float(vs[0].y), pmat, &vp[0]);
684
36.3M
            if (code < 0)
685
12
                return code;
686
36.3M
            code = gs_point_transform_inverse(fixed2float(vs[1].x),
687
36.3M
                                       fixed2float(vs[1].y), pmat, &vp[1]);
688
36.3M
            if (code < 0)
689
0
                return code;
690
36.3M
            gs_point_transform_inverse(fixed2float(vs[2].x),
691
36.3M
                                       fixed2float(vs[2].y), pmat, &vp[2]);
692
36.3M
            code = vdev_proc(vdev, curveto)
693
36.3M
                (vdev, state->prev.x, state->prev.y, vp[0].x, vp[0].y,
694
36.3M
                 vp[1].x, vp[1].y, vp[2].x, vp[2].y, state->type);
695
36.3M
            state->prev = vp[2];
696
36.3M
            break;
697
1.94M
        case gs_pe_closepath:
698
1.94M
            code = vdev_proc(vdev, closepath)
699
1.94M
                (vdev, state->prev.x, state->prev.y, state->start.x,
700
1.94M
                 state->start.y, state->type);
701
1.94M
            state->prev = state->start;
702
1.94M
            break;
703
0
        default:    /* can't happen */
704
0
            return -1;
705
77.6M
    }
706
77.6M
    return code;
707
77.6M
}
708
709
/* Write a polygon as part of a path. */
710
/* May call beginpath, moveto, lineto, closepath, endpath. */
711
int
712
gdev_vector_write_polygon(gx_device_vector * vdev, const gs_fixed_point * points,
713
                          uint count, bool close, gx_path_type_t type)
714
5.98M
{
715
5.98M
    int code = 0;
716
717
5.98M
    if (type != gx_path_type_none &&
718
5.98M
        (code = (*vdev_proc(vdev, beginpath)) (vdev, type)) < 0
719
5.98M
        )
720
0
        return code;
721
5.98M
    if (count > 0) {
722
5.98M
        double x = fixed2float(points[0].x) / vdev->scale.x, y = fixed2float(points[0].y) / vdev->scale.y;
723
5.98M
        double x_start = x, y_start = y, x_prev, y_prev;
724
5.98M
        uint i;
725
726
5.98M
        code = (*vdev_proc(vdev, moveto))
727
5.98M
            (vdev, 0.0, 0.0, x, y, type);
728
5.98M
        if (code >= 0)
729
23.9M
            for (i = 1; i < count && code >= 0; ++i) {
730
17.9M
                x_prev = x, y_prev = y;
731
17.9M
                code = (*vdev_proc(vdev, lineto))
732
17.9M
                    (vdev, x_prev, y_prev,
733
17.9M
                     (x = fixed2float(points[i].x) / vdev->scale.x),
734
17.9M
                     (y = fixed2float(points[i].y) / vdev->scale.y),
735
17.9M
                     type);
736
17.9M
            }
737
5.98M
        if (code >= 0 && close)
738
4.68M
            code = (*vdev_proc(vdev, closepath))
739
4.68M
                (vdev, x, y, x_start, y_start, type);
740
5.98M
    }
741
5.98M
    return (code >= 0 && type != gx_path_type_none ?
742
4.68M
            (*vdev_proc(vdev, endpath)) (vdev, type) : code);
743
5.98M
}
744
745
/* Write a rectangle as part of a path. */
746
/* May call moveto, lineto, closepath. */
747
int
748
gdev_vector_write_rectangle(gx_device_vector * vdev, fixed x0, fixed y0,
749
              fixed x1, fixed y1, bool close, gx_rect_direction_t direction)
750
1.30M
{
751
1.30M
    gs_fixed_point points[4];
752
753
1.30M
    points[0].x = x0, points[0].y = y0;
754
1.30M
    points[2].x = x1, points[2].y = y1;
755
1.30M
    if (direction == gx_rect_x_first)
756
1.30M
        points[1].x = x1, points[1].y = y0,
757
1.30M
            points[3].x = x0, points[3].y = y1;
758
0
    else
759
0
        points[1].x = x0, points[1].y = y1,
760
0
            points[3].x = x1, points[3].y = y0;
761
1.30M
    return gdev_vector_write_polygon(vdev, points, 4, close,
762
1.30M
                                     gx_path_type_none);
763
1.30M
}
764
765
/* Write a clipping path by calling the path procedures. */
766
int
767
gdev_vector_write_clip_path(gx_device_vector * vdev,
768
                            const gx_clip_path * pcpath)
769
977k
{
770
977k
    const gx_clip_rect *prect;
771
977k
    gx_clip_rect page_rect;
772
977k
    int code;
773
774
977k
    if (pcpath == 0) {
775
        /* There's no special provision for initclip. */
776
        /* Write a rectangle that covers the entire page. */
777
247k
        page_rect.xmin = page_rect.ymin = 0;
778
247k
        page_rect.xmax = vdev->width;
779
247k
        page_rect.ymax = vdev->height;
780
247k
        page_rect.next = 0;
781
247k
        prect = &page_rect;
782
730k
    } else if (pcpath->path_valid) {
783
272k
        return (*vdev_proc(vdev, dopath))
784
272k
            (vdev, &pcpath->path,
785
272k
             (pcpath->rule <= 0 ?
786
271k
              gx_path_type_clip | gx_path_type_winding_number :
787
272k
              gx_path_type_clip | gx_path_type_even_odd),
788
272k
             NULL);
789
457k
    } else {
790
457k
        const gx_clip_list *list = gx_cpath_list(pcpath);
791
792
457k
        prect = list->head;
793
457k
        if (prect == 0) {
794
455k
            prect = &list->single;
795
455k
            if (prect->xmax < prect->xmin || prect->ymax < prect->ymin)
796
0
                return 0;
797
455k
        }
798
457k
    }
799
    /* Write out the rectangles. */
800
705k
    code = (*vdev_proc(vdev, beginpath)) (vdev, gx_path_type_clip);
801
2.12M
    for (; code >= 0 && prect != 0; prect = prect->next)
802
1.41M
        if (prect->xmax > prect->xmin && prect->ymax > prect->ymin)
803
1.30M
            code = gdev_vector_write_rectangle
804
1.30M
                (vdev, int2fixed(prect->xmin), int2fixed(prect->ymin),
805
1.30M
                 int2fixed(prect->xmax), int2fixed(prect->ymax),
806
1.30M
                 false, gx_rect_x_first);
807
705k
    if (code >= 0)
808
705k
        code = (*vdev_proc(vdev, endpath)) (vdev, gx_path_type_clip);
809
705k
    return code;
810
977k
}
811
812
/* Update the clipping path if needed. */
813
int
814
gdev_vector_update_clip_path(gx_device_vector * vdev,
815
                             const gx_clip_path * pcpath)
816
74.8M
{
817
74.8M
    if (pcpath) {
818
8.72M
        if (pcpath->id != vdev->clip_path_id) {
819
730k
            int code = gdev_vector_write_clip_path(vdev, pcpath);
820
821
730k
            if (code < 0)
822
0
                return code;
823
730k
            vdev->clip_path_id = pcpath->id;
824
730k
        }
825
66.1M
    } else {
826
66.1M
        if (vdev->clip_path_id != vdev->no_clip_path_id) {
827
247k
            int code = gdev_vector_write_clip_path(vdev, NULL);
828
829
247k
            if (code < 0)
830
0
                return code;
831
247k
            vdev->clip_path_id = vdev->no_clip_path_id;
832
247k
        }
833
66.1M
    }
834
74.8M
    return 0;
835
74.8M
}
836
837
/* Close the output file and stream. */
838
int
839
gdev_vector_close_file(gx_device_vector * vdev)
840
65.6k
{
841
65.6k
    gp_file *f = vdev->file;
842
65.6k
    int err;
843
844
65.6k
    if (vdev->dash_pattern) {
845
182
        gs_free_object(vdev->memory->stable_memory, vdev->dash_pattern, "vector free dash pattern");
846
182
        vdev->dash_pattern = 0;
847
182
    }
848
65.6k
    if (vdev->bbox_device) {
849
0
        rc_decrement(vdev->bbox_device->icc_struct, "vector_close(bbox_device->icc_struct");
850
0
        vdev->bbox_device->icc_struct = NULL;
851
0
        gs_free_object(vdev->v_memory, vdev->bbox_device,
852
0
                   "vector_close(bbox_device)");
853
0
        vdev->bbox_device = 0;
854
0
    }
855
856
65.6k
    if (vdev->strm) {
857
65.6k
        sclose(vdev->strm);
858
65.6k
        gs_free_object(vdev->v_memory, vdev->strm, "vector_close(strm)");
859
65.6k
        vdev->strm = 0;
860
65.6k
        gs_free_object(vdev->v_memory, vdev->strmbuf, "vector_close(strmbuf)");
861
65.6k
        vdev->strmbuf = 0;
862
65.6k
    }
863
65.6k
    vdev->file = 0;
864
65.6k
    if (f) {
865
65.6k
        err = gp_ferror(f);
866
        /* We prevented sclose from closing the file. */
867
65.6k
        if (gx_device_close_output_file((gx_device *)vdev, vdev->fname, f) != 0
868
65.6k
                || err != 0)
869
0
            return_error(gs_error_ioerror);
870
65.6k
    }
871
65.6k
    return 0;
872
65.6k
}
873
874
/* ---------------- Image enumeration ---------------- */
875
876
/* Initialize for enumerating an image. */
877
int
878
gdev_vector_begin_image(gx_device_vector * vdev,
879
                        const gs_gstate * pgs, const gs_image_t * pim,
880
                        gs_image_format_t format, const gs_int_rect * prect,
881
              const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
882
                    gs_memory_t * mem, const gx_image_enum_procs_t * pprocs,
883
                        gdev_vector_image_enum_t * pie)
884
176k
{
885
176k
    const gs_color_space *pcs = pim->ColorSpace;
886
176k
    int num_components;
887
176k
    int bits_per_pixel;
888
176k
    int code;
889
890
176k
    if (pim->ImageMask)
891
169k
        bits_per_pixel = num_components = 1;
892
7.47k
    else
893
7.47k
        num_components = gs_color_space_num_components(pcs),
894
7.47k
            bits_per_pixel = pim->BitsPerComponent;
895
176k
    code = gx_image_enum_common_init((gx_image_enum_common_t *) pie,
896
176k
                                     (const gs_data_image_t *)pim,
897
176k
                                     pprocs, (gx_device *) vdev,
898
176k
                                     num_components, format);
899
176k
    if (code < 0)
900
0
        return code;
901
176k
    pie->bits_per_pixel = bits_per_pixel * num_components /
902
176k
        pie->num_planes;
903
176k
    pie->default_info = 0;
904
176k
    pie->bbox_info = 0;
905
176k
    if ((code = gdev_vector_update_log_op(vdev, pgs->log_op)) < 0 ||
906
176k
        (code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 ||
907
176k
        ((pim->ImageMask ||
908
176k
          (pim->CombineWithColor && rop3_uses_T(pgs->log_op))) &&
909
176k
         (code = gdev_vector_update_fill_color(vdev, pgs, pdcolor)) < 0) ||
910
176k
        (vdev->bbox_device &&
911
176k
         (code = (*dev_proc(vdev->bbox_device, begin_typed_image))
912
0
                           ((gx_device *) vdev->bbox_device, pgs, NULL,
913
0
                            (gs_image_common_t *)pim, prect,
914
0
                            pdcolor, pcpath, mem, &pie->bbox_info)) < 0)
915
176k
        )
916
0
        return code;
917
176k
    pie->memory = mem;
918
176k
    if (prect)
919
0
        pie->width = prect->q.x - prect->p.x,
920
0
            pie->height = prect->q.y - prect->p.y;
921
176k
    else
922
176k
        pie->width = pim->Width, pie->height = pim->Height;
923
176k
    pie->bits_per_row = pie->width * pie->bits_per_pixel;
924
176k
    pie->y = 0;
925
176k
    return 0;
926
176k
}
927
928
/* End an image, optionally supplying any necessary blank padding rows. */
929
/* Return 0 if we used the default implementation, 1 if not. */
930
int
931
gdev_vector_end_image(gx_device_vector * vdev,
932
         gdev_vector_image_enum_t * pie, bool draw_last, gx_color_index pad)
933
0
{
934
0
    int code;
935
936
0
    if (pie->default_info) {
937
0
        code = gx_image_end(pie->default_info, draw_last);
938
0
        if (code >= 0)
939
0
            code = 0;
940
0
    } else {     /* Fill out to the full image height. */
941
0
        if (pie->y < pie->height && pad != gx_no_color_index) {
942
0
            uint bytes_per_row = (pie->bits_per_row + 7) >> 3;
943
0
            byte *row = gs_alloc_bytes(pie->memory, bytes_per_row,
944
0
                                       "gdev_vector_end_image(fill)");
945
946
0
            if (row == 0)
947
0
                return_error(gs_error_VMerror);
948
/****** FILL VALUE IS WRONG ******/
949
0
            memset(row, (byte) pad, bytes_per_row);
950
0
            for (; pie->y < pie->height; pie->y++)
951
0
                gx_image_data((gx_image_enum_common_t *) pie,
952
0
                              (const byte **)&row, 0,
953
0
                              bytes_per_row, 1);
954
0
            gs_free_object(pie->memory, row,
955
0
                           "gdev_vector_end_image(fill)");
956
0
        }
957
0
        code = 1;
958
0
    }
959
0
    if (vdev->bbox_device) {
960
0
        int bcode = gx_image_end(pie->bbox_info, draw_last);
961
962
0
        if (bcode < 0)
963
0
            code = bcode;
964
0
    }
965
0
    gx_image_free_enum((gx_image_enum_common_t **)&pie);
966
0
    return code;
967
0
}
968
969
/* ================ Device procedures ================ */
970
971
376M
#define vdev ((gx_device_vector *)dev)
972
973
int gdev_vector_get_param(gx_device *dev, char *Param, void *list)
974
1.62M
{
975
1.62M
    gs_param_list * plist = (gs_param_list *)list;
976
1.62M
    gs_param_string ofns;
977
1.62M
    bool bool_true = 1, bool_false = 0;
978
979
1.62M
    ofns.data = (const byte *)vdev->fname,
980
1.62M
        ofns.size = strlen(vdev->fname),
981
1.62M
        ofns.persistent = false;
982
1.62M
    if (strcmp(Param, "OutputFile") == 0) {
983
0
        return param_write_string(plist, "OutputFile", &ofns);
984
0
    }
985
1.62M
    if (strcmp(Param, "HighLevelDevice") == 0) {
986
351k
        return param_write_bool(plist, "HighLevelDevice", &bool_true);
987
351k
    }
988
1.27M
    if (strcmp(Param, "SupportsRasterOPs") == 0) {
989
0
        return param_write_bool(plist, "SupportsRasterOPs", &bool_false);
990
0
    }
991
1.27M
    if (strcmp(Param, "NoInterpolateImagemasks") == 0) {
992
38
        return param_write_bool(plist, "NoInterpolateImagemasks", &bool_true);
993
38
    }
994
1.27M
    return gx_default_get_param(dev, Param, list);
995
1.27M
}
996
997
/* Get parameters. */
998
int
999
gdev_vector_get_params(gx_device * dev, gs_param_list * plist)
1000
1.48M
{
1001
1.48M
    int code = gx_default_get_params(dev, plist);
1002
1.48M
    int ecode;
1003
1.48M
    gs_param_string ofns;
1004
1.48M
    bool bool_true = 1;
1005
1006
1.48M
    if (code < 0)
1007
0
        return code;
1008
1.48M
    ofns.data = (const byte *)vdev->fname,
1009
1.48M
        ofns.size = strlen(vdev->fname),
1010
1.48M
        ofns.persistent = false;
1011
1.48M
    if ((ecode = param_write_string(plist, "OutputFile", &ofns)) < 0)
1012
0
        return ecode;
1013
1.48M
    if ((ecode = param_write_bool(plist, "HighLevelDevice", &bool_true)) < 0)
1014
0
        return ecode;
1015
1.48M
    if ((ecode = param_write_bool(plist, "NoInterpolateImagemasks", &bool_true)) < 0)
1016
0
        return ecode;
1017
1.48M
    return code;
1018
1.48M
}
1019
1020
/* Put parameters. */
1021
int
1022
gdev_vector_put_params(gx_device * dev, gs_param_list * plist)
1023
827k
{
1024
827k
    int ecode = 0;
1025
827k
    int code;
1026
827k
    int igni;
1027
827k
    bool ignb;
1028
827k
    gs_param_name param_name;
1029
827k
    gs_param_string ofns;
1030
827k
    bool open = dev->is_open, HighLevelDevice, NoInterpolateImagemasks;
1031
1032
827k
    code = param_read_bool(plist, (param_name = "HighLevelDevice"), &HighLevelDevice);
1033
827k
    if (code < 0)
1034
0
        return code;
1035
1036
827k
    code = param_read_bool(plist, (param_name = "NoInterpolateImagemasks"), &NoInterpolateImagemasks);
1037
827k
    if (code < 0)
1038
0
        return code;
1039
1040
827k
    switch (code = param_read_string(plist, (param_name = "OutputFile"), &ofns)) {
1041
105k
        case 0:
1042
            /*
1043
             * Vector devices typically write header information at the
1044
             * beginning of the file: changing the file name after writing
1045
             * any pages should be an error.
1046
             */
1047
105k
            if (ofns.size > fname_size) {
1048
0
                eprintf1("\nERROR: Output filename too long (maximum %d bytes).\n", fname_size);
1049
0
                ecode = gs_error_limitcheck;
1050
0
            }
1051
105k
            else if (!bytes_compare(ofns.data, ofns.size,
1052
105k
                                    (const byte *)vdev->fname,
1053
105k
                                    strlen(vdev->fname))
1054
105k
                     ) {
1055
                /* The new name is the same as the old name.  Do nothing. */
1056
40.3k
                ofns.data = 0;
1057
40.3k
                break;
1058
65.6k
            } else if (dev->LockSafetyParams) {
1059
0
                    ecode = gs_error_invalidaccess;
1060
0
                    goto ofe;
1061
0
            }
1062
65.6k
            break;
1063
65.6k
        default:
1064
0
            ecode = code;
1065
0
ofe:        param_signal_error(plist, param_name, ecode);
1066
            /* fall through */
1067
721k
        case 1:
1068
721k
            ofns.data = 0;
1069
721k
            break;
1070
827k
    }
1071
    /* Ignore the following printer device params */
1072
827k
    switch (code = param_read_bool(plist, (param_name = "BGPrint"), &ignb)) {
1073
0
        default:
1074
0
          ecode = code;
1075
0
          param_signal_error(plist, param_name, ecode);
1076
0
        case 0:
1077
827k
        case 1:
1078
827k
          break;
1079
827k
    }
1080
827k
    switch (code = param_read_int(plist, (param_name = "NumRenderingThreads"), &igni)) {
1081
0
        default:
1082
0
          ecode = code;
1083
0
          param_signal_error(plist, param_name, ecode);
1084
0
        case 0:
1085
827k
        case 1:
1086
827k
          break;
1087
827k
    }
1088
1089
827k
    if (ecode < 0)
1090
0
        return ecode;
1091
1092
827k
    {
1093
        /* Don't let gx_default_put_params close the device. */
1094
827k
        dev->is_open = false;
1095
827k
        code = gx_default_put_params(dev, plist);
1096
827k
        dev->is_open = open;
1097
827k
    }
1098
827k
    if (code < 0)
1099
412
        return code;
1100
1101
827k
    if (dev->color_info.anti_alias.text_bits != 1 || dev->color_info.anti_alias.graphics_bits != 1) {
1102
0
        emprintf(dev->memory,
1103
0
            "\n\n  ERROR:\n    Can't set GraphicsAlphaBits or TextAlphaBits with a vector device.\n");
1104
0
        return_error(gs_error_unregistered);
1105
0
    }
1106
1107
827k
    if (ofns.data != 0) {
1108
        /* If ofns.data is not NULL, then we have a different file name */
1109
65.6k
        memcpy(vdev->fname, ofns.data, ofns.size);
1110
65.6k
        vdev->fname[ofns.size] = 0;
1111
65.6k
        if (dev->is_open && vdev->strm != 0 && stell(vdev->strm) != 0) {
1112
            /* we want to close and re-open the device so we can change the file */
1113
0
            ecode = gs_closedevice(dev);
1114
0
            if (ecode < 0) {
1115
0
                param_signal_error(plist, param_name, ecode);
1116
0
                return ecode;    /* THIS MAY CAUSE PROBLEMS SINCE THE DEVICE MAY BE CLOSED */
1117
0
            }
1118
0
            if (vdev->file != 0) {
1119
0
                gx_device_bbox *bbdev = vdev->bbox_device;
1120
1121
0
                vdev->bbox_device = 0; /* don't let it be freed */
1122
0
                code = gdev_vector_close_file(vdev);
1123
0
                vdev->bbox_device = bbdev;
1124
0
                if (code < 0)
1125
0
                    return code;
1126
0
            }
1127
0
            ecode = gs_opendevice(dev);    /* opendevice is expected to open the new file */
1128
0
            if (ecode < 0) {
1129
0
                param_signal_error(plist, param_name, ecode);
1130
0
                return ecode;
1131
0
            }
1132
0
        }
1133
        /* device is open and hasn't written data yet, so open the file */
1134
65.6k
        else if (dev->is_open) {
1135
0
            return gdev_vector_open_file_options(vdev, vdev->strmbuf_size,
1136
0
                              vdev->open_options);
1137
0
        }
1138
65.6k
    }
1139
827k
    return 0;
1140
827k
}
1141
1142
/* ---------------- Defaults ---------------- */
1143
1144
int
1145
gdev_vector_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
1146
                           gx_color_index color)
1147
61.1M
{
1148
61.1M
    gx_drawing_color dcolor;
1149
1150
    /* Ignore the initial fill with white. */
1151
61.1M
    if (!vdev->in_page && color == vdev->white)
1152
197k
        return 0;
1153
    /*
1154
     * The original colorspace and client color are unknown so use
1155
     * set_nonclient_dev_color instead of color_set_pure.
1156
     */
1157
61.1M
    set_nonclient_dev_color(&dcolor, color);
1158
60.9M
    {
1159
        /* Make sure we aren't being clipped. */
1160
60.9M
        int code = gdev_vector_update_clip_path(vdev, NULL);
1161
1162
60.9M
        if (code < 0)
1163
0
            return code;
1164
60.9M
        if ((code = update_fill(vdev, NULL, &dcolor, rop3_T)) < 0)
1165
0
            return code;
1166
60.9M
    }
1167
60.9M
    if (vdev->bbox_device) {
1168
0
        int code = (*dev_proc(vdev->bbox_device, fill_rectangle))
1169
0
        ((gx_device *) vdev->bbox_device, x, y, w, h, color);
1170
1171
0
        if (code < 0)
1172
0
            return code;
1173
0
    }
1174
60.9M
    return (*vdev_proc(vdev, dorect)) (vdev, int2fixed(x), int2fixed(y),
1175
60.9M
                                       int2fixed(x + w), int2fixed(y + h),
1176
60.9M
                                       gx_path_type_fill);
1177
60.9M
}
1178
1179
int
1180
gdev_vector_fill_path(gx_device * dev, const gs_gstate * pgs,
1181
                      gx_path * ppath, const gx_fill_params * params,
1182
                 const gx_device_color * pdevc, const gx_clip_path * pcpath)
1183
6.66M
{
1184
6.66M
    int code;
1185
1186
6.66M
    if ((code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 ||
1187
6.66M
        (code = gdev_vector_prepare_fill(vdev, pgs, params, pdevc)) < 0 ||
1188
6.66M
        (vdev->bbox_device &&
1189
6.64M
         (code = (*dev_proc(vdev->bbox_device, fill_path))
1190
0
          ((gx_device *) vdev->bbox_device, pgs, ppath, params,
1191
0
           pdevc, pcpath)) < 0) ||
1192
6.66M
        (code = (*vdev_proc(vdev, dopath))
1193
6.64M
         (vdev, ppath,
1194
6.64M
          (params->rule > 0 ? gx_path_type_even_odd :
1195
6.64M
           gx_path_type_winding_number) | gx_path_type_fill |
1196
6.64M
           vdev->fill_options,
1197
6.64M
         NULL)) < 0
1198
6.66M
        )
1199
12.7k
        return gx_default_fill_path(dev, pgs, ppath, params, pdevc, pcpath);
1200
6.64M
    return code;
1201
6.66M
}
1202
1203
int
1204
gdev_vector_stroke_path(gx_device * dev, const gs_gstate * pgs,
1205
                        gx_path * ppath, const gx_stroke_params * params,
1206
              const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
1207
776k
{
1208
776k
    int code;
1209
776k
    double scale;
1210
776k
    int set_ctm;
1211
776k
    gs_matrix mat;
1212
1213
776k
    if ((code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 ||
1214
776k
        (set_ctm = gdev_vector_stroke_scaling(vdev, pgs, &scale, &mat)) != 0 ||
1215
776k
        (code = gdev_vector_prepare_stroke(vdev, pgs, params, pdcolor, scale)) < 0 ||
1216
776k
        (vdev->bbox_device &&
1217
401k
         (code = (*dev_proc(vdev->bbox_device, stroke_path))
1218
0
          ((gx_device *) vdev->bbox_device, pgs, ppath, params,
1219
0
           pdcolor, pcpath)) < 0) ||
1220
776k
        (code = (*vdev_proc(vdev, dopath))
1221
401k
         (vdev, ppath, gx_path_type_stroke | vdev->stroke_options, NULL)) < 0
1222
776k
        )
1223
375k
        return gx_default_stroke_path(dev, pgs, ppath, params, pdcolor, pcpath);
1224
400k
    return code;
1225
776k
}
1226
1227
int
1228
gdev_vector_fill_trapezoid(gx_device * dev, const gs_fixed_edge * left,
1229
        const gs_fixed_edge * right, fixed ybot, fixed ytop, bool swap_axes,
1230
                  const gx_device_color * pdevc, gs_logical_operation_t lop)
1231
59.8k
{
1232
59.8k
    fixed xl = left->start.x;
1233
59.8k
    fixed wl = left->end.x - xl;
1234
59.8k
    fixed yl = left->start.y;
1235
59.8k
    fixed hl = left->end.y - yl;
1236
59.8k
    fixed xr = right->start.x;
1237
59.8k
    fixed wr = right->end.x - xr;
1238
59.8k
    fixed yr = right->start.y;
1239
59.8k
    fixed hr = right->end.y - yr;
1240
59.8k
    fixed x0l = xl + fixed_mult_quo(wl, ybot - yl, hl);
1241
59.8k
    fixed x1l = xl + fixed_mult_quo(wl, ytop - yl, hl);
1242
59.8k
    fixed x0r = xr + fixed_mult_quo(wr, ybot - yr, hr);
1243
59.8k
    fixed x1r = xr + fixed_mult_quo(wr, ytop - yr, hr);
1244
1245
59.8k
#define y0 ybot
1246
59.8k
#define y1 ytop
1247
59.8k
    int code = update_fill(vdev, NULL, pdevc, lop);
1248
59.8k
    gs_fixed_point points[4];
1249
1250
59.8k
    if (code < 0)
1251
5.15k
        return gx_default_fill_trapezoid(dev, left, right, ybot, ytop,
1252
5.15k
                                         swap_axes, pdevc, lop);
1253
    /* Make sure we aren't being clipped. */
1254
54.6k
    code = gdev_vector_update_clip_path(vdev, NULL);
1255
54.6k
    if (code < 0)
1256
0
        return code;
1257
54.6k
    if (swap_axes)
1258
26.9k
        points[0].y = x0l, points[1].y = x0r,
1259
26.9k
            points[0].x = points[1].x = y0,
1260
26.9k
            points[2].y = x1r, points[3].y = x1l,
1261
26.9k
            points[2].x = points[3].x = y1;
1262
27.6k
    else
1263
27.6k
        points[0].x = x0l, points[1].x = x0r,
1264
27.6k
            points[0].y = points[1].y = y0,
1265
27.6k
            points[2].x = x1r, points[3].x = x1l,
1266
27.6k
            points[2].y = points[3].y = y1;
1267
54.6k
#undef y0
1268
54.6k
#undef y1
1269
54.6k
    if (vdev->bbox_device) {
1270
0
        int code = (*dev_proc(vdev->bbox_device, fill_trapezoid))
1271
0
        ((gx_device *) vdev->bbox_device, left, right, ybot, ytop,
1272
0
         swap_axes, pdevc, lop);
1273
1274
0
        if (code < 0)
1275
0
            return code;
1276
0
    }
1277
54.6k
    return gdev_vector_write_polygon(vdev, points, 4, true,
1278
54.6k
                                     gx_path_type_fill);
1279
54.6k
}
1280
1281
int
1282
gdev_vector_fill_parallelogram(gx_device * dev,
1283
                 fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
1284
                  const gx_device_color * pdevc, gs_logical_operation_t lop)
1285
4.62M
{
1286
4.62M
    fixed pax = px + ax, pay = py + ay;
1287
4.62M
    int code = update_fill(vdev, NULL, pdevc, lop);
1288
4.62M
    gs_fixed_point points[4];
1289
4.62M
    bool need_color_reset = false;
1290
1291
4.62M
    if (code < 0)
1292
0
        return gx_default_fill_parallelogram(dev, px, py, ax, ay, bx, by,
1293
0
                                             pdevc, lop);
1294
    /* Make sure we aren't being clipped. */
1295
4.62M
    if (vdev->clip_path_id != vdev->no_clip_path_id)
1296
        /* There is a clip path, and when we emit it we will start
1297
         * by executing a grestore, which will overwrite the colour
1298
         * we set up above....
1299
         */
1300
58
        need_color_reset = true;
1301
1302
4.62M
    code = gdev_vector_update_clip_path(vdev, NULL);
1303
4.62M
    if (code < 0)
1304
0
        return code;
1305
1306
4.62M
    if (need_color_reset) {
1307
58
        code = update_fill(vdev, NULL, pdevc, lop);
1308
58
        if (code < 0)
1309
0
            return code;
1310
58
    }
1311
4.62M
    if (vdev->bbox_device) {
1312
0
        code = (*dev_proc(vdev->bbox_device, fill_parallelogram))
1313
0
            ((gx_device *) vdev->bbox_device, px, py, ax, ay, bx, by,
1314
0
             pdevc, lop);
1315
0
        if (code < 0)
1316
0
            return code;
1317
0
    }
1318
4.62M
    points[0].x = px, points[0].y = py;
1319
4.62M
    points[1].x = pax, points[1].y = pay;
1320
4.62M
    points[2].x = pax + bx, points[2].y = pay + by;
1321
4.62M
    points[3].x = px + bx, points[3].y = py + by;
1322
4.62M
    return gdev_vector_write_polygon(vdev, points, 4, true,
1323
4.62M
                                     gx_path_type_fill);
1324
4.62M
}
1325
1326
int
1327
gdev_vector_fill_triangle(gx_device * dev,
1328
                 fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
1329
                  const gx_device_color * pdevc, gs_logical_operation_t lop)
1330
0
{
1331
0
    int code = update_fill(vdev, NULL, pdevc, lop);
1332
0
    gs_fixed_point points[3];
1333
1334
0
    if (code < 0)
1335
0
        return gx_default_fill_triangle(dev, px, py, ax, ay, bx, by,
1336
0
                                        pdevc, lop);
1337
    /* Make sure we aren't being clipped. */
1338
0
    code = gdev_vector_update_clip_path(vdev, NULL);
1339
0
    if (code < 0)
1340
0
        return code;
1341
0
    if (vdev->bbox_device) {
1342
0
        code = (*dev_proc(vdev->bbox_device, fill_triangle))
1343
0
            ((gx_device *) vdev->bbox_device, px, py, ax, ay, bx, by,
1344
0
             pdevc, lop);
1345
0
        if (code < 0)
1346
0
            return code;
1347
0
    }
1348
0
    points[0].x = px, points[0].y = py;
1349
0
    points[1].x = px + ax, points[1].y = py + ay;
1350
0
    points[2].x = px + bx, points[2].y = py + by;
1351
0
    return gdev_vector_write_polygon(vdev, points, 3, true,
1352
0
                                     gx_path_type_fill);
1353
0
}
1354
1355
int
1356
gdev_vector_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size)
1357
66.8M
{
1358
66.8M
    if (dev_spec_op == gxdso_get_dev_param) {
1359
1.32M
        int code;
1360
1.32M
        dev_param_req_t *request = (dev_param_req_t *)data;
1361
1.32M
        code = gdev_vector_get_param(pdev, request->Param, request->list);
1362
1.32M
        if (code != gs_error_undefined)
1363
229k
            return code;
1364
1.32M
    }
1365
66.5M
    return gx_default_dev_spec_op(pdev, dev_spec_op, data, size);
1366
66.8M
}
1367
1368
#undef vdev