Coverage Report

Created: 2026-07-24 07:44

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-2026 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
#include "gxdevsop.h"               /* For special ops */
29
30
typedef enum path_segment_e {
31
    pdfi_moveto_seg,
32
    pdfi_lineto_seg,
33
    pdfi_curveto_seg,
34
    pdfi_re_seg,
35
    pdfi_v_curveto_seg,
36
    pdfi_y_curveto_seg,
37
    pdfi_closepath_seg
38
} pdfi_path_segment;
39
40
static int StorePathSegment(pdf_context *ctx, pdfi_path_segment segment, double *pts)
41
28.7M
{
42
28.7M
    int size = 0;
43
44
28.7M
    switch (segment)
45
28.7M
    {
46
5.05M
        case pdfi_moveto_seg:
47
15.8M
        case pdfi_lineto_seg:
48
15.8M
            size = 2;
49
15.8M
            break;
50
2.44M
        case pdfi_re_seg:
51
2.58M
        case pdfi_v_curveto_seg:
52
2.74M
        case pdfi_y_curveto_seg:
53
2.74M
            size = 4;
54
2.74M
                break;
55
9.59M
        case pdfi_curveto_seg:
56
9.59M
            size = 6;
57
9.59M
            break;
58
580k
        case pdfi_closepath_seg:
59
580k
            break;
60
0
        default:
61
0
            return_error(gs_error_undefined);
62
0
            break;
63
28.7M
    }
64
28.7M
    if (ctx->PathSegments == NULL) {
65
5.36M
        ctx->PathSegments = (char *)gs_alloc_bytes(ctx->memory, 1024, "StorePathSegment");
66
5.36M
        if (ctx->PathSegments == NULL)
67
0
            return_error(gs_error_VMerror);
68
5.36M
        ctx->PathSegmentsCurrent = ctx->PathSegments;
69
5.36M
        ctx->PathSegmentsTop = ctx->PathSegments + 1024;
70
5.36M
    }
71
28.7M
    if (ctx->PathSegmentsCurrent == ctx->PathSegmentsTop) {
72
1.78k
        char *new_accumulator = NULL;
73
1.78k
        uint64_t old_size;
74
75
1.78k
        old_size = ctx->PathSegmentsCurrent - ctx->PathSegments;
76
1.78k
        new_accumulator = (char *)gs_alloc_bytes(ctx->memory, old_size + 1024, "StorePathSegment");
77
1.78k
        if (new_accumulator == NULL)
78
0
            return_error(gs_error_VMerror);
79
1.78k
        memcpy(new_accumulator, ctx->PathSegments, old_size);
80
1.78k
        ctx->PathSegmentsCurrent = new_accumulator + old_size;
81
1.78k
        gs_free_object(ctx->memory, ctx->PathSegments, "StorePathSegment");
82
1.78k
        ctx->PathSegments = new_accumulator;
83
1.78k
        ctx->PathSegmentsTop = ctx->PathSegments + old_size + 1024;
84
1.78k
    }
85
86
28.7M
    if (ctx->PathPts == NULL) {
87
5.36M
        ctx->PathPts = (double *)gs_alloc_bytes(ctx->memory, 4096, "StorePathSegment");
88
5.36M
        if (ctx->PathPts == NULL)
89
0
            return_error(gs_error_VMerror);
90
5.36M
        ctx->PathPtsCurrent = ctx->PathPts;
91
5.36M
        ctx->PathPtsTop = ctx->PathPts + (4096 / sizeof(double));
92
5.36M
    }
93
28.7M
    if (ctx->PathPtsCurrent + size > ctx->PathPtsTop) {
94
28.1k
        double *new_accumulator = NULL;
95
28.1k
        uint64_t old_size;
96
97
28.1k
        old_size = (char *)ctx->PathPtsCurrent - (char *)ctx->PathPts;
98
28.1k
        new_accumulator = (double *)gs_alloc_bytes(ctx->memory, old_size + 4096, "StorePathSegment");
99
28.1k
        if (new_accumulator == NULL)
100
0
            return_error(gs_error_VMerror);
101
28.1k
        memcpy(new_accumulator, ctx->PathPts, old_size);
102
28.1k
        ctx->PathPtsCurrent = new_accumulator + (old_size / sizeof(double));
103
28.1k
        gs_free_object(ctx->memory, ctx->PathPts, "StorePathSegment");
104
28.1k
        ctx->PathPts = new_accumulator;
105
28.1k
        ctx->PathPtsTop = ctx->PathPts + ((old_size + 4096) / sizeof(double));
106
28.1k
    }
107
108
28.7M
    *(ctx->PathSegmentsCurrent++) = (char)segment;
109
28.7M
    switch (segment)
110
28.7M
    {
111
5.05M
        case pdfi_moveto_seg:
112
15.8M
        case pdfi_lineto_seg:
113
15.8M
            memcpy(ctx->PathPtsCurrent, pts, 2 * sizeof(double));
114
15.8M
            ctx->PathPtsCurrent += 2;
115
15.8M
            break;
116
2.44M
        case pdfi_re_seg:
117
2.58M
        case pdfi_v_curveto_seg:
118
2.74M
        case pdfi_y_curveto_seg:
119
2.74M
            memcpy(ctx->PathPtsCurrent, pts, 4 * sizeof(double));
120
2.74M
            ctx->PathPtsCurrent += 4;
121
2.74M
            break;
122
9.59M
        case pdfi_curveto_seg:
123
9.59M
            memcpy(ctx->PathPtsCurrent, pts, 6 * sizeof(double));
124
9.59M
            ctx->PathPtsCurrent += 6;
125
9.59M
            break;
126
580k
        case pdfi_closepath_seg:
127
580k
            break;
128
28.7M
    }
129
28.7M
    return 0;
130
28.7M
}
131
132
static int ApplyStoredPath(pdf_context *ctx)
133
5.74M
{
134
5.74M
    int code = 0;
135
5.74M
    char *op = NULL;
136
5.74M
    double *dpts = NULL;
137
5.74M
    double *current;
138
139
5.74M
    if (ctx->PathSegments == NULL)
140
450k
        return 0;
141
142
5.29M
    if (ctx->PathPts == NULL) {
143
0
        code = gs_note_error(gs_error_unknownerror);
144
0
        goto error;
145
0
    }
146
147
5.29M
    if (ctx->pgs->current_point_valid) {
148
135k
        code = gs_newpath(ctx->pgs);
149
135k
        if (code < 0)
150
0
            goto error;
151
135k
    }
152
153
5.29M
    op = ctx->PathSegments;
154
5.29M
    dpts = ctx->PathPts;
155
5.29M
    current = dpts; /* Stop stupid compilers complaining. */
156
157
32.8M
    while (op < ctx->PathSegmentsCurrent) {
158
27.7M
        if (dpts > ctx->PathPtsCurrent) {
159
0
            code = gs_note_error(gs_error_unknownerror);
160
0
            goto error;
161
0
        }
162
163
27.7M
        switch(*op++) {
164
4.79M
            case pdfi_moveto_seg:
165
4.79M
                code = gs_moveto(ctx->pgs, dpts[0], dpts[1]);
166
4.79M
                current = dpts;
167
4.79M
                dpts+= 2;
168
4.79M
                break;
169
10.2M
            case pdfi_lineto_seg:
170
10.2M
                code = gs_lineto(ctx->pgs, dpts[0], dpts[1]);
171
10.2M
                current = dpts;
172
10.2M
                dpts+= 2;
173
10.2M
                break;
174
2.38M
            case pdfi_re_seg:
175
2.38M
                code = gs_moveto(ctx->pgs, dpts[0], dpts[1]);
176
2.38M
                if (code >= 0) {
177
2.38M
                    code = gs_rlineto(ctx->pgs, dpts[2], 0);
178
2.38M
                    if (code >= 0) {
179
2.38M
                        code = gs_rlineto(ctx->pgs, 0, dpts[3]);
180
2.38M
                        if (code >= 0) {
181
2.38M
                            code = gs_rlineto(ctx->pgs, -dpts[2], 0);
182
2.38M
                            if (code >= 0)
183
2.38M
                                code = gs_closepath(ctx->pgs);
184
2.38M
                        }
185
2.38M
                    }
186
2.38M
                }
187
2.38M
                current = dpts;
188
2.38M
                dpts+= 4;
189
2.38M
                break;
190
147k
            case pdfi_v_curveto_seg:
191
147k
                code = gs_curveto(ctx->pgs, current[0], current[1], dpts[0], dpts[1], dpts[2], dpts[3]);
192
147k
                current = dpts + 2;
193
147k
                dpts+= 4;
194
147k
                break;
195
156k
            case pdfi_y_curveto_seg:
196
156k
                code = gs_curveto(ctx->pgs, dpts[0], dpts[1], dpts[2], dpts[3], dpts[2], dpts[3]);
197
156k
                current = dpts + 2;
198
156k
                dpts+= 4;
199
156k
                break;
200
9.47M
            case pdfi_curveto_seg:
201
9.47M
                code = gs_curveto(ctx->pgs, dpts[0], dpts[1], dpts[2], dpts[3], dpts[4], dpts[5]);
202
9.47M
                current = dpts + 4;
203
9.47M
                dpts+= 6;
204
9.47M
                break;
205
538k
            case pdfi_closepath_seg:
206
538k
                code = gs_closepath(ctx->pgs);
207
538k
                break;
208
0
            default:
209
0
                code = gs_note_error(gs_error_rangecheck);
210
0
                break;
211
27.7M
        }
212
27.7M
        if (code < 0)
213
181k
            break;
214
27.7M
    }
215
216
5.29M
error:
217
5.29M
    gs_free_object(ctx->memory, ctx->PathSegments, "ApplyStoredPath");
218
5.29M
    ctx->PathSegmentsTop = ctx->PathSegmentsCurrent = ctx->PathSegments = NULL;
219
5.29M
    gs_free_object(ctx->memory, ctx->PathPts, "ApplyStoredPath");
220
5.29M
    ctx->PathPtsTop = ctx->PathPtsCurrent = ctx->PathPts = NULL;
221
5.29M
    return code;
222
5.29M
}
223
224
int pdfi_moveto (pdf_context *ctx)
225
5.85M
{
226
5.85M
    int code;
227
5.85M
    double xy[2];
228
229
5.85M
    if (ctx->text.BlockDepth != 0) {
230
23.2k
        if (ctx->text.TextClip) {
231
4
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
232
233
4
            ctx->text.TextClip = false;
234
4
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
235
4
        }
236
23.2k
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_moveto", NULL);
237
23.2k
        if (code < 0)
238
0
            return code;
239
23.2k
    }
240
241
5.85M
    code = pdfi_destack_reals(ctx, xy, 2);
242
5.85M
    if (code < 0)
243
799k
        return code;
244
245
5.05M
    return StorePathSegment(ctx, pdfi_moveto_seg, (double *)&xy);
246
5.85M
}
247
248
int pdfi_lineto (pdf_context *ctx)
249
11.3M
{
250
11.3M
    int code;
251
11.3M
    double xy[2];
252
253
11.3M
    if (ctx->text.BlockDepth != 0) {
254
7.73k
        ctx->text.BlockDepth = 0;
255
7.73k
        if (ctx->text.TextClip) {
256
0
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
257
258
0
            ctx->text.TextClip = false;
259
0
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
260
0
        }
261
7.73k
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_lineto", NULL);
262
7.73k
        if (code < 0)
263
0
            return code;
264
7.73k
    }
265
266
11.3M
    code = pdfi_destack_reals(ctx, xy, 2);
267
11.3M
    if (code < 0)
268
569k
        return code;
269
270
10.7M
    return StorePathSegment(ctx, pdfi_lineto_seg, (double *)&xy);
271
11.3M
}
272
273
static int pdfi_fill_inner(pdf_context *ctx, bool use_eofill)
274
2.25M
{
275
2.25M
    int code=0, code1;
276
2.25M
    pdfi_trans_state_t state;
277
278
2.25M
    if (ctx->text.BlockDepth != 0) {
279
12.8k
        ctx->text.BlockDepth = 0;
280
12.8k
        if (ctx->text.TextClip) {
281
4
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
282
283
4
            ctx->text.TextClip = false;
284
4
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
285
4
        }
286
12.8k
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_fill_inner", NULL);
287
12.8k
        if (code < 0)
288
0
            return code;
289
12.8k
    }
290
291
2.25M
    if (pdfi_oc_is_off(ctx))
292
43.9k
        goto exit;
293
294
2.20M
    code = ApplyStoredPath(ctx);
295
2.20M
    if (code < 0)
296
13.7k
        return code;
297
298
2.19M
    code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_Fill);
299
2.19M
    if (code == 0) {
300
        /* If we don't gsave/grestore round the fill, then the file
301
         * /tests_private/pdf/sumatra/954_-_dashed_lines_hardly_visible.pdf renders
302
         * incorrectly. However we must not gsave/grestore round the trans_setup
303
         * trans_teardown, because that might set pgs->soft_mask_id and if we restore
304
         * back to a point where that is not set then pdfwrite doesn't work properly.
305
         */
306
2.19M
        code = pdfi_gsave(ctx);
307
2.19M
        if (code < 0) goto exit;
308
309
2.19M
        if (use_eofill)
310
62.4k
            code = gs_eofill(ctx->pgs);
311
2.13M
        else
312
2.13M
            code = gs_fill(ctx->pgs);
313
2.19M
        code1 = pdfi_grestore(ctx);
314
2.19M
        if (code == 0) code = code1;
315
316
2.19M
        code1 = pdfi_trans_teardown(ctx, &state);
317
2.19M
        if (code == 0) code = code1;
318
2.19M
    }
319
320
2.23M
 exit:
321
2.23M
    code1 = pdfi_newpath(ctx);
322
2.23M
    if (code == 0) code = code1;
323
324
2.23M
    return code;
325
2.19M
}
326
327
int pdfi_fill(pdf_context *ctx)
328
2.18M
{
329
2.18M
    return pdfi_fill_inner(ctx, false);
330
2.18M
}
331
332
int pdfi_eofill(pdf_context *ctx)
333
66.3k
{
334
66.3k
    return pdfi_fill_inner(ctx, true);
335
66.3k
}
336
337
int pdfi_stroke(pdf_context *ctx)
338
2.85M
{
339
2.85M
    int code=0, code1;
340
2.85M
    pdfi_trans_state_t state;
341
342
2.85M
    if (ctx->text.BlockDepth != 0) {
343
6.84k
        ctx->text.BlockDepth = 0;
344
6.84k
        if (ctx->text.TextClip) {
345
0
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
346
347
0
            ctx->text.TextClip = false;
348
0
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
349
0
        }
350
6.84k
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_stroke", NULL);
351
6.84k
        if (code < 0)
352
0
            return code;
353
6.84k
    }
354
355
2.85M
    if (pdfi_oc_is_off(ctx))
356
22
        goto exit;
357
358
2.85M
    code = ApplyStoredPath(ctx);
359
2.85M
    if (code < 0)
360
141k
        return code;
361
362
2.71M
    gs_swapcolors_quick(ctx->pgs);
363
2.71M
    code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_Stroke);
364
2.71M
    if (code == 0) {
365
2.71M
        code = pdfi_gsave(ctx);
366
2.71M
        if (code < 0) goto exit;
367
368
2.71M
        code = gs_stroke(ctx->pgs);
369
370
2.71M
        code1 = pdfi_grestore(ctx);
371
2.71M
        if (code == 0) code = code1;
372
373
2.71M
        code1 = pdfi_trans_teardown(ctx, &state);
374
2.71M
        if (code == 0) code = code1;
375
2.71M
    }
376
2.71M
    gs_swapcolors_quick(ctx->pgs);
377
378
2.71M
 exit:
379
2.71M
    code1 = pdfi_newpath(ctx);
380
2.71M
    if (code == 0) code = code1;
381
382
2.71M
    return code;
383
2.71M
}
384
385
int pdfi_closepath_stroke(pdf_context *ctx)
386
76.5k
{
387
76.5k
    int code;
388
389
76.5k
    if (ctx->text.BlockDepth != 0) {
390
2.50k
        ctx->text.BlockDepth = 0;
391
2.50k
        if (ctx->text.TextClip) {
392
2
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
393
394
2
            ctx->text.TextClip = false;
395
2
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
396
2
        }
397
2.50k
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_closepath_stroke", NULL);
398
2.50k
        if (code < 0)
399
0
            return code;
400
2.50k
    }
401
402
76.5k
    code = StorePathSegment(ctx, pdfi_closepath_seg, NULL);
403
76.5k
    if (code < 0)
404
0
        return code;
405
406
76.5k
    return pdfi_stroke(ctx);
407
76.5k
}
408
409
int pdfi_curveto(pdf_context *ctx)
410
10.0M
{
411
10.0M
    int code;
412
10.0M
    double Values[6];
413
414
10.0M
    code = pdfi_destack_reals(ctx, Values, 6);
415
10.0M
    if (code < 0)
416
435k
        return code;
417
418
9.59M
    if (ctx->text.BlockDepth != 0) {
419
250
        ctx->text.BlockDepth = 0;
420
250
        if (ctx->text.TextClip) {
421
0
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
422
423
0
            ctx->text.TextClip = false;
424
0
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
425
0
        }
426
250
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_curveto", NULL);
427
250
        if (code < 0)
428
0
            return code;
429
250
    }
430
431
9.59M
    return StorePathSegment(ctx, pdfi_curveto_seg, (double *)&Values);
432
9.59M
}
433
434
int pdfi_v_curveto(pdf_context *ctx)
435
152k
{
436
152k
    int code;
437
152k
    double Values[4];
438
439
152k
    code = pdfi_destack_reals(ctx, Values, 4);
440
152k
    if (code < 0)
441
4.77k
        return code;
442
443
148k
    if (ctx->text.BlockDepth != 0) {
444
21
        ctx->text.BlockDepth = 0;
445
21
        if (ctx->text.TextClip) {
446
0
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
447
448
0
            ctx->text.TextClip = false;
449
0
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
450
0
        }
451
21
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_v_curveto", NULL);
452
21
        if (code < 0)
453
0
            return code;
454
21
    }
455
456
148k
    return StorePathSegment(ctx, pdfi_v_curveto_seg, (double *)&Values);
457
148k
}
458
459
int pdfi_y_curveto(pdf_context *ctx)
460
170k
{
461
170k
    int code;
462
170k
    double Values[4];
463
464
170k
    code = pdfi_destack_reals(ctx, Values, 4);
465
170k
    if (code < 0)
466
13.9k
        return code;
467
468
156k
    if (ctx->text.BlockDepth != 0) {
469
24
        ctx->text.BlockDepth = 0;
470
24
        if (ctx->text.TextClip) {
471
0
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
472
473
0
            ctx->text.TextClip = false;
474
0
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
475
0
        }
476
24
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_y_curveto", NULL);
477
24
        if (code < 0)
478
0
            return code;
479
24
    }
480
481
156k
    return StorePathSegment(ctx, pdfi_y_curveto_seg, (double *)&Values);
482
156k
}
483
484
int pdfi_closepath(pdf_context *ctx)
485
487k
{
486
487k
    int code;
487
488
487k
    if (ctx->text.BlockDepth != 0) {
489
760
        ctx->text.BlockDepth = 0;
490
760
        if (ctx->text.TextClip) {
491
3
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
492
493
3
            ctx->text.TextClip = false;
494
3
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
495
3
        }
496
760
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_closepath", NULL);
497
760
        if (code < 0)
498
0
            return code;
499
760
    }
500
501
487k
    return StorePathSegment(ctx, pdfi_closepath_seg, NULL);
502
487k
}
503
504
int pdfi_newpath(pdf_context *ctx)
505
6.12M
{
506
6.12M
    int code = 0, code1;
507
508
    /* This code is to deal with the wacky W and W* operators */
509
6.12M
    if (ctx->clip_active) {
510
654k
        if (ctx->PathSegments != NULL) {
511
616k
            code = ApplyStoredPath(ctx);
512
616k
            if (code < 0)
513
23.9k
                return code;
514
616k
        }
515
630k
        if (ctx->pgs->current_point_valid) {
516
589k
            if (ctx->do_eoclip)
517
54.5k
                code = gs_eoclip(ctx->pgs);
518
535k
            else
519
535k
                code = gs_clip(ctx->pgs);
520
589k
        }
521
630k
    }
522
6.09M
    ctx->clip_active = false;
523
524
6.09M
    if (ctx->PathSegments != NULL){
525
72.2k
        gs_free_object(ctx->memory, ctx->PathSegments, "ApplyStoredPath");
526
72.2k
        ctx->PathSegmentsTop = ctx->PathSegmentsCurrent = ctx->PathSegments = NULL;
527
72.2k
        gs_free_object(ctx->memory, ctx->PathPts, "ApplyStoredPath");
528
72.2k
        ctx->PathPtsTop = ctx->PathPtsCurrent = ctx->PathPts = NULL;
529
72.2k
    }
530
531
6.09M
    code1 = gs_newpath(ctx->pgs);
532
6.09M
    if (code == 0) code = code1;
533
534
6.09M
    if (ctx->text.BlockDepth != 0) {
535
3.77k
        ctx->text.BlockDepth = 0;
536
3.77k
        if (ctx->text.TextClip) {
537
0
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
538
539
0
            ctx->text.TextClip = false;
540
0
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
541
0
        }
542
3.77k
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_newpath", NULL);
543
3.77k
        if (code < 0)
544
0
            return code;
545
3.77k
    }
546
547
6.09M
    return code;
548
6.09M
}
549
550
int pdfi_b(pdf_context *ctx)
551
16.0k
{
552
16.0k
    int code;
553
554
16.0k
    if (ctx->text.BlockDepth != 0) {
555
474
        ctx->text.BlockDepth = 0;
556
474
        if (ctx->text.TextClip) {
557
0
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
558
559
0
            ctx->text.TextClip = false;
560
0
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
561
0
        }
562
474
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_b", NULL);
563
474
        if (code < 0)
564
0
            return code;
565
474
    }
566
567
16.0k
    code = StorePathSegment(ctx, pdfi_closepath_seg, NULL);
568
16.0k
    if (code < 0)
569
0
        return code;
570
571
16.0k
    return pdfi_B(ctx);
572
16.0k
}
573
574
int pdfi_b_star(pdf_context *ctx)
575
495
{
576
495
    int code;
577
578
495
    if (ctx->text.BlockDepth != 0) {
579
0
        ctx->text.BlockDepth = 0;
580
0
        if (ctx->text.TextClip) {
581
0
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
582
583
0
            ctx->text.TextClip = false;
584
0
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
585
0
        }
586
0
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_b_star", NULL);
587
0
        if (code < 0)
588
0
            return code;
589
0
    }
590
591
495
    code = StorePathSegment(ctx, pdfi_closepath_seg, NULL);
592
495
    if (code < 0)
593
0
        return code;
594
595
495
    return pdfi_B_star(ctx);
596
495
}
597
598
/* common code for B and B* */
599
static int pdfi_B_inner(pdf_context *ctx, bool use_eofill)
600
58.6k
{
601
58.6k
    int code=0, code1=0;
602
58.6k
    pdfi_trans_state_t state;
603
604
58.6k
    if (ctx->text.BlockDepth != 0) {
605
4.01k
        ctx->text.BlockDepth = 0;
606
4.01k
        if (ctx->text.TextClip) {
607
12
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
608
609
12
            ctx->text.TextClip = false;
610
12
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
611
12
        }
612
4.01k
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_B_inner", NULL);
613
4.01k
        if (code < 0)
614
0
            goto exit;
615
4.01k
    }
616
617
58.6k
    if (pdfi_oc_is_off(ctx))
618
8
        goto exit;
619
620
58.6k
    code = ApplyStoredPath(ctx);
621
58.6k
    if (code < 0)
622
2.23k
        return code;
623
624
56.3k
    code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_FillStroke);
625
56.3k
    if (code == 0) {
626
56.3k
        code = pdfi_gsave(ctx);
627
56.3k
        if (code < 0) goto exit;
628
629
56.3k
        if (use_eofill)
630
2.14k
            code = gs_eofillstroke(ctx->pgs, &code1);
631
54.2k
        else
632
54.2k
            code = gs_fillstroke(ctx->pgs, &code1);
633
634
56.3k
        code1 = pdfi_grestore(ctx);
635
56.3k
        if (code == 0) code = code1;
636
637
56.3k
        code1 = pdfi_trans_teardown(ctx, &state);
638
56.3k
        if (code >= 0) code = code1;
639
56.3k
    }
640
641
56.3k
 exit:
642
56.3k
    code1 = pdfi_newpath(ctx);
643
56.3k
    if (code == 0) code = code1;
644
645
56.3k
    return code;
646
56.3k
}
647
648
int pdfi_B(pdf_context *ctx)
649
56.3k
{
650
56.3k
    return pdfi_B_inner(ctx, false);
651
56.3k
}
652
653
int pdfi_B_star(pdf_context *ctx)
654
2.27k
{
655
2.27k
    return pdfi_B_inner(ctx, true);
656
2.27k
}
657
658
int pdfi_clip(pdf_context *ctx)
659
0
{
660
0
    int code = gs_clip(ctx->pgs);
661
662
0
    if (ctx->text.BlockDepth != 0) {
663
0
        ctx->text.BlockDepth = 0;
664
0
        if (ctx->text.TextClip) {
665
0
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
666
667
0
            ctx->text.TextClip = false;
668
0
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
669
0
        }
670
0
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_B_clip", NULL);
671
0
        if (code < 0)
672
0
            return code;
673
0
    }
674
675
0
    return code;
676
0
}
677
678
int pdfi_eoclip(pdf_context *ctx)
679
0
{
680
0
    int code = gs_eoclip(ctx->pgs);
681
682
0
    if (ctx->text.BlockDepth != 0) {
683
0
        ctx->text.BlockDepth = 0;
684
0
        if (ctx->text.TextClip) {
685
0
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
686
687
0
            ctx->text.TextClip = false;
688
0
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
689
0
        }
690
0
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_eoclip", NULL);
691
0
        if (code < 0)
692
0
            return code;
693
0
    }
694
695
0
     return code;
696
0
}
697
698
int pdfi_rectpath(pdf_context *ctx)
699
2.57M
{
700
2.57M
    int code;
701
2.57M
    double Values[4];
702
703
2.57M
    code = pdfi_destack_reals(ctx, Values, 4);
704
2.57M
    if (code < 0)
705
136k
        return code;
706
707
2.44M
    if (ctx->text.BlockDepth != 0) {
708
20.3k
        ctx->text.BlockDepth = 0;
709
20.3k
        if (ctx->text.TextClip) {
710
0
            gx_device *dev = gs_currentdevice_inline(ctx->pgs);
711
712
0
            ctx->text.TextClip = false;
713
0
            (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1);
714
0
        }
715
20.3k
        code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_rectpath", NULL);
716
20.3k
        if (code < 0)
717
0
            return code;
718
20.3k
    }
719
720
2.44M
    return StorePathSegment(ctx, pdfi_re_seg, (double *)&Values);
721
2.44M
}