Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gxpflat.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Path flattening algorithms */
18
#include "string_.h"
19
#include "gx.h"
20
#include "gserrors.h"
21
#include "gxarith.h"
22
#include "gxfixed.h"
23
#include "gzpath.h"
24
#include "memory_.h"
25
26
/* ---------------- Curve flattening ---------------- */
27
28
/*
29
 * To calculate how many points to sample along a path in order to
30
 * approximate it to the desired degree of flatness, we define
31
 *      dist((x,y)) = abs(x) + abs(y);
32
 * then the number of points we need is
33
 *      N = 1 + sqrt(3/4 * D / flatness),
34
 * where
35
 *      D = max(dist(p0 - 2*p1 + p2), dist(p1 - 2*p2 + p3)).
36
 * Since we are going to use a power of 2 for the number of intervals,
37
 * we can avoid the square root by letting
38
 *      N = 1 + 2^(ceiling(log2(3/4 * D / flatness) / 2)).
39
 * (Reference: DEC Paris Research Laboratory report #1, May 1989.)
40
 *
41
 * We treat two cases specially.  First, if the curve is very
42
 * short, we halve the flatness, to avoid turning short shallow curves
43
 * into short straight lines.  Second, if the curve forms part of a
44
 * character (indicated by flatness = 0), we let
45
 *      N = 1 + 2 * max(abs(x3-x0), abs(y3-y0)).
46
 * This is probably too conservative, but it produces good results.
47
 */
48
int
49
gx_curve_log2_samples(fixed x0, fixed y0, const curve_segment * pc,
50
                      fixed fixed_flat)
51
64.5M
{
52
64.5M
    fixed
53
64.5M
        x03 = pc->pt.x - x0,
54
64.5M
        y03 = pc->pt.y - y0;
55
64.5M
    int k;
56
57
64.5M
    if (x03 < 0)
58
29.0M
        x03 = -x03;
59
64.5M
    if (y03 < 0)
60
30.6M
        y03 = -y03;
61
64.5M
    if ((x03 | y03) < int2fixed(16))
62
29.5M
        fixed_flat >>= 1;
63
64.5M
    if (fixed_flat == 0) { /* Use the conservative method. */
64
5.43k
        fixed m = max(x03, y03);
65
66
8.30k
        for (k = 1; m > fixed_1;)
67
2.86k
            k++, m >>= 1;
68
64.5M
    } else {
69
64.5M
        const fixed
70
64.5M
              x12 = pc->p1.x - pc->p2.x, y12 = pc->p1.y - pc->p2.y,
71
64.5M
              dx0 = x0 - pc->p1.x - x12, dy0 = y0 - pc->p1.y - y12,
72
64.5M
              dx1 = x12 - pc->p2.x + pc->pt.x, dy1 = y12 - pc->p2.y + pc->pt.y,
73
64.5M
              adx0 = any_abs(dx0), ady0 = any_abs(dy0),
74
64.5M
              adx1 = any_abs(dx1), ady1 = any_abs(dy1);
75
64.5M
        fixed
76
64.5M
            d = max(adx0, adx1) + max(ady0, ady1);
77
        /*
78
         * The following statement is split up to work around a
79
         * bug in the gcc 2.7.2 optimizer on H-P RISC systems.
80
         */
81
64.5M
        uint qtmp = d - (d >> 2) /* 3/4 * D */ +fixed_flat - 1;
82
64.5M
        uint q = qtmp / fixed_flat;
83
84
64.5M
        if_debug6('2', "[2]d01=%g,%g d12=%g,%g d23=%g,%g\n",
85
64.5M
                  fixed2float(pc->p1.x - x0), fixed2float(pc->p1.y - y0),
86
64.5M
                  fixed2float(-x12), fixed2float(-y12),
87
64.5M
                  fixed2float(pc->pt.x - pc->p2.x), fixed2float(pc->pt.y - pc->p2.y));
88
64.5M
        if_debug2('2', "     D=%f, flat=%f,",
89
64.5M
                  fixed2float(d), fixed2float(fixed_flat));
90
        /* Now we want to set k = ceiling(log2(q) / 2). */
91
290M
        for (k = 0; q > 1;)
92
226M
            k++, q = (q + 3) >> 2;
93
64.5M
        if_debug1('2', " k=%d\n", k);
94
64.5M
    }
95
64.5M
    return k;
96
64.5M
}
97
98
/*
99
 * Split a curve segment into two pieces at the (parametric) midpoint.
100
 * Algorithm is from "The Beta2-split: A special case of the Beta-spline
101
 * Curve and Surface Representation," B. A. Barsky and A. D. DeRose, IEEE,
102
 * 1985, courtesy of Crispin Goswell.
103
 */
104
static void
105
split_curve_midpoint(fixed x0, fixed y0, const curve_segment * pc,
106
                     curve_segment * pc1, curve_segment * pc2)
107
1.09M
{       /*
108
                                 * We have to define midpoint carefully to avoid overflow.
109
                                 * (If it overflows, something really pathological is going
110
                                 * on, but we could get infinite recursion that way....)
111
                                 */
112
1.09M
#define midpoint(a,b)\
113
13.0M
  (arith_rshift_1(a) + arith_rshift_1(b) + (((a) | (b)) & 1))
114
1.09M
    fixed x12 = midpoint(pc->p1.x, pc->p2.x);
115
1.09M
    fixed y12 = midpoint(pc->p1.y, pc->p2.y);
116
117
    /*
118
     * pc1 or pc2 may be the same as pc, so we must be a little careful
119
     * about the order in which we store the results.
120
     */
121
1.09M
    pc1->p1.x = midpoint(x0, pc->p1.x);
122
1.09M
    pc1->p1.y = midpoint(y0, pc->p1.y);
123
1.09M
    pc2->p2.x = midpoint(pc->p2.x, pc->pt.x);
124
1.09M
    pc2->p2.y = midpoint(pc->p2.y, pc->pt.y);
125
1.09M
    pc1->p2.x = midpoint(pc1->p1.x, x12);
126
1.09M
    pc1->p2.y = midpoint(pc1->p1.y, y12);
127
1.09M
    pc2->p1.x = midpoint(x12, pc2->p2.x);
128
1.09M
    pc2->p1.y = midpoint(y12, pc2->p2.y);
129
1.09M
    if (pc2 != pc)
130
0
        pc2->pt.x = pc->pt.x,
131
0
            pc2->pt.y = pc->pt.y;
132
1.09M
    pc1->pt.x = midpoint(pc1->p2.x, pc2->p1.x);
133
1.09M
    pc1->pt.y = midpoint(pc1->p2.y, pc2->p1.y);
134
1.09M
#undef midpoint
135
1.09M
}
136
137
static inline void
138
print_points(const gs_fixed_point *points, int count)
139
52.5M
{
140
#ifdef DEBUG
141
    int i;
142
143
    if (!gs_debug_c('3'))
144
        return;
145
    for (i = 0; i < count; i++)
146
      if_debug2('3', "[3]out x=%ld y=%ld\n",
147
                (long)points[i].x, (long)points[i].y);
148
#endif
149
52.5M
}
150
151
bool
152
curve_coeffs_ranged(fixed x0, fixed x1, fixed x2, fixed x3,
153
                    fixed y0, fixed y1, fixed y2, fixed y3,
154
                    fixed *ax, fixed *bx, fixed *cx,
155
                    fixed *ay, fixed *by, fixed *cy,
156
                    int k)
157
35.9M
{
158
35.9M
    fixed x01, x12, y01, y12;
159
160
35.9M
    curve_points_to_coefficients(x0, x1, x2, x3,
161
35.9M
                                 *ax, *bx, *cx, x01, x12);
162
35.9M
    curve_points_to_coefficients(y0, y1, y2, y3,
163
35.9M
                                 *ay, *by, *cy, y01, y12);
164
637M
#   define max_fast (max_fixed / 6)
165
425M
#   define min_fast (-max_fast)
166
392M
#   define in_range(v) (v < max_fast && v > min_fast)
167
35.9M
    if (k > k_sample_max ||
168
35.9M
        !in_range(*ax) || !in_range(*ay) ||
169
35.9M
        !in_range(*bx) || !in_range(*by) ||
170
35.9M
        !in_range(*cx) || !in_range(*cy)
171
35.9M
        )
172
1.09M
        return false;
173
34.8M
#undef max_fast
174
34.8M
#undef min_fast
175
34.8M
#undef in_range
176
34.8M
    return true;
177
35.9M
}
178
179
/*  Initialize the iterator.
180
    Momotonic curves with non-zero length are only allowed.
181
 */
182
bool
183
gx_flattened_iterator__init(gx_flattened_iterator *self,
184
            fixed x0, fixed y0, const curve_segment *pc, int k)
185
35.9M
{
186
    /* Note : Immediately after the ininialization it keeps an invalid (zero length) segment. */
187
35.9M
    fixed x1, y1, x2, y2;
188
35.9M
    const int k2 = k << 1, k3 = k2 + k;
189
35.9M
    fixed bx2, by2, ax6, ay6;
190
191
35.9M
    x1 = pc->p1.x;
192
35.9M
    y1 = pc->p1.y;
193
35.9M
    x2 = pc->p2.x;
194
35.9M
    y2 = pc->p2.y;
195
35.9M
    self->x0 = self->lx0 = self->lx1 = x0;
196
35.9M
    self->y0 = self->ly0 = self->ly1 = y0;
197
35.9M
    self->x3 = pc->pt.x;
198
35.9M
    self->y3 = pc->pt.y;
199
35.9M
    if (!curve_coeffs_ranged(self->x0, x1, x2, self->x3,
200
35.9M
                             self->y0, y1, y2, self->y3,
201
35.9M
                             &self->ax, &self->bx, &self->cx,
202
35.9M
                             &self->ay, &self->by, &self->cy, k))
203
1.09M
        return false;
204
34.8M
    self->curve = true;
205
34.8M
    self->k = k;
206
#ifdef DEBUG
207
        if (gs_debug_c('3')) {
208
            dlprintf4("[3]x0=%f y0=%f x1=%f y1=%f\n",
209
                      fixed2float(self->x0), fixed2float(self->y0),
210
                      fixed2float(x1), fixed2float(y1));
211
            dlprintf5("   x2=%f y2=%f x3=%f y3=%f  k=%d\n",
212
                      fixed2float(x2), fixed2float(y2),
213
                      fixed2float(self->x3), fixed2float(self->y3), self->k);
214
        }
215
#endif
216
34.8M
    if (k == -1) {
217
        /* A special hook for gx_subdivide_curve_rec.
218
           Only checked the range.
219
           Returning with no initialization. */
220
363
        return true;
221
363
    }
222
34.8M
    self->rmask = (1 << k3) - 1;
223
34.8M
    self->i = (1 << k);
224
34.8M
    self->rx = self->ry = 0;
225
34.8M
    if_debug6('3', "[3]ax=%f bx=%f cx=%f\n   ay=%f by=%f cy=%f\n",
226
34.8M
              fixed2float(self->ax), fixed2float(self->bx), fixed2float(self->cx),
227
34.8M
              fixed2float(self->ay), fixed2float(self->by), fixed2float(self->cy));
228
34.8M
    bx2 = self->bx << 1;
229
34.8M
    by2 = self->by << 1;
230
34.8M
    ax6 = ((self->ax << 1) + self->ax) << 1;
231
34.8M
    ay6 = ((self->ay << 1) + self->ay) << 1;
232
34.8M
    self->idx = arith_rshift(self->cx, self->k);
233
34.8M
    self->idy = arith_rshift(self->cy, self->k);
234
34.8M
    self->rdx = ((uint)self->cx << k2) & self->rmask;
235
34.8M
    self->rdy = ((uint)self->cy << k2) & self->rmask;
236
    /* bx/y terms */
237
34.8M
    self->id2x = arith_rshift(bx2, k2);
238
34.8M
    self->id2y = arith_rshift(by2, k2);
239
34.8M
    self->rd2x = ((uint)bx2 << self->k) & self->rmask;
240
34.8M
    self->rd2y = ((uint)by2 << self->k) & self->rmask;
241
209M
#   define adjust_rem(r, q, rmask) if ( r > rmask ) q ++, r &= rmask
242
    /* We can compute all the remainders as ints, */
243
    /* because we know they don't exceed M. */
244
    /* cx/y terms */
245
34.8M
    self->idx += arith_rshift_1(self->id2x);
246
34.8M
    self->idy += arith_rshift_1(self->id2y);
247
34.8M
    self->rdx += ((uint)self->bx << self->k) & self->rmask,
248
34.8M
    self->rdy += ((uint)self->by << self->k) & self->rmask;
249
34.8M
    adjust_rem(self->rdx, self->idx, self->rmask);
250
34.8M
    adjust_rem(self->rdy, self->idy, self->rmask);
251
    /* ax/y terms */
252
34.8M
    self->idx += arith_rshift(self->ax, k3);
253
34.8M
    self->idy += arith_rshift(self->ay, k3);
254
34.8M
    self->rdx += (uint)self->ax & self->rmask;
255
34.8M
    self->rdy += (uint)self->ay & self->rmask;
256
34.8M
    adjust_rem(self->rdx, self->idx, self->rmask);
257
34.8M
    adjust_rem(self->rdy, self->idy, self->rmask);
258
34.8M
    self->id2x += self->id3x = arith_rshift(ax6, k3);
259
34.8M
    self->id2y += self->id3y = arith_rshift(ay6, k3);
260
34.8M
    self->rd2x += self->rd3x = (uint)ax6 & self->rmask,
261
34.8M
    self->rd2y += self->rd3y = (uint)ay6 & self->rmask;
262
34.8M
    adjust_rem(self->rd2x, self->id2x, self->rmask);
263
34.8M
    adjust_rem(self->rd2y, self->id2y, self->rmask);
264
34.8M
#   undef adjust_rem
265
34.8M
    return true;
266
34.8M
}
267
268
static inline bool
269
check_diff_overflow(fixed v0, fixed v1)
270
222M
{
271
222M
    if (v1 > 0)
272
205M
        return (v0 < min_fixed + v1);
273
16.4M
    else if (v1 < 0)
274
16.0M
        return (v0 > max_fixed + v1);
275
445k
    return false;
276
222M
}
277
278
bool
279
gx_check_fixed_diff_overflow(fixed v0, fixed v1)
280
222M
{
281
222M
    return check_diff_overflow(v0, v1);
282
222M
}
283
bool
284
gx_check_fixed_sum_overflow(fixed v0, fixed v1)
285
68.7k
{
286
    /* We assume that clamp_point_aux have been applied to v1,
287
       thus -v alweays exists.
288
     */
289
68.7k
    return check_diff_overflow(v0, -v1);
290
68.7k
}
291
292
/*  Initialize the iterator with a line. */
293
bool
294
gx_flattened_iterator__init_line(gx_flattened_iterator *self,
295
            fixed x0, fixed y0, fixed x1, fixed y1)
296
0
{
297
0
    bool ox = check_diff_overflow(x0, x1);
298
0
    bool oy = check_diff_overflow(y0, y1);
299
300
0
    self->x0 = self->lx0 = self->lx1 = x0;
301
0
    self->y0 = self->ly0 = self->ly1 = y0;
302
0
    self->x3 = x1;
303
0
    self->y3 = y1;
304
0
    if (ox || oy) {
305
        /* Subdivide a long line into 4 segments, because the filling algorithm
306
           and the stroking algorithm need to compute differences
307
           of coordinates of end points.
308
           We can't use 2 segments, because gx_flattened_iterator__next
309
           implements a special code for that case,
310
           which requires differences of coordinates as well.
311
         */
312
        /* Note : the result of subdivision may be not strongly colinear. */
313
0
        self->ax = self->bx = 0;
314
0
        self->ay = self->by = 0;
315
0
        self->cx = ((ox ? (x1 >> 1) - (x0 >> 1) : (x1 - x0) >> 1) + 1) >> 1;
316
0
        self->cy = ((oy ? (y1 >> 1) - (y0 >> 1) : (y1 - y0) >> 1) + 1) >> 1;
317
0
        self->rd3x = self->rd3y = self->id3x = self->id3y = 0;
318
0
        self->rd2x = self->rd2y = self->id2x = self->id2y = 0;
319
0
        self->idx = self->cx;
320
0
        self->idy = self->cy;
321
0
        self->rdx = self->rdy = 0;
322
0
        self->rx = self->ry = 0;
323
0
        self->rmask = 0;
324
0
        self->k = 2;
325
0
        self->i = 4;
326
0
    } else {
327
0
        self->k = 0;
328
0
        self->i = 1;
329
0
    }
330
0
    self->curve = false;
331
0
    return true;
332
0
}
333
334
#ifdef DEBUG
335
static inline void
336
gx_flattened_iterator__print_state(gx_flattened_iterator *self)
337
{
338
    if (!gs_debug_c('3'))
339
        return;
340
    dlprintf4("[3]dx=%f+%d, dy=%f+%d\n",
341
              fixed2float(self->idx), self->rdx,
342
              fixed2float(self->idy), self->rdy);
343
    dlprintf4("   d2x=%f+%d, d2y=%f+%d\n",
344
              fixed2float(self->id2x), self->rd2x,
345
              fixed2float(self->id2y), self->rd2y);
346
    dlprintf4("   d3x=%f+%d, d3y=%f+%d\n",
347
              fixed2float(self->id3x), self->rd3x,
348
              fixed2float(self->id3y), self->rd3y);
349
}
350
#endif
351
352
/* Move to the next segment and store it to self->lx0, self->ly0, self->lx1, self->ly1 .
353
 * Return true iff there exist more segments.
354
 */
355
int
356
gx_flattened_iterator__next(gx_flattened_iterator *self)
357
1.04G
{
358
    /*
359
     * We can compute successive values by finite differences,
360
     * using the formulas:
361
     x(t) =
362
     a*t^3 + b*t^2 + c*t + d =>
363
     dx(t) = x(t+e)-x(t) =
364
     a*(3*t^2*e + 3*t*e^2 + e^3) + b*(2*t*e + e^2) + c*e =
365
     (3*a*e)*t^2 + (3*a*e^2 + 2*b*e)*t + (a*e^3 + b*e^2 + c*e) =>
366
     d2x(t) = dx(t+e)-dx(t) =
367
     (3*a*e)*(2*t*e + e^2) + (3*a*e^2 + 2*b*e)*e =
368
     (6*a*e^2)*t + (6*a*e^3 + 2*b*e^2) =>
369
     d3x(t) = d2x(t+e)-d2x(t) =
370
     6*a*e^3;
371
     x(0) = d, dx(0) = (a*e^3 + b*e^2 + c*e),
372
     d2x(0) = 6*a*e^3 + 2*b*e^2;
373
     * In these formulas, e = 1/2^k; of course, there are separate
374
     * computations for the x and y values.
375
     *
376
     * There is a tradeoff in doing the above computation in fixed
377
     * point.  If we separate out the constant term (d) and require that
378
     * all the other values fit in a long, then on a 32-bit machine with
379
     * 12 bits of fraction in a fixed, k = 4 implies a maximum curve
380
     * size of 128 pixels; anything larger requires subdividing the
381
     * curve.  On the other hand, doing the computations in explicit
382
     * double precision slows down the loop by a factor of 3 or so.  We
383
384
     * found to our surprise that the latter is actually faster, because
385
     * the additional subdivisions cost more than the slower loop.
386
     *
387
     * We represent each quantity as I+R/M, where I is an "integer" and
388
     * the "remainder" R lies in the range 0 <= R < M=2^(3*k).  Note
389
     * that R may temporarily exceed M; for this reason, we require that
390
     * M have at least one free high-order bit.  To reduce the number of
391
     * variables, we don't actually compute M, only M-1 (rmask).  */
392
1.04G
    fixed x = self->lx1, y = self->ly1;
393
394
1.04G
    if (self->i <= 0)
395
0
        return_error(gs_error_unregistered); /* Must not happen. */
396
1.04G
    self->lx0 = self->lx1;
397
1.04G
    self->ly0 = self->ly1;
398
    /* Fast check for N == 3, a common special case for small characters. */
399
1.04G
    if (self->k <= 1) {
400
18.1M
        --self->i;
401
18.1M
        if (self->i == 0)
402
13.0M
            goto last;
403
10.0M
# define poly2(a,b,c) arith_rshift_1(arith_rshift_1(arith_rshift_1(a) + b) + c)
404
5.03M
        x += poly2(self->ax, self->bx, self->cx);
405
5.03M
        y += poly2(self->ay, self->by, self->cy);
406
5.03M
# undef poly2
407
5.03M
        if_debug2('3', "[3]dx=%f, dy=%f\n",
408
5.03M
                  fixed2float(x - self->x0), fixed2float(y - self->y0));
409
5.03M
        if_debug5('3', "[3]%s x=%g, y=%g x=%ld y=%ld\n",
410
5.03M
                  (((x ^ self->x0) | (y ^ self->y0)) & float2fixed(-0.5) ?
411
5.03M
                   "add" : "skip"),
412
5.03M
                  fixed2float(x), fixed2float(y), (long)x, (long)y);
413
5.03M
        self->lx1 = x, self->ly1 = y;
414
5.03M
        return true;
415
1.02G
    } else {
416
1.02G
        --self->i;
417
1.02G
        if (self->i == 0)
418
21.7M
            goto last; /* don't bother with last accum */
419
# ifdef DEBUG
420
            gx_flattened_iterator__print_state(self);
421
# endif
422
1.00G
# define accum(i, r, di, dr, rmask)\
423
6.01G
                        if ( (r += dr) > rmask ) r &= rmask, i += di + 1;\
424
6.01G
                        else i += di
425
1.00G
        accum(x, self->rx, self->idx, self->rdx, self->rmask);
426
1.00G
        accum(y, self->ry, self->idy, self->rdy, self->rmask);
427
1.00G
        accum(self->idx, self->rdx, self->id2x, self->rd2x, self->rmask);
428
1.00G
        accum(self->idy, self->rdy, self->id2y, self->rd2y, self->rmask);
429
1.00G
        accum(self->id2x, self->rd2x, self->id3x, self->rd3x, self->rmask);
430
1.00G
        accum(self->id2y, self->rd2y, self->id3y, self->rd3y, self->rmask);
431
1.00G
        if_debug5('3', "[3]%s x=%g, y=%g x=%ld y=%ld\n",
432
1.00G
                  (((x ^ self->lx0) | (y ^ self->ly0)) & float2fixed(-0.5) ?
433
1.00G
                   "add" : "skip"),
434
1.00G
                  fixed2float(x), fixed2float(y), (long)x, (long)y);
435
1.00G
# undef accum
436
1.00G
        self->lx1 = self->x = x;
437
1.00G
        self->ly1 = self->y = y;
438
1.00G
        return true;
439
1.02G
    }
440
34.8M
last:
441
34.8M
    self->lx1 = self->x3;
442
34.8M
    self->ly1 = self->y3;
443
34.8M
    if_debug4('3', "[3]last x=%g, y=%g x=%ld y=%ld\n",
444
34.8M
              fixed2float(self->lx1), fixed2float(self->ly1),
445
34.8M
              (long)self->lx1, (long)self->ly1);
446
34.8M
    return false;
447
1.04G
}
448
449
static inline void
450
gx_flattened_iterator__unaccum(gx_flattened_iterator *self)
451
0
{
452
0
#   define unaccum(i, r, di, dr, rmask)\
453
0
                    if ( r < dr ) r += rmask + 1 - dr, i -= di + 1;\
454
0
                    else r -= dr, i -= di
455
0
    unaccum(self->id2x, self->rd2x, self->id3x, self->rd3x, self->rmask);
456
0
    unaccum(self->id2y, self->rd2y, self->id3y, self->rd3y, self->rmask);
457
0
    unaccum(self->idx, self->rdx, self->id2x, self->rd2x, self->rmask);
458
0
    unaccum(self->idy, self->rdy, self->id2y, self->rd2y, self->rmask);
459
0
    unaccum(self->x, self->rx, self->idx, self->rdx, self->rmask);
460
0
    unaccum(self->y, self->ry, self->idy, self->rdy, self->rmask);
461
0
#   undef unaccum
462
0
}
463
464
/* Move back to the previous segment and store it to self->lx0, self->ly0, self->lx1, self->ly1 .
465
 * This only works for states reached with gx_flattened_iterator__next.
466
 * Return true iff there exist more segments.
467
 */
468
int
469
gx_flattened_iterator__prev(gx_flattened_iterator *self)
470
0
{
471
0
    bool last; /* i.e. the first one in the forth order. */
472
473
0
    if (self->i >= 1 << self->k)
474
0
        return_error(gs_error_unregistered); /* Must not happen. */
475
0
    self->lx1 = self->lx0;
476
0
    self->ly1 = self->ly0;
477
0
    if (self->k <= 1) {
478
        /* If k==0, we have a single segment, return it.
479
           If k==1 && i < 2, return the last segment.
480
           Otherwise must not pass here.
481
           We caould allow to pass here with self->i == 1 << self->k,
482
           but we want to check the assertion about the last segment below.
483
         */
484
0
        self->i++;
485
0
        self->lx0 = self->x0;
486
0
        self->ly0 = self->y0;
487
0
        return false;
488
0
    }
489
0
    gx_flattened_iterator__unaccum(self);
490
0
    self->i++;
491
#   ifdef DEBUG
492
    if_debug5('3', "[3]%s x=%g, y=%g x=%ld y=%ld\n",
493
              (((self->x ^ self->lx1) | (self->y ^ self->ly1)) & float2fixed(-0.5) ?
494
               "add" : "skip"),
495
              fixed2float(self->x), fixed2float(self->y),
496
              (long)self->x, (long)self->y);
497
    gx_flattened_iterator__print_state(self);
498
#   endif
499
0
    last = (self->i == (1 << self->k) - 1);
500
0
    self->lx0 = self->x;
501
0
    self->ly0 = self->y;
502
0
    if (last)
503
0
        if (self->lx0 != self->x0 || self->ly0 != self->y0)
504
0
            return_error(gs_error_unregistered); /* Must not happen. */
505
0
    return !last;
506
0
}
507
508
/* Switching from the forward scanning to the backward scanning for the filtered1. */
509
void
510
gx_flattened_iterator__switch_to_backscan(gx_flattened_iterator *self, bool not_first)
511
0
{
512
    /*  When scanning forth, the accumulator stands on the end of a segment,
513
        except for the last segment.
514
        When scanning back, the accumulator should stand on the beginning of a segment.
515
        Assuming at least one forward step is done.
516
    */
517
0
    if (not_first)
518
0
        if (self->i > 0 && self->k != 1 /* This case doesn't use the accumulator. */)
519
0
            gx_flattened_iterator__unaccum(self);
520
0
}
521
522
1.04G
#define max_points 50    /* arbitrary */
523
524
static int
525
generate_segments(gx_path * ppath, const gs_fixed_point *points,
526
                    int count, segment_notes notes)
527
52.5M
{
528
52.5M
    if (notes & sn_not_first) {
529
52.5M
        print_points(points, count);
530
52.5M
        return gx_path_add_lines_notes(ppath, points, count, notes);
531
52.5M
    } else {
532
0
        int code;
533
534
0
        print_points(points, 1);
535
0
        code = gx_path_add_line_notes(ppath, points[0].x, points[0].y, notes);
536
0
        if (code < 0)
537
0
            return code;
538
0
        print_points(points + 1, count - 1);
539
0
        return gx_path_add_lines_notes(ppath, points + 1, count - 1, notes | sn_not_first);
540
0
    }
541
52.5M
}
542
543
static int
544
gx_subdivide_curve_rec(gx_flattened_iterator *self,
545
                  gx_path * ppath, int k, curve_segment * pc,
546
                  segment_notes notes, gs_fixed_point *points)
547
34.8M
{
548
34.8M
    int code;
549
550
35.9M
top :
551
35.9M
    if (!gx_flattened_iterator__init(self,
552
35.9M
                ppath->position.x, ppath->position.y, pc, k)) {
553
        /* Curve is too long.  Break into two pieces and recur. */
554
1.09M
        curve_segment cseg;
555
556
1.09M
        k--;
557
1.09M
        split_curve_midpoint(ppath->position.x, ppath->position.y, pc, &cseg, pc);
558
1.09M
        code = gx_subdivide_curve_rec(self, ppath, k, &cseg, notes, points);
559
1.09M
        if (code < 0)
560
0
            return code;
561
1.09M
        notes |= sn_not_first;
562
1.09M
        goto top;
563
34.8M
    } else if (k < 0) {
564
        /* This used to be k == -1, but... If we have a very long curve, we will first
565
         * go through the code above to split the long curve into 2. In fact for very
566
         * long curves we can go through that multiple times. This can lead to k being
567
         * < -1 by the time we finish subdividing the curve, and that meant we did not
568
         * satisfy the exit condition here, leading to a loop until VM error.
569
         */
570
        /* fixme : Don't need to init the iterator. Just wanted to check in_range. */
571
1.55k
        return gx_path_add_curve_notes(ppath, pc->p1.x, pc->p1.y, pc->p2.x, pc->p2.y,
572
1.55k
                        pc->pt.x, pc->pt.y, notes);
573
34.8M
    } else {
574
34.8M
        gs_fixed_point *ppt = points;
575
34.8M
        bool more;
576
577
1.04G
        for(;;) {
578
1.04G
            code = gx_flattened_iterator__next(self);
579
580
1.04G
            if (code < 0)
581
0
                return code;
582
1.04G
            more = code;
583
1.04G
            ppt->x = self->lx1;
584
1.04G
            ppt->y = self->ly1;
585
1.04G
            ppt++;
586
1.04G
            if (ppt == &points[max_points] || !more) {
587
52.5M
                gs_fixed_point *pe = (more ?  ppt - 2 : ppt);
588
589
52.5M
                code = generate_segments(ppath, points, pe - points, notes);
590
52.5M
                if (code < 0)
591
0
                    return code;
592
52.5M
                if (!more)
593
34.8M
                    return 0;
594
17.6M
                notes |= sn_not_first;
595
17.6M
                memcpy(points, pe, (char *)ppt - (char *)pe);
596
17.6M
                ppt = points + (ppt - pe);
597
17.6M
            }
598
1.04G
        }
599
34.8M
    }
600
35.9M
}
601
602
#undef coord_near
603
604
/*
605
 * Flatten a segment of the path by repeated sampling.
606
 * 2^k is the number of lines to produce (i.e., the number of points - 1,
607
 * including the endpoints); we require k >= 1.
608
 * If k or any of the coefficient values are too large,
609
 * use recursive subdivision to whittle them down.
610
 */
611
612
int
613
gx_subdivide_curve(gx_path * ppath, int k, curve_segment * pc, segment_notes notes)
614
33.7M
{
615
33.7M
    gs_fixed_point points[max_points + 1];
616
33.7M
    gx_flattened_iterator iter;
617
618
33.7M
    return gx_subdivide_curve_rec(&iter, ppath, k, pc, notes, points);
619
33.7M
}
620
621
#undef max_points