~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to base/gxpcopy.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2001-2006 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, 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.
 
12
*/
 
13
 
 
14
/* $Id: gxpcopy.c 9062 2008-09-03 11:42:35Z leonardo $ */
 
15
/* Path copying and flattening */
 
16
#include "math_.h"
 
17
#include "gx.h"
 
18
#include "gserrors.h"
 
19
#include "gxfixed.h"
 
20
#include "gxfarith.h"
 
21
#include "gxistate.h"           /* for access to line params */
 
22
#include "gzpath.h"
 
23
#include "vdtrace.h"
 
24
 
 
25
/* Forward declarations */
 
26
static void adjust_point_to_tangent(segment *, const segment *,
 
27
                                     const gs_fixed_point *);
 
28
 
 
29
static inline int
 
30
break_line_if_long(gx_path *ppath, const segment *pseg)
 
31
{
 
32
    fixed x0 = ppath->position.x;
 
33
    fixed y0 = ppath->position.y;
 
34
 
 
35
    if (gx_check_fixed_diff_overflow(pseg->pt.x, x0) ||
 
36
        gx_check_fixed_diff_overflow(pseg->pt.y, y0)) {
 
37
        fixed x, y;
 
38
 
 
39
        if (gx_check_fixed_sum_overflow(pseg->pt.x, x0))
 
40
            x = (pseg->pt.x >> 1) + (x0 >> 1);
 
41
        else
 
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);
 
45
        else
 
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.
 
51
         */
 
52
    }
 
53
    return 0;
 
54
}
 
55
 
 
56
 
 
57
/* Copy a path, optionally flattening or monotonizing it. */
 
58
/* If the copy fails, free the new path. */
 
59
int
 
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)
 
63
{
 
64
    const segment *pseg;
 
65
    fixed flat = fixed_flatness;
 
66
    gs_fixed_point expansion;
 
67
    /*
 
68
     * Since we're going to be adding to the path, unshare it
 
69
     * before we start.
 
70
     */
 
71
    int code = gx_path_unshare(ppath);
 
72
 
 
73
    if (code < 0)
 
74
        return code;
 
75
#ifdef DEBUG
 
76
    if (gs_debug_c('P'))
 
77
        gx_dump_path(ppath_old, "before reducing");
 
78
#endif
 
79
    if (options & pco_for_stroke) {
 
80
        /* Precompute the maximum expansion of the bounding box. */
 
81
        double width = pis->line_params.half_width;
 
82
 
 
83
        expansion.x =
 
84
            float2fixed((fabs(pis->ctm.xx) + fabs(pis->ctm.yx)) * width) * 2;
 
85
        expansion.y =
 
86
            float2fixed((fabs(pis->ctm.xy) + fabs(pis->ctm.yy)) * width) * 2;
 
87
    } else 
 
88
        expansion.x = expansion.y = 0; /* Quiet gcc warning. */
 
89
    vd_setcolor(RGB(255,255,0));
 
90
    pseg = (const segment *)(ppath_old->first_subpath);
 
91
    while (pseg) {
 
92
        switch (pseg->type) {
 
93
            case s_start:
 
94
                code = gx_path_add_point(ppath,
 
95
                                         pseg->pt.x, pseg->pt.y);
 
96
                vd_moveto(pseg->pt.x, pseg->pt.y);
 
97
                break;
 
98
            case s_curve:
 
99
                {
 
100
                    const curve_segment *pc = (const curve_segment *)pseg;
 
101
 
 
102
                    if (fixed_flatness == max_fixed) {  /* don't flatten */
 
103
                        if (options & pco_monotonize)
 
104
                            code = gx_curve_monotonize(ppath, pc);
 
105
                        else
 
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);
 
109
                    } else {
 
110
                        fixed x0 = ppath->position.x;
 
111
                        fixed y0 = ppath->position.y;
 
112
                        segment_notes notes = pseg->notes;
 
113
                        curve_segment cseg;
 
114
                        int k;
 
115
 
 
116
                        if (options & pco_for_stroke) {
 
117
                            /*
 
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
 
125
                             * good results.
 
126
                             */
 
127
                            fixed min01, max01, min23, max23;
 
128
                            fixed ex, ey, flat_x, flat_y;
 
129
 
 
130
#define SET_EXTENT(r, c0, c1, c2, c3)\
 
131
    BEGIN\
 
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);\
 
137
    END
 
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);
 
140
#undef SET_EXTENT
 
141
                            /*
 
142
                             * We check for the degenerate case specially
 
143
                             * to avoid a division by zero.
 
144
                             */
 
145
                            if (ex == 0 || ey == 0)
 
146
                                k = 0;
 
147
                            else {
 
148
                                flat_x =
 
149
                                    fixed_mult_quo(fixed_flatness, ex,
 
150
                                                   ex + expansion.x);
 
151
                                flat_y =
 
152
                                    fixed_mult_quo(fixed_flatness, ey,
 
153
                                                   ey + expansion.y);
 
154
                                flat = min(flat_x, flat_y);
 
155
                                k = gx_curve_log2_samples(x0, y0, pc, flat);
 
156
                            }
 
157
                        } else
 
158
                            k = gx_curve_log2_samples(x0, y0, pc, flat);
 
159
                        if (options & pco_accurate) {
 
160
                            segment *start;
 
161
                            segment *end;
 
162
 
 
163
                            /*
 
164
                             * Add an extra line, which will become
 
165
                             * the tangent segment.
 
166
                             */
 
167
                            code = gx_path_add_line_notes(ppath, x0, y0,
 
168
                                                          notes);
 
169
                            if (code < 0)
 
170
                                break;
 
171
                            vd_lineto(x0, y0);
 
172
                            start = ppath->current_subpath->last;
 
173
                            notes |= sn_not_first;
 
174
                            cseg = *pc;
 
175
                            code = gx_subdivide_curve(ppath, k, &cseg, notes);
 
176
                            if (code < 0)
 
177
                                break;
 
178
                            /*
 
179
                             * Adjust the first and last segments so that
 
180
                             * they line up with the tangents.
 
181
                             */
 
182
                            end = ppath->current_subpath->last;
 
183
                            vd_lineto(ppath->position.x, ppath->position.y);
 
184
                            if ((code = gx_path_add_line_notes(ppath,
 
185
                                                          ppath->position.x,
 
186
                                                          ppath->position.y,
 
187
                                            pseg->notes | sn_not_first)) < 0)
 
188
                                break;
 
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);
 
193
                            else
 
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);
 
199
                            else
 
200
                                adjust_point_to_tangent(end, end->prev, &start->pt);
 
201
                        } else {
 
202
                            cseg = *pc;
 
203
                            code = gx_subdivide_curve(ppath, k, &cseg, notes);
 
204
                        }
 
205
                    }
 
206
                    break;
 
207
                }
 
208
            case s_line:
 
209
                code = break_line_if_long(ppath, pseg);
 
210
                if (code < 0)
 
211
                    break;
 
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);
 
215
                break;
 
216
            case s_dash: 
 
217
                {
 
218
                    const dash_segment *pd = (const dash_segment *)pseg;
 
219
 
 
220
                    code = gx_path_add_dash_notes(ppath,
 
221
                                       pd->pt.x, pd->pt.y, pd->tangent.x, pd->tangent.y, pseg->notes);
 
222
                    break;
 
223
                }
 
224
            case s_line_close:
 
225
                code = break_line_if_long(ppath, pseg);
 
226
                if (code < 0)
 
227
                    break;
 
228
                code = gx_path_close_subpath(ppath);
 
229
                vd_closepath;
 
230
                break;
 
231
            default:            /* can't happen */
 
232
                code = gs_note_error(gs_error_unregistered);
 
233
        }
 
234
        if (code < 0) {
 
235
            gx_path_new(ppath);
 
236
            return code;
 
237
        }
 
238
        pseg = pseg->next;
 
239
    }
 
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);
 
249
        } else {
 
250
            ppath->bbox_set = true;
 
251
            ppath->bbox = ppath_old->bbox;
 
252
        }
 
253
    }
 
254
#ifdef DEBUG
 
255
    if (gs_debug_c('P'))
 
256
        gx_dump_path(ppath, "after reducing");
 
257
#endif
 
258
    return 0;
 
259
}
 
260
 
 
261
/*
 
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)
 
267
 *      (X,Y) = (C*T,D*T)
 
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.
 
271
 */
 
272
static void
 
273
adjust_point_to_tangent(segment * pseg, const segment * next,
 
274
                        const gs_fixed_point * p1)
 
275
{
 
276
    const fixed x0 = pseg->pt.x, y0 = pseg->pt.y;
 
277
    const fixed fC = p1->x - x0, fD = p1->y - y0;
 
278
 
 
279
    /*
 
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).
 
283
     */
 
284
    if (fC == 0) {
 
285
        /* Vertical tangent. */
 
286
        const fixed DT = arith_rshift(next->pt.y - y0, 2);
 
287
 
 
288
        if (fD == 0)
 
289
            return;             /* anomalous case */
 
290
        if_debug1('2', "[2]adjusting vertical: DT = %g\n",
 
291
                  fixed2float(DT));
 
292
        if ((DT ^ fD) > 0)
 
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);
 
297
 
 
298
        if_debug1('2', "[2]adjusting horizontal: CT = %g\n",
 
299
                  fixed2float(CT));
 
300
        if ((CT ^ fC) > 0)
 
301
            pseg->pt.x = CT + x0;
 
302
    } else {
 
303
        /* General case. */
 
304
        const double C = fC, D = fD;
 
305
        double T = (C * (next->pt.x - x0) + D * (next->pt.y - y0)) /
 
306
        (C * C + D * D);
 
307
 
 
308
        if_debug3('2', "[2]adjusting: C = %g, D = %g, T = %g\n",
 
309
                  C, D, T);
 
310
        if (T > 0) {
 
311
            if (T > 1) {
 
312
                /* Don't go outside the curve bounding box. */
 
313
                T = 1;
 
314
            }
 
315
            pseg->pt.x = arith_rshift((fixed) (C * T), 2) + x0;
 
316
            pseg->pt.y = arith_rshift((fixed) (D * T), 2) + y0;
 
317
        }
 
318
    }
 
319
}
 
320
 
 
321
/* ---------------- Monotonic curves ---------------- */
 
322
 
 
323
/* Test whether a path is free of non-monotonic curves. */
 
324
bool
 
325
gx_path__check_curves(const gx_path * ppath, gx_path_copy_options options, fixed fixed_flat)
 
326
{
 
327
    const segment *pseg = (const segment *)(ppath->first_subpath);
 
328
    gs_fixed_point pt0;
 
329
 
 
330
    pt0.x = pt0.y = 0; /* Quiet gcc warning. */
 
331
    while (pseg) {
 
332
        switch (pseg->type) {
 
333
            case s_start:
 
334
                {
 
335
                    const subpath *psub = (const subpath *)pseg;
 
336
 
 
337
                    /* Skip subpaths without curves. */
 
338
                    if (!psub->curve_count)
 
339
                        pseg = psub->last;
 
340
                }
 
341
                break;
 
342
            case s_line:
 
343
                if (gx_check_fixed_diff_overflow(pseg->pt.x, pt0.x) ||
 
344
                    gx_check_fixed_diff_overflow(pseg->pt.y, pt0.y))
 
345
                    return false;
 
346
                break;
 
347
            case s_curve:
 
348
                {
 
349
                    const curve_segment *pc = (const curve_segment *)pseg;
 
350
 
 
351
                    if (options & pco_monotonize) {
 
352
                        double t[2];
 
353
                        int nz = gx_curve_monotonic_points(pt0.y,
 
354
                                               pc->p1.y, pc->p2.y, pc->pt.y, t);
 
355
 
 
356
                        if (nz != 0)
 
357
                            return false;
 
358
                        nz = gx_curve_monotonic_points(pt0.x,
 
359
                                               pc->p1.x, pc->p2.x, pc->pt.x, t);
 
360
                        if (nz != 0)
 
361
                            return false;
 
362
                    }
 
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);
 
366
 
 
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))
 
370
                            return false;
 
371
                    if (gx_check_fixed_diff_overflow(pseg->pt.x, pt0.x) ||
 
372
                        gx_check_fixed_diff_overflow(pseg->pt.y, pt0.y))
 
373
                        return false;
 
374
                    }
 
375
                }
 
376
                break;
 
377
            default:
 
378
                ;
 
379
        }
 
380
        pt0 = pseg->pt;
 
381
        pseg = pseg->next;
 
382
    }
 
383
    return true;
 
384
}
 
385
 
 
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.
 
392
 */
 
393
bool
 
394
gx_path_has_long_segments(const gx_path * ppath)
 
395
{
 
396
    const segment *pseg = (const segment *)(ppath->first_subpath);
 
397
    gs_fixed_point pt0;
 
398
 
 
399
    pt0.x = pt0.y = 0; /* Quiet gcc warning. */
 
400
    while (pseg) {
 
401
        switch (pseg->type) {
 
402
            case s_start:
 
403
                break;
 
404
            default:
 
405
                if (gx_check_fixed_diff_overflow(pseg->pt.x, pt0.x) ||
 
406
                    gx_check_fixed_diff_overflow(pseg->pt.y, pt0.y))
 
407
                    return true;
 
408
                break;
 
409
        }
 
410
        pt0 = pseg->pt;
 
411
        pseg = pseg->next;
 
412
    }
 
413
    return false;
 
414
}
 
415
 
 
416
/* Monotonize a curve, by splitting it if necessary. */
 
417
/* In the worst case, this could split the curve into 9 pieces. */
 
418
int
 
419
gx_curve_monotonize(gx_path * ppath, const curve_segment * pc)
 
420
{
 
421
    fixed x0 = ppath->position.x, y0 = ppath->position.y;
 
422
    segment_notes notes = pc->notes;
 
423
    double t[4], tt = 1, tp;
 
424
    int c[4];
 
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;
 
429
 
 
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);
 
433
    n = n0 + n1;
 
434
    if (n == 0)
 
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);
 
437
    if (n0 > 0)
 
438
        c[0] = 1;
 
439
    if (n0 > 1)
 
440
        c[1] = 1;
 
441
    if (n1 > 0)
 
442
        c[n0] = 2;
 
443
    if (n1 > 1)
 
444
        c[n0 + 1] = 2;
 
445
    /* Order roots : */
 
446
    for (i = 0; i < n; i++)
 
447
        for (j = i + 1; j < n; j++)
 
448
            if (t[i] > t[j]) {
 
449
                int w;
 
450
                double v = t[i]; t[i] = t[j]; t[j] = v;
 
451
                w = c[i]; c[i] = c[j]; c[j] = w;
 
452
            }
 
453
    /* Drop roots near zero : */
 
454
    for (k = 0; k < n; k++)
 
455
        if (t[k] >= delta)
 
456
            break;
 
457
    /* Merge close roots, and drop roots at 1 : */
 
458
    if (t[n - 1] > 1 - delta)
 
459
        n--;
 
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. */
 
463
            c[j] |= c[i];
 
464
        } else {
 
465
            j++;
 
466
            t[j] = t[i];
 
467
            c[j] = c[i];
 
468
        }
 
469
    n = j + 1;
 
470
    /* Do split : */
 
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. */
 
474
    ay *= 3, by *= 2;
 
475
    px = x0;
 
476
    py = y0;
 
477
    qx = (fixed)((pc->p1.x - px) * t[0] + 0.5);
 
478
    qy = (fixed)((pc->p1.y - py) * t[0] + 0.5);
 
479
    tp = 0;
 
480
    for (i = k; i < n; i++) {
 
481
        double ti = t[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);
 
490
        int code;
 
491
 
 
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)
 
499
            qx = -qx, qy = -qy;
 
500
        if ((double)(sx - px) * rx + (double)(sy - py) * ry < 0)
 
501
            rx = -rx, ry = -qy;
 
502
        /* Do add : */
 
503
        code = gx_path_add_curve_notes(ppath, px + qx, py + qy, sx - rx, sy - ry, sx, sy, notes);
 
504
        if (code < 0)
 
505
            return code;
 
506
        notes |= sn_not_first;
 
507
        px = sx;
 
508
        py = sy;
 
509
        qx = (fixed)(dx * tt / 3 + 0.5);
 
510
        qy = (fixed)(dy * tt / 3 + 0.5);
 
511
        tp = t[i];
 
512
    }
 
513
    sx = pc->pt.x;
 
514
    sy = pc->pt.y;
 
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)
 
519
        qx = -qx, qy = -qy;
 
520
    if ((double)(sx - px) * rx + (double)(sy - py) * ry < 0)
 
521
        rx = -rx, ry = -qy;
 
522
    return gx_path_add_curve_notes(ppath, px + qx, py + qy, sx - rx, sy - ry, sx, sy, notes);
 
523
}
 
524
 
 
525
/*
 
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).
 
531
 */
 
532
int
 
533
gx_curve_monotonic_points(fixed v0, fixed v1, fixed v2, fixed v3,
 
534
                          double pst[2])
 
535
{
 
536
    /*
 
537
       Let
 
538
       v(t) = a*t^3 + b*t^2 + c*t + d, 0 <= t <= 1.
 
539
       Then
 
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).
 
552
     */
 
553
    fixed v01, v12, a, b, c, b2, a3;
 
554
    fixed dv_end, b2abs, a3abs;
 
555
 
 
556
    curve_points_to_coefficients(v0, v1, v2, v3, a, b, c, v01, v12);
 
557
    b2 = b << 1;
 
558
    a3 = (a << 1) + a;
 
559
    /*
 
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|.
 
562
     */
 
563
    if (a == 0) {
 
564
        if ((b ^ c) < 0 && any_abs(c) < any_abs(b2) && c != 0) {
 
565
            *pst = (double)(-c) / b2;
 
566
            return 1;
 
567
        } else
 
568
            return 0;
 
569
    }
 
570
    /*
 
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|.
 
574
     */
 
575
    if (c == 0) {
 
576
        if ((a ^ b) < 0 && any_abs(b2) < any_abs(a3) && b != 0) {
 
577
            *pst = (double)(-b2) / a3;
 
578
            return 1;
 
579
        } else
 
580
            return 0;
 
581
    }
 
582
    /*
 
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|.
 
587
     */
 
588
    else if ((dv_end = a3 + b2 + c) == 0) {
 
589
        if ((a ^ b) < 0 &&
 
590
            (b2abs = any_abs(b2)) > (a3abs = any_abs(a3)) &&
 
591
            b2abs < a3abs << 1
 
592
            ) {
 
593
            *pst = (double)(-b2 - a3) / a3;
 
594
            return 1;
 
595
        } else
 
596
            return 0;
 
597
    }
 
598
    /*
 
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].
 
602
     */
 
603
    else if ((dv_end ^ c) < 0);
 
604
    /*
 
605
       If sign(a) = sign(b), no valid zero exists,
 
606
       since dv is monotonic on [0..1] and has the same sign
 
607
       at both endpoints.
 
608
     */
 
609
    else if ((a ^ b) >= 0)
 
610
        return 0;
 
611
    /*
 
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)
 
617
       by observing
 
618
       d2v(t) = 6*a*t + 2*b
 
619
       which has a zero only at
 
620
       t1 = -b / 3*a
 
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.
 
623
     */
 
624
    else if (any_abs(b) >= any_abs(a3))
 
625
        return 0;
 
626
    /*
 
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.
 
631
     */
 
632
    {
 
633
        double nbf = (double)(-b);
 
634
        double a3f = (double)a3;
 
635
        double radicand = nbf * nbf - a3f * c;
 
636
 
 
637
        if (radicand < 0) {
 
638
            if_debug1('2', "[2]negative radicand = %g\n", radicand);
 
639
            return 0;
 
640
        } {
 
641
            double root = sqrt(radicand);
 
642
            int nzeros = 0;
 
643
            double z = (nbf - root) / a3f;
 
644
 
 
645
            /*
 
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
 
649
             * explicitly.
 
650
             */
 
651
            if_debug2('2', "[2]zeros at %g, %g\n", z, (nbf + root) / a3f);
 
652
            if (z > 0 && z < 1)
 
653
                *pst = z, nzeros = 1;
 
654
            if (root != 0) {
 
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;
 
659
                    else
 
660
                        pst[nzeros] = z;
 
661
                    nzeros++;
 
662
                }
 
663
            }
 
664
            return nzeros;
 
665
        }
 
666
    }
 
667
}
 
668
 
 
669
/* ---------------- Path optimization for the filling algorithm. ---------------- */
 
670
 
 
671
static bool
 
672
find_contacting_segments(const subpath *sp0, segment *sp0last, 
 
673
                         const subpath *sp1, segment *sp1last, 
 
674
                         segment **sc0, segment **sc1)
 
675
{
 
676
    segment *s0, *s1;
 
677
    const segment *s0s, *s1s;
 
678
    int count0, count1, search_limit = 50;
 
679
    int min_length = fixed_1 * 1;
 
680
 
 
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++) {
 
691
        s0s = s0->prev;
 
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++) {
 
695
                s1s = s1->prev;
 
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);
 
702
 
 
703
                            if (y0 <= y1) {
 
704
                                *sc0 = s0;
 
705
                                *sc1 = s1;
 
706
                                return true;
 
707
                            }
 
708
                        }
 
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);
 
712
 
 
713
                            if (y0 <= y1) {
 
714
                                *sc0 = s0;
 
715
                                *sc1 = s1;
 
716
                                return true;
 
717
                            }
 
718
                        }
 
719
                    }
 
720
                }
 
721
            }
 
722
        }
 
723
    }
 
724
    return false;
 
725
}
 
726
 
 
727
int
 
728
gx_path_merge_contacting_contours(gx_path *ppath)
 
729
{
 
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;
 
736
 
 
737
    for (; sp0 != NULL; sp0 = (subpath *)sp0->last->next) {
 
738
        segment *sp0last = sp0->last;
 
739
        subpath *sp1 = (subpath *)sp0last->next, *spnext;
 
740
        subpath *sp1p = sp0;
 
741
        int count;
 
742
        
 
743
        for (count = 0; sp1 != NULL && count < window; sp1 = spnext, count++) {
 
744
            segment *sp1last = sp1->last;
 
745
            segment *sc0, *sc1, *old_first;
 
746
                
 
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;
 
753
                sp1->prev = 0;
 
754
                sp1last->next = 0;
 
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;
 
759
                }
 
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");
 
769
                } else {
 
770
                    /* Insert the closing line segment. */
 
771
                    /* sp1 is not longer in use. Convert it to the line segment : */
 
772
                    sp1->type = s_line;
 
773
                    sp1last->next = (segment *)sp1;
 
774
                    sp1->next = NULL;
 
775
                    sp1->prev = sp1last;
 
776
                    sp1->last = NULL; /* Safety for garbager. */
 
777
                    sp1last = (segment *)sp1;
 
778
                }
 
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 : */
 
785
                    sp1last = sc1->prev;
 
786
                    sc1->prev->next = 0;
 
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;
 
791
                    }
 
792
                    gs_free_object(gs_memory_stable(ppath->memory), sp1, "gx_path_merge_contacting_contours");
 
793
                    sp1 = 0; /* Safety. */
 
794
                }
 
795
                /* Insert the subpath 1 into the subpath 0 before sc0 :*/
 
796
                sc0->prev->next = sc1;
 
797
                sc1->prev = sc0->prev;
 
798
                sp1last->next = sc0;
 
799
                sc0->prev = sp1last;
 
800
                /* Remove degenearte "bridge" segments : (fixme: Not done due to low importance). */
 
801
                /* Edit the subpath count : */
 
802
                ppath->subpath_count--;
 
803
            } else
 
804
                sp1p = sp1;
 
805
        }
 
806
    }
 
807
    return 0;
 
808
}
 
809