Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/psi/zdps1.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
/* Level 2 / Display PostScript graphics extensions */
18
#include "ghost.h"
19
#include "oper.h"
20
#include "gsmatrix.h"
21
#include "gspath.h"
22
#include "gspath2.h"
23
#include "gsstate.h"
24
#include "gxgstate.h"
25
#include "ialloc.h"
26
#include "igstate.h"
27
#include "ivmspace.h"
28
#include "store.h"
29
#include "stream.h"
30
#include "ibnum.h"
31
32
/* Forward references */
33
static int gstate_unshare(i_ctx_t *);
34
35
/* Declare exported procedures (for zupath.c) */
36
int zsetbbox(i_ctx_t *);
37
38
/* Structure descriptors */
39
public_st_igstate_obj();
40
41
/* Extend the `copy' operator to deal with gstates. */
42
/* This is done with a hack -- we know that gstates are the only */
43
/* t_astruct subtype that implements copy. */
44
static int
45
z1copy(i_ctx_t *i_ctx_p)
46
0
{
47
0
    os_ptr op = osp;
48
0
    int code = zcopy(i_ctx_p);
49
50
0
    if (code >= 0)
51
0
        return code;
52
0
    if (!r_has_type(op, t_astruct))
53
0
        return code;
54
0
    return zcopy_gstate(i_ctx_p);
55
0
}
56
57
/* ------ Graphics state ------ */
58
59
/* <bool> setstrokeadjust - */
60
static int
61
zsetstrokeadjust(i_ctx_t *i_ctx_p)
62
89.2k
{
63
89.2k
    os_ptr op = osp;
64
65
89.2k
    check_type(*op, t_boolean);
66
89.2k
    gs_setstrokeadjust(igs, op->value.boolval);
67
89.2k
    pop(1);
68
89.2k
    return 0;
69
89.2k
}
70
71
/* - currentstrokeadjust <bool> */
72
static int
73
zcurrentstrokeadjust(i_ctx_t *i_ctx_p)
74
4
{
75
4
    os_ptr op = osp;
76
77
4
    push(1);
78
4
    make_bool(op, gs_currentstrokeadjust(igs));
79
4
    return 0;
80
4
}
81
82
/* ------ Graphics state objects ------ */
83
84
/*
85
 * Check to make sure that all the elements of a graphics state
86
 * can be stored in the given allocation space.
87
 */
88
/* ****** DOESN'T CHECK THE NON-REFS. ****** */
89
static int
90
gstate_check_space(i_ctx_t *i_ctx_p, int_gstate *isp, uint space)
91
317
{
92
    /*
93
     * ****** WORKAROUND ALERT ******
94
     * This code doesn't check the space of the non-refs, or copy their
95
     * contents, so it can create dangling references from global VM to
96
     * local VM.  Because of this, we simply disallow writing into gstates
97
     * in global VM (including creating them in the first place) if the
98
     * save level is greater than 0.
99
     * ****** WORKAROUND ALERT ******
100
     */
101
317
#if 1       /* ****** WORKAROUND ****** */
102
317
    if (space != avm_local && imemory_save_level(iimemory) > 0)
103
0
        return_error(gs_error_invalidaccess);
104
317
#endif        /* ****** END ****** */
105
11.0k
#define gsref_check(p) store_check_space(space, p)
106
11.0k
    int_gstate_map_refs(isp, gsref_check);
107
317
#undef gsref_check
108
317
    return 0;
109
317
}
110
111
/* - gstate <gstate> */
112
int
113
zgstate(i_ctx_t *i_ctx_p)
114
316
{
115
316
    os_ptr op = osp;
116
117
316
    int code = gstate_check_space(i_ctx_p, istate, icurrent_space);
118
316
    igstate_obj *pigo;
119
316
    gs_gstate *pnew;
120
316
    int_gstate *isp;
121
122
316
    if (code < 0)
123
0
        return code;
124
316
    pigo = ialloc_struct(igstate_obj, &st_igstate_obj, "gstate");
125
316
    if (pigo == 0)
126
0
        return_error(gs_error_VMerror);
127
316
    pnew = gs_gstate_copy(igs, imemory);
128
316
    if (pnew == 0) {
129
0
        ifree_object(pigo, "gstate");
130
0
        return_error(gs_error_VMerror);
131
0
    }
132
316
    isp = gs_int_gstate(pnew);
133
11.0k
    int_gstate_map_refs(isp, ref_mark_new);
134
316
    push(1);
135
    /*
136
     * Since igstate_obj isn't a ref, but only contains a ref, save won't
137
     * clear its l_new bit automatically, and restore won't set it
138
     * automatically; we have to make sure this ref is on the changes chain.
139
     */
140
316
    make_iastruct(op, a_all, pigo);
141
#if 0 /* Bug 689849 "gstate leaks memory" */
142
    make_null(&pigo->gstate);
143
    ref_save(op, &pigo->gstate, "gstate");
144
    make_istruct_new(&pigo->gstate, 0, pnew);
145
#else
146
316
    make_istruct(&pigo->gstate, 0, pnew);
147
316
#endif
148
316
    return 0;
149
316
}
150
151
/* copy for gstates */
152
int
153
zcopy_gstate(i_ctx_t *i_ctx_p)
154
0
{
155
0
    os_ptr op = osp;
156
0
    os_ptr op1 = op - 1;
157
0
    gs_gstate *pgs;
158
0
    gs_gstate *pgs1;
159
0
    int_gstate *pistate;
160
0
    gs_memory_t *mem;
161
0
    int code;
162
163
0
    check_stype(*op, st_igstate_obj);
164
0
    check_stype(*op1, st_igstate_obj);
165
0
    check_write(*op);
166
0
    code = gstate_unshare(i_ctx_p);
167
0
    if (code < 0)
168
0
        return code;
169
0
    pgs = igstate_ptr(op);
170
0
    pgs1 = igstate_ptr(op1);
171
0
    pistate = gs_int_gstate(pgs);
172
0
    code = gstate_check_space(i_ctx_p, gs_int_gstate(pgs1), r_space(op));
173
0
    if (code < 0)
174
0
        return code;
175
0
#define gsref_save(p) ref_save(op, p, "copygstate")
176
0
    int_gstate_map_refs(pistate, gsref_save);
177
0
#undef gsref_save
178
0
    mem = gs_gstate_swap_memory(pgs, imemory);
179
0
    code = gs_copygstate(pgs, pgs1);
180
0
    gs_gstate_swap_memory(pgs, mem);
181
0
    if (code < 0)
182
0
        return code;
183
0
    int_gstate_map_refs(pistate, ref_mark_new);
184
0
    *op1 = *op;
185
0
    pop(1);
186
0
    return 0;
187
0
}
188
189
/* <gstate> currentgstate <gstate> */
190
int
191
zcurrentgstate(i_ctx_t *i_ctx_p)
192
11
{
193
11
    os_ptr op = osp;
194
11
    gs_gstate *pgs;
195
11
    int_gstate *pistate;
196
11
    int code;
197
11
    gs_memory_t *mem;
198
199
11
    check_stype(*op, st_igstate_obj);
200
1
    check_write(*op);
201
1
    code = gstate_unshare(i_ctx_p);
202
1
    if (code < 0)
203
0
        return code;
204
1
    pgs = igstate_ptr(op);
205
1
    pistate = gs_int_gstate(pgs);
206
1
    code = gstate_check_space(i_ctx_p, istate, r_space(op));
207
1
    if (code < 0)
208
0
        return code;
209
35
#define gsref_save(p) ref_save(op, p, "currentgstate")
210
35
    int_gstate_map_refs(pistate, gsref_save);
211
1
#undef gsref_save
212
1
    mem = gs_gstate_swap_memory(pgs, imemory);
213
1
    code = gs_currentgstate(pgs, igs);
214
1
    gs_gstate_swap_memory(pgs, mem);
215
1
    if (code < 0)
216
0
        return code;
217
35
    int_gstate_map_refs(pistate, ref_mark_new);
218
1
    return 0;
219
1
}
220
221
/* <gstate> setgstate - */
222
int
223
zsetgstate(i_ctx_t *i_ctx_p)
224
4
{
225
4
    os_ptr op = osp;
226
4
    int code;
227
228
4
    check_stype(*op, st_igstate_obj);
229
4
    check_read(*op);
230
4
    code = gs_setgstate(igs, igstate_ptr(op));
231
4
    if (code < 0)
232
0
        return code;
233
4
    pop(1);
234
4
    return 0;
235
4
}
236
237
/* ------ Rectangles ------- */
238
239
/*
240
 * We preallocate a short list for rectangles, because
241
 * the rectangle operators usually will involve very few rectangles.
242
 */
243
4
#define MAX_LOCAL_RECTS 5
244
typedef struct local_rects_s {
245
    gs_rect *pr;
246
    uint count;
247
    gs_rect rl[MAX_LOCAL_RECTS];
248
} local_rects_t;
249
250
/* Forward references */
251
static int rect_get(local_rects_t *, os_ptr, gs_memory_t *);
252
static void rect_release(local_rects_t *, gs_memory_t *);
253
254
/* <x> <y> <width> <height> .rectappend - */
255
/* <numarray|numstring> .rectappend - */
256
static int
257
zrectappend(i_ctx_t *i_ctx_p)
258
0
{
259
0
    os_ptr op = osp;
260
0
    local_rects_t lr;
261
0
    int npop = rect_get(&lr, op, imemory);
262
0
    int code;
263
264
0
    if (npop < 0)
265
0
        return npop;
266
0
    code = gs_rectappend(igs, lr.pr, lr.count);
267
0
    rect_release(&lr, imemory);
268
0
    if (code < 0)
269
0
        return code;
270
0
    pop(npop);
271
0
    return 0;
272
0
}
273
274
/* <x> <y> <width> <height> rectclip - */
275
/* <numarray|numstring> rectclip - */
276
static int
277
zrectclip(i_ctx_t *i_ctx_p)
278
23.0k
{
279
23.0k
    os_ptr op = osp;
280
23.0k
    local_rects_t lr;
281
23.0k
    int npop = rect_get(&lr, op, imemory);
282
23.0k
    int code;
283
284
23.0k
    if (npop < 0)
285
17
        return npop;
286
23.0k
    code = gs_rectclip(igs, lr.pr, lr.count);
287
23.0k
    rect_release(&lr, imemory);
288
23.0k
    if (code < 0)
289
0
        return code;
290
23.0k
    pop(npop);
291
23.0k
    return 0;
292
23.0k
}
293
294
/* <x> <y> <width> <height> rectfill - */
295
/* <numarray|numstring> rectfill - */
296
static int
297
zrectfill(i_ctx_t *i_ctx_p)
298
8.43k
{
299
8.43k
    os_ptr op = osp;
300
8.43k
    local_rects_t lr;
301
8.43k
    int npop = rect_get(&lr, op, imemory);
302
8.43k
    int code;
303
304
8.43k
    if (npop < 0)
305
30
        return npop;
306
8.40k
    code = gs_rectfill(igs, lr.pr, lr.count);
307
8.40k
    rect_release(&lr, imemory);
308
8.40k
    if (code < 0)
309
0
        return code;
310
8.40k
    pop(npop);
311
8.40k
    return 0;
312
8.40k
}
313
314
/* <x> <y> <width> <height> rectstroke - */
315
/* <numarray|numstring> rectstroke - */
316
static int
317
zrectstroke(i_ctx_t *i_ctx_p)
318
98
{
319
98
    os_ptr op = osp;
320
98
    gs_matrix mat;
321
98
    local_rects_t lr;
322
98
    int npop, code;
323
324
98
    if (read_matrix(imemory, op, &mat) >= 0) {
325
        /* Concatenate the matrix to the CTM just before stroking the path. */
326
1
        npop = rect_get(&lr, op - 1, imemory);
327
1
        if (npop < 0)
328
1
            return npop;
329
0
        code = gs_rectstroke(igs, lr.pr, lr.count, &mat);
330
0
        npop++;
331
97
    } else {
332
        /* No matrix. */
333
97
        npop = rect_get(&lr, op, imemory);
334
97
        if (npop < 0)
335
13
            return npop;
336
84
        code = gs_rectstroke(igs, lr.pr, lr.count, (gs_matrix *) 0);
337
84
    }
338
84
    rect_release(&lr, imemory);
339
84
    if (code < 0)
340
0
        return code;
341
84
    pop(npop);
342
84
    return 0;
343
84
}
344
345
/* --- Internal routines --- */
346
347
/* Get rectangles from the stack. */
348
/* Return the number of elements to pop (>0) if OK, <0 if error. */
349
static int
350
rect_get(local_rects_t * plr, os_ptr op, gs_memory_t *mem)
351
31.5k
{
352
31.5k
    int format, code;
353
31.5k
    uint n, count;
354
31.5k
    gs_rect *pr;
355
31.5k
    double rv[4];
356
357
31.5k
    switch (r_type(op)) {
358
7
        case t_array:
359
7
        case t_mixedarray:
360
7
        case t_shortarray:
361
17
        case t_string:
362
17
            code = num_array_format(op);
363
17
            if (code < 0)
364
10
                return code;
365
7
            format = code;
366
7
            count = num_array_size(op, format);
367
7
            if (count % 4)
368
3
                return_error(gs_error_typecheck);
369
4
            count /= 4;
370
4
            break;
371
31.5k
        default:    /* better be 4 numbers */
372
31.5k
            code = num_params(op, 4, rv);
373
31.5k
            if (code < 0)
374
48
                return code;
375
31.5k
            plr->pr = plr->rl;
376
31.5k
            plr->count = 1;
377
31.5k
            plr->rl[0].q.x = (plr->rl[0].p.x = rv[0]) + rv[2];
378
31.5k
            plr->rl[0].q.y = (plr->rl[0].p.y = rv[1]) + rv[3];
379
31.5k
            return 4;
380
31.5k
    }
381
4
    plr->count = count;
382
4
    if (count <= MAX_LOCAL_RECTS)
383
4
        pr = plr->rl;
384
0
    else {
385
0
        pr = (gs_rect *)gs_alloc_byte_array(mem, count, sizeof(gs_rect),
386
0
                                            "rect_get");
387
0
        if (pr == 0)
388
0
            return_error(gs_error_VMerror);
389
0
    }
390
4
    plr->pr = pr;
391
4
    for (n = 0; n < count; n++, pr++) {
392
0
        ref rnum;
393
0
        int i;
394
395
0
        for (i = 0; i < 4; i++) {
396
0
            code = num_array_get(mem, (const ref *)op, format,
397
0
                                 (n << 2) + i, &rnum);
398
0
            switch (code) {
399
0
                case t_integer:
400
0
                    rv[i] = (double)rnum.value.intval;
401
0
                    break;
402
0
                case t_real:
403
0
                    rv[i] = rnum.value.realval;
404
0
                    break;
405
0
                default:  /* code < 0 */
406
0
                    return code;
407
0
            }
408
0
        }
409
0
        pr->q.x = (pr->p.x = rv[0]) + rv[2];
410
0
        pr->q.y = (pr->p.y = rv[1]) + rv[3];
411
0
    }
412
4
    return 1;
413
4
}
414
415
/* Release the rectangle list if needed. */
416
static void
417
rect_release(local_rects_t * plr, gs_memory_t *mem)
418
31.5k
{
419
31.5k
    if (plr->pr != plr->rl)
420
0
        gs_free_object(mem, plr->pr, "rect_release");
421
31.5k
}
422
423
/* ------ Graphics state ------ */
424
425
/* <llx> <lly> <urx> <ury> setbbox - */
426
int
427
zsetbbox(i_ctx_t *i_ctx_p)
428
32
{
429
32
    os_ptr op = osp;
430
32
    double box[4];
431
432
32
    int code = num_params(op, 4, box);
433
434
32
    if (code < 0)
435
11
        return code;
436
21
    if ((code = gs_setbbox(igs, box[0], box[1], box[2], box[3])) < 0)
437
11
        return code;
438
10
    pop(4);
439
10
    return 0;
440
21
}
441
442
/* ------ Initialization procedure ------ */
443
444
const op_def zdps1_l2_op_defs[] =
445
{
446
    op_def_begin_level2(),
447
                /* Graphics state */
448
    {"0currentstrokeadjust", zcurrentstrokeadjust},
449
    {"1setstrokeadjust", zsetstrokeadjust},
450
                /* Graphics state objects */
451
    {"1copy", z1copy},
452
    {"1currentgstate", zcurrentgstate},
453
    {"0gstate", zgstate},
454
    {"1setgstate", zsetgstate},
455
                /* Rectangles */
456
    {"1.rectappend", zrectappend},
457
    {"1rectclip", zrectclip},
458
    {"1rectfill", zrectfill},
459
    {"1rectstroke", zrectstroke},
460
                /* Graphics state components */
461
    {"4setbbox", zsetbbox},
462
    op_def_end(0)
463
};
464
465
/* ------ Internal routines ------ */
466
467
/* Ensure that a gstate is not shared with an outer save level. */
468
/* *op is of type t_astruct(igstate_obj). */
469
static int
470
gstate_unshare(i_ctx_t *i_ctx_p)
471
1
{
472
1
    os_ptr op = osp;
473
1
    ref *pgsref = &r_ptr(op, igstate_obj)->gstate;
474
1
    gs_gstate *pgs = r_ptr(pgsref, gs_gstate);
475
1
    gs_gstate *pnew;
476
1
    int_gstate *isp;
477
478
1
    if (!ref_must_save(pgsref))
479
0
        return 0;
480
    /* Copy the gstate. */
481
1
    pnew = gs_gstate_copy(pgs, pgs->memory);
482
1
    if (pnew == 0)
483
0
        return_error(gs_error_VMerror);
484
1
    isp = gs_int_gstate(pnew);
485
35
    int_gstate_map_refs(isp, ref_mark_new);
486
1
    ref_do_save(op, pgsref, "gstate_unshare");
487
1
    make_istruct_new(pgsref, 0, pnew);
488
1
    return 0;
489
1
}