Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gxpcopy.c
Line
Count
Source
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
/* Path copying and flattening */
18
#include "math_.h"
19
#include "gx.h"
20
#include "gserrors.h"
21
#include "gxfixed.h"
22
#include "gxfarith.h"
23
#include "gxgstate.h"   /* for access to line params */
24
#include "gzpath.h"
25
26
/* Forward declarations */
27
static void adjust_point_to_tangent(segment *, const segment *,
28
                                     const gs_fixed_point *);
29
30
static inline int
31
break_line_if_long(gx_path *ppath, const segment *pseg)
32
76.6M
{
33
76.6M
    fixed x0 = ppath->position.x;
34
76.6M
    fixed y0 = ppath->position.y;
35
36
76.6M
    if (gx_check_fixed_diff_overflow(pseg->pt.x, x0) ||
37
76.5M
        gx_check_fixed_diff_overflow(pseg->pt.y, y0)) {
38
34.8k
        fixed x, y;
39
40
34.8k
        if (gx_check_fixed_sum_overflow(pseg->pt.x, x0))
41
2.58k
            x = (pseg->pt.x >> 1) + (x0 >> 1);
42
32.3k
        else
43
32.3k
            x = (pseg->pt.x + x0) >> 1;
44
34.8k
        if (gx_check_fixed_sum_overflow(pseg->pt.y, y0))
45
1.20k
            y = (pseg->pt.y >> 1) + (y0 >> 1);
46
33.6k
        else
47
33.6k
            y = (pseg->pt.y + y0) >> 1;
48
34.8k
        return gx_path_add_line_notes(ppath, x, y, pseg->notes);
49
        /* WARNING: Stringly speaking, the next half segment must get
50
           the sn_not_first flag. We don't bother, because that flag
51
           has no important meaning with colinear segments.
52
         */
53
34.8k
    }
54
76.5M
    return 0;
55
76.6M
}
56
static inline int
57
break_gap_if_long(gx_path *ppath, const segment *pseg)
58
270k
{
59
270k
    fixed x0 = ppath->position.x;
60
270k
    fixed y0 = ppath->position.y;
61
62
270k
    if (gx_check_fixed_diff_overflow(pseg->pt.x, x0) ||
63
270k
        gx_check_fixed_diff_overflow(pseg->pt.y, y0)) {
64
0
        fixed x, y;
65
66
0
        if (gx_check_fixed_sum_overflow(pseg->pt.x, x0))
67
0
            x = (pseg->pt.x >> 1) + (x0 >> 1);
68
0
        else
69
0
            x = (pseg->pt.x + x0) >> 1;
70
0
        if (gx_check_fixed_sum_overflow(pseg->pt.y, y0))
71
0
            y = (pseg->pt.y >> 1) + (y0 >> 1);
72
0
        else
73
0
            y = (pseg->pt.y + y0) >> 1;
74
0
        return gx_path_add_gap_notes(ppath, x, y, pseg->notes);
75
        /* WARNING: Stringly speaking, the next half segment must get
76
           the sn_not_first flag. We don't bother, because that flag
77
           has no important meaning with colinear segments.
78
         */
79
0
    }
80
270k
    return 0;
81
270k
}
82
83
/* Copy a path, optionally flattening or monotonizing it. */
84
/* If the copy fails, free the new path. */
85
int
86
gx_path_copy_reducing(const gx_path *ppath_old, gx_path *ppath,
87
                      fixed fixed_flatness, const gs_gstate *pgs,
88
                      gx_path_copy_options options)
89
14.7M
{
90
14.7M
    const segment *pseg;
91
14.7M
    fixed flat = fixed_flatness;
92
14.7M
    gs_fixed_point expansion;
93
    /*
94
     * Since we're going to be adding to the path, unshare it
95
     * before we start.
96
     */
97
14.7M
    int code = gx_path_unshare(ppath);
98
99
14.7M
    if (code < 0)
100
0
        return code;
101
#ifdef DEBUG
102
    if (gs_debug_c('P'))
103
        gx_dump_path(ppath_old, "before reducing");
104
#endif
105
14.7M
    if (options & pco_for_stroke) {
106
        /* Precompute the maximum expansion of the bounding box. */
107
415k
        double width = pgs->line_params.half_width;
108
109
415k
        expansion.x =
110
415k
            float2fixed((fabs(pgs->ctm.xx) + fabs(pgs->ctm.yx)) * width) * 2;
111
415k
        expansion.y =
112
415k
            float2fixed((fabs(pgs->ctm.xy) + fabs(pgs->ctm.yy)) * width) * 2;
113
415k
    } else
114
14.2M
        expansion.x = expansion.y = 0; /* Quiet gcc warning. */
115
14.7M
    pseg = (const segment *)(ppath_old->first_subpath);
116
169M
    while (pseg) {
117
154M
        switch (pseg->type) {
118
16.2M
            case s_start:
119
16.2M
                code = gx_path_add_point(ppath,
120
16.2M
                                         pseg->pt.x, pseg->pt.y);
121
16.2M
                break;
122
61.5M
            case s_curve:
123
61.5M
                {
124
61.5M
                    const curve_segment *pc = (const curve_segment *)pseg;
125
126
61.5M
                    if (fixed_flatness == max_fixed) { /* don't flatten */
127
30.0M
                        if (options & pco_monotonize)
128
0
                            code = gx_curve_monotonize(ppath, pc);
129
30.0M
                        else
130
30.0M
                            code = gx_path_add_curve_notes(ppath,
131
30.0M
                                     pc->p1.x, pc->p1.y, pc->p2.x, pc->p2.y,
132
30.0M
                                           pc->pt.x, pc->pt.y, pseg->notes);
133
31.4M
                    } else {
134
31.4M
                        fixed x0 = ppath->position.x;
135
31.4M
                        fixed y0 = ppath->position.y;
136
31.4M
                        segment_notes notes = pseg->notes;
137
31.4M
                        curve_segment cseg;
138
31.4M
                        int k;
139
140
31.4M
                        if (options & pco_for_stroke) {
141
                            /*
142
                             * When flattening for stroking, the flatness
143
                             * must apply to the outside of the resulting
144
                             * stroked region.  We approximate this by
145
                             * dividing the flatness by the ratio of the
146
                             * expanded bounding box to the original
147
                             * bounding box.  This is crude, but pretty
148
                             * simple to calculate, and produces reasonably
149
                             * good results.
150
                             */
151
3.15M
                            fixed min01, max01, min23, max23;
152
3.15M
                            fixed ex, ey, flat_x, flat_y;
153
154
3.15M
#define SET_EXTENT(r, c0, c1, c2, c3)\
155
6.30M
    BEGIN\
156
6.30M
        if (c0 < c1) min01 = c0, max01 = c1;\
157
6.30M
        else         min01 = c1, max01 = c0;\
158
6.30M
        if (c2 < c3) min23 = c2, max23 = c3;\
159
6.30M
        else         min23 = c3, max23 = c2;\
160
6.30M
        r = max(max01, max23) - min(min01, min23);\
161
6.30M
    END
162
3.15M
                            SET_EXTENT(ex, x0, pc->p1.x, pc->p2.x, pc->pt.x);
163
3.15M
                            SET_EXTENT(ey, y0, pc->p1.y, pc->p2.y, pc->pt.y);
164
3.15M
#undef SET_EXTENT
165
                            /*
166
                             * We check for the degenerate case specially
167
                             * to avoid a division by zero.
168
                             */
169
3.15M
                            if (ex == 0 || ey == 0)
170
143k
                                if (ex != 0) {
171
93.2k
                                    flat = fixed_mult_quo(fixed_flatness, ex,
172
93.2k
                                                          ex + expansion.x);
173
93.2k
                                    k = gx_curve_log2_samples(x0,y0,pc,flat);
174
93.2k
                                } else if (ey != 0) {
175
5.18k
                                    flat = fixed_mult_quo(fixed_flatness, ey,
176
5.18k
                                                          ey + expansion.y);
177
5.18k
                                    k = gx_curve_log2_samples(x0,y0,pc,flat);
178
5.18k
                                } else
179
44.8k
                                    k = 0;
180
3.00M
                            else {
181
3.00M
                                flat_x =
182
3.00M
                                    fixed_mult_quo(fixed_flatness, ex,
183
3.00M
                                                   ex + expansion.x);
184
3.00M
                                flat_y =
185
3.00M
                                    fixed_mult_quo(fixed_flatness, ey,
186
3.00M
                                                   ey + expansion.y);
187
3.00M
                                flat = min(flat_x, flat_y);
188
3.00M
                                k = gx_curve_log2_samples(x0, y0, pc, flat);
189
3.00M
                            }
190
3.15M
                        } else
191
28.3M
                            k = gx_curve_log2_samples(x0, y0, pc, flat);
192
31.4M
                        if (options & pco_accurate) {
193
31.4M
                            segment *start;
194
31.4M
                            segment *end;
195
196
                            /*
197
                             * Add an extra line, which will become
198
                             * the tangent segment.
199
                             */
200
31.4M
                            code = gx_path_add_line_notes(ppath, x0, y0,
201
31.4M
                                                          notes);
202
31.4M
                            if (code < 0)
203
0
                                break;
204
31.4M
                            start = ppath->current_subpath->last;
205
31.4M
                            notes |= sn_not_first;
206
31.4M
                            cseg = *pc;
207
31.4M
                            code = gx_subdivide_curve(ppath, k, &cseg, notes);
208
31.4M
                            if (code < 0)
209
0
                                break;
210
                            /*
211
                             * Adjust the first and last segments so that
212
                             * they line up with the tangents.
213
                             */
214
31.4M
                            end = ppath->current_subpath->last;
215
31.4M
                            if ((code = gx_path_add_line_notes(ppath,
216
31.4M
                                                          ppath->position.x,
217
31.4M
                                                          ppath->position.y,
218
31.4M
                                            pseg->notes | sn_not_first)) < 0)
219
0
                                break;
220
31.4M
                            if (start->next->pt.x != pc->p1.x || start->next->pt.y != pc->p1.y)
221
31.4M
                                adjust_point_to_tangent(start, start->next, &pc->p1);
222
54.9k
                            else if (start->next->pt.x != pc->p2.x || start->next->pt.y != pc->p2.y)
223
818
                                adjust_point_to_tangent(start, start->next, &pc->p2);
224
54.1k
                            else
225
54.1k
                                adjust_point_to_tangent(start, start->next, &end->prev->pt);
226
31.4M
                            if (end->prev->pt.x != pc->p2.x || end->prev->pt.y != pc->p2.y)
227
31.4M
                                adjust_point_to_tangent(end, end->prev, &pc->p2);
228
69.3k
                            else if (end->prev->pt.x != pc->p1.x || end->prev->pt.y != pc->p1.y)
229
682
                                adjust_point_to_tangent(end, end->prev, &pc->p1);
230
68.6k
                            else
231
68.6k
                                adjust_point_to_tangent(end, end->prev, &start->pt);
232
31.4M
                        } else {
233
0
                            cseg = *pc;
234
0
                            code = gx_subdivide_curve(ppath, k, &cseg, notes);
235
0
                        }
236
31.4M
                    }
237
61.5M
                    break;
238
61.5M
                }
239
62.6M
            case s_line:
240
62.6M
                code = break_line_if_long(ppath, pseg);
241
62.6M
                if (code < 0)
242
0
                    break;
243
62.6M
                code = gx_path_add_line_notes(ppath,
244
62.6M
                                       pseg->pt.x, pseg->pt.y, pseg->notes);
245
62.6M
                break;
246
270k
            case s_gap:
247
270k
                code = break_gap_if_long(ppath, pseg);
248
270k
                if (code < 0)
249
0
                    break;
250
270k
                code = gx_path_add_gap_notes(ppath,
251
270k
                                       pseg->pt.x, pseg->pt.y, pseg->notes);
252
270k
                break;
253
0
            case s_dash:
254
0
                {
255
0
                    const dash_segment *pd = (const dash_segment *)pseg;
256
257
0
                    code = gx_path_add_dash_notes(ppath,
258
0
                                       pd->pt.x, pd->pt.y, pd->tangent.x, pd->tangent.y, pseg->notes);
259
0
                    break;
260
270k
                }
261
13.9M
            case s_line_close:
262
13.9M
                code = break_line_if_long(ppath, pseg);
263
13.9M
                if (code < 0)
264
0
                    break;
265
13.9M
                code = gx_path_close_subpath(ppath);
266
13.9M
                break;
267
0
            default:    /* can't happen */
268
0
                code = gs_note_error(gs_error_unregistered);
269
154M
        }
270
154M
        if (code < 0) {
271
0
            gx_path_new(ppath);
272
0
            return code;
273
0
        }
274
154M
        pseg = pseg->next;
275
154M
    }
276
14.7M
    if (path_last_is_moveto(ppath_old)) {
277
1.31M
        code = gx_path_add_point(ppath, ppath_old->position.x,
278
1.31M
                          ppath_old->position.y);
279
1.31M
        if (code < 0) {
280
0
            gx_path_new(ppath);
281
0
            return code;
282
0
        }
283
1.31M
    }
284
14.7M
    if (ppath_old->bbox_set) {
285
0
        if (ppath->bbox_set) {
286
0
            ppath->bbox.p.x = min(ppath_old->bbox.p.x, ppath->bbox.p.x);
287
0
            ppath->bbox.p.y = min(ppath_old->bbox.p.y, ppath->bbox.p.y);
288
0
            ppath->bbox.q.x = max(ppath_old->bbox.q.x, ppath->bbox.q.x);
289
0
            ppath->bbox.q.y = max(ppath_old->bbox.q.y, ppath->bbox.q.y);
290
0
        } else {
291
0
            ppath->bbox_set = true;
292
0
            ppath->bbox = ppath_old->bbox;
293
0
        }
294
0
    }
295
#ifdef DEBUG
296
    if (gs_debug_c('P'))
297
        gx_dump_path(ppath, "after reducing");
298
#endif
299
14.7M
    return 0;
300
14.7M
}
301
302
/*
303
 * Adjust one end of a line (the first or last line of a flattened curve)
304
 * so it falls on the curve tangent.  The closest point on the line from
305
 * (0,0) to (C,D) to a point (U,V) -- i.e., the point on the line at which
306
 * a perpendicular line from the point intersects it -- is given by
307
 *      T = (C*U + D*V) / (C^2 + D^2)
308
 *      (X,Y) = (C*T,D*T)
309
 * However, any smaller value of T will also work: the one we actually
310
 * use is 0.25 * the value we just derived.  We must check that
311
 * numerical instabilities don't lead to a negative value of T.
312
 */
313
static void
314
adjust_point_to_tangent(segment * pseg, const segment * next,
315
                        const gs_fixed_point * p1)
316
62.9M
{
317
62.9M
    const fixed x0 = pseg->pt.x, y0 = pseg->pt.y;
318
62.9M
    const fixed fC = p1->x - x0, fD = p1->y - y0;
319
320
    /*
321
     * By far the commonest case is that the end of the curve is
322
     * horizontal or vertical.  Check for this specially, because
323
     * we can handle it with far less work (and no floating point).
324
     */
325
62.9M
    if (fC == 0) {
326
        /* Vertical tangent. */
327
9.70M
        const fixed DT = arith_rshift(next->pt.y - y0, 2);
328
329
9.70M
        if (fD == 0)
330
710k
            return;    /* anomalous case */
331
9.70M
        if_debug1('2', "[2]adjusting vertical: DT = %g\n",
332
8.99M
                  fixed2float(DT));
333
8.99M
        if ((DT ^ fD) > 0) /* lgtm [cpp/bitwise-sign-check] */
334
8.94M
            pseg->pt.y = DT + y0;
335
53.2M
    } else if (fD == 0) {
336
        /* Horizontal tangent. */
337
10.8M
        const fixed CT = arith_rshift(next->pt.x - x0, 2);
338
339
10.8M
        if_debug1('2', "[2]adjusting horizontal: CT = %g\n",
340
10.8M
                  fixed2float(CT));
341
10.8M
        if ((CT ^ fC) > 0) /* lgtm [cpp/bitwise-sign-check] */
342
10.7M
            pseg->pt.x = CT + x0;
343
42.3M
    } else {
344
        /* General case. */
345
42.3M
        const double C = fC, D = fD;
346
42.3M
        double T = (C * (next->pt.x - x0) + D * (next->pt.y - y0)) /
347
42.3M
        (C * C + D * D);
348
349
42.3M
        if_debug3('2', "[2]adjusting: C = %g, D = %g, T = %g\n",
350
42.3M
                  C, D, T);
351
42.3M
        if (T > 0) {
352
42.3M
            if (T > 1) {
353
                /* Don't go outside the curve bounding box. */
354
21.4M
                T = 1;
355
21.4M
            }
356
42.3M
            pseg->pt.x = arith_rshift((fixed) (C * T), 2) + x0;
357
42.3M
            pseg->pt.y = arith_rshift((fixed) (D * T), 2) + y0;
358
42.3M
        }
359
42.3M
    }
360
62.9M
}
361
362
/* ---------------- Monotonic curves ---------------- */
363
364
/* Test whether a path is free of non-monotonic curves. */
365
bool
366
gx_path__check_curves(const gx_path * ppath, gx_path_copy_options options, fixed fixed_flat)
367
0
{
368
0
    const segment *pseg = (const segment *)(ppath->first_subpath);
369
0
    gs_fixed_point pt0;
370
371
0
    pt0.x = pt0.y = 0; /* Quiet gcc warning. */
372
0
    while (pseg) {
373
0
        switch (pseg->type) {
374
0
            case s_start:
375
0
                {
376
0
                    const subpath *psub = (const subpath *)pseg;
377
378
                    /* Skip subpaths without curves. */
379
0
                    if (!psub->curve_count)
380
0
                        pseg = psub->last;
381
0
                }
382
0
                break;
383
0
            case s_line:
384
0
            case s_gap:
385
0
                if (gx_check_fixed_diff_overflow(pseg->pt.x, pt0.x) ||
386
0
                    gx_check_fixed_diff_overflow(pseg->pt.y, pt0.y))
387
0
                    return false;
388
0
                break;
389
0
            case s_curve:
390
0
                {
391
0
                    const curve_segment *pc = (const curve_segment *)pseg;
392
393
0
                    if (options & pco_monotonize) {
394
0
                        double t[2];
395
0
                        int nz = gx_curve_monotonic_points(pt0.y,
396
0
                                               pc->p1.y, pc->p2.y, pc->pt.y, t);
397
398
0
                        if (nz != 0)
399
0
                            return false;
400
0
                        nz = gx_curve_monotonic_points(pt0.x,
401
0
                                               pc->p1.x, pc->p2.x, pc->pt.x, t);
402
0
                        if (nz != 0)
403
0
                            return false;
404
0
                    }
405
0
                    if (options & pco_small_curves) {
406
0
                        fixed ax, bx, cx, ay, by, cy;
407
0
                        int k = gx_curve_log2_samples(pt0.x, pt0.y, pc, fixed_flat);
408
409
0
                        if(!curve_coeffs_ranged(pt0.x, pc->p1.x, pc->p2.x, pc->pt.x,
410
0
                                pt0.y, pc->p1.y, pc->p2.y, pc->pt.y,
411
0
                                &ax, &bx, &cx, &ay, &by, &cy, k))
412
0
                            return false;
413
0
                    if (gx_check_fixed_diff_overflow(pseg->pt.x, pt0.x) ||
414
0
                        gx_check_fixed_diff_overflow(pseg->pt.y, pt0.y))
415
0
                        return false;
416
0
                    }
417
0
                }
418
0
                break;
419
0
            default:
420
0
                ;
421
0
        }
422
0
        pt0 = pseg->pt;
423
0
        pseg = pseg->next;
424
0
    }
425
0
    return true;
426
0
}
427
428
/* Test whether a path is free of long segments. */
429
/* WARNING : This function checks the distance between
430
 * the starting point and the ending point of a segment.
431
 * When they are not too far, a curve nevertheless may be too long.
432
 * Don't worry about it here, because we assume
433
 * this function is never called with paths which have curves.
434
 */
435
bool
436
gx_path_has_long_segments(const gx_path * ppath)
437
5.40M
{
438
5.40M
    const segment *pseg = (const segment *)(ppath->first_subpath);
439
5.40M
    gs_fixed_point pt0;
440
441
5.40M
    pt0.x = pt0.y = 0; /* Quiet gcc warning. */
442
19.1M
    while (pseg) {
443
13.7M
        switch (pseg->type) {
444
3.37M
            case s_start:
445
3.37M
                break;
446
10.4M
            default:
447
10.4M
                if (gx_check_fixed_diff_overflow(pseg->pt.x, pt0.x) ||
448
10.4M
                    gx_check_fixed_diff_overflow(pseg->pt.y, pt0.y))
449
9.65k
                    return true;
450
10.4M
                break;
451
13.7M
        }
452
13.7M
        pt0 = pseg->pt;
453
13.7M
        pseg = pseg->next;
454
13.7M
    }
455
5.39M
    return false;
456
5.40M
}
457
458
/* Monotonize a curve, by splitting it if necessary. */
459
/* In the worst case, this could split the curve into 9 pieces. */
460
int
461
gx_curve_monotonize(gx_path * ppath, const curve_segment * pc)
462
844k
{
463
844k
    fixed x0 = ppath->position.x, y0 = ppath->position.y;
464
844k
    segment_notes notes = pc->notes;
465
844k
    double t[5], tt = 1, tp;
466
844k
    int c[5];
467
844k
    int n0, n1, n, i, j, k = 0;
468
844k
    fixed ax, bx, cx, ay, by, cy, v01, v12;
469
844k
    fixed px, py, qx, qy, rx, ry, sx, sy;
470
844k
    const double delta = 0.0000001;
471
472
    /* Roots of the derivative : */
473
844k
    n0 = gx_curve_monotonic_points(x0, pc->p1.x, pc->p2.x, pc->pt.x, t);
474
844k
    n1 = gx_curve_monotonic_points(y0, pc->p1.y, pc->p2.y, pc->pt.y, t + n0);
475
844k
    n = n0 + n1;
476
844k
    if (n == 0)
477
821k
        return gx_path_add_curve_notes(ppath, pc->p1.x, pc->p1.y,
478
821k
                pc->p2.x, pc->p2.y, pc->pt.x, pc->pt.y, notes);
479
23.0k
    if (n0 > 0)
480
13.1k
        c[0] = 1;
481
23.0k
    if (n0 > 1)
482
2
        c[1] = 1;
483
23.0k
    if (n1 > 0)
484
10.7k
        c[n0] = 2;
485
23.0k
    if (n1 > 1)
486
0
        c[n0 + 1] = 2;
487
    /* Order roots : */
488
46.9k
    for (i = 0; i < n; i++)
489
24.8k
        for (j = i + 1; j < n; j++)
490
939
            if (t[i] > t[j]) {
491
395
                int w;
492
395
                double v = t[i]; t[i] = t[j]; t[j] = v;
493
395
                w = c[i]; c[i] = c[j]; c[j] = w;
494
395
            }
495
    /* Drop roots near zero : */
496
23.0k
    for (k = 0; k < n; k++)
497
23.0k
        if (t[k] >= delta)
498
23.0k
            break;
499
    /* Merge close roots, and drop roots at 1 : */
500
23.0k
    if (t[n - 1] > 1 - delta)
501
0
        n--;
502
23.9k
    for (i = k + 1, j = k; i < n && t[k] < 1 - delta; i++)
503
939
        if (any_abs(t[i] - t[j]) < delta) {
504
0
            t[j] = (t[j] + t[i]) / 2; /* Unlikely 3 roots are close. */
505
0
            c[j] |= c[i];
506
939
        } else {
507
939
            j++;
508
939
            t[j] = t[i];
509
939
            c[j] = c[i];
510
939
        }
511
23.0k
    n = j + 1;
512
    /* Do split : */
513
23.0k
    curve_points_to_coefficients(x0, pc->p1.x, pc->p2.x, pc->pt.x, ax, bx, cx, v01, v12);
514
23.0k
    curve_points_to_coefficients(y0, pc->p1.y, pc->p2.y, pc->pt.y, ay, by, cy, v01, v12);
515
23.0k
    ax *= 3, bx *= 2; /* Coefficients of the derivative. */
516
23.0k
    ay *= 3, by *= 2;
517
23.0k
    px = x0;
518
23.0k
    py = y0;
519
23.0k
    qx = (fixed)((pc->p1.x - px) * t[0] + 0.5);
520
23.0k
    qy = (fixed)((pc->p1.y - py) * t[0] + 0.5);
521
23.0k
    tp = 0;
522
46.9k
    for (i = k; i < n; i++) {
523
23.9k
        double ti = t[i];
524
23.9k
        double t2 = ti * ti, t3 = t2 * ti;
525
23.9k
        double omt = 1 - ti, omt2 = omt * omt, omt3 = omt2 * omt;
526
23.9k
        double x = x0 * omt3 + 3 * pc->p1.x * omt2 * ti + 3 * pc->p2.x * omt * t2 + pc->pt.x * t3;
527
23.9k
        double y = y0 * omt3 + 3 * pc->p1.y * omt2 * ti + 3 * pc->p2.y * omt * t2 + pc->pt.y * t3;
528
23.9k
        double ddx = (c[i] & 1 ? 0 : ax * t2 + bx * ti + cx); /* Suppress noise. */
529
23.9k
        double ddy = (c[i] & 2 ? 0 : ay * t2 + by * ti + cy);
530
23.9k
        fixed dx = (fixed)(ddx + 0.5);
531
23.9k
        fixed dy = (fixed)(ddy + 0.5);
532
23.9k
        int code;
533
534
23.9k
        tt = (i + 1 < n ? t[i + 1] : 1) - ti;
535
23.9k
        rx = (fixed)(dx * (t[i] - tp) / 3 + 0.5);
536
23.9k
        ry = (fixed)(dy * (t[i] - tp) / 3 + 0.5);
537
23.9k
        sx = (fixed)(x + 0.5);
538
23.9k
        sy = (fixed)(y + 0.5);
539
        /* Suppress the derivative sign noise near a peak : */
540
23.9k
        if ((double)(sx - px) * qx + (double)(sy - py) * qy < 0)
541
0
            qx = -qx, qy = -qy;
542
23.9k
        if ((double)(sx - px) * rx + (double)(sy - py) * ry < 0)
543
0
            rx = -rx, ry = -qy;
544
        /* Do add : */
545
23.9k
        code = gx_path_add_curve_notes(ppath, px + qx, py + qy, sx - rx, sy - ry, sx, sy, notes);
546
23.9k
        if (code < 0)
547
0
            return code;
548
23.9k
        notes |= sn_not_first;
549
23.9k
        px = sx;
550
23.9k
        py = sy;
551
23.9k
        qx = (fixed)(dx * tt / 3 + 0.5);
552
23.9k
        qy = (fixed)(dy * tt / 3 + 0.5);
553
23.9k
        tp = t[i];
554
23.9k
    }
555
23.0k
    sx = pc->pt.x;
556
23.0k
    sy = pc->pt.y;
557
23.0k
    rx = (fixed)((pc->pt.x - pc->p2.x) * tt + 0.5);
558
23.0k
    ry = (fixed)((pc->pt.y - pc->p2.y) * tt + 0.5);
559
    /* Suppress the derivative sign noise near peaks : */
560
23.0k
    if ((double)(sx - px) * qx + (double)(sy - py) * qy < 0)
561
0
        qx = -qx, qy = -qy;
562
23.0k
    if ((double)(sx - px) * rx + (double)(sy - py) * ry < 0)
563
0
        rx = -rx, ry = -qy;
564
23.0k
    return gx_path_add_curve_notes(ppath, px + qx, py + qy, sx - rx, sy - ry, sx, sy, notes);
565
23.0k
}
566
567
/*
568
 * Split a curve if necessary into pieces that are monotonic in X or Y as a
569
 * function of the curve parameter t.  This allows us to rasterize curves
570
 * directly without pre-flattening.  This takes a fair amount of analysis....
571
 * Store the values of t of the split points in pst[0] and pst[1].  Return
572
 * the number of split points (0, 1, or 2).
573
 */
574
int
575
gx_curve_monotonic_points(fixed v0, fixed v1, fixed v2, fixed v3,
576
                          double pst[2])
577
1.68M
{
578
    /*
579
       Let
580
       v(t) = a*t^3 + b*t^2 + c*t + d, 0 <= t <= 1.
581
       Then
582
       dv(t) = 3*a*t^2 + 2*b*t + c.
583
       v(t) has a local minimum or maximum (or inflection point)
584
       precisely where dv(t) = 0.  Now the roots of dv(t) = 0 (i.e.,
585
       the zeros of dv(t)) are at
586
       t =  ( -2*b +/- sqrt(4*b^2 - 12*a*c) ) / 6*a
587
       =    ( -b +/- sqrt(b^2 - 3*a*c) ) / 3*a
588
       (Note that real roots exist iff b^2 >= 3*a*c.)
589
       We want to know if these lie in the range (0..1).
590
       (The endpoints don't count.)  Call such a root a "valid zero."
591
       Since computing the roots is expensive, we would like to have
592
       some cheap tests to filter out cases where they don't exist
593
       (i.e., where the curve is already monotonic).
594
     */
595
1.68M
    fixed v01, v12, a, b, c, b2, a3;
596
1.68M
    fixed dv_end, b2abs, a3abs;
597
598
1.68M
    curve_points_to_coefficients(v0, v1, v2, v3, a, b, c, v01, v12);
599
1.68M
    b2 = b << 1;
600
1.68M
    a3 = (a << 1) + a;
601
    /*
602
       If a = 0, the only possible zero is t = -c / 2*b.
603
       This zero is valid iff sign(c) != sign(b) and 0 < |c| < 2*|b|.
604
     */
605
1.68M
    if (a == 0) {
606
352k
        if ((b ^ c) < 0 && any_abs(c) < any_abs(b2) && c != 0) {
607
6.72k
            *pst = (double)(-c) / b2;
608
6.72k
            return 1;
609
6.72k
        } else
610
345k
            return 0;
611
352k
    }
612
    /*
613
       Iff a curve is horizontal at t = 0, c = 0.  In this case,
614
       there can be at most one other zero, at -2*b / 3*a.
615
       This zero is valid iff sign(a) != sign(b) and 0 < 2*|b| < 3*|a|.
616
     */
617
1.33M
    if (c == 0) {
618
186k
        if ((a ^ b) < 0 && any_abs(b2) < any_abs(a3) && b != 0) {
619
0
            *pst = (double)(-b2) / a3;
620
0
            return 1;
621
0
        } else
622
186k
            return 0;
623
186k
    }
624
    /*
625
       Similarly, iff a curve is horizontal at t = 1, 3*a + 2*b + c = 0.
626
       In this case, there can be at most one other zero,
627
       at -1 - 2*b / 3*a, iff sign(a) != sign(b) and 1 < -2*b / 3*a < 2,
628
       i.e., 3*|a| < 2*|b| < 6*|a|.
629
     */
630
1.14M
    else if ((dv_end = a3 + b2 + c) == 0) {
631
186k
        if ((a ^ b) < 0 &&
632
74.8k
            (b2abs = any_abs(b2)) > (a3abs = any_abs(a3)) &&
633
74.8k
            b2abs < a3abs << 1
634
186k
            ) {
635
0
            *pst = (double)(-b2 - a3) / a3;
636
0
            return 1;
637
0
        } else
638
186k
            return 0;
639
186k
    }
640
    /*
641
       If sign(dv_end) != sign(c), at least one valid zero exists,
642
       since dv(0) and dv(1) have opposite signs and hence
643
       dv(t) must be zero somewhere in the interval [0..1].
644
     */
645
962k
    else if ((dv_end ^ c) < 0);
646
    /*
647
       If sign(a) = sign(b), no valid zero exists,
648
       since dv is monotonic on [0..1] and has the same sign
649
       at both endpoints.
650
     */
651
945k
    else if ((a ^ b) >= 0)
652
472k
        return 0;
653
    /*
654
       Otherwise, dv(t) may be non-monotonic on [0..1]; it has valid zeros
655
       iff its sign anywhere in this interval is different from its sign
656
       at the endpoints, which occurs iff it has an extremum in this
657
       interval and the extremum is of the opposite sign from c.
658
       To find this out, we look for the local extremum of dv(t)
659
       by observing
660
       d2v(t) = 6*a*t + 2*b
661
       which has a zero only at
662
       t1 = -b / 3*a
663
       Now if t1 <= 0 or t1 >= 1, no valid zero exists.
664
       Note that we just determined that sign(a) != sign(b), so we know t1 > 0.
665
     */
666
473k
    else if (any_abs(b) >= any_abs(a3))
667
471k
        return 0;
668
    /*
669
       Otherwise, we just go ahead with the computation of the roots,
670
       and test them for being in the correct range.  Note that a valid
671
       zero is an inflection point of v(t) iff d2v(t) = 0; we don't
672
       bother to check for this case, since it's rare.
673
     */
674
19.0k
    {
675
19.0k
        double nbf = (double)(-b);
676
19.0k
        double a3f = (double)a3;
677
19.0k
        double radicand = nbf * nbf - a3f * c;
678
679
19.0k
        if (radicand < 0) {
680
994
            if_debug1('2', "[2]negative radicand = %g\n", radicand);
681
994
            return 0;
682
18.0k
        } {
683
18.0k
            double root = sqrt(radicand);
684
18.0k
            int nzeros = 0;
685
18.0k
            double z = (nbf - root) / a3f;
686
687
            /*
688
             * We need to return the zeros in the correct order.
689
             * We know that root is non-negative, but a3f may be either
690
             * positive or negative, so we need to check the ordering
691
             * explicitly.
692
             */
693
18.0k
            if_debug2('2', "[2]zeros at %g, %g\n", z, (nbf + root) / a3f);
694
18.0k
            if (z > 0 && z < 1)
695
8.54k
                *pst = z, nzeros = 1;
696
18.0k
            if (root != 0) {
697
18.0k
                z = (nbf + root) / a3f;
698
18.0k
                if (z > 0 && z < 1) {
699
8.67k
                    if (nzeros && a3f < 0)  /* order is reversed */
700
2
                        pst[1] = *pst, *pst = z;
701
8.67k
                    else
702
8.67k
                        pst[nzeros] = z;
703
8.67k
                    nzeros++;
704
8.67k
                }
705
18.0k
            }
706
18.0k
            return nzeros;
707
19.0k
        }
708
19.0k
    }
709
19.0k
}
710
711
/* ---------------- Path optimization for the filling algorithm. ---------------- */
712
713
static bool
714
find_contacting_segments(const subpath *sp0, segment *sp0last,
715
                         const subpath *sp1, segment *sp1last,
716
                         segment **sc0, segment **sc1)
717
0
{
718
0
    segment *s0, *s1;
719
0
    const segment *s0s, *s1s;
720
0
    int count0, count1, search_limit = 50;
721
0
    int min_length = fixed_1 * 1;
722
723
    /* This is a simplified algorithm, which only checks for quazi-colinear vertical lines.
724
       "Quazi-vertical" means dx <= 1 && dy >= min_length . */
725
    /* To avoid a big unuseful expence of the processor time,
726
       we search the first subpath from the end
727
       (assuming that it was recently merged near the end),
728
       and restrict the search with search_limit segments
729
       against a quadratic scanning of two long subpaths.
730
       Thus algorithm is not necessary finds anything contacting.
731
       Instead it either quickly finds something, or maybe not. */
732
0
    for (s0 = sp0last, count0 = 0; count0 < search_limit && s0 != (segment *)sp0; s0 = s0->prev, count0++) {
733
0
        s0s = s0->prev;
734
0
        if ((s0->type == s_line || s0->type == s_gap) &&
735
0
            (s0s->pt.x == s0->pt.x ||
736
0
             (any_abs(s0s->pt.x - s0->pt.x) == 1 &&
737
0
              any_abs(s0s->pt.y - s0->pt.y) > min_length))) {
738
0
            for (s1 = sp1last, count1 = 0; count1 < search_limit && s1 != (segment *)sp1; s1 = s1->prev, count1++) {
739
0
                s1s = s1->prev;
740
0
                if ((s1->type == s_line || s1->type == s_gap) &&
741
0
                    (s1s->pt.x == s1->pt.x ||
742
0
                     (any_abs(s1s->pt.x - s1->pt.x) == 1 && any_abs(s1s->pt.y - s1->pt.y) > min_length))) {
743
0
                    if (s0s->pt.x == s1s->pt.x || s0->pt.x == s1->pt.x || s0->pt.x == s1s->pt.x || s0s->pt.x == s1->pt.x) {
744
0
                        if (s0s->pt.y < s0->pt.y && s1s->pt.y > s1->pt.y) {
745
0
                            fixed y0 = max(s0s->pt.y, s1->pt.y);
746
0
                            fixed y1 = min(s0->pt.y, s1s->pt.y);
747
748
0
                            if (y0 <= y1) {
749
0
                                *sc0 = s0;
750
0
                                *sc1 = s1;
751
0
                                return true;
752
0
                            }
753
0
                        }
754
0
                        if (s0s->pt.y > s0->pt.y && s1s->pt.y < s1->pt.y) {
755
0
                            fixed y0 = max(s0->pt.y, s1s->pt.y);
756
0
                            fixed y1 = min(s0s->pt.y, s1->pt.y);
757
758
0
                            if (y0 <= y1) {
759
0
                                *sc0 = s0;
760
0
                                *sc1 = s1;
761
0
                                return true;
762
0
                            }
763
0
                        }
764
0
                    }
765
0
                }
766
0
            }
767
0
        }
768
0
    }
769
0
    return false;
770
0
}
771
772
int
773
gx_path_merge_contacting_contours(gx_path *ppath)
774
0
{
775
    /* Now this is a simplified algorithm,
776
       which merge only contours by a common quazi-vertical line. */
777
    /* Note the merged contour is not equivalent to sum of original contours,
778
       because we ignore small coordinate differences within fixed_epsilon. */
779
0
    int window = 5/* max spot holes */ * 6/* segments per subpath */;
780
0
    subpath *sp0 = ppath->segments->contents.subpath_first;
781
782
0
    for (; sp0 != NULL; sp0 = (subpath *)sp0->last->next) {
783
0
        segment *sp0last = sp0->last;
784
0
        subpath *sp1 = (subpath *)sp0last->next, *spnext;
785
0
        subpath *sp1p = sp0;
786
0
        int count;
787
788
0
        for (count = 0; sp1 != NULL && count < window; sp1 = spnext, count++) {
789
0
            segment *sp1last = sp1->last;
790
0
            segment *sc0, *sc1, *old_first;
791
792
0
            spnext = (subpath *)sp1last->next;
793
0
            if (find_contacting_segments(sp0, sp0last, sp1, sp1last, &sc0, &sc1)) {
794
                /* Detach the subpath 1 from the path: */
795
0
                sp1->prev->next = sp1last->next;
796
0
                if (sp1last->next != NULL)
797
0
                    sp1last->next->prev = sp1->prev;
798
0
                sp1->prev = 0;
799
0
                sp1last->next = 0;
800
0
                old_first = sp1->next;
801
                /* sp1 is not longer in use. Move subpath_current from it for safe removing : */
802
0
                if (ppath->segments->contents.subpath_current == sp1) {
803
0
                    ppath->segments->contents.subpath_current = sp1p;
804
0
                }
805
0
                if (sp1last->type == s_line_close) {
806
                    /* Change 'closepath' of the subpath 1 to a line (maybe degenerate) : */
807
0
                    sp1last->type = s_line;
808
                    /* sp1 is not longer in use. Free it : */
809
0
                    gs_free_object(gs_memory_stable(ppath->memory), sp1, "gx_path_merge_contacting_contours");
810
0
                } else if (sp1last->pt.x == sp1->pt.x && sp1last->pt.y == sp1->pt.y) {
811
                    /* Implicit closepath with zero length. Don't need a new segment. */
812
                    /* sp1 is not longer in use. Free it : */
813
0
                    gs_free_object(gs_memory_stable(ppath->memory), sp1, "gx_path_merge_contacting_contours");
814
0
                } else {
815
                    /* Insert the closing line segment. */
816
                    /* sp1 is not longer in use. Convert it to the line segment : */
817
0
                    sp1->type = s_line;
818
0
                    sp1last->next = (segment *)sp1;
819
0
                    sp1->next = NULL;
820
0
                    sp1->prev = sp1last;
821
0
                    sp1->last = NULL; /* Safety for garbager. */
822
0
                    sp1last = (segment *)sp1;
823
0
                }
824
0
                sp1 = 0; /* Safety. */
825
                /* Rotate the subpath 1 to sc1 : */
826
0
                {   /* Detach s_start and make a loop : */
827
0
                    sp1last->next = old_first;
828
0
                    old_first->prev = sp1last;
829
                    /* Unlink before sc1 : */
830
0
                    sp1last = sc1->prev;
831
0
                    sc1->prev->next = 0;
832
0
                    sc1->prev = 0; /* Safety. */
833
                    /* sp1 is not longer in use. Free it : */
834
0
                    if (ppath->segments->contents.subpath_current == sp1) {
835
0
                        ppath->segments->contents.subpath_current = sp1p;
836
0
                    }
837
0
                    gs_free_object(gs_memory_stable(ppath->memory), sp1, "gx_path_merge_contacting_contours");
838
0
                    sp1 = 0; /* Safety. */
839
0
                }
840
                /* Insert the subpath 1 into the subpath 0 before sc0 :*/
841
0
                sc0->prev->next = sc1;
842
0
                sc1->prev = sc0->prev;
843
0
                sp1last->next = sc0;
844
0
                sc0->prev = sp1last;
845
                /* Remove degenearte "bridge" segments : (fixme: Not done due to low importance). */
846
                /* Edit the subpath count : */
847
0
                ppath->subpath_count--;
848
0
            } else
849
0
                sp1p = sp1;
850
0
        }
851
0
    }
852
0
    return 0;
853
0
}
854
855
static int
856
is_colinear(gs_fixed_rect *rect, fixed x, fixed y)
857
26.3k
{
858
26.3k
    fixed x0 = rect->p.x;
859
26.3k
    fixed y0 = rect->p.y;
860
26.3k
    fixed x1 = rect->q.x;
861
26.3k
    fixed y1 = rect->q.y;
862
863
26.3k
    if (x0 == x1) {
864
12.4k
        if (y0 == y1) {
865
            /* Initial case */
866
            /* Still counts as colinear */
867
10.5k
        } else if (x == x0) {
868
            /* OK! */
869
1.60k
        } else {
870
1.60k
            return 0; /* Not colinear */
871
1.60k
        }
872
13.8k
    } else if (rect->p.y == rect->q.y) {
873
5.96k
        if (y == rect->p.y) {
874
            /* OK */
875
5.69k
        } else {
876
266
            return 0; /* Not colinear */
877
266
        }
878
7.93k
    } else {
879
        /* Need to do hairy maths */
880
        /* The distance of a point (x,y) from the line passing through
881
         * (x0,y0) and (x1,y1) is:
882
         * d = |(y1-y0)x - (x1-x0)y + x1y0 - y1x0| / SQR((y1-y0)^2 + (x1-x0)^2)
883
         *
884
         * We want d <= epsilon to count as colinear.
885
         *
886
         * d = |(y1-y0)x - (x1-x0)y + x1y0 - y1x0| / SQR((y1-y0)^2 + (x1-x0)^2) <= epsilon
887
         *
888
         * |(y1-y0)x - (x1-x0)y + x1y0 - y1x0| <= epsilon * SQR((y1-y0)^2 + (x1-x0)^2)
889
         *
890
         * ((y1-y0)x - (x1-x0)y + x1y0 - y1x0)^2 <= epsilon^2 * ((y1-y0)^2 + (x1-x0)^2)
891
         */
892
7.93k
        int64_t ix1 = ((int64_t)x1);
893
7.93k
        int64_t iy1 = ((int64_t)y1);
894
7.93k
        int64_t dx  = ix1 - x0;
895
7.93k
        int64_t dy  = iy1 - y0;
896
7.93k
        int64_t num = dy*x - dx*y + ix1*y0 - iy1*x0;
897
7.93k
        int64_t den = dx*dx + dy*dy;
898
7.93k
        int epsilon_squared = 2;
899
900
7.93k
        if (num < 0)
901
1.19k
            num = -num;
902
8.51k
        while (num > (1<<30)) {
903
584
            num >>= 2;
904
584
            den >>= 1;
905
584
            if (den == 0)
906
0
                return 0; /* Not colinear */
907
584
        }
908
7.93k
        num *= num;
909
7.93k
        if (num > epsilon_squared * den)
910
7.33k
            return 0;
911
7.93k
    }
912
    /* rect is not really a rect. It's just a pair of points. We guarantee that x0 <= x1. */
913
17.1k
    if (x == x0) {
914
3.76k
        if (y < y0)
915
227
            rect->p.y = y;
916
3.53k
        else if (y > y1)
917
1.52k
            rect->q.y = y;
918
13.3k
    } else if (x < x0) {
919
2.79k
        rect->p.x = x;
920
2.79k
        rect->p.y = y;
921
10.5k
    } else {
922
10.5k
        rect->q.x = x;
923
10.5k
        rect->q.y = y;
924
10.5k
    }
925
926
17.1k
    return 1;
927
26.3k
}
928
929
static int
930
gx_path_copy_eliding_1d(const gx_path *ppath_old, gx_path *ppath)
931
8.70k
{
932
8.70k
    const segment *pseg;
933
    /*
934
     * Since we're going to be adding to the path, unshare it
935
     * before we start.
936
     */
937
8.70k
    int code = gx_path_unshare(ppath);
938
939
8.70k
    if (code < 0)
940
0
        return code;
941
#ifdef DEBUG
942
    if (gs_debug_c('P'))
943
        gx_dump_path(ppath_old, "before eliding_1d");
944
#endif
945
946
8.70k
    pseg = (const segment *)(ppath_old->first_subpath);
947
18.1k
    while (pseg != NULL) {
948
9.41k
        const segment *look = pseg;
949
9.41k
        gs_fixed_rect rect;
950
951
9.41k
        rect.p.x = rect.q.x = look->pt.x;
952
9.41k
        rect.p.y = rect.q.y = look->pt.y;
953
954
9.41k
        if (look->type != s_start) {
955
0
            dlprintf("Unlikely?");
956
0
        }
957
958
9.41k
        look = look->next;
959
24.0k
        while (look != NULL && look->type != s_start) {
960
23.8k
            if (look->type == s_curve) {
961
7.21k
                const curve_segment *pc = (const curve_segment *)look;
962
7.21k
                if (!is_colinear(&rect, pc->p1.x, pc->p1.y) ||
963
1.26k
                    !is_colinear(&rect, pc->p2.x, pc->p2.y) ||
964
1.18k
                    !is_colinear(&rect, pc->pt.x, pc->pt.y))
965
6.68k
                    goto not_colinear;
966
16.6k
            } else if (!is_colinear(&rect, look->pt.x, look->pt.y)) {
967
2.51k
                goto not_colinear;
968
2.51k
            }
969
14.6k
            look = look->next;
970
14.6k
        }
971
213
        pseg = look;
972
213
        if (0)
973
0
        {
974
9.20k
not_colinear:
975
            /* Not colinear. We want to keep this section. */
976
163k
            while (look != NULL && look->type != s_start)
977
154k
                look = look->next;
978
181k
            while (pseg != look && code >= 0) {
979
                /* Copy */
980
172k
                switch (pseg->type) {
981
9.20k
                    case s_start:
982
9.20k
                        code = gx_path_add_point(ppath,
983
9.20k
                                                 pseg->pt.x, pseg->pt.y);
984
9.20k
                        break;
985
27.6k
                    case s_curve:
986
27.6k
                        {
987
27.6k
                            const curve_segment *pc = (const curve_segment *)pseg;
988
989
27.6k
                            code = gx_path_add_curve_notes(ppath,
990
27.6k
                                             pc->p1.x, pc->p1.y, pc->p2.x, pc->p2.y,
991
27.6k
                                                   pc->pt.x, pc->pt.y, pseg->notes);
992
27.6k
                            break;
993
0
                        }
994
132k
                    case s_line:
995
132k
                        code = gx_path_add_line_notes(ppath,
996
132k
                                               pseg->pt.x, pseg->pt.y, pseg->notes);
997
132k
                        break;
998
0
                    case s_gap:
999
0
                        code = gx_path_add_gap_notes(ppath,
1000
0
                                               pseg->pt.x, pseg->pt.y, pseg->notes);
1001
0
                        break;
1002
0
                    case s_dash:
1003
0
                        {
1004
0
                            const dash_segment *pd = (const dash_segment *)pseg;
1005
1006
0
                            code = gx_path_add_dash_notes(ppath,
1007
0
                                               pd->pt.x, pd->pt.y, pd->tangent.x, pd->tangent.y, pseg->notes);
1008
0
                            break;
1009
0
                        }
1010
3.24k
                    case s_line_close:
1011
3.24k
                        code = gx_path_close_subpath(ppath);
1012
3.24k
                        break;
1013
0
                    default:    /* can't happen */
1014
0
                        code = gs_note_error(gs_error_unregistered);
1015
172k
                }
1016
172k
                pseg = pseg->next;
1017
172k
            }
1018
9.20k
            if (code < 0) {
1019
0
                gx_path_new(ppath);
1020
0
                return code;
1021
0
            }
1022
9.20k
        }
1023
213
    }
1024
8.70k
    ppath->bbox_set = false;
1025
#ifdef DEBUG
1026
    if (gs_debug_c('P'))
1027
        gx_dump_path(ppath, "after eliding_1d");
1028
#endif
1029
8.70k
    return 0;
1030
8.70k
}
1031
1032
int
1033
gx_path_elide_1d(gx_path *ppath)
1034
8.70k
{
1035
8.70k
    int code;
1036
8.70k
    gx_path path;
1037
1038
8.70k
    gx_path_init_local(&path, ppath->memory);
1039
8.70k
    code = gx_path_copy_eliding_1d(ppath, &path);
1040
8.70k
    if (code < 0)
1041
0
        return code;
1042
8.70k
    gx_path_assign_free(ppath, &path);
1043
8.70k
    gx_path_free(&path, "gx_path_elide_1d");
1044
1045
8.70k
    return 0;
1046
8.70k
}