Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_fixcpp/sys/src/cmd/gs/src/gxpflat.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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