1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: gxpcopy.c 9062 2008-09-03 11:42:35Z leonardo $ */
15
/* Path copying and flattening */
21
#include "gxistate.h" /* for access to line params */
25
/* Forward declarations */
26
static void adjust_point_to_tangent(segment *, const segment *,
27
const gs_fixed_point *);
30
break_line_if_long(gx_path *ppath, const segment *pseg)
32
fixed x0 = ppath->position.x;
33
fixed y0 = ppath->position.y;
35
if (gx_check_fixed_diff_overflow(pseg->pt.x, x0) ||
36
gx_check_fixed_diff_overflow(pseg->pt.y, y0)) {
39
if (gx_check_fixed_sum_overflow(pseg->pt.x, x0))
40
x = (pseg->pt.x >> 1) + (x0 >> 1);
42
x = (pseg->pt.x + x0) >> 1;
43
if (gx_check_fixed_sum_overflow(pseg->pt.y, y0))
44
y = (pseg->pt.y >> 1) + (y0 >> 1);
46
y = (pseg->pt.y + y0) >> 1;
47
return gx_path_add_line_notes(ppath, x, y, pseg->notes);
48
/* WARNING: Stringly speaking, the next half segment must get
49
the sn_not_first flag. We don't bother, because that flag
50
has no important meaning with colinear segments.
57
/* Copy a path, optionally flattening or monotonizing it. */
58
/* If the copy fails, free the new path. */
60
gx_path_copy_reducing(const gx_path *ppath_old, gx_path *ppath,
61
fixed fixed_flatness, const gs_imager_state *pis,
62
gx_path_copy_options options)
65
fixed flat = fixed_flatness;
66
gs_fixed_point expansion;
68
* Since we're going to be adding to the path, unshare it
71
int code = gx_path_unshare(ppath);
77
gx_dump_path(ppath_old, "before reducing");
79
if (options & pco_for_stroke) {
80
/* Precompute the maximum expansion of the bounding box. */
81
double width = pis->line_params.half_width;
84
float2fixed((fabs(pis->ctm.xx) + fabs(pis->ctm.yx)) * width) * 2;
86
float2fixed((fabs(pis->ctm.xy) + fabs(pis->ctm.yy)) * width) * 2;
88
expansion.x = expansion.y = 0; /* Quiet gcc warning. */
89
vd_setcolor(RGB(255,255,0));
90
pseg = (const segment *)(ppath_old->first_subpath);
94
code = gx_path_add_point(ppath,
95
pseg->pt.x, pseg->pt.y);
96
vd_moveto(pseg->pt.x, pseg->pt.y);
100
const curve_segment *pc = (const curve_segment *)pseg;
102
if (fixed_flatness == max_fixed) { /* don't flatten */
103
if (options & pco_monotonize)
104
code = gx_curve_monotonize(ppath, pc);
106
code = gx_path_add_curve_notes(ppath,
107
pc->p1.x, pc->p1.y, pc->p2.x, pc->p2.y,
108
pc->pt.x, pc->pt.y, pseg->notes);
110
fixed x0 = ppath->position.x;
111
fixed y0 = ppath->position.y;
112
segment_notes notes = pseg->notes;
116
if (options & pco_for_stroke) {
118
* When flattening for stroking, the flatness
119
* must apply to the outside of the resulting
120
* stroked region. We approximate this by
121
* dividing the flatness by the ratio of the
122
* expanded bounding box to the original
123
* bounding box. This is crude, but pretty
124
* simple to calculate, and produces reasonably
127
fixed min01, max01, min23, max23;
128
fixed ex, ey, flat_x, flat_y;
130
#define SET_EXTENT(r, c0, c1, c2, c3)\
132
if (c0 < c1) min01 = c0, max01 = c1;\
133
else min01 = c1, max01 = c0;\
134
if (c2 < c3) min23 = c2, max23 = c3;\
135
else min23 = c3, max23 = c2;\
136
r = max(max01, max23) - min(min01, min23);\
138
SET_EXTENT(ex, x0, pc->p1.x, pc->p2.x, pc->pt.x);
139
SET_EXTENT(ey, y0, pc->p1.y, pc->p2.y, pc->pt.y);
142
* We check for the degenerate case specially
143
* to avoid a division by zero.
145
if (ex == 0 || ey == 0)
149
fixed_mult_quo(fixed_flatness, ex,
152
fixed_mult_quo(fixed_flatness, ey,
154
flat = min(flat_x, flat_y);
155
k = gx_curve_log2_samples(x0, y0, pc, flat);
158
k = gx_curve_log2_samples(x0, y0, pc, flat);
159
if (options & pco_accurate) {
164
* Add an extra line, which will become
165
* the tangent segment.
167
code = gx_path_add_line_notes(ppath, x0, y0,
172
start = ppath->current_subpath->last;
173
notes |= sn_not_first;
175
code = gx_subdivide_curve(ppath, k, &cseg, notes);
179
* Adjust the first and last segments so that
180
* they line up with the tangents.
182
end = ppath->current_subpath->last;
183
vd_lineto(ppath->position.x, ppath->position.y);
184
if ((code = gx_path_add_line_notes(ppath,
187
pseg->notes | sn_not_first)) < 0)
189
if (start->next->pt.x != pc->p1.x || start->next->pt.y != pc->p1.y)
190
adjust_point_to_tangent(start, start->next, &pc->p1);
191
else if (start->next->pt.x != pc->p2.x || start->next->pt.y != pc->p2.y)
192
adjust_point_to_tangent(start, start->next, &pc->p2);
194
adjust_point_to_tangent(start, start->next, &end->prev->pt);
195
if (end->prev->pt.x != pc->p2.x || end->prev->pt.y != pc->p2.y)
196
adjust_point_to_tangent(end, end->prev, &pc->p2);
197
else if (end->prev->pt.x != pc->p1.x || end->prev->pt.y != pc->p1.y)
198
adjust_point_to_tangent(end, end->prev, &pc->p1);
200
adjust_point_to_tangent(end, end->prev, &start->pt);
203
code = gx_subdivide_curve(ppath, k, &cseg, notes);
209
code = break_line_if_long(ppath, pseg);
212
code = gx_path_add_line_notes(ppath,
213
pseg->pt.x, pseg->pt.y, pseg->notes);
214
vd_lineto(pseg->pt.x, pseg->pt.y);
218
const dash_segment *pd = (const dash_segment *)pseg;
220
code = gx_path_add_dash_notes(ppath,
221
pd->pt.x, pd->pt.y, pd->tangent.x, pd->tangent.y, pseg->notes);
225
code = break_line_if_long(ppath, pseg);
228
code = gx_path_close_subpath(ppath);
231
default: /* can't happen */
232
code = gs_note_error(gs_error_unregistered);
240
if (path_last_is_moveto(ppath_old))
241
gx_path_add_point(ppath, ppath_old->position.x,
242
ppath_old->position.y);
243
if (ppath_old->bbox_set) {
244
if (ppath->bbox_set) {
245
ppath->bbox.p.x = min(ppath_old->bbox.p.x, ppath->bbox.p.x);
246
ppath->bbox.p.y = min(ppath_old->bbox.p.y, ppath->bbox.p.y);
247
ppath->bbox.q.x = max(ppath_old->bbox.q.x, ppath->bbox.q.x);
248
ppath->bbox.q.y = max(ppath_old->bbox.q.y, ppath->bbox.q.y);
250
ppath->bbox_set = true;
251
ppath->bbox = ppath_old->bbox;
256
gx_dump_path(ppath, "after reducing");
262
* Adjust one end of a line (the first or last line of a flattened curve)
263
* so it falls on the curve tangent. The closest point on the line from
264
* (0,0) to (C,D) to a point (U,V) -- i.e., the point on the line at which
265
* a perpendicular line from the point intersects it -- is given by
266
* T = (C*U + D*V) / (C^2 + D^2)
268
* However, any smaller value of T will also work: the one we actually
269
* use is 0.25 * the value we just derived. We must check that
270
* numerical instabilities don't lead to a negative value of T.
273
adjust_point_to_tangent(segment * pseg, const segment * next,
274
const gs_fixed_point * p1)
276
const fixed x0 = pseg->pt.x, y0 = pseg->pt.y;
277
const fixed fC = p1->x - x0, fD = p1->y - y0;
280
* By far the commonest case is that the end of the curve is
281
* horizontal or vertical. Check for this specially, because
282
* we can handle it with far less work (and no floating point).
285
/* Vertical tangent. */
286
const fixed DT = arith_rshift(next->pt.y - y0, 2);
289
return; /* anomalous case */
290
if_debug1('2', "[2]adjusting vertical: DT = %g\n",
293
pseg->pt.y = DT + y0;
294
} else if (fD == 0) {
295
/* Horizontal tangent. */
296
const fixed CT = arith_rshift(next->pt.x - x0, 2);
298
if_debug1('2', "[2]adjusting horizontal: CT = %g\n",
301
pseg->pt.x = CT + x0;
304
const double C = fC, D = fD;
305
double T = (C * (next->pt.x - x0) + D * (next->pt.y - y0)) /
308
if_debug3('2', "[2]adjusting: C = %g, D = %g, T = %g\n",
312
/* Don't go outside the curve bounding box. */
315
pseg->pt.x = arith_rshift((fixed) (C * T), 2) + x0;
316
pseg->pt.y = arith_rshift((fixed) (D * T), 2) + y0;
321
/* ---------------- Monotonic curves ---------------- */
323
/* Test whether a path is free of non-monotonic curves. */
325
gx_path__check_curves(const gx_path * ppath, gx_path_copy_options options, fixed fixed_flat)
327
const segment *pseg = (const segment *)(ppath->first_subpath);
330
pt0.x = pt0.y = 0; /* Quiet gcc warning. */
332
switch (pseg->type) {
335
const subpath *psub = (const subpath *)pseg;
337
/* Skip subpaths without curves. */
338
if (!psub->curve_count)
343
if (gx_check_fixed_diff_overflow(pseg->pt.x, pt0.x) ||
344
gx_check_fixed_diff_overflow(pseg->pt.y, pt0.y))
349
const curve_segment *pc = (const curve_segment *)pseg;
351
if (options & pco_monotonize) {
353
int nz = gx_curve_monotonic_points(pt0.y,
354
pc->p1.y, pc->p2.y, pc->pt.y, t);
358
nz = gx_curve_monotonic_points(pt0.x,
359
pc->p1.x, pc->p2.x, pc->pt.x, t);
363
if (options & pco_small_curves) {
364
fixed ax, bx, cx, ay, by, cy;
365
int k = gx_curve_log2_samples(pt0.x, pt0.y, pc, fixed_flat);
367
if(!curve_coeffs_ranged(pt0.x, pc->p1.x, pc->p2.x, pc->pt.x,
368
pt0.y, pc->p1.y, pc->p2.y, pc->pt.y,
369
&ax, &bx, &cx, &ay, &by, &cy, k))
371
if (gx_check_fixed_diff_overflow(pseg->pt.x, pt0.x) ||
372
gx_check_fixed_diff_overflow(pseg->pt.y, pt0.y))
386
/* Test whether a path is free of long segments. */
387
/* WARNING : This function checks the distance between
388
* the starting point and the ending point of a segment.
389
* When they are not too far, a curve nevertheless may be too long.
390
* Don't worry about it here, because we assume
391
* this function is never called with paths which have curves.
394
gx_path_has_long_segments(const gx_path * ppath)
396
const segment *pseg = (const segment *)(ppath->first_subpath);
399
pt0.x = pt0.y = 0; /* Quiet gcc warning. */
401
switch (pseg->type) {
405
if (gx_check_fixed_diff_overflow(pseg->pt.x, pt0.x) ||
406
gx_check_fixed_diff_overflow(pseg->pt.y, pt0.y))
416
/* Monotonize a curve, by splitting it if necessary. */
417
/* In the worst case, this could split the curve into 9 pieces. */
419
gx_curve_monotonize(gx_path * ppath, const curve_segment * pc)
421
fixed x0 = ppath->position.x, y0 = ppath->position.y;
422
segment_notes notes = pc->notes;
423
double t[4], tt = 1, tp;
425
int n0, n1, n, i, j, k = 0;
426
fixed ax, bx, cx, ay, by, cy, v01, v12;
427
fixed px, py, qx, qy, rx, ry, sx, sy;
428
const double delta = 0.0000001;
430
/* Roots of the derivative : */
431
n0 = gx_curve_monotonic_points(x0, pc->p1.x, pc->p2.x, pc->pt.x, t);
432
n1 = gx_curve_monotonic_points(y0, pc->p1.y, pc->p2.y, pc->pt.y, t + n0);
435
return gx_path_add_curve_notes(ppath, pc->p1.x, pc->p1.y,
436
pc->p2.x, pc->p2.y, pc->pt.x, pc->pt.y, notes);
446
for (i = 0; i < n; i++)
447
for (j = i + 1; j < n; j++)
450
double v = t[i]; t[i] = t[j]; t[j] = v;
451
w = c[i]; c[i] = c[j]; c[j] = w;
453
/* Drop roots near zero : */
454
for (k = 0; k < n; k++)
457
/* Merge close roots, and drop roots at 1 : */
458
if (t[n - 1] > 1 - delta)
460
for (i = k + 1, j = k; i < n && t[k] < 1 - delta; i++)
461
if (any_abs(t[i] - t[j]) < delta) {
462
t[j] = (t[j] + t[i]) / 2; /* Unlikely 3 roots are close. */
471
curve_points_to_coefficients(x0, pc->p1.x, pc->p2.x, pc->pt.x, ax, bx, cx, v01, v12);
472
curve_points_to_coefficients(y0, pc->p1.y, pc->p2.y, pc->pt.y, ay, by, cy, v01, v12);
473
ax *= 3, bx *= 2; /* Coefficients of the derivative. */
477
qx = (fixed)((pc->p1.x - px) * t[0] + 0.5);
478
qy = (fixed)((pc->p1.y - py) * t[0] + 0.5);
480
for (i = k; i < n; i++) {
482
double t2 = ti * ti, t3 = t2 * ti;
483
double omt = 1 - ti, omt2 = omt * omt, omt3 = omt2 * omt;
484
double x = x0 * omt3 + 3 * pc->p1.x * omt2 * ti + 3 * pc->p2.x * omt * t2 + pc->pt.x * t3;
485
double y = y0 * omt3 + 3 * pc->p1.y * omt2 * ti + 3 * pc->p2.y * omt * t2 + pc->pt.y * t3;
486
double ddx = (c[i] & 1 ? 0 : ax * t2 + bx * ti + cx); /* Suppress noise. */
487
double ddy = (c[i] & 2 ? 0 : ay * t2 + by * ti + cy);
488
fixed dx = (fixed)(ddx + 0.5);
489
fixed dy = (fixed)(ddy + 0.5);
492
tt = (i + 1 < n ? t[i + 1] : 1) - ti;
493
rx = (fixed)(dx * (t[i] - tp) / 3 + 0.5);
494
ry = (fixed)(dy * (t[i] - tp) / 3 + 0.5);
495
sx = (fixed)(x + 0.5);
496
sy = (fixed)(y + 0.5);
497
/* Suppress the derivative sign noise near a peak : */
498
if ((double)(sx - px) * qx + (double)(sy - py) * qy < 0)
500
if ((double)(sx - px) * rx + (double)(sy - py) * ry < 0)
503
code = gx_path_add_curve_notes(ppath, px + qx, py + qy, sx - rx, sy - ry, sx, sy, notes);
506
notes |= sn_not_first;
509
qx = (fixed)(dx * tt / 3 + 0.5);
510
qy = (fixed)(dy * tt / 3 + 0.5);
515
rx = (fixed)((pc->pt.x - pc->p2.x) * tt + 0.5);
516
ry = (fixed)((pc->pt.y - pc->p2.y) * tt + 0.5);
517
/* Suppress the derivative sign noise near peaks : */
518
if ((double)(sx - px) * qx + (double)(sy - py) * qy < 0)
520
if ((double)(sx - px) * rx + (double)(sy - py) * ry < 0)
522
return gx_path_add_curve_notes(ppath, px + qx, py + qy, sx - rx, sy - ry, sx, sy, notes);
526
* Split a curve if necessary into pieces that are monotonic in X or Y as a
527
* function of the curve parameter t. This allows us to rasterize curves
528
* directly without pre-flattening. This takes a fair amount of analysis....
529
* Store the values of t of the split points in pst[0] and pst[1]. Return
530
* the number of split points (0, 1, or 2).
533
gx_curve_monotonic_points(fixed v0, fixed v1, fixed v2, fixed v3,
538
v(t) = a*t^3 + b*t^2 + c*t + d, 0 <= t <= 1.
540
dv(t) = 3*a*t^2 + 2*b*t + c.
541
v(t) has a local minimum or maximum (or inflection point)
542
precisely where dv(t) = 0. Now the roots of dv(t) = 0 (i.e.,
543
the zeros of dv(t)) are at
544
t = ( -2*b +/- sqrt(4*b^2 - 12*a*c) ) / 6*a
545
= ( -b +/- sqrt(b^2 - 3*a*c) ) / 3*a
546
(Note that real roots exist iff b^2 >= 3*a*c.)
547
We want to know if these lie in the range (0..1).
548
(The endpoints don't count.) Call such a root a "valid zero."
549
Since computing the roots is expensive, we would like to have
550
some cheap tests to filter out cases where they don't exist
551
(i.e., where the curve is already monotonic).
553
fixed v01, v12, a, b, c, b2, a3;
554
fixed dv_end, b2abs, a3abs;
556
curve_points_to_coefficients(v0, v1, v2, v3, a, b, c, v01, v12);
560
If a = 0, the only possible zero is t = -c / 2*b.
561
This zero is valid iff sign(c) != sign(b) and 0 < |c| < 2*|b|.
564
if ((b ^ c) < 0 && any_abs(c) < any_abs(b2) && c != 0) {
565
*pst = (double)(-c) / b2;
571
Iff a curve is horizontal at t = 0, c = 0. In this case,
572
there can be at most one other zero, at -2*b / 3*a.
573
This zero is valid iff sign(a) != sign(b) and 0 < 2*|b| < 3*|a|.
576
if ((a ^ b) < 0 && any_abs(b2) < any_abs(a3) && b != 0) {
577
*pst = (double)(-b2) / a3;
583
Similarly, iff a curve is horizontal at t = 1, 3*a + 2*b + c = 0.
584
In this case, there can be at most one other zero,
585
at -1 - 2*b / 3*a, iff sign(a) != sign(b) and 1 < -2*b / 3*a < 2,
586
i.e., 3*|a| < 2*|b| < 6*|a|.
588
else if ((dv_end = a3 + b2 + c) == 0) {
590
(b2abs = any_abs(b2)) > (a3abs = any_abs(a3)) &&
593
*pst = (double)(-b2 - a3) / a3;
599
If sign(dv_end) != sign(c), at least one valid zero exists,
600
since dv(0) and dv(1) have opposite signs and hence
601
dv(t) must be zero somewhere in the interval [0..1].
603
else if ((dv_end ^ c) < 0);
605
If sign(a) = sign(b), no valid zero exists,
606
since dv is monotonic on [0..1] and has the same sign
609
else if ((a ^ b) >= 0)
612
Otherwise, dv(t) may be non-monotonic on [0..1]; it has valid zeros
613
iff its sign anywhere in this interval is different from its sign
614
at the endpoints, which occurs iff it has an extremum in this
615
interval and the extremum is of the opposite sign from c.
616
To find this out, we look for the local extremum of dv(t)
619
which has a zero only at
621
Now if t1 <= 0 or t1 >= 1, no valid zero exists.
622
Note that we just determined that sign(a) != sign(b), so we know t1 > 0.
624
else if (any_abs(b) >= any_abs(a3))
627
Otherwise, we just go ahead with the computation of the roots,
628
and test them for being in the correct range. Note that a valid
629
zero is an inflection point of v(t) iff d2v(t) = 0; we don't
630
bother to check for this case, since it's rare.
633
double nbf = (double)(-b);
634
double a3f = (double)a3;
635
double radicand = nbf * nbf - a3f * c;
638
if_debug1('2', "[2]negative radicand = %g\n", radicand);
641
double root = sqrt(radicand);
643
double z = (nbf - root) / a3f;
646
* We need to return the zeros in the correct order.
647
* We know that root is non-negative, but a3f may be either
648
* positive or negative, so we need to check the ordering
651
if_debug2('2', "[2]zeros at %g, %g\n", z, (nbf + root) / a3f);
653
*pst = z, nzeros = 1;
655
z = (nbf + root) / a3f;
656
if (z > 0 && z < 1) {
657
if (nzeros && a3f < 0) /* order is reversed */
658
pst[1] = *pst, *pst = z;
669
/* ---------------- Path optimization for the filling algorithm. ---------------- */
672
find_contacting_segments(const subpath *sp0, segment *sp0last,
673
const subpath *sp1, segment *sp1last,
674
segment **sc0, segment **sc1)
677
const segment *s0s, *s1s;
678
int count0, count1, search_limit = 50;
679
int min_length = fixed_1 * 1;
681
/* This is a simplified algorithm, which only checks for quazi-colinear vertical lines.
682
"Quazi-vertical" means dx <= 1 && dy >= min_length . */
683
/* To avoid a big unuseful expence of the processor time,
684
we search the first subpath from the end
685
(assuming that it was recently merged near the end),
686
and restrict the search with search_limit segments
687
against a quadratic scanning of two long subpaths.
688
Thus algorithm is not necessary finds anything contacting.
689
Instead it either quickly finds something, or maybe not. */
690
for (s0 = sp0last, count0 = 0; count0 < search_limit && s0 != (segment *)sp0; s0 = s0->prev, count0++) {
692
if (s0->type == s_line && (s0s->pt.x == s0->pt.x ||
693
(any_abs(s0s->pt.x - s0->pt.x) == 1 && any_abs(s0s->pt.y - s0->pt.y) > min_length))) {
694
for (s1 = sp1last, count1 = 0; count1 < search_limit && s1 != (segment *)sp1; s1 = s1->prev, count1++) {
696
if (s1->type == s_line && (s1s->pt.x == s1->pt.x ||
697
(any_abs(s1s->pt.x - s1->pt.x) == 1 && any_abs(s1s->pt.y - s1->pt.y) > min_length))) {
698
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) {
699
if (s0s->pt.y < s0->pt.y && s1s->pt.y > s1->pt.y) {
700
fixed y0 = max(s0s->pt.y, s1->pt.y);
701
fixed y1 = min(s0->pt.y, s1s->pt.y);
709
if (s0s->pt.y > s0->pt.y && s1s->pt.y < s1->pt.y) {
710
fixed y0 = max(s0->pt.y, s1s->pt.y);
711
fixed y1 = min(s0s->pt.y, s1->pt.y);
728
gx_path_merge_contacting_contours(gx_path *ppath)
730
/* Now this is a simplified algorithm,
731
which merge only contours by a common quazi-vertical line. */
732
/* Note the merged contour is not equivalent to sum of original contours,
733
because we ignore small coordinate differences within fixed_epsilon. */
734
int window = 5/* max spot holes */ * 6/* segments per subpath */;
735
subpath *sp0 = ppath->segments->contents.subpath_first;
737
for (; sp0 != NULL; sp0 = (subpath *)sp0->last->next) {
738
segment *sp0last = sp0->last;
739
subpath *sp1 = (subpath *)sp0last->next, *spnext;
743
for (count = 0; sp1 != NULL && count < window; sp1 = spnext, count++) {
744
segment *sp1last = sp1->last;
745
segment *sc0, *sc1, *old_first;
747
spnext = (subpath *)sp1last->next;
748
if (find_contacting_segments(sp0, sp0last, sp1, sp1last, &sc0, &sc1)) {
749
/* Detach the subpath 1 from the path: */
750
sp1->prev->next = sp1last->next;
751
if (sp1last->next != NULL)
752
sp1last->next->prev = sp1->prev;
755
old_first = sp1->next;
756
/* sp1 is not longer in use. Move subpath_current from it for safe removing : */
757
if (ppath->segments->contents.subpath_current == sp1) {
758
ppath->segments->contents.subpath_current = sp1p;
760
if (sp1last->type == s_line_close) {
761
/* Change 'closepath' of the subpath 1 to a line (maybe degenerate) : */
762
sp1last->type = s_line;
763
/* sp1 is not longer in use. Free it : */
764
gs_free_object(gs_memory_stable(ppath->memory), sp1, "gx_path_merge_contacting_contours");
765
} else if (sp1last->pt.x == sp1->pt.x && sp1last->pt.y == sp1->pt.y) {
766
/* Implicit closepath with zero length. Don't need a new segment. */
767
/* sp1 is not longer in use. Free it : */
768
gs_free_object(gs_memory_stable(ppath->memory), sp1, "gx_path_merge_contacting_contours");
770
/* Insert the closing line segment. */
771
/* sp1 is not longer in use. Convert it to the line segment : */
773
sp1last->next = (segment *)sp1;
776
sp1->last = NULL; /* Safety for garbager. */
777
sp1last = (segment *)sp1;
779
sp1 = 0; /* Safety. */
780
/* Rotate the subpath 1 to sc1 : */
781
{ /* Detach s_start and make a loop : */
782
sp1last->next = old_first;
783
old_first->prev = sp1last;
784
/* Unlink before sc1 : */
787
sc1->prev = 0; /* Safety. */
788
/* sp1 is not longer in use. Free it : */
789
if (ppath->segments->contents.subpath_current == sp1) {
790
ppath->segments->contents.subpath_current = sp1p;
792
gs_free_object(gs_memory_stable(ppath->memory), sp1, "gx_path_merge_contacting_contours");
793
sp1 = 0; /* Safety. */
795
/* Insert the subpath 1 into the subpath 0 before sc0 :*/
796
sc0->prev->next = sc1;
797
sc1->prev = sc0->prev;
800
/* Remove degenearte "bridge" segments : (fixme: Not done due to low importance). */
801
/* Edit the subpath count : */
802
ppath->subpath_count--;