Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/psi/zpath1.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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
/* PostScript Level 1 additional path operators */
18
#include "memory_.h"
19
#include "ghost.h"
20
#include "oper.h"
21
#include "oparc.h"    /* for prototypes */
22
#include "estack.h"   /* for pathforall */
23
#include "ialloc.h"
24
#include "igstate.h"
25
#include "gsstruct.h"
26
#include "gspath.h"
27
#include "store.h"
28
29
/* Forward references */
30
static int common_arc(i_ctx_t *,
31
          int (*)(gs_gstate *, double, double, double, double, double));
32
static int common_arct(i_ctx_t *, float *);
33
34
/* <x> <y> <r> <ang1> <ang2> arc - */
35
int
36
zarc(i_ctx_t *i_ctx_p)
37
80.0k
{
38
80.0k
    return common_arc(i_ctx_p, gs_arc);
39
80.0k
}
40
41
/* <x> <y> <r> <ang1> <ang2> arcn - */
42
int
43
zarcn(i_ctx_t *i_ctx_p)
44
129
{
45
129
    return common_arc(i_ctx_p, gs_arcn);
46
129
}
47
48
/* Common code for arc[n] */
49
static int
50
common_arc(i_ctx_t *i_ctx_p,
51
      int (*aproc)(gs_gstate *, double, double, double, double, double))
52
80.1k
{
53
80.1k
    os_ptr op = osp;
54
80.1k
    double xyra[5];   /* x, y, r, ang1, ang2 */
55
80.1k
    int code;
56
57
80.1k
    check_op(5);
58
80.1k
    code = num_params(op, 5, xyra);
59
80.1k
    if (code < 0)
60
14
        return code;
61
80.0k
    code = (*aproc)(igs, xyra[0], xyra[1], xyra[2], xyra[3], xyra[4]);
62
80.0k
    if (code >= 0)
63
80.0k
        pop(5);
64
80.0k
    return code;
65
80.1k
}
66
67
/* <x1> <y1> <x2> <y2> <r> arct - */
68
int
69
zarct(i_ctx_t *i_ctx_p)
70
23
{
71
23
    int code = common_arct(i_ctx_p, (float *)0);
72
73
23
    if (code < 0)
74
23
        return code;
75
0
    pop(5);
76
0
    return 0;
77
23
}
78
79
/* <x1> <y1> <x2> <y2> <r> arcto <xt1> <yt1> <xt2> <yt2> */
80
static int
81
zarcto(i_ctx_t *i_ctx_p)
82
29
{
83
29
    os_ptr op = osp;
84
29
    float tanxy[4];   /* xt1, yt1, xt2, yt2 */
85
29
    int code = common_arct(i_ctx_p, tanxy);
86
87
29
    if (code < 0)
88
29
        return code;
89
0
    make_real(op - 4, tanxy[0]);
90
0
    make_real(op - 3, tanxy[1]);
91
0
    make_real(op - 2, tanxy[2]);
92
0
    make_real(op - 1, tanxy[3]);
93
0
    pop(1);
94
0
    return 0;
95
29
}
96
97
/* Common code for arct[o] */
98
static int
99
common_arct(i_ctx_t *i_ctx_p, float *tanxy)
100
52
{
101
52
    os_ptr op = osp;
102
52
    double args[5];   /* x1, y1, x2, y2, r */
103
52
    int code;
104
105
52
    check_op(5);
106
20
    code = num_params(op, 5, args);
107
20
    if (code < 0)
108
6
        return code;
109
14
    return gs_arcto(igs, args[0], args[1], args[2], args[3], args[4], tanxy);
110
20
}
111
112
/* - .dashpath - */
113
static int
114
zdashpath(i_ctx_t *i_ctx_p)
115
0
{
116
0
    return gs_dashpath(igs);
117
0
}
118
119
/* - flattenpath - */
120
static int
121
zflattenpath(i_ctx_t *i_ctx_p)
122
1.56k
{
123
1.56k
    return gs_flattenpath(igs);
124
1.56k
}
125
126
/* - reversepath - */
127
static int
128
zreversepath(i_ctx_t *i_ctx_p)
129
50
{
130
50
    return gs_reversepath(igs);
131
50
}
132
133
/* - strokepath - */
134
static int
135
zstrokepath(i_ctx_t *i_ctx_p)
136
147
{
137
147
    return gs_strokepath(igs);
138
147
}
139
140
/* - clippath - */
141
static int
142
zclippath(i_ctx_t *i_ctx_p)
143
4.65k
{
144
4.65k
    return gs_clippath(igs);
145
4.65k
}
146
147
/* <bool> .pathbbox <llx> <lly> <urx> <ury> */
148
static int
149
z1pathbbox(i_ctx_t *i_ctx_p)
150
6.05k
{
151
6.05k
    os_ptr op = osp;
152
6.05k
    gs_rect box;
153
6.05k
    int code;
154
155
6.05k
    check_op(1);
156
6.05k
    check_type(*op, t_boolean);
157
6.05k
    code = gs_upathbbox(igs, &box, op->value.boolval);
158
6.05k
    if (code < 0)
159
18
        return code;
160
6.05k
    push(3);
161
6.03k
    make_real(op - 3, box.p.x);
162
6.03k
    make_real(op - 2, box.p.y);
163
6.03k
    make_real(op - 1, box.q.x);
164
6.03k
    make_real(op, box.q.y);
165
6.03k
    return 0;
166
6.03k
}
167
168
/*
169
 * In order to match Adobe output on a Genoa test, pathbbox must be an
170
 * operator, not an operator procedure, even though it has a trivial
171
 * definition as a procedure.
172
 */
173
static int
174
zpathbbox(i_ctx_t *i_ctx_p)
175
6.05k
{
176
6.05k
    os_ptr op = osp;
177
6.05k
    int code;
178
179
6.05k
    push(1);
180
6.05k
    make_false(op);
181
6.05k
    code = z1pathbbox(i_ctx_p);
182
6.05k
    if (code < 0) {
183
18
        pop(1);      /* remove the Boolean */
184
18
    }
185
6.05k
    return code;
186
6.05k
}
187
188
/* <moveproc> <lineproc> <curveproc> <closeproc> pathforall - */
189
static int path_continue(i_ctx_t *);
190
static int path_cleanup(i_ctx_t *);
191
static int
192
zpathforall(i_ctx_t *i_ctx_p)
193
18
{
194
18
    os_ptr op = osp;
195
18
    gs_path_enum *penum;
196
18
    int code;
197
198
18
    check_op(4);
199
18
    check_proc(op[-3]);
200
3
    check_proc(op[-2]);
201
0
    check_proc(op[-1]);
202
0
    check_proc(*op);
203
0
    check_estack(8);
204
205
0
    if ((penum = gs_path_enum_alloc(imemory, "pathforall")) == 0)
206
0
        return_error(gs_error_VMerror);
207
0
    code = gs_path_enum_init(imemory, penum, igs);
208
0
    if (code < 0) {
209
0
        ifree_object(penum, "path_cleanup");
210
0
        return code;
211
0
    }
212
    /* Push a mark, the four procedures, and the path enumerator. */
213
0
    push_mark_estack(es_for, path_cleanup); /* iterator */
214
0
    memcpy(esp + 1, op - 3, 4 * sizeof(ref)); /* 4 procs */
215
0
    esp += 5;
216
0
    make_istruct(esp, 0, penum);
217
0
    push_op_estack(path_continue);
218
0
    pop(4);
219
0
    op -= 4;
220
0
    return o_push_estack;
221
0
}
222
/* Continuation procedure for pathforall */
223
static void pf_push(i_ctx_t *, gs_point *, int);
224
static int
225
path_continue(i_ctx_t *i_ctx_p)
226
0
{
227
0
    gs_path_enum *penum = r_ptr(esp, gs_path_enum);
228
0
    gs_point ppts[3];
229
0
    int code;
230
231
    /* Make sure we have room on the o-stack for the worst case */
232
    /* before we enumerate the next path element. */
233
0
    check_ostack(6);   /* 3 points for curveto */
234
0
    code = gs_path_enum_next(penum, ppts);
235
0
    switch (code) {
236
0
        case 0:   /* all done */
237
0
            esp -= 6;
238
0
            path_cleanup(i_ctx_p);
239
0
            return o_pop_estack;
240
0
        default:    /* error */
241
0
            esp -= 6;
242
0
            path_cleanup(i_ctx_p);
243
0
            return code;
244
0
        case gs_pe_moveto:
245
0
            esp[2] = esp[-4]; /* moveto proc */
246
0
            pf_push(i_ctx_p, ppts, 1);
247
0
            break;
248
0
        case gs_pe_lineto:
249
0
            esp[2] = esp[-3]; /* lineto proc */
250
0
            pf_push(i_ctx_p, ppts, 1);
251
0
            break;
252
0
        case gs_pe_curveto:
253
0
            esp[2] = esp[-2]; /* curveto proc */
254
0
            pf_push(i_ctx_p, ppts, 3);
255
0
            break;
256
0
        case gs_pe_closepath:
257
0
            esp[2] = esp[-1]; /* closepath proc */
258
0
            break;
259
0
    }
260
0
    push_op_estack(path_continue);
261
0
    ++esp;     /* include pushed procedure */
262
0
    return o_push_estack;
263
0
}
264
/* Internal procedure to push one or more points */
265
static void
266
pf_push(i_ctx_t *i_ctx_p, gs_point * ppts, int n)
267
0
{
268
0
    os_ptr op = osp;
269
270
0
    while (n--) {
271
0
        op += 2;
272
0
        make_real(op - 1, ppts->x);
273
0
        make_real(op, ppts->y);
274
0
        ppts++;
275
0
    }
276
0
    osp = op;
277
0
}
278
/* Clean up after a pathforall */
279
static int
280
path_cleanup(i_ctx_t *i_ctx_p)
281
0
{
282
0
    gs_path_enum *penum = r_ptr(esp + 6, gs_path_enum);
283
284
0
    gs_path_enum_cleanup(penum);
285
0
    ifree_object(penum, "path_cleanup");
286
    /* We need to 'null' the ref on the exec stack because a later GC could
287
     * run off the top of the stack and try to reloc the pointer, even
288
     * though we've freed it. See the fix for bug 707007.
289
     */
290
0
    make_null(esp + 6);
291
0
    return 0;
292
0
}
293
294
/* ------ Initialization procedure ------ */
295
296
const op_def zpath1_op_defs[] =
297
{
298
    {"5arc", zarc},
299
    {"5arcn", zarcn},
300
    {"5arct", zarct},
301
    {"5arcto", zarcto},
302
    {"0clippath", zclippath},
303
    {"0.dashpath", zdashpath},
304
    {"0flattenpath", zflattenpath},
305
    {"4pathforall", zpathforall},
306
    {"0reversepath", zreversepath},
307
    {"0strokepath", zstrokepath},
308
    {"1.pathbbox", z1pathbbox},
309
    {"0pathbbox", zpathbbox},
310
                /* Internal operators */
311
    {"0%path_continue", path_continue},
312
    op_def_end(0)
313
};