Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gxpcopy.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* 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
34.0M
{
33
34.0M
    fixed x0 = ppath->position.x;
34
34.0M
    fixed y0 = ppath->position.y;
35
36
34.0M
    if (gx_check_fixed_diff_overflow(pseg->pt.x, x0) ||
37
34.0M
        gx_check_fixed_diff_overflow(pseg->pt.y, y0)) {
38
6.57k
        fixed x, y;
39
40
6.57k
        if (gx_check_fixed_sum_overflow(pseg->pt.x, x0))
41
389
            x = (pseg->pt.x >> 1) + (x0 >> 1);
42
6.19k
        else
43
6.19k
            x = (pseg->pt.x + x0) >> 1;
44
6.57k
        if (gx_check_fixed_sum_overflow(pseg->pt.y, y0))
45
136
            y = (pseg->pt.y >> 1) + (y0 >> 1);
46
6.44k
        else
47
6.44k
            y = (pseg->pt.y + y0) >> 1;
48
6.57k
        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
6.57k
    }
54
34.0M
    return 0;
55
34.0M
}
56
static inline int
57
break_gap_if_long(gx_path *ppath, const segment *pseg)
58
0
{
59
0
    fixed x0 = ppath->position.x;
60
0
    fixed y0 = ppath->position.y;
61
62
0
    if (gx_check_fixed_diff_overflow(pseg->pt.x, x0) ||
63
0
        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
0
    return 0;
81
0
}
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
5.38M
{
90
5.38M
    const segment *pseg;
91
5.38M
    fixed flat = fixed_flatness;
92
5.38M
    gs_fixed_point expansion;
93
    /*
94
     * Since we're going to be adding to the path, unshare it
95
     * before we start.
96
     */
97
5.38M
    int code = gx_path_unshare(ppath);
98
99
5.38M
    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
5.38M
    if (options & pco_for_stroke) {
106
        /* Precompute the maximum expansion of the bounding box. */
107
113k
        double width = pgs->line_params.half_width;
108
109
113k
        expansion.x =
110
113k
            float2fixed((fabs(pgs->ctm.xx) + fabs(pgs->ctm.yx)) * width) * 2;
111
113k
        expansion.y =
112
113k
            float2fixed((fabs(pgs->ctm.xy) + fabs(pgs->ctm.yy)) * width) * 2;
113
113k
    } else
114
5.26M
        expansion.x = expansion.y = 0; /* Quiet gcc warning. */
115
5.38M
    pseg = (const segment *)(ppath_old->first_subpath);
116
74.9M
    while (pseg) {
117
69.5M
        switch (pseg->type) {
118
6.44M
            case s_start:
119
6.44M
                code = gx_path_add_point(ppath,
120
6.44M
                                         pseg->pt.x, pseg->pt.y);
121
6.44M
                break;
122
29.1M
            case s_curve:
123
29.1M
                {
124
29.1M
                    const curve_segment *pc = (const curve_segment *)pseg;
125
126
29.1M
                    if (fixed_flatness == max_fixed) { /* don't flatten */
127
14.2M
                        if (options & pco_monotonize)
128
0
                            code = gx_curve_monotonize(ppath, pc);
129
14.2M
                        else
130
14.2M
                            code = gx_path_add_curve_notes(ppath,
131
14.2M
                                     pc->p1.x, pc->p1.y, pc->p2.x, pc->p2.y,
132
14.2M
                                           pc->pt.x, pc->pt.y, pseg->notes);
133
14.9M
                    } else {
134
14.9M
                        fixed x0 = ppath->position.x;
135
14.9M
                        fixed y0 = ppath->position.y;
136
14.9M
                        segment_notes notes = pseg->notes;
137
14.9M
                        curve_segment cseg;
138
14.9M
                        int k;
139
140
14.9M
                        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
1.32M
                            fixed min01, max01, min23, max23;
152
1.32M
                            fixed ex, ey, flat_x, flat_y;
153
154
1.32M
#define SET_EXTENT(r, c0, c1, c2, c3)\
155
2.64M
    BEGIN\
156
2.64M
        if (c0 < c1) min01 = c0, max01 = c1;\
157
2.64M
        else         min01 = c1, max01 = c0;\
158
2.64M
        if (c2 < c3) min23 = c2, max23 = c3;\
159
2.64M
        else         min23 = c3, max23 = c2;\
160
2.64M
        r = max(max01, max23) - min(min01, min23);\
161
2.64M
    END
162
1.32M
                            SET_EXTENT(ex, x0, pc->p1.x, pc->p2.x, pc->pt.x);
163
1.32M
                            SET_EXTENT(ey, y0, pc->p1.y, pc->p2.y, pc->pt.y);
164
1.32M
#undef SET_EXTENT
165
                            /*
166
                             * We check for the degenerate case specially
167
                             * to avoid a division by zero.
168
                             */
169
1.32M
                            if (ex == 0 || ey == 0)
170
18.6k
                                if (ex != 0) {
171
9.62k
                                    flat = fixed_mult_quo(fixed_flatness, ex,
172
9.62k
                                                          ex + expansion.x);
173
9.62k
                                    k = gx_curve_log2_samples(x0,y0,pc,flat);
174
9.62k
                                } else if (ey != 0) {
175
3.43k
                                    flat = fixed_mult_quo(fixed_flatness, ey,
176
3.43k
                                                          ey + expansion.y);
177
3.43k
                                    k = gx_curve_log2_samples(x0,y0,pc,flat);
178
3.43k
                                } else
179
5.63k
                                    k = 0;
180
1.30M
                            else {
181
1.30M
                                flat_x =
182
1.30M
                                    fixed_mult_quo(fixed_flatness, ex,
183
1.30M
                                                   ex + expansion.x);
184
1.30M
                                flat_y =
185
1.30M
                                    fixed_mult_quo(fixed_flatness, ey,
186
1.30M
                                                   ey + expansion.y);
187
1.30M
                                flat = min(flat_x, flat_y);
188
1.30M
                                k = gx_curve_log2_samples(x0, y0, pc, flat);
189
1.30M
                            }
190
1.32M
                        } else
191
13.5M
                            k = gx_curve_log2_samples(x0, y0, pc, flat);
192
14.9M
                        if (options & pco_accurate) {
193
14.9M
                            segment *start;
194
14.9M
                            segment *end;
195
196
                            /*
197
                             * Add an extra line, which will become
198
                             * the tangent segment.
199
                             */
200
14.9M
                            code = gx_path_add_line_notes(ppath, x0, y0,
201
14.9M
                                                          notes);
202
14.9M
                            if (code < 0)
203
0
                                break;
204
14.9M
                            start = ppath->current_subpath->last;
205
14.9M
                            notes |= sn_not_first;
206
14.9M
                            cseg = *pc;
207
14.9M
                            code = gx_subdivide_curve(ppath, k, &cseg, notes);
208
14.9M
                            if (code < 0)
209
2
                                break;
210
                            /*
211
                             * Adjust the first and last segments so that
212
                             * they line up with the tangents.
213
                             */
214
14.9M
                            end = ppath->current_subpath->last;
215
14.9M
                            if ((code = gx_path_add_line_notes(ppath,
216
14.9M
                                                          ppath->position.x,
217
14.9M
                                                          ppath->position.y,
218
14.9M
                                            pseg->notes | sn_not_first)) < 0)
219
0
                                break;
220
14.9M
                            if (start->next->pt.x != pc->p1.x || start->next->pt.y != pc->p1.y)
221
14.8M
                                adjust_point_to_tangent(start, start->next, &pc->p1);
222
26.6k
                            else if (start->next->pt.x != pc->p2.x || start->next->pt.y != pc->p2.y)
223
602
                                adjust_point_to_tangent(start, start->next, &pc->p2);
224
26.0k
                            else
225
26.0k
                                adjust_point_to_tangent(start, start->next, &end->prev->pt);
226
14.9M
                            if (end->prev->pt.x != pc->p2.x || end->prev->pt.y != pc->p2.y)
227
14.8M
                                adjust_point_to_tangent(end, end->prev, &pc->p2);
228
38.1k
                            else if (end->prev->pt.x != pc->p1.x || end->prev->pt.y != pc->p1.y)
229
313
                                adjust_point_to_tangent(end, end->prev, &pc->p1);
230
37.8k
                            else
231
37.8k
                                adjust_point_to_tangent(end, end->prev, &start->pt);
232
14.9M
                        } else {
233
0
                            cseg = *pc;
234
0
                            code = gx_subdivide_curve(ppath, k, &cseg, notes);
235
0
                        }
236
14.9M
                    }
237
29.1M
                    break;
238
29.1M
                }
239
29.1M
            case s_line:
240
28.1M
                code = break_line_if_long(ppath, pseg);
241
28.1M
                if (code < 0)
242
0
                    break;
243
28.1M
                code = gx_path_add_line_notes(ppath,
244
28.1M
                                       pseg->pt.x, pseg->pt.y, pseg->notes);
245
28.1M
                break;
246
0
            case s_gap:
247
0
                code = break_gap_if_long(ppath, pseg);
248
0
                if (code < 0)
249
0
                    break;
250
0
                code = gx_path_add_gap_notes(ppath,
251
0
                                       pseg->pt.x, pseg->pt.y, pseg->notes);
252
0
                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
0
                }
261
5.90M
            case s_line_close:
262
5.90M
                code = break_line_if_long(ppath, pseg);
263
5.90M
                if (code < 0)
264
0
                    break;
265
5.90M
                code = gx_path_close_subpath(ppath);
266
5.90M
                break;
267
0
            default:    /* can't happen */
268
0
                code = gs_note_error(gs_error_unregistered);
269
69.5M
        }
270
69.5M
        if (code < 0) {
271
2
            gx_path_new(ppath);
272
2
            return code;
273
2
        }
274
69.5M
        pseg = pseg->next;
275
69.5M
    }
276
5.38M
    if (path_last_is_moveto(ppath_old)) {
277
604k
        code = gx_path_add_point(ppath, ppath_old->position.x,
278
604k
                          ppath_old->position.y);
279
604k
        if (code < 0) {
280
0
            gx_path_new(ppath);
281
0
            return code;
282
0
        }
283
604k
    }
284
5.38M
    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
5.38M
    return 0;
300
5.38M
}
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
29.8M
{
317
29.8M
    const fixed x0 = pseg->pt.x, y0 = pseg->pt.y;
318
29.8M
    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
29.8M
    if (fC == 0) {
326
        /* Vertical tangent. */
327
4.88M
        const fixed DT = arith_rshift(next->pt.y - y0, 2);
328
329
4.88M
        if (fD == 0)
330
354k
            return;    /* anomalous case */
331
4.88M
        if_debug1('2', "[2]adjusting vertical: DT = %g\n",
332
4.53M
                  fixed2float(DT));
333
4.53M
        if ((DT ^ fD) > 0) /* lgtm [cpp/bitwise-sign-check] */
334
4.50M
            pseg->pt.y = DT + y0;
335
24.9M
    } else if (fD == 0) {
336
        /* Horizontal tangent. */
337
5.79M
        const fixed CT = arith_rshift(next->pt.x - x0, 2);
338
339
5.79M
        if_debug1('2', "[2]adjusting horizontal: CT = %g\n",
340
5.79M
                  fixed2float(CT));
341
5.79M
        if ((CT ^ fC) > 0) /* lgtm [cpp/bitwise-sign-check] */
342
5.77M
            pseg->pt.x = CT + x0;
343
19.1M
    } else {
344
        /* General case. */
345
19.1M
        const double C = fC, D = fD;
346
19.1M
        double T = (C * (next->pt.x - x0) + D * (next->pt.y - y0)) /
347
19.1M
        (C * C + D * D);
348
349
19.1M
        if_debug3('2', "[2]adjusting: C = %g, D = %g, T = %g\n",
350
19.1M
                  C, D, T);
351
19.1M
        if (T > 0) {
352
19.1M
            if (T > 1) {
353
                /* Don't go outside the curve bounding box. */
354
9.24M
                T = 1;
355
9.24M
            }
356
19.1M
            pseg->pt.x = arith_rshift((fixed) (C * T), 2) + x0;
357
19.1M
            pseg->pt.y = arith_rshift((fixed) (D * T), 2) + y0;
358
19.1M
        }
359
19.1M
    }
360
29.8M
}
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
548k
{
438
548k
    const segment *pseg = (const segment *)(ppath->first_subpath);
439
548k
    gs_fixed_point pt0;
440
441
548k
    pt0.x = pt0.y = 0; /* Quiet gcc warning. */
442
3.83M
    while (pseg) {
443
3.29M
        switch (pseg->type) {
444
590k
            case s_start:
445
590k
                break;
446
2.70M
            default:
447
2.70M
                if (gx_check_fixed_diff_overflow(pseg->pt.x, pt0.x) ||
448
2.70M
                    gx_check_fixed_diff_overflow(pseg->pt.y, pt0.y))
449
1.93k
                    return true;
450
2.69M
                break;
451
3.29M
        }
452
3.28M
        pt0 = pseg->pt;
453
3.28M
        pseg = pseg->next;
454
3.28M
    }
455
546k
    return false;
456
548k
}
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
0
{
463
0
    fixed x0 = ppath->position.x, y0 = ppath->position.y;
464
0
    segment_notes notes = pc->notes;
465
0
    double t[5], tt = 1, tp;
466
0
    int c[5];
467
0
    int n0, n1, n, i, j, k = 0;
468
0
    fixed ax, bx, cx, ay, by, cy, v01, v12;
469
0
    fixed px, py, qx, qy, rx, ry, sx, sy;
470
0
    const double delta = 0.0000001;
471
472
    /* Roots of the derivative : */
473
0
    n0 = gx_curve_monotonic_points(x0, pc->p1.x, pc->p2.x, pc->pt.x, t);
474
0
    n1 = gx_curve_monotonic_points(y0, pc->p1.y, pc->p2.y, pc->pt.y, t + n0);
475
0
    n = n0 + n1;
476
0
    if (n == 0)
477
0
        return gx_path_add_curve_notes(ppath, pc->p1.x, pc->p1.y,
478
0
                pc->p2.x, pc->p2.y, pc->pt.x, pc->pt.y, notes);
479
0
    if (n0 > 0)
480
0
        c[0] = 1;
481
0
    if (n0 > 1)
482
0
        c[1] = 1;
483
0
    if (n1 > 0)
484
0
        c[n0] = 2;
485
0
    if (n1 > 1)
486
0
        c[n0 + 1] = 2;
487
    /* Order roots : */
488
0
    for (i = 0; i < n; i++)
489
0
        for (j = i + 1; j < n; j++)
490
0
            if (t[i] > t[j]) {
491
0
                int w;
492
0
                double v = t[i]; t[i] = t[j]; t[j] = v;
493
0
                w = c[i]; c[i] = c[j]; c[j] = w;
494
0
            }
495
    /* Drop roots near zero : */
496
0
    for (k = 0; k < n; k++)
497
0
        if (t[k] >= delta)
498
0
            break;
499
    /* Merge close roots, and drop roots at 1 : */
500
0
    if (t[n - 1] > 1 - delta)
501
0
        n--;
502
0
    for (i = k + 1, j = k; i < n && t[k] < 1 - delta; i++)
503
0
        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
0
        } else {
507
0
            j++;
508
0
            t[j] = t[i];
509
0
            c[j] = c[i];
510
0
        }
511
0
    n = j + 1;
512
    /* Do split : */
513
0
    curve_points_to_coefficients(x0, pc->p1.x, pc->p2.x, pc->pt.x, ax, bx, cx, v01, v12);
514
0
    curve_points_to_coefficients(y0, pc->p1.y, pc->p2.y, pc->pt.y, ay, by, cy, v01, v12);
515
0
    ax *= 3, bx *= 2; /* Coefficients of the derivative. */
516
0
    ay *= 3, by *= 2;
517
0
    px = x0;
518
0
    py = y0;
519
0
    qx = (fixed)((pc->p1.x - px) * t[0] + 0.5);
520
0
    qy = (fixed)((pc->p1.y - py) * t[0] + 0.5);
521
0
    tp = 0;
522
0
    for (i = k; i < n; i++) {
523
0
        double ti = t[i];
524
0
        double t2 = ti * ti, t3 = t2 * ti;
525
0
        double omt = 1 - ti, omt2 = omt * omt, omt3 = omt2 * omt;
526
0
        double x = x0 * omt3 + 3 * pc->p1.x * omt2 * ti + 3 * pc->p2.x * omt * t2 + pc->pt.x * t3;
527
0
        double y = y0 * omt3 + 3 * pc->p1.y * omt2 * ti + 3 * pc->p2.y * omt * t2 + pc->pt.y * t3;
528
0
        double ddx = (c[i] & 1 ? 0 : ax * t2 + bx * ti + cx); /* Suppress noise. */
529
0
        double ddy = (c[i] & 2 ? 0 : ay * t2 + by * ti + cy);
530
0
        fixed dx = (fixed)(ddx + 0.5);
531
0
        fixed dy = (fixed)(ddy + 0.5);
532
0
        int code;
533
534
0
        tt = (i + 1 < n ? t[i + 1] : 1) - ti;
535
0
        rx = (fixed)(dx * (t[i] - tp) / 3 + 0.5);
536
0
        ry = (fixed)(dy * (t[i] - tp) / 3 + 0.5);
537
0
        sx = (fixed)(x + 0.5);
538
0
        sy = (fixed)(y + 0.5);
539
        /* Suppress the derivative sign noise near a peak : */
540
0
        if ((double)(sx - px) * qx + (double)(sy - py) * qy < 0)
541
0
            qx = -qx, qy = -qy;
542
0
        if ((double)(sx - px) * rx + (double)(sy - py) * ry < 0)
543
0
            rx = -rx, ry = -qy;
544
        /* Do add : */
545
0
        code = gx_path_add_curve_notes(ppath, px + qx, py + qy, sx - rx, sy - ry, sx, sy, notes);
546
0
        if (code < 0)
547
0
            return code;
548
0
        notes |= sn_not_first;
549
0
        px = sx;
550
0
        py = sy;
551
0
        qx = (fixed)(dx * tt / 3 + 0.5);
552
0
        qy = (fixed)(dy * tt / 3 + 0.5);
553
0
        tp = t[i];
554
0
    }
555
0
    sx = pc->pt.x;
556
0
    sy = pc->pt.y;
557
0
    rx = (fixed)((pc->pt.x - pc->p2.x) * tt + 0.5);
558
0
    ry = (fixed)((pc->pt.y - pc->p2.y) * tt + 0.5);
559
    /* Suppress the derivative sign noise near peaks : */
560
0
    if ((double)(sx - px) * qx + (double)(sy - py) * qy < 0)
561
0
        qx = -qx, qy = -qy;
562
0
    if ((double)(sx - px) * rx + (double)(sy - py) * ry < 0)
563
0
        rx = -rx, ry = -qy;
564
0
    return gx_path_add_curve_notes(ppath, px + qx, py + qy, sx - rx, sy - ry, sx, sy, notes);
565
0
}
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
0
{
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
0
    fixed v01, v12, a, b, c, b2, a3;
596
0
    fixed dv_end, b2abs, a3abs;
597
598
0
    curve_points_to_coefficients(v0, v1, v2, v3, a, b, c, v01, v12);
599
0
    b2 = b << 1;
600
0
    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
0
    if (a == 0) {
606
0
        if ((b ^ c) < 0 && any_abs(c) < any_abs(b2) && c != 0) {
607
0
            *pst = (double)(-c) / b2;
608
0
            return 1;
609
0
        } else
610
0
            return 0;
611
0
    }
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
0
    if (c == 0) {
618
0
        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
0
            return 0;
623
0
    }
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
0
    else if ((dv_end = a3 + b2 + c) == 0) {
631
0
        if ((a ^ b) < 0 &&
632
0
            (b2abs = any_abs(b2)) > (a3abs = any_abs(a3)) &&
633
0
            b2abs < a3abs << 1
634
0
            ) {
635
0
            *pst = (double)(-b2 - a3) / a3;
636
0
            return 1;
637
0
        } else
638
0
            return 0;
639
0
    }
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
0
    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
0
    else if ((a ^ b) >= 0)
652
0
        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
0
    else if (any_abs(b) >= any_abs(a3))
667
0
        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
0
    {
675
0
        double nbf = (double)(-b);
676
0
        double a3f = (double)a3;
677
0
        double radicand = nbf * nbf - a3f * c;
678
679
0
        if (radicand < 0) {
680
0
            if_debug1('2', "[2]negative radicand = %g\n", radicand);
681
0
            return 0;
682
0
        } {
683
0
            double root = sqrt(radicand);
684
0
            int nzeros = 0;
685
0
            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
0
            if_debug2('2', "[2]zeros at %g, %g\n", z, (nbf + root) / a3f);
694
0
            if (z > 0 && z < 1)
695
0
                *pst = z, nzeros = 1;
696
0
            if (root != 0) {
697
0
                z = (nbf + root) / a3f;
698
0
                if (z > 0 && z < 1) {
699
0
                    if (nzeros && a3f < 0) /* order is reversed */
700
0
                        pst[1] = *pst, *pst = z;
701
0
                    else
702
0
                        pst[nzeros] = z;
703
0
                    nzeros++;
704
0
                }
705
0
            }
706
0
            return nzeros;
707
0
        }
708
0
    }
709
0
}
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
0
{
858
0
    fixed x0 = rect->p.x;
859
0
    fixed y0 = rect->p.y;
860
0
    fixed x1 = rect->q.x;
861
0
    fixed y1 = rect->q.y;
862
863
0
    if (x0 == x1) {
864
0
        if (y0 == y1) {
865
            /* Initial case */
866
            /* Still counts as colinear */
867
0
        } else if (x == x0) {
868
            /* OK! */
869
0
        } else {
870
0
            return 0; /* Not colinear */
871
0
        }
872
0
    } else if (rect->p.y == rect->q.y) {
873
0
        if (y == rect->p.y) {
874
            /* OK */
875
0
        } else {
876
0
            return 0; /* Not colinear */
877
0
        }
878
0
    } 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
0
        int64_t ix1 = ((int64_t)x1);
893
0
        int64_t iy1 = ((int64_t)y1);
894
0
        int64_t dx  = ix1 - x0;
895
0
        int64_t dy  = iy1 - y0;
896
0
        int64_t num = dy*x - dx*y + ix1*y0 - iy1*x0;
897
0
        int64_t den = dx*dx + dy*dy;
898
0
        int epsilon_squared = 2;
899
900
0
        if (num < 0)
901
0
            num = -num;
902
0
        while (num > (1<<30)) {
903
0
            num >>= 2;
904
0
            den >>= 1;
905
0
            if (den == 0)
906
0
                return 0; /* Not colinear */
907
0
        }
908
0
        num *= num;
909
0
        if (num > epsilon_squared * den)
910
0
            return 0;
911
0
    }
912
    /* rect is not really a rect. It's just a pair of points. We guarantee that x0 <= x1. */
913
0
    if (x == x0) {
914
0
        if (y < y0)
915
0
            rect->p.y = y;
916
0
        else if (y > y1)
917
0
            rect->q.y = y;
918
0
    } else if (x < x0) {
919
0
        rect->p.x = x;
920
0
        rect->p.y = y;
921
0
    } else {
922
0
        rect->q.x = x;
923
0
        rect->q.y = y;
924
0
    }
925
926
0
    return 1;
927
0
}
928
929
static int
930
gx_path_copy_eliding_1d(const gx_path *ppath_old, gx_path *ppath)
931
0
{
932
0
    const segment *pseg;
933
    /*
934
     * Since we're going to be adding to the path, unshare it
935
     * before we start.
936
     */
937
0
    int code = gx_path_unshare(ppath);
938
939
0
    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
0
    pseg = (const segment *)(ppath_old->first_subpath);
947
0
    while (pseg != NULL) {
948
0
        const segment *look = pseg;
949
0
        gs_fixed_rect rect;
950
951
0
        rect.p.x = rect.q.x = look->pt.x;
952
0
        rect.p.y = rect.q.y = look->pt.y;
953
954
0
        if (look->type != s_start) {
955
0
            dlprintf("Unlikely?");
956
0
        }
957
958
0
        look = look->next;
959
0
        while (look != NULL && look->type != s_start) {
960
0
            if (look->type == s_curve) {
961
0
                const curve_segment *pc = (const curve_segment *)look;
962
0
                if (!is_colinear(&rect, pc->p1.x, pc->p1.y) ||
963
0
                    !is_colinear(&rect, pc->p2.x, pc->p2.y) ||
964
0
                    !is_colinear(&rect, pc->pt.x, pc->pt.y))
965
0
                    goto not_colinear;
966
0
            } else if (!is_colinear(&rect, look->pt.x, look->pt.y)) {
967
0
                goto not_colinear;
968
0
            }
969
0
            look = look->next;
970
0
        }
971
0
        pseg = look;
972
0
        if (0)
973
0
        {
974
0
not_colinear:
975
            /* Not colinear. We want to keep this section. */
976
0
            while (look != NULL && look->type != s_start)
977
0
                look = look->next;
978
0
            while (pseg != look && code >= 0) {
979
                /* Copy */
980
0
                switch (pseg->type) {
981
0
                    case s_start:
982
0
                        code = gx_path_add_point(ppath,
983
0
                                                 pseg->pt.x, pseg->pt.y);
984
0
                        break;
985
0
                    case s_curve:
986
0
                        {
987
0
                            const curve_segment *pc = (const curve_segment *)pseg;
988
989
0
                            code = gx_path_add_curve_notes(ppath,
990
0
                                             pc->p1.x, pc->p1.y, pc->p2.x, pc->p2.y,
991
0
                                                   pc->pt.x, pc->pt.y, pseg->notes);
992
0
                            break;
993
0
                        }
994
0
                    case s_line:
995
0
                        code = gx_path_add_line_notes(ppath,
996
0
                                               pseg->pt.x, pseg->pt.y, pseg->notes);
997
0
                        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
0
                    case s_line_close:
1011
0
                        code = gx_path_close_subpath(ppath);
1012
0
                        break;
1013
0
                    default:    /* can't happen */
1014
0
                        code = gs_note_error(gs_error_unregistered);
1015
0
                }
1016
0
                pseg = pseg->next;
1017
0
            }
1018
0
            if (code < 0) {
1019
0
                gx_path_new(ppath);
1020
0
                return code;
1021
0
            }
1022
0
        }
1023
0
    }
1024
0
    ppath->bbox_set = false;
1025
#ifdef DEBUG
1026
    if (gs_debug_c('P'))
1027
        gx_dump_path(ppath, "after eliding_1d");
1028
#endif
1029
0
    return 0;
1030
0
}
1031
1032
int
1033
gx_path_elide_1d(gx_path *ppath)
1034
0
{
1035
0
    int code;
1036
0
    gx_path path;
1037
1038
0
    gx_path_init_local(&path, ppath->memory);
1039
0
    code = gx_path_copy_eliding_1d(ppath, &path);
1040
0
    if (code < 0)
1041
0
        return code;
1042
0
    gx_path_assign_free(ppath, &path);
1043
0
    gx_path_free(&path, "gx_path_elide_1d");
1044
1045
0
    return 0;
1046
0
}