Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gdevvec.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* 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
11.2k
{
47
11.2k
    return 0;
48
11.2k
}
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
4.40M
{
61
4.40M
    bool do_close =
62
4.40M
        (type & (gx_path_type_stroke | gx_path_type_always_close)) != 0;
63
4.40M
    gs_fixed_rect rbox;
64
4.40M
    gx_path_rectangular_type rtype = gx_path_is_rectangular(ppath, &rbox);
65
4.40M
    gs_path_enum cenum;
66
4.40M
    gdev_vector_dopath_state_t state;
67
4.40M
    gs_fixed_point line_start, line_end;
68
4.40M
    bool incomplete_line = false;
69
4.40M
    bool need_moveto = false;
70
4.40M
    int code;
71
72
4.40M
    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
4.40M
    if (rtype != prt_none &&
80
4.40M
        (!(type & gx_path_type_stroke) || rtype == prt_closed) &&
81
4.40M
        (pmat == 0 || is_xxyy(pmat) || is_xyyx(pmat)) &&
82
4.40M
        (state.scale_mat.xx == 1.0 && state.scale_mat.yy == 1.0 &&
83
427k
         is_xxyy(&state.scale_mat) &&
84
427k
         is_fzero2(state.scale_mat.tx, state.scale_mat.ty))
85
4.40M
        ) {
86
427k
        gs_point p, q;
87
88
427k
        gs_point_transform_inverse((double)rbox.p.x, (double)rbox.p.y,
89
427k
                                   &state.scale_mat, &p);
90
427k
        gs_point_transform_inverse((double)rbox.q.x, (double)rbox.q.y,
91
427k
                                   &state.scale_mat, &q);
92
427k
        code = vdev_proc(vdev, dorect)(vdev, (fixed)p.x, (fixed)p.y,
93
427k
                                       (fixed)q.x, (fixed)q.y, type);
94
427k
        if (code >= 0)
95
413k
            return code;
96
        /* If the dorect proc failed, use a general path. */
97
427k
    }
98
3.99M
    code = vdev_proc(vdev, beginpath)(vdev, type);
99
3.99M
    if (code < 0)
100
484
        return code;
101
3.99M
    gx_path_enum_init(&cenum, ppath);
102
32.7M
    for (;;) {
103
32.7M
        gs_fixed_point vs[3];
104
32.7M
        int pe_op = gx_path_enum_next(&cenum, vs);
105
106
32.9M
    sw:
107
32.9M
        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
32.9M
        switch (pe_op) {
154
375k
        case 0:   /* done */
155
3.99M
        done:
156
3.99M
            code = vdev_proc(vdev, endpath)(vdev, type);
157
3.99M
            return (code < 0 ? code : 0);
158
6.75M
        case gs_pe_curveto:
159
6.75M
            if (need_moveto) { /* see gs_pe_moveto case */
160
437k
                code = gdev_vector_dopath_segment(&state, gs_pe_moveto,
161
437k
                                                  &line_start);
162
437k
                if (code < 0)
163
0
                    return code;
164
437k
                need_moveto = false;
165
437k
            }
166
6.75M
            line_start = vs[2];
167
6.75M
            goto draw;
168
4.34M
        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
4.34M
            line_start = vs[0];
176
4.34M
            if (!(type & gx_path_type_stroke) && (type & gx_path_type_fill)) {
177
4.29M
                need_moveto = true;
178
4.29M
                continue;
179
4.29M
            }
180
50.7k
            goto draw;
181
17.6M
        case gs_pe_lineto:
182
17.6M
        case gs_pe_gapto:
183
17.6M
            if (need_moveto) { /* see gs_pe_moveto case */
184
3.83M
                code = gdev_vector_dopath_segment(&state, gs_pe_moveto,
185
3.83M
                                                  &line_start);
186
3.83M
                if (code < 0)
187
0
                    return code;
188
3.83M
                need_moveto = false;
189
3.83M
            }
190
17.6M
            line_start = vs[0];
191
17.6M
            goto draw;
192
3.76M
        case gs_pe_closepath:
193
3.76M
            if (need_moveto) { /* see gs_pe_moveto case */
194
563
                need_moveto = false;
195
563
                continue;
196
563
            }
197
3.76M
            if (!do_close) {
198
3.74M
                pe_op = gx_path_enum_next(&cenum, vs);
199
3.74M
                if (pe_op == 0)
200
3.61M
                    goto done;
201
131k
                code = gdev_vector_dopath_segment(&state, gs_pe_closepath, vs);
202
131k
                if (code < 0)
203
0
                    return code;
204
131k
                goto sw;
205
131k
            }
206
            /* falls through */
207
24.5M
        draw:
208
24.5M
            code = gdev_vector_dopath_segment(&state, pe_op, vs);
209
24.5M
            if (code < 0)
210
0
                return code;
211
32.9M
        }
212
24.5M
        incomplete_line = false; /* only needed if optimizing */
213
24.5M
    }
214
3.99M
}
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
46.5k
{
238
46.5k
    vdev->black = gx_device_black((gx_device *)vdev);
239
46.5k
    vdev->white = gx_device_white((gx_device *)vdev);
240
46.5k
}
241
242
/* Initialize the state. */
243
void
244
gdev_vector_init(gx_device_vector * vdev)
245
46.5k
{
246
46.5k
    gdev_vector_reset(vdev);
247
46.5k
    if (dev_proc(vdev, dev_spec_op) == gx_default_dev_spec_op)
248
20.7k
        set_dev_proc(vdev, dev_spec_op, gdev_vector_dev_spec_op);
249
250
46.5k
    vdev->scale.x = vdev->scale.y = 1.0;
251
46.5k
    vdev->in_page = false;
252
46.5k
    gdev_vector_load_cache(vdev);
253
46.5k
}
254
255
/* Reset the remembered graphics state. */
256
void
257
gdev_vector_reset(gx_device_vector * vdev)
258
46.5k
{
259
46.5k
    static const gs_gstate state_initial =
260
46.5k
    {gs_gstate_initial(1.0)};
261
262
46.5k
    vdev->state = state_initial;
263
46.5k
    gx_hld_saved_color_init(&vdev->saved_fill_color);
264
46.5k
    gx_hld_saved_color_init(&vdev->saved_stroke_color);
265
46.5k
    vdev->clip_path_id =
266
46.5k
        vdev->no_clip_path_id = gs_next_ids(vdev->memory, 1);
267
46.5k
}
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
36.7k
{
274
36.7k
    bool binary = !(open_options & VECTOR_OPEN_FILE_ASCII);
275
36.7k
    int code = -1;    /* (only for testing, never returned) */
276
36.7k
    cmm_dev_profile_t *icc_struct = 0;
277
278
    /* Open the file as seekable or sequential, as requested. */
279
36.7k
    if (!(open_options & VECTOR_OPEN_FILE_SEQUENTIAL)) {
280
        /* Try to open as seekable. */
281
16.0k
        code =
282
16.0k
            gx_device_open_output_file((gx_device *)vdev, vdev->fname,
283
16.0k
                                       binary, true, &vdev->file);
284
16.0k
    }
285
36.7k
    if (code < 0 && (open_options & (VECTOR_OPEN_FILE_SEQUENTIAL |
286
20.7k
                                     VECTOR_OPEN_FILE_SEQUENTIAL_OK))) {
287
        /* Try to open as sequential. */
288
20.7k
        code = gx_device_open_output_file((gx_device *)vdev, vdev->fname,
289
20.7k
                                          binary, false, &vdev->file);
290
20.7k
    }
291
36.7k
    if ((code >= 0) && (dev_proc(vdev, get_profile) != NULL)) {
292
36.7k
        code = dev_proc(vdev, get_profile)((gx_device *)vdev, &icc_struct);
293
36.7k
    }
294
295
36.7k
    if (code < 0)
296
0
        return code;
297
36.7k
    if ((vdev->strmbuf = gs_alloc_bytes(vdev->v_memory, strmbuf_size,
298
36.7k
                                        "vector_open(strmbuf)")) == 0 ||
299
36.7k
        (vdev->strm = s_alloc(vdev->v_memory,
300
36.7k
                              "vector_open(strm)")) == 0 ||
301
36.7k
        ((open_options & VECTOR_OPEN_FILE_BBOX) &&
302
36.7k
         (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
36.7k
        ) {
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
36.7k
    vdev->strmbuf_size = strmbuf_size;
324
36.7k
    swrite_file(vdev->strm, vdev->file, vdev->strmbuf, strmbuf_size);
325
36.7k
    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
36.7k
    vdev->strm->procs.close = vdev->strm->procs.flush;
331
36.7k
    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
36.7k
    code = install_internal_subclass_devices((gx_device **)&vdev, NULL);
351
36.7k
    if (code < 0)
352
0
        return code;
353
354
36.7k
    return 0;
355
36.7k
}
356
357
/* Get the current stream, calling beginpage if in_page is false. */
358
stream *
359
gdev_vector_stream(gx_device_vector * vdev)
360
154M
{
361
154M
    if (!vdev->in_page) {
362
14.2k
        (*vdev_proc(vdev, beginpage)) (vdev);
363
14.2k
        vdev->in_page = true;
364
14.2k
    }
365
154M
    return vdev->strm;
366
154M
}
367
368
/* Update the logical operation. */
369
int
370
gdev_vector_update_log_op(gx_device_vector * vdev, gs_logical_operation_t lop)
371
46.8M
{
372
46.8M
    gs_logical_operation_t diff = lop ^ vdev->state.log_op;
373
374
46.8M
    if (diff != 0) {
375
230k
        int code = (*vdev_proc(vdev, setlogop)) (vdev, lop, diff);
376
377
230k
        if (code < 0)
378
0
            return code;
379
230k
        vdev->state.log_op = lop;
380
230k
    }
381
46.8M
    return 0;
382
46.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
46.8M
{
394
46.8M
    gx_hl_saved_color temp;
395
46.8M
    int code;
396
46.8M
    bool hl_color = (*vdev_proc(vdev, can_handle_hl_color)) (vdev, pgs, pdcolor);
397
46.8M
    const gs_gstate *pgs_for_hl_color = (hl_color ? pgs : NULL);
398
399
46.8M
    gx_hld_save_color(pgs_for_hl_color, pdcolor, &temp);
400
46.8M
    if (gx_hld_saved_color_equal(&temp, sc))
401
32.2M
        return 0;
402
14.6M
    code = (*setcolor) (vdev, pgs_for_hl_color, pdcolor);
403
14.6M
    if (code < 0)
404
3.07k
        return code;
405
14.6M
    *sc = temp;
406
14.6M
    return 0;
407
14.6M
}
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
46.6M
{
415
46.6M
    return gdev_vector_update_color(vdev, pgs, pdcolor, &vdev->saved_fill_color,
416
46.6M
                                    vdev_proc(vdev, setfillcolor));
417
46.6M
}
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
42.9M
{
424
42.9M
    int code = gdev_vector_update_fill_color(vdev, pgs, pdcolor);
425
426
42.9M
    if (code < 0)
427
2.91k
        return code;
428
42.9M
    return gdev_vector_update_log_op(vdev, lop);
429
42.9M
}
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
4.22M
{
436
4.22M
    if (params->flatness != vdev->state.flatness) {
437
5.91k
        int code = (*vdev_proc(vdev, setflat)) (vdev, params->flatness);
438
439
5.91k
        if (code < 0)
440
0
            return code;
441
5.91k
        vdev->state.flatness = params->flatness;
442
5.91k
    }
443
4.22M
    return update_fill(vdev, pgs, pdcolor, pgs->log_op);
444
4.22M
}
445
446
/* Compare two dash patterns. */
447
static bool
448
dash_pattern_eq(const float *stored, const gx_dash_params * set, double scale)
449
1.19k
{
450
1.19k
    int i;
451
452
3.34k
    for (i = 0; i < set->pattern_size; ++i)
453
2.34k
        if (stored[i] != (float)(set->pattern[i] * scale))
454
193
            return false;
455
1.00k
    return true;
456
1.19k
}
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
216k
{
466
216k
    if (pgs) {
467
216k
        int pattern_size = pgs->line_params.dash.pattern_size;
468
216k
        float dash_offset = pgs->line_params.dash.offset * scale;
469
216k
        float half_width = pgs->line_params.half_width * scale;
470
471
216k
        if (dash_offset != vdev->state.line_params.dash.offset ||
472
216k
            pattern_size != vdev->state.line_params.dash.pattern_size ||
473
216k
            (pattern_size != 0 &&
474
211k
             !dash_pattern_eq(vdev->dash_pattern, &pgs->line_params.dash,
475
1.19k
                              scale))
476
216k
            ) {
477
5.50k
            float *pattern;
478
5.50k
            int i, code;
479
480
5.50k
            pattern = (float *)gs_alloc_bytes(vdev->memory->stable_memory, pattern_size * sizeof(float), "vector allocate dash pattern");
481
11.0k
            for (i = 0; i < pattern_size; ++i)
482
5.58k
                pattern[i] = pgs->line_params.dash.pattern[i] * scale;
483
5.50k
            code = (*vdev_proc(vdev, setdash))
484
5.50k
                (vdev, pattern, pattern_size, dash_offset);
485
5.50k
            if (code < 0)
486
0
                return code;
487
5.50k
            if (vdev->dash_pattern)
488
1.65k
                gs_free_object(vdev->memory->stable_memory, vdev->dash_pattern, "vector free old dash pattern");
489
5.50k
            vdev->dash_pattern = pattern;
490
5.50k
            vdev->dash_pattern_size = pattern_size;
491
492
5.50k
            vdev->state.line_params.dash.pattern_size = pattern_size;
493
5.50k
            vdev->state.line_params.dash.offset = dash_offset;
494
5.50k
        }
495
216k
        if (half_width != vdev->state.line_params.half_width) {
496
70.0k
            int code = (*vdev_proc(vdev, setlinewidth))
497
70.0k
                (vdev, half_width * 2);
498
499
70.0k
            if (code < 0)
500
0
                return code;
501
70.0k
            vdev->state.line_params.half_width = half_width;
502
70.0k
        }
503
216k
        if (pgs->line_params.miter_limit != vdev->state.line_params.miter_limit) {
504
3.87k
            int code = (*vdev_proc(vdev, setmiterlimit))
505
3.87k
                (vdev, pgs->line_params.miter_limit);
506
507
3.87k
            if (code < 0)
508
0
                return code;
509
3.87k
            gx_set_miter_limit(&vdev->state.line_params,
510
3.87k
                               pgs->line_params.miter_limit);
511
3.87k
        }
512
        /* FIXME: Should cope with end_cap and dash_cap too */
513
216k
        if (pgs->line_params.start_cap != vdev->state.line_params.start_cap) {
514
7.39k
            int code = (*vdev_proc(vdev, setlinecap))
515
7.39k
                (vdev, pgs->line_params.start_cap);
516
517
7.39k
            if (code < 0)
518
0
                return code;
519
7.39k
            vdev->state.line_params.start_cap = pgs->line_params.start_cap;
520
7.39k
        }
521
216k
        if (pgs->line_params.join != vdev->state.line_params.join) {
522
6.35k
            int code = (*vdev_proc(vdev, setlinejoin))
523
6.35k
                (vdev, pgs->line_params.join);
524
525
6.35k
            if (code < 0)
526
0
                return code;
527
6.35k
            vdev->state.line_params.join = pgs->line_params.join;
528
216k
        } {
529
216k
            int code = gdev_vector_update_log_op(vdev, pgs->log_op);
530
531
216k
            if (code < 0)
532
0
                return code;
533
216k
        }
534
216k
    }
535
216k
    if (params) {
536
216k
        if (params->flatness != vdev->state.flatness) {
537
8.48k
            int code = (*vdev_proc(vdev, setflat)) (vdev, params->flatness);
538
539
8.48k
            if (code < 0)
540
0
                return code;
541
8.48k
            vdev->state.flatness = params->flatness;
542
8.48k
        }
543
216k
    }
544
216k
    if (pdcolor) {
545
216k
        int code = gdev_vector_update_color(vdev, pgs, pdcolor,
546
216k
                    &vdev->saved_stroke_color, vdev_proc(vdev, setstrokecolor));
547
548
216k
        if (code < 0)
549
157
            return code;
550
216k
    }
551
216k
    return 0;
552
216k
}
553
554
/*
555
 * Compute the scale for transforming the line width and dash pattern for a
556
 * stroke operation, and, if necessary to handle anisotropic scaling, a full
557
 * transformation matrix to be inverse-applied to the path elements as well.
558
 * Return 0 if only scaling, 1 if a full matrix is needed.
559
 */
560
int
561
gdev_vector_stroke_scaling(const gx_device_vector *vdev,
562
                           const gs_gstate *pgs,
563
                           double *pscale, gs_matrix *pmat)
564
272k
{
565
272k
    bool set_ctm = true;
566
272k
    double scale = 1;
567
568
    /*
569
     * If the CTM is not uniform, stroke width depends on angle.
570
     * We'd like to avoid resetting the CTM, so we check for uniform
571
     * CTMs explicitly.  Note that in PDF, unlike PostScript, it is
572
     * the CTM at the time of the stroke operation, not the CTM at
573
     * the time the path was constructed, that is used for transforming
574
     * the points of the path; so if we have to reset the CTM, we must
575
     * do it before constructing the path, and inverse-transform all
576
     * the coordinates.
577
     */
578
272k
    if (is_xxyy(&pgs->ctm)) {
579
271k
        scale = fabs(pgs->ctm.xx);
580
271k
        set_ctm = fabs(pgs->ctm.yy) != scale;
581
271k
    } else if (is_xyyx(&pgs->ctm)) {
582
59
        scale = fabs(pgs->ctm.xy);
583
59
        set_ctm = fabs(pgs->ctm.yx) != scale;
584
784
    } else if ((pgs->ctm.xx == pgs->ctm.yy && pgs->ctm.xy == -pgs->ctm.yx) ||
585
784
               (pgs->ctm.xx == -pgs->ctm.yy && pgs->ctm.xy == pgs->ctm.yx)
586
784
        ) {
587
332
        scale = hypot(pgs->ctm.xx, pgs->ctm.xy);
588
332
        set_ctm = false;
589
332
    }
590
272k
    if (set_ctm) {
591
        /*
592
         * Adobe Acrobat Reader has limitations on the maximum user
593
         * coordinate value.  If we scale the matrix down too far, the
594
         * coordinates will get too big: limit the scale factor to prevent
595
         * this from happening.  (This does no harm for other output
596
         * formats.)
597
         */
598
104k
        double
599
104k
            mxx = pgs->ctm.xx / vdev->scale.x,
600
104k
            mxy = pgs->ctm.xy / vdev->scale.y,
601
104k
            myx = pgs->ctm.yx / vdev->scale.x,
602
104k
            myy = pgs->ctm.yy / vdev->scale.y;
603
604
104k
        scale = 0.5 * (fabs(mxx) + fabs(mxy) + fabs(myx) + fabs(myy));
605
104k
        pmat->xx = mxx / scale, pmat->xy = mxy / scale;
606
104k
        pmat->yx = myx / scale, pmat->yy = myy / scale;
607
104k
        pmat->tx = pmat->ty = 0;
608
104k
    }
609
272k
    *pscale = scale;
610
272k
    return (int)set_ctm;
611
272k
}
612
613
/* Initialize for writing a path using the default implementation. */
614
void
615
gdev_vector_dopath_init(gdev_vector_dopath_state_t *state,
616
                        gx_device_vector *vdev, gx_path_type_t type,
617
                        const gs_matrix *pmat)
618
5.34M
{
619
5.34M
    state->vdev = vdev;
620
5.34M
    state->type = type;
621
5.34M
    if (pmat) {
622
49.4k
        state->scale_mat = *pmat;
623
        /*
624
         * The path element writing procedures all divide the coordinates
625
         * by the scale, so we must compensate for that here.
626
         */
627
49.4k
        gs_matrix_scale(&state->scale_mat, 1.0 / vdev->scale.x,
628
49.4k
                        1.0 / vdev->scale.y, &state->scale_mat);
629
5.29M
    } else {
630
5.29M
        gs_make_scaling(vdev->scale.x, vdev->scale.y, &state->scale_mat);
631
5.29M
    }
632
5.34M
    state->first = true;
633
634
    /* This is purely to prevent Coverity from thinking gdev_vector_dopath()
635
    could use uninitialised state->start.x. */
636
5.34M
    state->start.x = 0;
637
5.34M
    state->start.y = 0;
638
5.34M
}
639
640
/*
641
 * Put a segment of an enumerated path on the output file.
642
 * pe_op is assumed to be valid and non-zero.
643
 */
644
int
645
gdev_vector_dopath_segment(gdev_vector_dopath_state_t *state, int pe_op,
646
                           gs_fixed_point *vs)
647
36.6M
{
648
36.6M
    gx_device_vector *vdev = state->vdev;
649
36.6M
    const gs_matrix *const pmat = &state->scale_mat;
650
36.6M
    gs_point vp[3];
651
36.6M
    int code;
652
653
36.6M
    switch (pe_op) {
654
5.15M
        case gs_pe_moveto:
655
5.15M
            code = gs_point_transform_inverse(fixed2float(vs[0].x),
656
5.15M
                                       fixed2float(vs[0].y), pmat, &vp[0]);
657
5.15M
            if (code < 0)
658
2
                return code;
659
5.15M
            if (state->first)
660
4.52M
                state->start = vp[0], state->first = false;
661
5.15M
            code = vdev_proc(vdev, moveto)
662
5.15M
                (vdev, 0/*unused*/, 0/*unused*/, vp[0].x, vp[0].y,
663
5.15M
                 state->type);
664
5.15M
            state->prev = vp[0];
665
5.15M
            break;
666
20.7M
        case gs_pe_lineto:
667
20.7M
        case gs_pe_gapto: /* FIXME */
668
20.7M
            code = gs_point_transform_inverse(fixed2float(vs[0].x),
669
20.7M
                                       fixed2float(vs[0].y), pmat, &vp[0]);
670
20.7M
            if (code < 0)
671
2
                return code;
672
20.7M
            code = vdev_proc(vdev, lineto)
673
20.7M
                (vdev, state->prev.x, state->prev.y, vp[0].x, vp[0].y,
674
20.7M
                 state->type);
675
20.7M
            state->prev = vp[0];
676
20.7M
            break;
677
10.5M
        case gs_pe_curveto:
678
10.5M
            code = gs_point_transform_inverse(fixed2float(vs[0].x),
679
10.5M
                                       fixed2float(vs[0].y), pmat, &vp[0]);
680
10.5M
            if (code < 0)
681
0
                return code;
682
10.5M
            code = gs_point_transform_inverse(fixed2float(vs[1].x),
683
10.5M
                                       fixed2float(vs[1].y), pmat, &vp[1]);
684
10.5M
            if (code < 0)
685
0
                return code;
686
10.5M
            gs_point_transform_inverse(fixed2float(vs[2].x),
687
10.5M
                                       fixed2float(vs[2].y), pmat, &vp[2]);
688
10.5M
            code = vdev_proc(vdev, curveto)
689
10.5M
                (vdev, state->prev.x, state->prev.y, vp[0].x, vp[0].y,
690
10.5M
                 vp[1].x, vp[1].y, vp[2].x, vp[2].y, state->type);
691
10.5M
            state->prev = vp[2];
692
10.5M
            break;
693
204k
        case gs_pe_closepath:
694
204k
            code = vdev_proc(vdev, closepath)
695
204k
                (vdev, state->prev.x, state->prev.y, state->start.x,
696
204k
                 state->start.y, state->type);
697
204k
            state->prev = state->start;
698
204k
            break;
699
0
        default:    /* can't happen */
700
0
            return -1;
701
36.6M
    }
702
36.6M
    return code;
703
36.6M
}
704
705
/* Write a polygon as part of a path. */
706
/* May call beginpath, moveto, lineto, closepath, endpath. */
707
int
708
gdev_vector_write_polygon(gx_device_vector * vdev, const gs_fixed_point * points,
709
                          uint count, bool close, gx_path_type_t type)
710
253k
{
711
253k
    int code = 0;
712
713
253k
    if (type != gx_path_type_none &&
714
253k
        (code = (*vdev_proc(vdev, beginpath)) (vdev, type)) < 0
715
253k
        )
716
0
        return code;
717
253k
    if (count > 0) {
718
253k
        double x = fixed2float(points[0].x) / vdev->scale.x, y = fixed2float(points[0].y) / vdev->scale.y;
719
253k
        double x_start = x, y_start = y, x_prev, y_prev;
720
253k
        uint i;
721
722
253k
        code = (*vdev_proc(vdev, moveto))
723
253k
            (vdev, 0.0, 0.0, x, y, type);
724
253k
        if (code >= 0)
725
1.01M
            for (i = 1; i < count && code >= 0; ++i) {
726
760k
                x_prev = x, y_prev = y;
727
760k
                code = (*vdev_proc(vdev, lineto))
728
760k
                    (vdev, x_prev, y_prev,
729
760k
                     (x = fixed2float(points[i].x) / vdev->scale.x),
730
760k
                     (y = fixed2float(points[i].y) / vdev->scale.y),
731
760k
                     type);
732
760k
            }
733
253k
        if (code >= 0 && close)
734
98.9k
            code = (*vdev_proc(vdev, closepath))
735
98.9k
                (vdev, x, y, x_start, y_start, type);
736
253k
    }
737
253k
    return (code >= 0 && type != gx_path_type_none ?
738
154k
            (*vdev_proc(vdev, endpath)) (vdev, type) : code);
739
253k
}
740
741
/* Write a rectangle as part of a path. */
742
/* May call moveto, lineto, closepath. */
743
int
744
gdev_vector_write_rectangle(gx_device_vector * vdev, fixed x0, fixed y0,
745
              fixed x1, fixed y1, bool close, gx_rect_direction_t direction)
746
154k
{
747
154k
    gs_fixed_point points[4];
748
749
154k
    points[0].x = x0, points[0].y = y0;
750
154k
    points[2].x = x1, points[2].y = y1;
751
154k
    if (direction == gx_rect_x_first)
752
154k
        points[1].x = x1, points[1].y = y0,
753
154k
            points[3].x = x0, points[3].y = y1;
754
0
    else
755
0
        points[1].x = x0, points[1].y = y1,
756
0
            points[3].x = x1, points[3].y = y0;
757
154k
    return gdev_vector_write_polygon(vdev, points, 4, close,
758
154k
                                     gx_path_type_none);
759
154k
}
760
761
/* Write a clipping path by calling the path procedures. */
762
int
763
gdev_vector_write_clip_path(gx_device_vector * vdev,
764
                            const gx_clip_path * pcpath)
765
134k
{
766
134k
    const gx_clip_rect *prect;
767
134k
    gx_clip_rect page_rect;
768
134k
    int code;
769
770
134k
    if (pcpath == 0) {
771
        /* There's no special provision for initclip. */
772
        /* Write a rectangle that covers the entire page. */
773
25.9k
        page_rect.xmin = page_rect.ymin = 0;
774
25.9k
        page_rect.xmax = vdev->width;
775
25.9k
        page_rect.ymax = vdev->height;
776
25.9k
        page_rect.next = 0;
777
25.9k
        prect = &page_rect;
778
108k
    } else if (pcpath->path_valid) {
779
92.6k
        return (*vdev_proc(vdev, dopath))
780
92.6k
            (vdev, &pcpath->path,
781
92.6k
             (pcpath->rule <= 0 ?
782
91.6k
              gx_path_type_clip | gx_path_type_winding_number :
783
92.6k
              gx_path_type_clip | gx_path_type_even_odd),
784
92.6k
             NULL);
785
92.6k
    } else {
786
15.7k
        const gx_clip_list *list = gx_cpath_list(pcpath);
787
788
15.7k
        prect = list->head;
789
15.7k
        if (prect == 0)
790
14.9k
            prect = &list->single;
791
15.7k
    }
792
    /* Write out the rectangles. */
793
41.6k
    code = (*vdev_proc(vdev, beginpath)) (vdev, gx_path_type_clip);
794
197k
    for (; code >= 0 && prect != 0; prect = prect->next)
795
156k
        if (prect->xmax > prect->xmin && prect->ymax > prect->ymin)
796
154k
            code = gdev_vector_write_rectangle
797
154k
                (vdev, int2fixed(prect->xmin), int2fixed(prect->ymin),
798
154k
                 int2fixed(prect->xmax), int2fixed(prect->ymax),
799
154k
                 false, gx_rect_x_first);
800
41.6k
    if (code >= 0)
801
41.6k
        code = (*vdev_proc(vdev, endpath)) (vdev, gx_path_type_clip);
802
41.6k
    return code;
803
134k
}
804
805
/* Update the clipping path if needed. */
806
int
807
gdev_vector_update_clip_path(gx_device_vector * vdev,
808
                             const gx_clip_path * pcpath)
809
46.8M
{
810
46.8M
    if (pcpath) {
811
8.07M
        if (pcpath->id != vdev->clip_path_id) {
812
108k
            int code = gdev_vector_write_clip_path(vdev, pcpath);
813
814
108k
            if (code < 0)
815
5
                return code;
816
108k
            vdev->clip_path_id = pcpath->id;
817
108k
        }
818
38.7M
    } else {
819
38.7M
        if (vdev->clip_path_id != vdev->no_clip_path_id) {
820
25.9k
            int code = gdev_vector_write_clip_path(vdev, NULL);
821
822
25.9k
            if (code < 0)
823
0
                return code;
824
25.9k
            vdev->clip_path_id = vdev->no_clip_path_id;
825
25.9k
        }
826
38.7M
    }
827
46.8M
    return 0;
828
46.8M
}
829
830
/* Close the output file and stream. */
831
int
832
gdev_vector_close_file(gx_device_vector * vdev)
833
36.7k
{
834
36.7k
    gp_file *f = vdev->file;
835
36.7k
    int err;
836
837
36.7k
    if (vdev->dash_pattern) {
838
101
        gs_free_object(vdev->memory->stable_memory, vdev->dash_pattern, "vector free dash pattern");
839
101
        vdev->dash_pattern = 0;
840
101
    }
841
36.7k
    if (vdev->bbox_device) {
842
0
        rc_decrement(vdev->bbox_device->icc_struct, "vector_close(bbox_device->icc_struct");
843
0
        vdev->bbox_device->icc_struct = NULL;
844
0
        gs_free_object(vdev->v_memory, vdev->bbox_device,
845
0
                   "vector_close(bbox_device)");
846
0
        vdev->bbox_device = 0;
847
0
    }
848
849
36.7k
    if (vdev->strm) {
850
36.7k
        sclose(vdev->strm);
851
36.7k
        gs_free_object(vdev->v_memory, vdev->strm, "vector_close(strm)");
852
36.7k
        vdev->strm = 0;
853
36.7k
        gs_free_object(vdev->v_memory, vdev->strmbuf, "vector_close(strmbuf)");
854
36.7k
        vdev->strmbuf = 0;
855
36.7k
    }
856
36.7k
    vdev->file = 0;
857
36.7k
    if (f) {
858
36.7k
        err = gp_ferror(f);
859
        /* We prevented sclose from closing the file. */
860
36.7k
        if (gx_device_close_output_file((gx_device *)vdev, vdev->fname, f) != 0
861
36.7k
                || err != 0)
862
0
            return_error(gs_error_ioerror);
863
36.7k
    }
864
36.7k
    return 0;
865
36.7k
}
866
867
/* ---------------- Image enumeration ---------------- */
868
869
/* Initialize for enumerating an image. */
870
int
871
gdev_vector_begin_image(gx_device_vector * vdev,
872
                        const gs_gstate * pgs, const gs_image_t * pim,
873
                        gs_image_format_t format, const gs_int_rect * prect,
874
              const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
875
                    gs_memory_t * mem, const gx_image_enum_procs_t * pprocs,
876
                        gdev_vector_image_enum_t * pie)
877
3.37k
{
878
3.37k
    const gs_color_space *pcs = pim->ColorSpace;
879
3.37k
    int num_components;
880
3.37k
    int bits_per_pixel;
881
3.37k
    int code;
882
883
3.37k
    if (pim->ImageMask)
884
60
        bits_per_pixel = num_components = 1;
885
3.31k
    else
886
3.31k
        num_components = gs_color_space_num_components(pcs),
887
3.31k
            bits_per_pixel = pim->BitsPerComponent;
888
3.37k
    code = gx_image_enum_common_init((gx_image_enum_common_t *) pie,
889
3.37k
                                     (const gs_data_image_t *)pim,
890
3.37k
                                     pprocs, (gx_device *) vdev,
891
3.37k
                                     num_components, format);
892
3.37k
    if (code < 0)
893
0
        return code;
894
3.37k
    pie->bits_per_pixel = bits_per_pixel * num_components /
895
3.37k
        pie->num_planes;
896
3.37k
    pie->default_info = 0;
897
3.37k
    pie->bbox_info = 0;
898
3.37k
    if ((code = gdev_vector_update_log_op(vdev, pgs->log_op)) < 0 ||
899
3.37k
        (code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 ||
900
3.37k
        ((pim->ImageMask ||
901
3.37k
          (pim->CombineWithColor && rop3_uses_T(pgs->log_op))) &&
902
3.37k
         (code = gdev_vector_update_fill_color(vdev, pgs, pdcolor)) < 0) ||
903
3.37k
        (vdev->bbox_device &&
904
3.37k
         (code = (*dev_proc(vdev->bbox_device, begin_typed_image))
905
0
                           ((gx_device *) vdev->bbox_device, pgs, NULL,
906
0
                            (gs_image_common_t *)pim, prect,
907
0
                            pdcolor, pcpath, mem, &pie->bbox_info)) < 0)
908
3.37k
        )
909
5
        return code;
910
3.37k
    pie->memory = mem;
911
3.37k
    if (prect)
912
0
        pie->width = prect->q.x - prect->p.x,
913
0
            pie->height = prect->q.y - prect->p.y;
914
3.37k
    else
915
3.37k
        pie->width = pim->Width, pie->height = pim->Height;
916
3.37k
    pie->bits_per_row = pie->width * pie->bits_per_pixel;
917
3.37k
    pie->y = 0;
918
3.37k
    return 0;
919
3.37k
}
920
921
/* End an image, optionally supplying any necessary blank padding rows. */
922
/* Return 0 if we used the default implementation, 1 if not. */
923
int
924
gdev_vector_end_image(gx_device_vector * vdev,
925
         gdev_vector_image_enum_t * pie, bool draw_last, gx_color_index pad)
926
0
{
927
0
    int code;
928
929
0
    if (pie->default_info) {
930
0
        code = gx_image_end(pie->default_info, draw_last);
931
0
        if (code >= 0)
932
0
            code = 0;
933
0
    } else {     /* Fill out to the full image height. */
934
0
        if (pie->y < pie->height && pad != gx_no_color_index) {
935
0
            uint bytes_per_row = (pie->bits_per_row + 7) >> 3;
936
0
            byte *row = gs_alloc_bytes(pie->memory, bytes_per_row,
937
0
                                       "gdev_vector_end_image(fill)");
938
939
0
            if (row == 0)
940
0
                return_error(gs_error_VMerror);
941
/****** FILL VALUE IS WRONG ******/
942
0
            memset(row, (byte) pad, bytes_per_row);
943
0
            for (; pie->y < pie->height; pie->y++)
944
0
                gx_image_data((gx_image_enum_common_t *) pie,
945
0
                              (const byte **)&row, 0,
946
0
                              bytes_per_row, 1);
947
0
            gs_free_object(pie->memory, row,
948
0
                           "gdev_vector_end_image(fill)");
949
0
        }
950
0
        code = 1;
951
0
    }
952
0
    if (vdev->bbox_device) {
953
0
        int bcode = gx_image_end(pie->bbox_info, draw_last);
954
955
0
        if (bcode < 0)
956
0
            code = bcode;
957
0
    }
958
0
    gx_image_free_enum((gx_image_enum_common_t **)&pie);
959
0
    return code;
960
0
}
961
962
/* ================ Device procedures ================ */
963
964
218M
#define vdev ((gx_device_vector *)dev)
965
966
int gdev_vector_get_param(gx_device *dev, char *Param, void *list)
967
637k
{
968
637k
    gs_param_list * plist = (gs_param_list *)list;
969
637k
    gs_param_string ofns;
970
637k
    bool bool_true = 1;
971
972
637k
    ofns.data = (const byte *)vdev->fname,
973
637k
        ofns.size = strlen(vdev->fname),
974
637k
        ofns.persistent = false;
975
637k
    if (strcmp(Param, "OutputFile") == 0) {
976
0
        return param_write_string(plist, "OutputFile", &ofns);
977
0
    }
978
637k
    if (strcmp(Param, "HighLevelDevice") == 0) {
979
112k
        return param_write_bool(plist, "HighLevelDevice", &bool_true);
980
112k
    }
981
524k
    if (strcmp(Param, "NoInterpolateImagemasks") == 0) {
982
0
        return param_write_bool(plist, "NoInterpolateImagemasks", &bool_true);
983
0
    }
984
524k
    return gx_default_get_param(dev, Param, list);
985
524k
}
986
987
/* Get parameters. */
988
int
989
gdev_vector_get_params(gx_device * dev, gs_param_list * plist)
990
536k
{
991
536k
    int code = gx_default_get_params(dev, plist);
992
536k
    int ecode;
993
536k
    gs_param_string ofns;
994
536k
    bool bool_true = 1;
995
996
536k
    if (code < 0)
997
0
        return code;
998
536k
    ofns.data = (const byte *)vdev->fname,
999
536k
        ofns.size = strlen(vdev->fname),
1000
536k
        ofns.persistent = false;
1001
536k
    if ((ecode = param_write_string(plist, "OutputFile", &ofns)) < 0)
1002
0
        return ecode;
1003
536k
    if ((ecode = param_write_bool(plist, "HighLevelDevice", &bool_true)) < 0)
1004
0
        return ecode;
1005
536k
    if ((ecode = param_write_bool(plist, "NoInterpolateImagemasks", &bool_true)) < 0)
1006
0
        return ecode;
1007
536k
    return code;
1008
536k
}
1009
1010
/* Put parameters. */
1011
int
1012
gdev_vector_put_params(gx_device * dev, gs_param_list * plist)
1013
379k
{
1014
379k
    int ecode = 0;
1015
379k
    int code;
1016
379k
    int igni;
1017
379k
    bool ignb;
1018
379k
    gs_param_name param_name;
1019
379k
    gs_param_string ofns;
1020
379k
    bool open = dev->is_open, HighLevelDevice, NoInterpolateImagemasks;
1021
1022
379k
    code = param_read_bool(plist, (param_name = "HighLevelDevice"), &HighLevelDevice);
1023
379k
    if (code < 0)
1024
0
        return code;
1025
1026
379k
    code = param_read_bool(plist, (param_name = "NoInterpolateImagemasks"), &NoInterpolateImagemasks);
1027
379k
    if (code < 0)
1028
0
        return code;
1029
1030
379k
    switch (code = param_read_string(plist, (param_name = "OutputFile"), &ofns)) {
1031
49.7k
        case 0:
1032
            /*
1033
             * Vector devices typically write header information at the
1034
             * beginning of the file: changing the file name after writing
1035
             * any pages should be an error.
1036
             */
1037
49.7k
            if (ofns.size > fname_size) {
1038
0
                eprintf1("\nERROR: Output filename too long (maximum %d bytes).\n", fname_size);
1039
0
                ecode = gs_error_limitcheck;
1040
0
            }
1041
49.7k
            else if (!bytes_compare(ofns.data, ofns.size,
1042
49.7k
                                    (const byte *)vdev->fname,
1043
49.7k
                                    strlen(vdev->fname))
1044
49.7k
                     ) {
1045
                /* The new name is the same as the old name.  Do nothing. */
1046
12.9k
                ofns.data = 0;
1047
12.9k
                break;
1048
36.7k
            } else if (dev->LockSafetyParams) {
1049
0
                    ecode = gs_error_invalidaccess;
1050
0
                    goto ofe;
1051
0
            }
1052
36.7k
            break;
1053
36.7k
        default:
1054
0
            ecode = code;
1055
0
ofe:        param_signal_error(plist, param_name, ecode);
1056
            /* fall through */
1057
329k
        case 1:
1058
329k
            ofns.data = 0;
1059
329k
            break;
1060
379k
    }
1061
    /* Ignore the following printer device params */
1062
379k
    switch (code = param_read_bool(plist, (param_name = "BGPrint"), &ignb)) {
1063
0
        default:
1064
0
          ecode = code;
1065
0
          param_signal_error(plist, param_name, ecode);
1066
0
        case 0:
1067
379k
        case 1:
1068
379k
          break;
1069
379k
    }
1070
379k
    switch (code = param_read_int(plist, (param_name = "NumRenderingThreads"), &igni)) {
1071
0
        default:
1072
0
          ecode = code;
1073
0
          param_signal_error(plist, param_name, ecode);
1074
0
        case 0:
1075
379k
        case 1:
1076
379k
          break;
1077
379k
    }
1078
1079
379k
    if (ecode < 0)
1080
0
        return ecode;
1081
1082
379k
    {
1083
        /* Don't let gx_default_put_params close the device. */
1084
379k
        dev->is_open = false;
1085
379k
        code = gx_default_put_params(dev, plist);
1086
379k
        dev->is_open = open;
1087
379k
    }
1088
379k
    if (code < 0)
1089
171
        return code;
1090
1091
379k
    if (dev->color_info.anti_alias.text_bits != 1 || dev->color_info.anti_alias.graphics_bits != 1) {
1092
0
        emprintf(dev->memory,
1093
0
            "\n\n  ERROR:\n    Can't set GraphicsAlphaBits or TextAlphaBits with a vector device.\n");
1094
0
        return_error(gs_error_unregistered);
1095
0
    }
1096
1097
379k
    if (ofns.data != 0) {
1098
        /* If ofns.data is not NULL, then we have a different file name */
1099
36.7k
        memcpy(vdev->fname, ofns.data, ofns.size);
1100
36.7k
        vdev->fname[ofns.size] = 0;
1101
36.7k
        if (dev->is_open && vdev->strm != 0 && stell(vdev->strm) != 0) {
1102
            /* we want to close and re-open the device so we can change the file */
1103
0
            ecode = gs_closedevice(dev);
1104
0
            if (ecode < 0) {
1105
0
                param_signal_error(plist, param_name, ecode);
1106
0
                return ecode;    /* THIS MAY CAUSE PROBLEMS SINCE THE DEVICE MAY BE CLOSED */
1107
0
            }
1108
0
            if (vdev->file != 0) {
1109
0
                gx_device_bbox *bbdev = vdev->bbox_device;
1110
1111
0
                vdev->bbox_device = 0; /* don't let it be freed */
1112
0
                code = gdev_vector_close_file(vdev);
1113
0
                vdev->bbox_device = bbdev;
1114
0
                if (code < 0)
1115
0
                    return code;
1116
0
            }
1117
0
            ecode = gs_opendevice(dev);    /* opendevice is expected to open the new file */
1118
0
            if (ecode < 0) {
1119
0
                param_signal_error(plist, param_name, ecode);
1120
0
                return ecode;
1121
0
            }
1122
0
        }
1123
        /* device is open and hasn't written data yet, so open the file */
1124
36.7k
        else if (dev->is_open) {
1125
0
            return gdev_vector_open_file_options(vdev, vdev->strmbuf_size,
1126
0
                              vdev->open_options);
1127
0
        }
1128
36.7k
    }
1129
379k
    return 0;
1130
379k
}
1131
1132
/* ---------------- Defaults ---------------- */
1133
1134
int
1135
gdev_vector_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
1136
                           gx_color_index color)
1137
38.8M
{
1138
38.8M
    gx_drawing_color dcolor;
1139
1140
    /* Ignore the initial fill with white. */
1141
38.8M
    if (!vdev->in_page && color == vdev->white)
1142
218k
        return 0;
1143
    /*
1144
     * The original colorspace and client color are unknown so use
1145
     * set_nonclient_dev_color instead of color_set_pure.
1146
     */
1147
38.8M
    set_nonclient_dev_color(&dcolor, color);
1148
38.5M
    {
1149
        /* Make sure we aren't being clipped. */
1150
38.5M
        int code = gdev_vector_update_clip_path(vdev, NULL);
1151
1152
38.5M
        if (code < 0)
1153
0
            return code;
1154
38.5M
        if ((code = update_fill(vdev, NULL, &dcolor, rop3_T)) < 0)
1155
0
            return code;
1156
38.5M
    }
1157
38.5M
    if (vdev->bbox_device) {
1158
0
        int code = (*dev_proc(vdev->bbox_device, fill_rectangle))
1159
0
        ((gx_device *) vdev->bbox_device, x, y, w, h, color);
1160
1161
0
        if (code < 0)
1162
0
            return code;
1163
0
    }
1164
38.5M
    return (*vdev_proc(vdev, dorect)) (vdev, int2fixed(x), int2fixed(y),
1165
38.5M
                                       int2fixed(x + w), int2fixed(y + h),
1166
38.5M
                                       gx_path_type_fill);
1167
38.5M
}
1168
1169
int
1170
gdev_vector_fill_path(gx_device * dev, const gs_gstate * pgs,
1171
                      gx_path * ppath, const gx_fill_params * params,
1172
                 const gx_device_color * pdevc, const gx_clip_path * pcpath)
1173
4.22M
{
1174
4.22M
    int code;
1175
1176
4.22M
    if ((code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 ||
1177
4.22M
        (code = gdev_vector_prepare_fill(vdev, pgs, params, pdevc)) < 0 ||
1178
4.22M
        (vdev->bbox_device &&
1179
4.22M
         (code = (*dev_proc(vdev->bbox_device, fill_path))
1180
0
          ((gx_device *) vdev->bbox_device, pgs, ppath, params,
1181
0
           pdevc, pcpath)) < 0) ||
1182
4.22M
        (code = (*vdev_proc(vdev, dopath))
1183
4.22M
         (vdev, ppath,
1184
4.22M
          (params->rule > 0 ? gx_path_type_even_odd :
1185
4.22M
           gx_path_type_winding_number) | gx_path_type_fill |
1186
4.22M
           vdev->fill_options,
1187
4.22M
         NULL)) < 0
1188
4.22M
        )
1189
2.55k
        return gx_default_fill_path(dev, pgs, ppath, params, pdevc, pcpath);
1190
4.22M
    return code;
1191
4.22M
}
1192
1193
int
1194
gdev_vector_stroke_path(gx_device * dev, const gs_gstate * pgs,
1195
                        gx_path * ppath, const gx_stroke_params * params,
1196
              const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
1197
139k
{
1198
139k
    int code;
1199
139k
    double scale;
1200
139k
    int set_ctm;
1201
139k
    gs_matrix mat;
1202
1203
139k
    if ((code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 ||
1204
139k
        (set_ctm = gdev_vector_stroke_scaling(vdev, pgs, &scale, &mat)) != 0 ||
1205
139k
        (code = gdev_vector_prepare_stroke(vdev, pgs, params, pdcolor, scale)) < 0 ||
1206
139k
        (vdev->bbox_device &&
1207
84.9k
         (code = (*dev_proc(vdev->bbox_device, stroke_path))
1208
0
          ((gx_device *) vdev->bbox_device, pgs, ppath, params,
1209
0
           pdcolor, pcpath)) < 0) ||
1210
139k
        (code = (*vdev_proc(vdev, dopath))
1211
84.9k
         (vdev, ppath, gx_path_type_stroke | vdev->stroke_options, NULL)) < 0
1212
139k
        )
1213
54.9k
        return gx_default_stroke_path(dev, pgs, ppath, params, pdcolor, pcpath);
1214
84.8k
    return code;
1215
139k
}
1216
1217
int
1218
gdev_vector_fill_trapezoid(gx_device * dev, const gs_fixed_edge * left,
1219
        const gs_fixed_edge * right, fixed ybot, fixed ytop, bool swap_axes,
1220
                  const gx_device_color * pdevc, gs_logical_operation_t lop)
1221
91.7k
{
1222
91.7k
    fixed xl = left->start.x;
1223
91.7k
    fixed wl = left->end.x - xl;
1224
91.7k
    fixed yl = left->start.y;
1225
91.7k
    fixed hl = left->end.y - yl;
1226
91.7k
    fixed xr = right->start.x;
1227
91.7k
    fixed wr = right->end.x - xr;
1228
91.7k
    fixed yr = right->start.y;
1229
91.7k
    fixed hr = right->end.y - yr;
1230
91.7k
    fixed x0l = xl + fixed_mult_quo(wl, ybot - yl, hl);
1231
91.7k
    fixed x1l = xl + fixed_mult_quo(wl, ytop - yl, hl);
1232
91.7k
    fixed x0r = xr + fixed_mult_quo(wr, ybot - yr, hr);
1233
91.7k
    fixed x1r = xr + fixed_mult_quo(wr, ytop - yr, hr);
1234
1235
91.7k
#define y0 ybot
1236
91.7k
#define y1 ytop
1237
91.7k
    int code = update_fill(vdev, NULL, pdevc, lop);
1238
91.7k
    gs_fixed_point points[4];
1239
1240
91.7k
    if (code < 0)
1241
678
        return gx_default_fill_trapezoid(dev, left, right, ybot, ytop,
1242
678
                                         swap_axes, pdevc, lop);
1243
    /* Make sure we aren't being clipped. */
1244
91.0k
    code = gdev_vector_update_clip_path(vdev, NULL);
1245
91.0k
    if (code < 0)
1246
0
        return code;
1247
91.0k
    if (swap_axes)
1248
40.4k
        points[0].y = x0l, points[1].y = x0r,
1249
40.4k
            points[0].x = points[1].x = y0,
1250
40.4k
            points[2].y = x1r, points[3].y = x1l,
1251
40.4k
            points[2].x = points[3].x = y1;
1252
50.5k
    else
1253
50.5k
        points[0].x = x0l, points[1].x = x0r,
1254
50.5k
            points[0].y = points[1].y = y0,
1255
50.5k
            points[2].x = x1r, points[3].x = x1l,
1256
50.5k
            points[2].y = points[3].y = y1;
1257
91.0k
#undef y0
1258
91.0k
#undef y1
1259
91.0k
    if (vdev->bbox_device) {
1260
0
        int code = (*dev_proc(vdev->bbox_device, fill_trapezoid))
1261
0
        ((gx_device *) vdev->bbox_device, left, right, ybot, ytop,
1262
0
         swap_axes, pdevc, lop);
1263
1264
0
        if (code < 0)
1265
0
            return code;
1266
0
    }
1267
91.0k
    return gdev_vector_write_polygon(vdev, points, 4, true,
1268
91.0k
                                     gx_path_type_fill);
1269
91.0k
}
1270
1271
int
1272
gdev_vector_fill_parallelogram(gx_device * dev,
1273
                 fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
1274
                  const gx_device_color * pdevc, gs_logical_operation_t lop)
1275
7.87k
{
1276
7.87k
    fixed pax = px + ax, pay = py + ay;
1277
7.87k
    int code = update_fill(vdev, NULL, pdevc, lop);
1278
7.87k
    gs_fixed_point points[4];
1279
7.87k
    bool need_color_reset = false;
1280
1281
7.87k
    if (code < 0)
1282
0
        return gx_default_fill_parallelogram(dev, px, py, ax, ay, bx, by,
1283
0
                                             pdevc, lop);
1284
    /* Make sure we aren't being clipped. */
1285
7.87k
    if (vdev->clip_path_id != vdev->no_clip_path_id)
1286
        /* There is a clip path, and when we emit it we will start
1287
         * by executing a grestore, which will overwrite the colour
1288
         * we set up above....
1289
         */
1290
4
        need_color_reset = true;
1291
1292
7.87k
    code = gdev_vector_update_clip_path(vdev, NULL);
1293
7.87k
    if (code < 0)
1294
0
        return code;
1295
1296
7.87k
    if (need_color_reset) {
1297
4
        code = update_fill(vdev, NULL, pdevc, lop);
1298
4
        if (code < 0)
1299
0
            return code;
1300
4
    }
1301
7.87k
    if (vdev->bbox_device) {
1302
0
        code = (*dev_proc(vdev->bbox_device, fill_parallelogram))
1303
0
            ((gx_device *) vdev->bbox_device, px, py, ax, ay, bx, by,
1304
0
             pdevc, lop);
1305
0
        if (code < 0)
1306
0
            return code;
1307
0
    }
1308
7.87k
    points[0].x = px, points[0].y = py;
1309
7.87k
    points[1].x = pax, points[1].y = pay;
1310
7.87k
    points[2].x = pax + bx, points[2].y = pay + by;
1311
7.87k
    points[3].x = px + bx, points[3].y = py + by;
1312
7.87k
    return gdev_vector_write_polygon(vdev, points, 4, true,
1313
7.87k
                                     gx_path_type_fill);
1314
7.87k
}
1315
1316
int
1317
gdev_vector_fill_triangle(gx_device * dev,
1318
                 fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
1319
                  const gx_device_color * pdevc, gs_logical_operation_t lop)
1320
0
{
1321
0
    int code = update_fill(vdev, NULL, pdevc, lop);
1322
0
    gs_fixed_point points[3];
1323
1324
0
    if (code < 0)
1325
0
        return gx_default_fill_triangle(dev, px, py, ax, ay, bx, by,
1326
0
                                        pdevc, lop);
1327
    /* Make sure we aren't being clipped. */
1328
0
    code = gdev_vector_update_clip_path(vdev, NULL);
1329
0
    if (code < 0)
1330
0
        return code;
1331
0
    if (vdev->bbox_device) {
1332
0
        code = (*dev_proc(vdev->bbox_device, fill_triangle))
1333
0
            ((gx_device *) vdev->bbox_device, px, py, ax, ay, bx, by,
1334
0
             pdevc, lop);
1335
0
        if (code < 0)
1336
0
            return code;
1337
0
    }
1338
0
    points[0].x = px, points[0].y = py;
1339
0
    points[1].x = px + ax, points[1].y = py + ay;
1340
0
    points[2].x = px + bx, points[2].y = py + by;
1341
0
    return gdev_vector_write_polygon(vdev, points, 3, true,
1342
0
                                     gx_path_type_fill);
1343
0
}
1344
1345
int
1346
gdev_vector_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size)
1347
10.5M
{
1348
10.5M
    if (dev_spec_op == gxdso_get_dev_param) {
1349
550k
        int code;
1350
550k
        dev_param_req_t *request = (dev_param_req_t *)data;
1351
550k
        code = gdev_vector_get_param(pdev, request->Param, request->list);
1352
550k
        if (code != gs_error_undefined)
1353
117k
            return code;
1354
550k
    }
1355
10.4M
    return gx_default_dev_spec_op(pdev, dev_spec_op, data, size);
1356
10.5M
}
1357
1358
#undef vdev