/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 |