Coverage Report

Created: 2025-11-16 07:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pdf/pdf_path.c
Line
Count
Source
1
/* Copyright (C) 2018-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
/* Path operations for the PDF interpreter */
17
18
#include "pdf_int.h"
19
#include "pdf_font_types.h"
20
#include "pdf_gstate.h"
21
#include "pdf_path.h"
22
#include "pdf_stack.h"
23
#include "pdf_trans.h"
24
#include "gstypes.h"
25
#include "pdf_optcontent.h"
26
#include "gspath.h"         /* For gs_moveto() and friends */
27
#include "gspaint.h"        /* For gs_fill() and friends */
28
29
typedef enum path_segment_e {
30
    pdfi_moveto_seg,
31
    pdfi_lineto_seg,
32
    pdfi_curveto_seg,
33
    pdfi_re_seg,
34
    pdfi_v_curveto_seg,
35
    pdfi_y_curveto_seg,
36
    pdfi_closepath_seg
37
} pdfi_path_segment;
38
39
static int StorePathSegment(pdf_context *ctx, pdfi_path_segment segment, double *pts)
40
46.4M
{
41
46.4M
    int size = 0;
42
43
46.4M
    switch (segment)
44
46.4M
    {
45
8.74M
        case pdfi_moveto_seg:
46
26.5M
        case pdfi_lineto_seg:
47
26.5M
            size = 2;
48
26.5M
            break;
49
4.64M
        case pdfi_re_seg:
50
4.82M
        case pdfi_v_curveto_seg:
51
5.02M
        case pdfi_y_curveto_seg:
52
5.02M
            size = 4;
53
5.02M
                break;
54
13.6M
        case pdfi_curveto_seg:
55
13.6M
            size = 6;
56
13.6M
            break;
57
1.18M
        case pdfi_closepath_seg:
58
1.18M
            break;
59
0
        default:
60
0
            return_error(gs_error_undefined);
61
0
            break;
62
46.4M
    }
63
46.4M
    if (ctx->PathSegments == NULL) {
64
9.49M
        ctx->PathSegments = (char *)gs_alloc_bytes(ctx->memory, 1024, "StorePathSegment");
65
9.49M
        if (ctx->PathSegments == NULL)
66
0
            return_error(gs_error_VMerror);
67
9.49M
        ctx->PathSegmentsCurrent = ctx->PathSegments;
68
9.49M
        ctx->PathSegmentsTop = ctx->PathSegments + 1024;
69
9.49M
    }
70
46.4M
    if (ctx->PathSegmentsCurrent == ctx->PathSegmentsTop) {
71
4.54k
        char *new_accumulator = NULL;
72
4.54k
        uint64_t old_size;
73
74
4.54k
        old_size = ctx->PathSegmentsCurrent - ctx->PathSegments;
75
4.54k
        new_accumulator = (char *)gs_alloc_bytes(ctx->memory, old_size + 1024, "StorePathSegment");
76
4.54k
        if (new_accumulator == NULL)
77
0
            return_error(gs_error_VMerror);
78
4.54k
        memcpy(new_accumulator, ctx->PathSegments, old_size);
79
4.54k
        ctx->PathSegmentsCurrent = new_accumulator + old_size;
80
4.54k
        gs_free_object(ctx->memory, ctx->PathSegments, "StorePathSegment");
81
4.54k
        ctx->PathSegments = new_accumulator;
82
4.54k
        ctx->PathSegmentsTop = ctx->PathSegments + old_size + 1024;
83
4.54k
    }
84
85
46.4M
    if (ctx->PathPts == NULL) {
86
9.49M
        ctx->PathPts = (double *)gs_alloc_bytes(ctx->memory, 4096, "StorePathSegment");
87
9.49M
        if (ctx->PathPts == NULL)
88
0
            return_error(gs_error_VMerror);
89
9.49M
        ctx->PathPtsCurrent = ctx->PathPts;
90
9.49M
        ctx->PathPtsTop = ctx->PathPts + (4096 / sizeof(double));
91
9.49M
    }
92
46.4M
    if (ctx->PathPtsCurrent + size > ctx->PathPtsTop) {
93
57.2k
        double *new_accumulator = NULL;
94
57.2k
        uint64_t old_size;
95
96
57.2k
        old_size = (char *)ctx->PathPtsCurrent - (char *)ctx->PathPts;
97
57.2k
        new_accumulator = (double *)gs_alloc_bytes(ctx->memory, old_size + 4096, "StorePathSegment");
98
57.2k
        if (new_accumulator == NULL)
99
0
            return_error(gs_error_VMerror);
100
57.2k
        memcpy(new_accumulator, ctx->PathPts, old_size);
101
57.2k
        ctx->PathPtsCurrent = new_accumulator + (old_size / sizeof(double));
102
57.2k
        gs_free_object(ctx->memory, ctx->PathPts, "StorePathSegment");
103
57.2k
        ctx->PathPts = new_accumulator;
104
57.2k
        ctx->PathPtsTop = ctx->PathPts + ((old_size + 4096) / sizeof(double));
105
57.2k
    }
106
107
46.4M
    *(ctx->PathSegmentsCurrent++) = (char)segment;
108
46.4M
    switch (segment)
109
46.4M
    {
110
8.74M
        case pdfi_moveto_seg:
111
26.5M
        case pdfi_lineto_seg:
112
26.5M
            memcpy(ctx->PathPtsCurrent, pts, 2 * sizeof(double));
113
26.5M
            ctx->PathPtsCurrent += 2;
114
26.5M
            break;
115
4.64M
        case pdfi_re_seg:
116
4.82M
        case pdfi_v_curveto_seg:
117
5.02M
        case pdfi_y_curveto_seg:
118
5.02M
            memcpy(ctx->PathPtsCurrent, pts, 4 * sizeof(double));
119
5.02M
            ctx->PathPtsCurrent += 4;
120
5.02M
            break;
121
13.6M
        case pdfi_curveto_seg:
122
13.6M
            memcpy(ctx->PathPtsCurrent, pts, 6 * sizeof(double));
123
13.6M
            ctx->PathPtsCurrent += 6;
124
13.6M
            break;
125
1.18M
        case pdfi_closepath_seg:
126
1.18M
            break;
127
46.4M
    }
128
46.4M
    return 0;
129
46.4M
}
130
131
static int ApplyStoredPath(pdf_context *ctx)
132
10.0M
{
133
10.0M
    int code = 0;
134
10.0M
    char *op = NULL;
135
10.0M
    double *dpts = NULL;
136
10.0M
    double *current;
137
138
10.0M
    if (ctx->PathSegments == NULL)
139
686k
        return 0;
140
141
9.34M
    if (ctx->PathPts == NULL) {
142
0
        code = gs_note_error(gs_error_unknownerror);
143
0
        goto error;
144
0
    }
145
146
9.34M
    if (ctx->pgs->current_point_valid) {
147
30.8k
        code = gs_newpath(ctx->pgs);
148
30.8k
        if (code < 0)
149
0
            goto error;
150
30.8k
    }
151
152
9.34M
    op = ctx->PathSegments;
153
9.34M
    dpts = ctx->PathPts;
154
9.34M
    current = dpts; /* Stop stupid compilers complaining. */
155
156
53.1M
    while (op < ctx->PathSegmentsCurrent) {
157
44.1M
        if (dpts > ctx->PathPtsCurrent) {
158
0
            code = gs_note_error(gs_error_unknownerror);
159
0
            goto error;
160
0
        }
161
162
44.1M
        switch(*op++) {
163
8.28M
            case pdfi_moveto_seg:
164
8.28M
                code = gs_moveto(ctx->pgs, dpts[0], dpts[1]);
165
8.28M
                current = dpts;
166
8.28M
                dpts+= 2;
167
8.28M
                break;
168
16.7M
            case pdfi_lineto_seg:
169
16.7M
                code = gs_lineto(ctx->pgs, dpts[0], dpts[1]);
170
16.7M
                current = dpts;
171
16.7M
                dpts+= 2;
172
16.7M
                break;
173
4.54M
            case pdfi_re_seg:
174
4.54M
                code = gs_moveto(ctx->pgs, dpts[0], dpts[1]);
175
4.54M
                if (code >= 0) {
176
4.54M
                    code = gs_rlineto(ctx->pgs, dpts[2], 0);
177
4.54M
                    if (code >= 0) {
178
4.54M
                        code = gs_rlineto(ctx->pgs, 0, dpts[3]);
179
4.54M
                        if (code >= 0) {
180
4.54M
                            code = gs_rlineto(ctx->pgs, -dpts[2], 0);
181
4.54M
                            if (code >= 0)
182
4.54M
                                code = gs_closepath(ctx->pgs);
183
4.54M
                        }
184
4.54M
                    }
185
4.54M
                }
186
4.54M
                current = dpts;
187
4.54M
                dpts+= 4;
188
4.54M
                break;
189
181k
            case pdfi_v_curveto_seg:
190
181k
                code = gs_curveto(ctx->pgs, current[0], current[1], dpts[0], dpts[1], dpts[2], dpts[3]);
191
181k
                current = dpts + 2;
192
181k
                dpts+= 4;
193
181k
                break;
194
192k
            case pdfi_y_curveto_seg:
195
192k
                code = gs_curveto(ctx->pgs, dpts[0], dpts[1], dpts[2], dpts[3], dpts[2], dpts[3]);
196
192k
                current = dpts + 2;
197
192k
                dpts+= 4;
198
192k
                break;
199
13.1M
            case pdfi_curveto_seg:
200
13.1M
                code = gs_curveto(ctx->pgs, dpts[0], dpts[1], dpts[2], dpts[3], dpts[4], dpts[5]);
201
13.1M
                current = dpts + 4;
202
13.1M
                dpts+= 6;
203
13.1M
                break;
204
1.09M
            case pdfi_closepath_seg:
205
1.09M
                code = gs_closepath(ctx->pgs);
206
1.09M
                break;
207
0
            default:
208
0
                code = gs_note_error(gs_error_rangecheck);
209
0
                break;
210
44.1M
        }
211
44.1M
        if (code < 0)
212
294k
            break;
213
44.1M
    }
214
215
9.34M
error:
216
9.34M
    gs_free_object(ctx->memory, ctx->PathSegments, "ApplyStoredPath");
217
9.34M
    ctx->PathSegmentsTop = ctx->PathSegmentsCurrent = ctx->PathSegments = NULL;
218
9.34M
    gs_free_object(ctx->memory, ctx->PathPts, "ApplyStoredPath");
219
9.34M
    ctx->PathPtsTop = ctx->PathPtsCurrent = ctx->PathPts = NULL;
220
9.34M
    return code;
221
9.34M
}
222
223
int pdfi_moveto (pdf_context *ctx)
224
9.95M
{
225
9.95M
    int code;
226
9.95M
    double xy[2];
227
228
9.95M
    if (ctx->text.BlockDepth != 0)
229
348k
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_moveto", NULL);
230
231
9.95M
    code = pdfi_destack_reals(ctx, xy, 2);
232
9.95M
    if (code < 0)
233
1.20M
        return code;
234
235
8.74M
    return StorePathSegment(ctx, pdfi_moveto_seg, (double *)&xy);
236
9.95M
}
237
238
int pdfi_lineto (pdf_context *ctx)
239
18.7M
{
240
18.7M
    int code;
241
18.7M
    double xy[2];
242
243
18.7M
    if (ctx->text.BlockDepth != 0)
244
363k
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_lineto", NULL);
245
246
18.7M
    code = pdfi_destack_reals(ctx, xy, 2);
247
18.7M
    if (code < 0)
248
940k
        return code;
249
250
17.8M
    return StorePathSegment(ctx, pdfi_lineto_seg, (double *)&xy);
251
18.7M
}
252
253
static int pdfi_fill_inner(pdf_context *ctx, bool use_eofill)
254
3.43M
{
255
3.43M
    int code=0, code1;
256
3.43M
    pdfi_trans_state_t state;
257
258
3.43M
    if (ctx->text.BlockDepth != 0)
259
186k
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_fill_inner", NULL);
260
261
3.43M
    if (pdfi_oc_is_off(ctx))
262
84.7k
        goto exit;
263
264
3.35M
    code = ApplyStoredPath(ctx);
265
3.35M
    if (code < 0)
266
22.1k
        return code;
267
268
3.33M
    code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_Fill);
269
3.33M
    if (code == 0) {
270
        /* If we don't gsave/grestore round the fill, then the file
271
         * /tests_private/pdf/sumatra/954_-_dashed_lines_hardly_visible.pdf renders
272
         * incorrectly. However we must not gsave/grestore round the trans_setup
273
         * trans_teardown, because that might set pgs->soft_mask_id and if we restore
274
         * back to a point where that is not set then pdfwrite doesn't work properly.
275
         */
276
3.33M
        code = pdfi_gsave(ctx);
277
3.33M
        if (code < 0) goto exit;
278
279
3.33M
        if (use_eofill)
280
126k
            code = gs_eofill(ctx->pgs);
281
3.20M
        else
282
3.20M
            code = gs_fill(ctx->pgs);
283
3.33M
        code1 = pdfi_grestore(ctx);
284
3.33M
        if (code == 0) code = code1;
285
286
3.33M
        code1 = pdfi_trans_teardown(ctx, &state);
287
3.33M
        if (code == 0) code = code1;
288
3.33M
    }
289
290
3.41M
 exit:
291
3.41M
    code1 = pdfi_newpath(ctx);
292
3.41M
    if (code == 0) code = code1;
293
294
3.41M
    return code;
295
3.33M
}
296
297
int pdfi_fill(pdf_context *ctx)
298
3.30M
{
299
3.30M
    return pdfi_fill_inner(ctx, false);
300
3.30M
}
301
302
int pdfi_eofill(pdf_context *ctx)
303
132k
{
304
132k
    return pdfi_fill_inner(ctx, true);
305
132k
}
306
307
int pdfi_stroke(pdf_context *ctx)
308
5.42M
{
309
5.42M
    int code=0, code1;
310
5.42M
    pdfi_trans_state_t state;
311
312
5.42M
    if (ctx->text.BlockDepth != 0)
313
313k
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_stroke", NULL);
314
315
5.42M
    if (pdfi_oc_is_off(ctx))
316
54
        goto exit;
317
318
5.42M
    code = ApplyStoredPath(ctx);
319
5.42M
    if (code < 0)
320
212k
        return code;
321
322
5.21M
    gs_swapcolors_quick(ctx->pgs);
323
5.21M
    code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_Stroke);
324
5.21M
    if (code == 0) {
325
5.21M
        code = pdfi_gsave(ctx);
326
5.21M
        if (code < 0) goto exit;
327
328
5.21M
        code = gs_stroke(ctx->pgs);
329
330
5.21M
        code1 = pdfi_grestore(ctx);
331
5.21M
        if (code == 0) code = code1;
332
333
5.21M
        code1 = pdfi_trans_teardown(ctx, &state);
334
5.21M
        if (code == 0) code = code1;
335
5.21M
    }
336
5.21M
    gs_swapcolors_quick(ctx->pgs);
337
338
5.21M
 exit:
339
5.21M
    code1 = pdfi_newpath(ctx);
340
5.21M
    if (code == 0) code = code1;
341
342
5.21M
    return code;
343
5.21M
}
344
345
int pdfi_closepath_stroke(pdf_context *ctx)
346
121k
{
347
121k
    int code;
348
349
121k
    if (ctx->text.BlockDepth != 0)
350
38.9k
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_closepath_stroke", NULL);
351
352
121k
    code = StorePathSegment(ctx, pdfi_closepath_seg, NULL);
353
121k
    if (code < 0)
354
0
        return code;
355
356
121k
    return pdfi_stroke(ctx);
357
121k
}
358
359
int pdfi_curveto(pdf_context *ctx)
360
14.3M
{
361
14.3M
    int code;
362
14.3M
    double Values[6];
363
364
14.3M
    code = pdfi_destack_reals(ctx, Values, 6);
365
14.3M
    if (code < 0)
366
684k
        return code;
367
368
13.6M
    if (ctx->text.BlockDepth != 0)
369
17.6k
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_curveto", NULL);
370
371
13.6M
    return StorePathSegment(ctx, pdfi_curveto_seg, (double *)&Values);
372
14.3M
}
373
374
int pdfi_v_curveto(pdf_context *ctx)
375
188k
{
376
188k
    int code;
377
188k
    double Values[4];
378
379
188k
    code = pdfi_destack_reals(ctx, Values, 4);
380
188k
    if (code < 0)
381
7.10k
        return code;
382
383
181k
    if (ctx->text.BlockDepth != 0)
384
68
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_v_curveto", NULL);
385
386
181k
    return StorePathSegment(ctx, pdfi_v_curveto_seg, (double *)&Values);
387
188k
}
388
389
int pdfi_y_curveto(pdf_context *ctx)
390
219k
{
391
219k
    int code;
392
219k
    double Values[4];
393
394
219k
    code = pdfi_destack_reals(ctx, Values, 4);
395
219k
    if (code < 0)
396
26.2k
        return code;
397
398
192k
    if (ctx->text.BlockDepth != 0)
399
102
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_y_curveto", NULL);
400
401
192k
    return StorePathSegment(ctx, pdfi_y_curveto_seg, (double *)&Values);
402
219k
}
403
404
int pdfi_closepath(pdf_context *ctx)
405
1.03M
{
406
1.03M
    if (ctx->text.BlockDepth != 0)
407
73.2k
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_closepath", NULL);
408
409
1.03M
    return StorePathSegment(ctx, pdfi_closepath_seg, NULL);
410
1.03M
}
411
412
int pdfi_newpath(pdf_context *ctx)
413
10.7M
{
414
10.7M
    int code = 0, code1;
415
416
    /* This code is to deal with the wacky W and W* operators */
417
10.7M
    if (ctx->clip_active) {
418
1.24M
        if (ctx->PathSegments != NULL) {
419
1.17M
            code = ApplyStoredPath(ctx);
420
1.17M
            if (code < 0)
421
56.1k
                return code;
422
1.17M
        }
423
1.19M
        if (ctx->pgs->current_point_valid) {
424
1.11M
            if (ctx->do_eoclip)
425
72.5k
                code = gs_eoclip(ctx->pgs);
426
1.04M
            else
427
1.04M
                code = gs_clip(ctx->pgs);
428
1.11M
        }
429
1.19M
    }
430
10.6M
    ctx->clip_active = false;
431
432
10.6M
    if (ctx->PathSegments != NULL){
433
141k
        gs_free_object(ctx->memory, ctx->PathSegments, "ApplyStoredPath");
434
141k
        ctx->PathSegmentsTop = ctx->PathSegmentsCurrent = ctx->PathSegments = NULL;
435
141k
        gs_free_object(ctx->memory, ctx->PathPts, "ApplyStoredPath");
436
141k
        ctx->PathPtsTop = ctx->PathPtsCurrent = ctx->PathPts = NULL;
437
141k
    }
438
439
10.6M
    code1 = gs_newpath(ctx->pgs);
440
10.6M
    if (code == 0) code = code1;
441
442
10.6M
    if (ctx->text.BlockDepth != 0)
443
586k
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_newpath", NULL);
444
445
10.6M
    return code;
446
10.7M
}
447
448
int pdfi_b(pdf_context *ctx)
449
19.8k
{
450
19.8k
    int code;
451
452
19.8k
    if (ctx->text.BlockDepth != 0)
453
9.41k
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_b", NULL);
454
455
19.8k
    code = StorePathSegment(ctx, pdfi_closepath_seg, NULL);
456
19.8k
    if (code < 0)
457
0
        return code;
458
459
19.8k
    return pdfi_B(ctx);
460
19.8k
}
461
462
int pdfi_b_star(pdf_context *ctx)
463
1.34k
{
464
1.34k
    int code;
465
466
1.34k
    if (ctx->text.BlockDepth != 0)
467
12
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_b_star", NULL);
468
469
1.34k
    code = StorePathSegment(ctx, pdfi_closepath_seg, NULL);
470
1.34k
    if (code < 0)
471
0
        return code;
472
473
1.34k
    return pdfi_B_star(ctx);
474
1.34k
}
475
476
/* common code for B and B* */
477
static int pdfi_B_inner(pdf_context *ctx, bool use_eofill)
478
80.6k
{
479
80.6k
    int code=0, code1=0;
480
80.6k
    pdfi_trans_state_t state;
481
482
80.6k
    if (ctx->text.BlockDepth != 0)
483
37.9k
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_B_inner", NULL);
484
485
80.6k
    if (pdfi_oc_is_off(ctx))
486
8
        goto exit;
487
488
80.6k
    code = ApplyStoredPath(ctx);
489
80.6k
    if (code < 0)
490
3.61k
        return code;
491
492
77.0k
    code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_FillStroke);
493
77.0k
    if (code == 0) {
494
77.0k
        code = pdfi_gsave(ctx);
495
77.0k
        if (code < 0) goto exit;
496
497
77.0k
        if (use_eofill)
498
3.14k
            code = gs_eofillstroke(ctx->pgs, &code1);
499
73.8k
        else
500
73.8k
            code = gs_fillstroke(ctx->pgs, &code1);
501
502
77.0k
        code1 = pdfi_grestore(ctx);
503
77.0k
        if (code == 0) code = code1;
504
505
77.0k
        code1 = pdfi_trans_teardown(ctx, &state);
506
77.0k
        if (code >= 0) code = code1;
507
77.0k
    }
508
509
77.0k
 exit:
510
77.0k
    code1 = pdfi_newpath(ctx);
511
77.0k
    if (code == 0) code = code1;
512
513
77.0k
    return code;
514
77.0k
}
515
516
int pdfi_B(pdf_context *ctx)
517
76.7k
{
518
76.7k
    return pdfi_B_inner(ctx, false);
519
76.7k
}
520
521
int pdfi_B_star(pdf_context *ctx)
522
3.89k
{
523
3.89k
    return pdfi_B_inner(ctx, true);
524
3.89k
}
525
526
int pdfi_clip(pdf_context *ctx)
527
0
{
528
0
    int code = gs_clip(ctx->pgs);
529
530
0
    if (ctx->text.BlockDepth != 0)
531
0
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_B_clip", NULL);
532
533
0
    return code;
534
0
}
535
536
int pdfi_eoclip(pdf_context *ctx)
537
0
{
538
0
    int code = gs_eoclip(ctx->pgs);
539
540
0
    if (ctx->text.BlockDepth != 0)
541
0
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_eoclip", NULL);
542
543
0
     return code;
544
0
}
545
546
int pdfi_rectpath(pdf_context *ctx)
547
4.88M
{
548
4.88M
    int code;
549
4.88M
    double Values[4];
550
551
4.88M
    code = pdfi_destack_reals(ctx, Values, 4);
552
4.88M
    if (code < 0)
553
235k
        return code;
554
555
4.64M
    if (ctx->text.BlockDepth != 0)
556
190k
        pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_rectpath", NULL);
557
558
4.64M
    return StorePathSegment(ctx, pdfi_re_seg, (double *)&Values);
559
4.88M
}