Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gxfill.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2025 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
/* A topological spot decomposition algorithm with dropout prevention. */
18
/*
19
   This is a dramaticly reorganized and improved revision of the
20
   filling algorithm, which was initially coded by Henry Stiles.
21
   The main improvements are:
22
        1. A dropout prevention for character fill.
23
        2. The spot topology analysis support
24
           for True Type grid fitting.
25
        3. Fixed the contiguity of a spot covering
26
           for shading fills with no dropouts.
27
*/
28
/* See is_spotan about the spot topology analysis support. */
29
/* Also defining lower-level path filling procedures */
30
31
#include "gx.h"
32
#include "gserrors.h"
33
#include "gsstruct.h"
34
#include "gxfixed.h"
35
#include "gxdevice.h"
36
#include "gzpath.h"
37
#include "gzcpath.h"
38
#include "gxdcolor.h"
39
#include "gxhttile.h"
40
#include "gxgstate.h"
41
#include "gxpaint.h"            /* for prototypes */
42
#include "gxfill.h"
43
#include "gxpath.h"
44
#include "gsptype1.h"
45
#include "gsptype2.h"
46
#include "gxpcolor.h"
47
#include "gdevddrw.h"
48
#include "gzspotan.h" /* Only for gx_san_trap_store. */
49
#include "memory_.h"
50
#include "stdint_.h"
51
#include "gsstate.h"            /* for gs_currentcpsimode */
52
#include "gxdevsop.h"
53
#include "gxscanc.h"
54
/*
55
#include "gxfilltr.h" - Do not remove this comment. "gxfilltr.h" is included below.
56
#include "gxfillsl.h" - Do not remove this comment. "gxfillsl.h" is included below.
57
#include "gxfillts.h" - Do not remove this comment. "gxfillts.h" is included below.
58
*/
59
#include "assert_.h"
60
61
/* #define ENABLE_TRAP_AMALGAMATION */
62
63
/*
64
 * ENABLE_TRAP_AMALGAMATION - Experimental trap amalgamation code, disabled
65
 * by default.
66
 *
67
 * Set this if you think that the potential gains from only having to send
68
 * one trapezoid rather than 3 trapezoids justifies the costs in
69
 * calculating whether this is possible.
70
 *
71
 * Note: Due to rounding inaccuracies while scan converting, there are
72
 * cases where the rectangles can round to different pixel boundaries than
73
 * the trapezoids do. This means that enabling the TRY_TO_EXTEND_TRAP
74
 * define will cause rendering differences, but tests seem to indicate that
75
 * this only happens in very borderline cases.
76
 */
77
#ifdef ENABLE_TRAP_AMALGAMATION
78
#define TRY_TO_EXTEND_TRAP 1
79
#else
80
0
#define TRY_TO_EXTEND_TRAP 0
81
#endif
82
83
#ifdef COLLECT_STATS_FILL
84
/* Define the statistics structure instance. */
85
stats_fill_t stats_fill;
86
#endif
87
88
/* A predicate for spot insideness. */
89
/* rule = -1 for winding number rule, i.e. */
90
/* we are inside if the winding number is non-zero; */
91
/* rule = 1 for even-odd rule, i.e. */
92
/* we are inside if the winding number is odd. */
93
0
#define INSIDE_PATH_P(inside, rule) ((inside & rule) != 0)
94
95
/* ---------------- Active line management ---------------- */
96
97
/*
98
 * Define the ordering criterion for active lines that overlap in Y.
99
 * Return -1, 0, or 1 if lp1 precedes, coincides with, or follows lp2.
100
 *
101
 * The lines' x_current values are correct for some Y value that crosses
102
 * both of them and that is not both the start of one and the end of the
103
 * other.  (Neither line is horizontal.)  We want the ordering at this
104
 * Y value, or, of the x_current values are equal, greater Y values
105
 * (if any: this Y value might be the end of both lines).
106
 */
107
static int
108
x_order(const active_line *lp1, const active_line *lp2)
109
0
{
110
0
    bool s1;
111
112
0
    INCR(order);
113
0
    if (!lp1 || !lp2 || lp1->x_current < lp2->x_current)
114
0
        return -1;
115
0
    else if (lp1->x_current > lp2->x_current)
116
0
        return 1;
117
    /*
118
     * We need to compare the slopes of the lines.  Start by
119
     * checking one fast case, where the slopes have opposite signs.
120
     */
121
0
    if ((s1 = lp1->start.x < lp1->end.x) != (lp2->start.x < lp2->end.x))
122
0
        return (s1 ? 1 : -1);
123
    /*
124
     * We really do have to compare the slopes.  Fortunately, this isn't
125
     * needed very often.  We want the sign of the comparison
126
     * dx1/dy1 - dx2/dy2, or (since we know dy1 and dy2 are positive)
127
     * dx1 * dy2 - dx2 * dy1.  In principle, we can't simply do this using
128
     * doubles, since we need complete accuracy and doubles don't have
129
     * enough fraction bits.  However, with the usual 20+12-bit fixeds and
130
     * 64-bit doubles, both of the factors would have to exceed 2^15
131
     * device space pixels for the result to be inaccurate, so we
132
     * simply disregard this possibility.  ****** FIX SOMEDAY ******
133
     */
134
0
    INCR(slow_order);
135
0
    {
136
0
        fixed dx1 = lp1->end.x - lp1->start.x,
137
0
            dy1 = lp1->end.y - lp1->start.y;
138
0
        fixed dx2 = lp2->end.x - lp2->start.x,
139
0
            dy2 = lp2->end.y - lp2->start.y;
140
0
        double diff = (double)dx1 * dy2 - (double)dx2 * dy1;
141
142
0
        return (diff < 0 ? -1 : diff > 0 ? 1 : 0);
143
0
    }
144
0
}
145
146
/*
147
 * The active_line structure isn't really simple, but since its instances
148
 * only exist temporarily during a fill operation, we don't have to
149
 * worry about a garbage collection occurring.
150
 */
151
gs_private_st_simple(st_active_line, active_line, "active_line");
152
153
#ifdef DEBUG
154
/* Internal procedures for printing and checking active lines. */
155
static void
156
print_active_line(const gs_memory_t *mem, const char *label, const active_line * alp)
157
{
158
    dmlprintf5(mem, "[f]%s "PRI_INTPTR"(%d): x_current=%f x_next=%f\n",
159
               label, (intptr_t)alp, alp->direction,
160
               fixed2float(alp->x_current), fixed2float(alp->x_next));
161
    dmlprintf5(mem, "    start=(%f,%f) pt_end="PRI_INTPTR"(%f,%f)\n",
162
               fixed2float(alp->start.x), fixed2float(alp->start.y),
163
               (intptr_t)alp->pseg,
164
               fixed2float(alp->end.x), fixed2float(alp->end.y));
165
    dmlprintf2(mem, "    prev="PRI_INTPTR" next="PRI_INTPTR"\n",
166
               (intptr_t)alp->prev, (intptr_t)alp->next);
167
}
168
static void
169
print_line_list(const gs_memory_t *mem, const active_line * flp)
170
{
171
    const active_line *lp;
172
173
    for (lp = flp; lp != 0; lp = lp->next) {
174
        fixed xc = lp->x_current, xn = lp->x_next;
175
176
        dmlprintf3(mem, "[f]"PRI_INTPTR"(%d): x_current/next=%g",
177
                  (intptr_t)lp, lp->direction,
178
                  fixed2float(xc));
179
        if (xn != xc)
180
            dmprintf1(mem, "/%g", fixed2float(xn));
181
        dmputc(mem, '\n');
182
    }
183
}
184
static inline void
185
print_al(const gs_memory_t *mem, const char *label, const active_line * alp)
186
{
187
    if (gs_debug_c('F'))
188
        print_active_line(mem, label, alp);
189
}
190
#else
191
0
#define print_al(mem,label,alp) DO_NOTHING
192
#endif
193
194
static inline bool
195
is_spotan_device(gx_device * dev)
196
20.7M
{
197
    /* Use open_device procedure to identify the type of the device
198
     * instead of the standard gs_object_type() because gs_cpath_accum_device
199
     * is allocated on the stack i.e. has no block header with a descriptor
200
     * but has dev->memory set like a heap-allocated device.
201
     */
202
20.7M
    return dev_proc(dev, open_device) == san_open;
203
20.7M
}
204
205
/* Forward declarations */
206
static void free_line_list(line_list *);
207
static int add_y_list(gx_path *, line_list *);
208
static int add_y_line_aux(const segment * prev_lp, const segment * lp,
209
            const gs_fixed_point *curr, const gs_fixed_point *prev, int dir, line_list *ll);
210
static void insert_x_new(active_line *, line_list *);
211
static int  end_x_line(active_line *, const line_list *, bool);
212
static int step_al(active_line *alp, bool move_iterator);
213
214
0
#define FILL_LOOP_PROC(proc) int proc(line_list *, fixed band_mask)
215
static FILL_LOOP_PROC(spot_into_scan_lines);
216
static FILL_LOOP_PROC(spot_into_trapezoids);
217
218
/*
219
 * This is the general path filling algorithm.
220
 * It uses the center-of-pixel rule for filling
221
 * We can implement Microsoft's upper-left-corner-of-pixel rule
222
 * by subtracting (0.5, 0.5) from all the coordinates in the path.
223
 *
224
 * The adjust parameters are a hack for keeping regions
225
 * from coming out too faint: they specify an amount by which to expand
226
 * the sides of every filled region.
227
 * Setting adjust = fixed_half is supposed to produce the effect of Adobe's
228
 * any-part-of-pixel rule, but it doesn't quite, because of the
229
 * closed/open interval rule for regions.  We detect this as a special case
230
 * and do the slightly ugly things necessary to make it work.
231
 */
232
233
/* Initialize the line list for a path. */
234
static inline void
235
init_line_list(line_list *ll, gs_memory_t * mem)
236
0
{
237
0
    ll->memory = mem;
238
0
    ll->active_area = 0;
239
0
    ll->next_active = ll->local_active;
240
0
    ll->limit = ll->next_active + MAX_LOCAL_ACTIVE;
241
0
    ll->close_count = 0;
242
0
    ll->y_list = 0;
243
0
    ll->y_line = 0;
244
0
    ll->h_list0 = ll->h_list1 = 0;
245
246
0
    ll->x_head.prev = NULL;
247
    /* Bug 695234: Initialise the following to pacify valgrind */
248
0
    ll->x_head.start.x = 0;
249
0
    ll->x_head.start.y = 0;
250
0
    ll->x_head.end.x = 0;
251
0
    ll->x_head.end.y = 0;
252
253
    /* Do not initialize ll->bbox_left, ll->bbox_width - they were set in advance. */
254
0
    INCR(fill);
255
0
}
256
257
/* Unlink any line_close segments added temporarily. */
258
static inline void
259
unclose_path(gx_path * ppath, int count)
260
0
{
261
0
    subpath *psub;
262
263
0
    for (psub = ppath->first_subpath; count != 0;
264
0
         psub = (subpath *) psub->last->next
265
0
        )
266
0
        if (psub->last == (segment *) & psub->closer) {
267
0
            segment *prev = psub->closer.prev, *next = psub->closer.next;
268
269
0
            prev->next = next;
270
0
            if (next)
271
0
                next->prev = prev;
272
0
            psub->last = prev;
273
0
            count--;
274
0
        }
275
0
}
276
277
/*
278
 * The general fill  path algorithm.
279
 */
280
static int
281
gx_general_fill_path(gx_device * pdev, const gs_gstate * pgs,
282
                     gx_path * ppath, const gx_fill_params * params,
283
                 const gx_device_color * pdevc, const gx_clip_path * pcpath)
284
113M
{
285
113M
    gs_fixed_point adjust;
286
113M
    gs_logical_operation_t lop = pgs->log_op;
287
113M
    gs_fixed_rect ibox, bbox, sbox;
288
113M
    gx_device_clip cdev;
289
113M
    gx_device *dev = pdev;
290
113M
    gx_device *save_dev = dev;
291
113M
    gx_path ffpath;
292
113M
    gx_path *pfpath;
293
113M
    int code;
294
113M
    int max_fill_band = dev->max_fill_band;
295
113M
#define NO_BAND_MASK ((fixed)(-1) << (sizeof(fixed) * 8 - 1))
296
113M
    const bool is_character = params->adjust.x == -1; /* See gxgstate.h */
297
113M
    bool fill_by_trapezoids;
298
113M
    bool big_path = ppath->subpath_count > 50;
299
113M
    fill_options fo;
300
113M
    line_list lst;
301
113M
    int clipping = 0;
302
113M
    int scanconverter;
303
304
113M
    *(const fill_options **)&lst.fo = &fo; /* break 'const'. */
305
    /*
306
     * Compute the bounding box before we flatten the path.
307
     * This can save a lot of time if the path has curves.
308
     * If the path is neither fully within nor fully outside
309
     * the quick-check boxes, we could recompute the bounding box
310
     * and make the checks again after flattening the path,
311
     * but right now we don't bother.
312
     */
313
113M
    gx_path_bbox(ppath, &ibox);
314
113M
    if (is_character)
315
0
        adjust.x = adjust.y = 0;
316
113M
    else
317
113M
        adjust = params->adjust;
318
113M
    lst.contour_count = 0;
319
113M
    lst.windings = NULL;
320
113M
    lst.bbox_left = fixed2int(ibox.p.x - adjust.x - fixed_epsilon);
321
113M
    lst.bbox_width = fixed2int(fixed_ceiling(ibox.q.x + adjust.x)) - lst.bbox_left;
322
    /* Check the bounding boxes. */
323
113M
    if_debug6m('f', pdev->memory, "[f]adjust=%g,%g bbox=(%g,%g),(%g,%g)\n",
324
113M
               fixed2float(adjust.x), fixed2float(adjust.y),
325
113M
               fixed2float(ibox.p.x), fixed2float(ibox.p.y),
326
113M
               fixed2float(ibox.q.x), fixed2float(ibox.q.y));
327
113M
    if (pcpath)
328
22.0M
        gx_cpath_inner_box(pcpath, &bbox);
329
91.0M
    else
330
91.0M
        (*dev_proc(dev, get_clipping_box)) (dev, &bbox);
331
113M
    if (!rect_within(ibox, bbox)) {
332
        /*
333
         * Intersect the path box and the clip bounding box.
334
         * If the intersection is empty, this fill is a no-op.
335
         */
336
102M
        if (pcpath)
337
18.2M
            gx_cpath_outer_box(pcpath, &bbox);
338
102M
        if_debug4m('f', pdev->memory, "   outer_box=(%g,%g),(%g,%g)\n",
339
102M
                   fixed2float(bbox.p.x), fixed2float(bbox.p.y),
340
102M
                   fixed2float(bbox.q.x), fixed2float(bbox.q.y));
341
102M
        rect_intersect(ibox, bbox);
342
102M
        if (ibox.p.x - adjust.x >= ibox.q.x + adjust.x ||
343
102M
            ibox.p.y - adjust.y >= ibox.q.y + adjust.y
344
102M
            ) {                 /* Intersection of boxes is empty! */
345
92.2M
            return 0;
346
92.2M
        }
347
        /*
348
         * The path is neither entirely inside the inner clip box
349
         * nor entirely outside the outer clip box.
350
         * If we had to flatten the path, this is where we would
351
         * recompute its bbox and make the tests again,
352
         * but we don't bother right now.
353
         *
354
         * If there is a clipping path, set up a clipping device.
355
         */
356
10.2M
        if (pcpath) {
357
3.15M
            dev = (gx_device *) & cdev;
358
3.15M
            gx_make_clip_device_on_stack(&cdev, pcpath, save_dev);
359
3.15M
            cdev.max_fill_band = save_dev->max_fill_band;
360
3.15M
            clipping = 1;
361
3.15M
        }
362
10.2M
    }
363
    /*
364
     * Compute the proper adjustment values.
365
     * To get the effect of the any-part-of-pixel rule,
366
     * we may have to tweak them slightly.
367
     * NOTE: We changed the adjust_right/above value from 0.5+epsilon
368
     * to 0.5 in release 5.01; even though this does the right thing
369
     * in every case we could imagine, we aren't confident that it's
370
     * correct.  (The old values were definitely incorrect, since they
371
     * caused 1-pixel-wide/high objects to color 2 pixels even if
372
     * they fell exactly on pixel boundaries.)
373
     */
374
20.7M
    if (adjust.x == fixed_half)
375
18.7M
        fo.adjust_left = fixed_half - fixed_epsilon,
376
18.7M
            fo.adjust_right = fixed_half /* + fixed_epsilon */ ;        /* see above */
377
1.97M
    else
378
1.97M
        fo.adjust_left = fo.adjust_right = adjust.x;
379
20.7M
    if (adjust.y == fixed_half)
380
18.7M
        fo.adjust_below = fixed_half - fixed_epsilon,
381
18.7M
            fo.adjust_above = fixed_half /* + fixed_epsilon */ ;        /* see above */
382
1.97M
    else
383
1.97M
        fo.adjust_below = fo.adjust_above = adjust.y;
384
20.7M
    sbox.p.x = ibox.p.x - adjust.x;
385
20.7M
    sbox.p.y = ibox.p.y - adjust.y;
386
20.7M
    sbox.q.x = ibox.q.x + adjust.x;
387
20.7M
    sbox.q.y = ibox.q.y + adjust.y;
388
20.7M
    fo.pdevc = pdevc;
389
20.7M
    fo.lop = lop;
390
20.7M
    fo.fixed_flat = float2fixed(params->flatness);
391
20.7M
    fo.ymin = ibox.p.y;
392
20.7M
    fo.ymax = ibox.q.y;
393
20.7M
    fo.dev = dev;
394
20.7M
    fo.pbox = &sbox;
395
20.7M
    fo.rule = params->rule;
396
20.7M
    fo.is_spotan = is_spotan_device(dev);
397
20.7M
    fo.fill_direct = color_writes_pure(pdevc, lop);
398
20.7M
    fo.fill_rect = (fo.fill_direct ? dev_proc(dev, fill_rectangle) : NULL);
399
20.7M
    fo.fill_trap = dev_proc(dev, fill_trapezoid);
400
401
    /*
402
     * We have a choice of two different filling algorithms:
403
     * scan-line-based and trapezoid-based.  They compare as follows:
404
     *
405
     *      Scan    Trap
406
     *      ----    ----
407
     *       skip   +draw   0-height horizontal lines
408
     *       slow   +fast   rectangles
409
     *      +fast    slow   curves
410
     *      +yes     no     write pixels at most once when adjust != 0
411
     *
412
     * Normally we use the scan line algorithm for characters, where curve
413
     * speed is important, and for non-idempotent RasterOps, where double
414
     * pixel writing must be avoided, and the trapezoid algorithm otherwise.
415
     * However, we always use the trapezoid algorithm for rectangles.
416
     */
417
20.7M
    fill_by_trapezoids = (!gx_path_has_curves(ppath) ||
418
20.7M
                          params->flatness >= 1.0 || fo.is_spotan);
419
420
20.7M
    if (fill_by_trapezoids && !fo.is_spotan && !lop_is_idempotent(lop)) {
421
673k
        gs_fixed_rect rbox;
422
423
673k
        if (gx_path_is_rectangular(ppath, &rbox)) {
424
494k
            int x0 = fixed2int_pixround(rbox.p.x - fo.adjust_left);
425
494k
            int y0 = fixed2int_pixround(rbox.p.y - fo.adjust_below);
426
494k
            int x1 = fixed2int_pixround(rbox.q.x + fo.adjust_right);
427
494k
            int y1 = fixed2int_pixround(rbox.q.y + fo.adjust_above);
428
429
494k
            code = gx_fill_rectangle_device_rop(x0, y0, x1 - x0, y1 - y0,
430
494k
                                                pdevc, dev, lop);
431
494k
            goto exit;
432
494k
        }
433
178k
        if (fo.adjust_left | fo.adjust_right | fo.adjust_below | fo.adjust_above)
434
144k
            fill_by_trapezoids = false; /* avoid double writing pixels */
435
178k
    }
436
437
20.2M
    if (!fo.is_spotan && ((scanconverter = gs_getscanconverter(pdev->memory)) >= GS_SCANCONVERTER_EDGEBUFFER ||
438
20.2M
                          (scanconverter == GS_SCANCONVERTER_DEFAULT && GS_SCANCONVERTER_DEFAULT_IS_EDGEBUFFER))) {
439
20.2M
        gx_scan_converter_t *sc;
440
        /* If we have a request for accurate curves, make sure we exactly
441
         * match what we'd get for stroking. */
442
20.2M
        if (!big_path && pgs->accurate_curves && gx_path_has_curves(ppath))
443
7.06M
        {
444
7.06M
            gx_path_init_local(&ffpath, ppath->memory);
445
7.06M
            code = gx_path_copy_reducing(ppath, &ffpath, fo.fixed_flat, NULL,
446
7.06M
                                         pco_small_curves | pco_accurate);
447
7.06M
            if (code < 0)
448
0
                goto exit;
449
7.06M
            ppath = &ffpath;
450
7.06M
        }
451
452
20.2M
        if (fill_by_trapezoids && !lop_is_idempotent(lop))
453
33.7k
            fill_by_trapezoids = 0;
454
20.2M
        if (!fill_by_trapezoids)
455
2.05M
        {
456
2.05M
            if (adjust.x == 0 && adjust.y == 0)
457
1.22M
                sc = &gx_scan_converter;
458
830k
            else
459
830k
                sc = &gx_scan_converter_app;
460
18.2M
        } else {
461
18.2M
            if (adjust.x == 0 && adjust.y == 0)
462
751k
                sc = &gx_scan_converter_tr;
463
17.4M
            else
464
17.4M
                sc = &gx_scan_converter_tr_app;
465
18.2M
        }
466
20.2M
        code = gx_scan_convert_and_fill(sc,
467
20.2M
                                        dev,
468
20.2M
                                        ppath,
469
20.2M
                                        &ibox,
470
20.2M
                                        fo.fixed_flat,
471
20.2M
                                        params->rule,
472
20.2M
                                        pdevc,
473
20.2M
                                       (!fill_by_trapezoids && fo.fill_direct) ? -1 : (int)pgs->log_op);
474
20.2M
        if (ppath == &ffpath)
475
7.06M
            gx_path_free(ppath, "gx_general_fill_path");
476
20.2M
        goto exit;
477
20.2M
    }
478
479
0
    gx_path_init_local(&ffpath, ppath->memory);
480
0
    if (!big_path && !gx_path_has_curves(ppath))        /* don't need to flatten */
481
0
        pfpath = ppath;
482
0
    else if (is_spotan_device(dev))
483
0
        pfpath = ppath;
484
0
    else if (!big_path && !pgs->accurate_curves && gx_path__check_curves(ppath, pco_small_curves, fo.fixed_flat))
485
0
        pfpath = ppath;
486
0
    else {
487
0
        code = gx_path_copy_reducing(ppath, &ffpath, fo.fixed_flat, NULL,
488
0
                                     pco_small_curves | (pgs->accurate_curves ? pco_accurate : 0));
489
0
        if (code < 0)
490
0
            goto exit;
491
0
        pfpath = &ffpath;
492
0
        if (big_path) {
493
0
            code = gx_path_merge_contacting_contours(pfpath);
494
0
            if (code < 0)
495
0
                goto exit;
496
0
        }
497
0
    }
498
0
    fo.fill_by_trapezoids = fill_by_trapezoids;
499
    /* Initialize the active line list. */
500
0
    init_line_list(&lst, ppath->memory);
501
0
    if ((code = add_y_list(pfpath, &lst)) < 0)
502
0
        goto nope;
503
0
    {
504
0
        FILL_LOOP_PROC((*fill_loop));
505
506
        /* Some short-sighted compilers won't allow a conditional here.... */
507
0
        if (fill_by_trapezoids)
508
0
            fill_loop = spot_into_trapezoids;
509
0
        else
510
0
            fill_loop = spot_into_scan_lines;
511
0
        if (gs_currentcpsimode(pgs->memory) && is_character) {
512
0
            if (lst.contour_count > countof(lst.local_windings)) {
513
0
                lst.windings = (int *)gs_alloc_byte_array(pdev->memory, lst.contour_count,
514
0
                                sizeof(int), "gx_general_fill_path");
515
0
                if (lst.windings == NULL)
516
0
                    return_error(gs_error_VMerror);
517
0
            } else
518
0
                lst.windings = lst.local_windings;
519
0
            memset(lst.windings, 0, sizeof(lst.windings[0]) * lst.contour_count);
520
0
        }
521
0
        code = (*fill_loop)
522
0
            (&lst, (max_fill_band == 0 ? NO_BAND_MASK : int2fixed(-max_fill_band)));
523
0
        if (lst.windings != NULL && lst.windings != lst.local_windings)
524
0
            gs_free_object(pdev->memory, lst.windings, "gx_general_fill_path");
525
0
    }
526
0
  nope:if (lst.close_count != 0)
527
0
        unclose_path(pfpath, lst.close_count);
528
0
    free_line_list(&lst);
529
0
    if (pfpath != ppath)        /* had to flatten */
530
0
        gx_path_free(pfpath, "gx_general_fill_path");
531
#ifdef COLLECT_STATS_FILL
532
    if (gs_debug_c('f')) {
533
        dmlputs(ppath->memory,
534
                "[f]  # alloc    up  down horiz step slowx  iter  find  band bstep bfill\n");
535
        dmlprintf5(ppath->memory, " %5ld %5ld %5ld %5ld %5ld",
536
                   stats_fill.fill, stats_fill.fill_alloc,
537
                   stats_fill.y_up, stats_fill.y_down,
538
                   stats_fill.horiz);
539
        dmlprintf4(ppath->memory, " %5ld %5ld %5ld %5ld",
540
                   stats_fill.x_step, stats_fill.slow_x,
541
                   stats_fill.iter, stats_fill.find_y);
542
        dmlprintf3(ppath->memory, " %5ld %5ld %5ld\n",
543
                   stats_fill.band, stats_fill.band_step,
544
                   stats_fill.band_fill);
545
        dmlputs(ppath->memory,
546
                "[f]    afill slant shall sfill mqcrs order slowo\n");
547
        dmlprintf7(ppath->memory, "       %5ld %5ld %5ld %5ld %5ld %5ld %5ld\n",
548
                   stats_fill.afill, stats_fill.slant,
549
                   stats_fill.slant_shallow, stats_fill.sfill,
550
                   stats_fill.mq_cross, stats_fill.order,
551
                   stats_fill.slow_order);
552
    }
553
#endif
554
20.7M
exit:
555
20.7M
    if (clipping)
556
3.15M
        gx_destroy_clip_device_on_stack(&cdev);
557
20.7M
    return code;
558
0
}
559
560
static int
561
pass_shading_area_through_clip_path_device(gx_device * pdev, const gs_gstate * pgs,
562
                     gx_path * ppath, const gx_fill_params * params,
563
                 const gx_device_color * pdevc, const gx_clip_path * pcpath)
564
0
{
565
0
    if (pdevc == NULL) {
566
0
        gx_device_clip *cdev = (gx_device_clip *)pdev;
567
568
0
        return dev_proc(cdev->target, fill_path)(cdev->target, pgs, ppath, params, pdevc, pcpath);
569
0
    }
570
    /* We know that tha clip path device implements fill_path with default proc. */
571
0
    return gx_default_fill_path(pdev, pgs, ppath, params, pdevc, pcpath);
572
0
}
573
574
/*  Optimization for shading and halftone fill :
575
    The general filling algorithm subdivides the fill region into
576
    trapezoid or rectangle subregions and then paints each subregion
577
    with given color. If the color is complex, it also needs to be subdivided
578
    into constant color rectangles. In the worst case it gives
579
    a multiple of numbers of rectangles, which may be too slow.
580
    A faster processing may be obtained with installing a clipper
581
    device with the filling path, and then render the complex color
582
    through it. The speeding up happens due to the clipper device
583
    is optimised for fast scans through neighbour clipping rectangles.
584
*/
585
int
586
gx_default_fill_path_shading_or_pattern(gx_device * pdev, const gs_gstate * pgs,
587
                                        gx_path * ppath, const gx_fill_params * params,
588
                                        const gx_device_color * pdevc, const gx_clip_path * pcpath)
589
779k
{
590
779k
    int code = 0, clipping = 0;
591
    /*  We need a single clipping path here, because shadings and
592
        halftones don't take 2 paths. Compute the clipping path intersection.
593
    */
594
779k
    gx_clip_path cpath_intersection, cpath_with_shading_bbox;
595
779k
    const gx_clip_path *pcpath1, *pcpath2;
596
779k
    gs_gstate *pgs_noconst = (gs_gstate *)pgs; /* Break const. */
597
598
779k
    if (ppath != NULL) {
599
720k
        code = gx_cpath_init_local_shared_nested(&cpath_intersection, pcpath, pdev->memory, 1);
600
720k
        if (code < 0)
601
0
            return code;
602
720k
        if (pcpath == NULL) {
603
292k
            gs_fixed_rect clip_box1;
604
605
292k
            (*dev_proc(pdev, get_clipping_box)) (pdev, &clip_box1);
606
292k
            code = gx_cpath_from_rectangle(&cpath_intersection, &clip_box1);
607
292k
        }
608
720k
        if (code >= 0)
609
720k
            code = gx_cpath_intersect_with_params(&cpath_intersection, ppath, params->rule,
610
720k
                                                  pgs_noconst, params);
611
720k
        pcpath1 = &cpath_intersection;
612
720k
    } else
613
59.3k
        pcpath1 = pcpath;
614
779k
    pcpath2 = pcpath1;
615
779k
    if (code >= 0)
616
779k
        code = gx_dc_pattern2_clip_with_bbox(pdevc, pdev, &cpath_with_shading_bbox, &pcpath1);
617
    /* Do fill : */
618
779k
    if (code >= 0) {
619
779k
        gs_fixed_rect clip_box;
620
779k
        gs_int_rect cb;
621
779k
        const gx_rop_source_t *rs = NULL;
622
779k
        gx_device *dev;
623
779k
        gx_device_clip cdev;
624
625
779k
        gx_cpath_outer_box(pcpath1, &clip_box);
626
779k
        cb.p.x = fixed2int_pixround(clip_box.p.x);
627
779k
        cb.p.y = fixed2int_pixround(clip_box.p.y);
628
779k
        cb.q.x = fixed2int_pixround(clip_box.q.x);
629
779k
        cb.q.y = fixed2int_pixround(clip_box.q.y);
630
779k
        if (gx_dc_is_pattern2_color(pdevc) &&
631
779k
                (*dev_proc(pdev, dev_spec_op))(pdev,
632
62.0k
                         gxdso_pattern_handles_clip_path, NULL, 0) > 0) {
633
            /* A special interaction with clist writer device :
634
               pass the intersected clipping path. It uses an unusual call to
635
               fill_path with NULL device color. */
636
2.03k
            code = (*dev_proc(pdev, fill_path))(pdev, pgs, ppath, params, NULL, pcpath1);
637
2.03k
            dev = pdev;
638
777k
        } else {
639
777k
            gx_make_clip_device_on_stack(&cdev, pcpath1, pdev);
640
777k
            dev = (gx_device *)&cdev;
641
777k
            if ((*dev_proc(pdev, dev_spec_op))(pdev,
642
777k
                        gxdso_pattern_shading_area, NULL, 0) > 0)
643
0
                set_dev_proc(&cdev, fill_path, pass_shading_area_through_clip_path_device);
644
777k
            code = 0;
645
777k
            clipping = 1;
646
777k
        }
647
779k
        if (code >= 0) {
648
            /* Check clip rectangle covers an actual area */
649
779k
            if (cb.p.x != cb.q.x && cb.p.y != cb.q.y)
650
403k
                code = pdevc->type->fill_rectangle(pdevc,
651
403k
                        cb.p.x, cb.p.y, cb.q.x - cb.p.x, cb.q.y - cb.p.y,
652
403k
                        dev, pgs->log_op, rs);
653
779k
        }
654
779k
        if (clipping)
655
777k
            gx_destroy_clip_device_on_stack(&cdev);
656
779k
    }
657
779k
    if (ppath != NULL)
658
720k
        gx_cpath_free(&cpath_intersection, "shading_fill_cpath_intersection");
659
779k
    if (pcpath1 != pcpath2)
660
93
        gx_cpath_free(&cpath_with_shading_bbox, "shading_fill_cpath_intersection");
661
662
779k
    return code;
663
779k
}
664
665
/*
666
 * Fill a path.  This is the default implementation of the driver
667
 * fill_path procedure.
668
 */
669
int
670
gx_default_fill_path(gx_device * pdev, const gs_gstate * pgs,
671
                     gx_path * ppath, const gx_fill_params * params,
672
                 const gx_device_color * pdevc, const gx_clip_path * pcpath)
673
113M
{
674
113M
    if (gx_dc_is_pattern2_color(pdevc) ||
675
113M
        pdevc->type == &gx_dc_type_data_ht_colored ||
676
113M
        (gx_dc_is_pattern1_color(pdevc) &&
677
113M
         gx_pattern_tile_is_clist(pdevc->colors.pattern.p_tile)))
678
721k
        return gx_default_fill_path_shading_or_pattern(pdev, pgs, ppath, params, pdevc, pcpath);
679
113M
    else
680
113M
        return gx_general_fill_path(pdev, pgs, ppath, params, pdevc, pcpath);
681
113M
}
682
683
int
684
gx_default_lock_pattern(gx_device *pdev,
685
                        gs_gstate *pgs,
686
                        gs_id      pattern_id,
687
                        int        lock)
688
328
{
689
328
    return gx_pattern_cache_entry_set_lock(pgs, pattern_id, lock);
690
328
}
691
692
/*
693
 * Fill/Stroke a path.  This is the default implementation of the driver
694
 * fill_path procedure.
695
 */
696
int
697
gx_default_fill_stroke_path(gx_device * pdev, const gs_gstate * pgs,
698
                            gx_path * ppath,
699
                            const gx_fill_params * params_fill,
700
                            const gx_device_color * pdevc_fill,
701
                            const gx_stroke_params * params_stroke,
702
                            const gx_device_color * pdevc_stroke,
703
                            const gx_clip_path * pcpath)
704
57.8k
{
705
57.8k
    int code = dev_proc(pdev, fill_path)(pdev, pgs, ppath, params_fill, pdevc_fill, pcpath);
706
707
57.8k
    if (code < 0)
708
0
        return code;
709
    /* Swap colors to make sure the pgs colorspace is correct for stroke */
710
57.8k
    gs_swapcolors_quick(pgs);
711
57.8k
    code = dev_proc(pdev, stroke_path)(pdev, pgs, ppath, params_stroke, pdevc_stroke, pcpath);
712
57.8k
    gs_swapcolors_quick(pgs);
713
57.8k
    return code;
714
57.8k
}
715
716
/* Free the line list. */
717
static void
718
free_line_list(line_list *ll)
719
0
{
720
    /* Free any individually allocated active_lines. */
721
0
    gs_memory_t *mem = ll->memory;
722
0
    active_line *alp;
723
724
0
    while ((alp = ll->active_area) != 0) {
725
0
        active_line *next = alp->alloc_next;
726
727
0
        gs_free_object(mem, alp, "active line");
728
0
        ll->active_area = next;
729
0
    }
730
0
}
731
732
static inline active_line *
733
make_al(line_list *ll)
734
0
{
735
0
    active_line *alp = ll->next_active;
736
737
0
    if (alp == ll->limit) {     /* Allocate separately */
738
0
        alp = gs_alloc_struct(ll->memory, active_line,
739
0
                              &st_active_line, "active line");
740
0
        if (alp == 0)
741
0
            return NULL;
742
0
        alp->alloc_next = ll->active_area;
743
0
        ll->active_area = alp;
744
0
        INCR(fill_alloc);
745
0
    } else
746
0
        ll->next_active++;
747
0
    alp->contour_count = ll->contour_count;
748
0
    return alp;
749
0
}
750
751
/* Insert the new line in the Y ordering */
752
static void
753
insert_y_line(line_list *ll, active_line *alp)
754
0
{
755
0
    active_line *yp = ll->y_line;
756
0
    active_line *nyp;
757
0
    fixed y_start = alp->start.y;
758
759
0
    if (yp == 0) {
760
0
        alp->next = alp->prev = 0;
761
0
        ll->y_list = alp;
762
0
    } else if (y_start >= yp->start.y) {        /* Insert the new line after y_line */
763
0
        while (INCR_EXPR(y_up),
764
0
               ((nyp = yp->next) != NULL &&
765
0
                y_start > nyp->start.y)
766
0
            )
767
0
            yp = nyp;
768
0
        alp->next = nyp;
769
0
        alp->prev = yp;
770
0
        yp->next = alp;
771
0
        if (nyp)
772
0
            nyp->prev = alp;
773
0
    } else {            /* Insert the new line before y_line */
774
0
        while (INCR_EXPR(y_down),
775
0
               ((nyp = yp->prev) != NULL &&
776
0
                y_start < nyp->start.y)
777
0
            )
778
0
            yp = nyp;
779
0
        alp->prev = nyp;
780
0
        alp->next = yp;
781
0
        yp->prev = alp;
782
0
        if (nyp)
783
0
            nyp->next = alp;
784
0
        else
785
0
            ll->y_list = alp;
786
0
    }
787
0
    ll->y_line = alp;
788
0
    print_al(ll->memory, "add ", alp);
789
0
}
790
791
typedef struct contour_cursor_s {
792
    segment *prev, *pseg, *pfirst, *plast;
793
    gx_flattened_iterator fi;
794
    bool more_flattened;
795
    bool first_flattened;
796
    int dir;
797
    bool monotonic_y;
798
    bool monotonic_x;
799
    bool crossing;
800
} contour_cursor;
801
802
static inline int
803
compute_dir(const fill_options *fo, fixed y0, fixed y1)
804
0
{
805
0
    if (max(y0, y1) < fo->ymin)
806
0
        return DIR_OUT_OF_Y_RANGE;
807
0
    if (min(y0, y1) > fo->ymax)
808
0
        return DIR_OUT_OF_Y_RANGE;
809
0
    return (y0 < y1 ? DIR_UP :
810
0
            y0 > y1 ? DIR_DOWN : DIR_HORIZONTAL);
811
0
}
812
813
static inline int
814
add_y_curve_part(line_list *ll, segment *s0, segment *s1, int dir,
815
    gx_flattened_iterator *fi, bool more1, bool step_back, bool monotonic_x)
816
0
{
817
0
    active_line *alp = make_al(ll);
818
0
    int code;
819
820
0
    if (alp == NULL)
821
0
        return_error(gs_error_VMerror);
822
0
    alp->pseg = (dir == DIR_UP ? s1 : s0);
823
0
    alp->direction = dir;
824
0
    alp->fi = *fi;
825
0
    alp->more_flattened = more1;
826
0
    if (dir != DIR_UP && more1)
827
0
        gx_flattened_iterator__switch_to_backscan(&alp->fi, more1);
828
0
    if (step_back) {
829
0
        do {
830
0
            code = gx_flattened_iterator__prev(&alp->fi);
831
0
            if (code < 0)
832
0
                return code;
833
0
            alp->more_flattened = code;
834
0
            if (compute_dir(ll->fo, alp->fi.ly0, alp->fi.ly1) != 2)
835
0
                break;
836
0
        } while (alp->more_flattened);
837
0
    }
838
0
    code = step_al(alp, false);
839
0
    if (code < 0)
840
0
        return code;
841
0
    alp->monotonic_y = false;
842
0
    alp->monotonic_x = monotonic_x;
843
0
    insert_y_line(ll, alp);
844
0
    return 0;
845
0
}
846
847
static inline int
848
add_y_line(const segment * prev_lp, const segment * lp, int dir, line_list *ll)
849
0
{
850
0
    return add_y_line_aux(prev_lp, lp, &lp->pt, &prev_lp->pt, dir, ll);
851
0
}
852
853
static inline int
854
start_al_pair(line_list *ll, contour_cursor *q, contour_cursor *p)
855
0
{
856
0
    int code;
857
858
0
    if (q->monotonic_y)
859
0
        code = add_y_line(q->prev, q->pseg, DIR_DOWN, ll);
860
0
    else
861
0
        code = add_y_curve_part(ll, q->prev, q->pseg, DIR_DOWN, &q->fi,
862
0
                            !q->first_flattened, false, q->monotonic_x);
863
0
    if (code < 0)
864
0
        return code;
865
0
    if (p->monotonic_y)
866
0
        code = add_y_line(p->prev, p->pseg, DIR_UP, ll);
867
0
    else
868
0
        code = add_y_curve_part(ll, p->prev, p->pseg, DIR_UP, &p->fi,
869
0
                            p->more_flattened, false, p->monotonic_x);
870
0
    return code;
871
0
}
872
873
/* Start active lines from a minimum of a possibly non-monotonic curve. */
874
static int
875
start_al_pair_from_min(line_list *ll, contour_cursor *q)
876
0
{
877
0
    int dir, code;
878
0
    const fill_options * const fo = ll->fo;
879
880
    /* q stands at the first segment, which isn't last. */
881
0
    do {
882
0
        code = gx_flattened_iterator__next(&q->fi);
883
0
        if (code < 0)
884
0
            return code;
885
0
        q->more_flattened = code;
886
0
        dir = compute_dir(fo, q->fi.ly0, q->fi.ly1);
887
0
        if (q->fi.ly0 > fo->ymax && ll->y_break > q->fi.y0)
888
0
            ll->y_break = q->fi.ly0;
889
0
        if (q->fi.ly1 > fo->ymax && ll->y_break > q->fi.ly1)
890
0
            ll->y_break = q->fi.ly1;
891
0
        if (q->fi.ly0 >= fo->ymin) {
892
0
            if (dir == DIR_UP && ll->main_dir == DIR_DOWN) {
893
0
                code = add_y_curve_part(ll, q->prev, q->pseg, DIR_DOWN, &q->fi,
894
0
                                        true, true, q->monotonic_x);
895
0
                if (code < 0)
896
0
                    return code;
897
0
                code = add_y_curve_part(ll, q->prev, q->pseg, DIR_UP, &q->fi,
898
0
                                        q->more_flattened, false, q->monotonic_x);
899
0
                if (code < 0)
900
0
                    return code;
901
0
            } else if (q->fi.ly1 < fo->ymin) {
902
0
                code = add_y_curve_part(ll, q->prev, q->pseg, DIR_DOWN, &q->fi,
903
0
                                        true, false, q->monotonic_x);
904
0
                if (code < 0)
905
0
                    return code;
906
0
            }
907
0
        } else if (q->fi.ly1 >= fo->ymin) {
908
0
            code = add_y_curve_part(ll, q->prev, q->pseg, DIR_UP, &q->fi,
909
0
                                    q->more_flattened, false, q->monotonic_x);
910
0
            if (code < 0)
911
0
                return code;
912
0
        }
913
0
        q->first_flattened = false;
914
0
        q->dir = dir;
915
0
        if (dir == DIR_DOWN || dir == DIR_UP)
916
0
            ll->main_dir = dir;
917
0
    } while(q->more_flattened);
918
    /* q stands at the last segment. */
919
0
    return 0;
920
    /* note : it doesn't depend on the number of curve minimums,
921
       which may vary due to arithmetic errors. */
922
0
}
923
924
static inline int
925
init_contour_cursor(const fill_options * const fo, contour_cursor *q)
926
0
{
927
0
    if (q->pseg->type == s_curve) {
928
0
        curve_segment *s = (curve_segment *)q->pseg;
929
0
        fixed ymin = min(min(q->prev->pt.y, s->p1.y), min(s->p2.y, s->pt.y));
930
0
        fixed ymax = max(max(q->prev->pt.y, s->p1.y), max(s->p2.y, s->pt.y));
931
0
        bool in_band = ymin <= fo->ymax && ymax >= fo->ymin;
932
0
        q->crossing = ymin < fo->ymin && ymax >= fo->ymin;
933
0
        q->monotonic_y = !in_band ||
934
0
            (!q->crossing &&
935
0
            ((q->prev->pt.y <= s->p1.y && s->p1.y <= s->p2.y && s->p2.y <= s->pt.y) ||
936
0
             (q->prev->pt.y >= s->p1.y && s->p1.y >= s->p2.y && s->p2.y >= s->pt.y)));
937
0
        q->monotonic_x =
938
0
            ((q->prev->pt.x <= s->p1.x && s->p1.x <= s->p2.x && s->p2.x <= s->pt.x) ||
939
0
             (q->prev->pt.x >= s->p1.x && s->p1.x >= s->p2.x && s->p2.x >= s->pt.x));
940
0
    } else
941
0
        q->monotonic_y = true;
942
0
    if (!q->monotonic_y) {
943
0
        curve_segment *s = (curve_segment *)q->pseg;
944
0
        int k = gx_curve_log2_samples(q->prev->pt.x, q->prev->pt.y, s, fo->fixed_flat);
945
946
0
        if (!gx_flattened_iterator__init(&q->fi, q->prev->pt.x, q->prev->pt.y, s, k))
947
0
            return_error(gs_error_rangecheck);
948
0
    } else {
949
0
        q->dir = compute_dir(fo, q->prev->pt.y, q->pseg->pt.y);
950
0
        gx_flattened_iterator__init_line(&q->fi,
951
0
            q->prev->pt.x, q->prev->pt.y, q->pseg->pt.x, q->pseg->pt.y); /* fake for curves. */
952
0
    }
953
0
    q->first_flattened = true;
954
0
    return 0;
955
0
}
956
957
static int
958
scan_contour(line_list *ll, segment *pfirst, segment *plast, segment *prev)
959
0
{
960
0
    contour_cursor p, q;
961
0
    int code;
962
0
    bool only_horizontal = true, saved = false;
963
0
    const fill_options * const fo = ll->fo;
964
0
    contour_cursor save_q;
965
966
0
    q.prev = prev;
967
0
    q.pseg = plast;
968
0
    q.pfirst = pfirst;
969
0
    q.plast = plast;
970
971
0
    memset(&save_q, 0, sizeof(save_q)); /* Quiet gcc warning. */
972
0
    p.monotonic_x = false; /* Quiet gcc warning. */
973
0
    q.monotonic_x = false; /* Quiet gcc warning. */
974
975
    /* The first thing we do is to walk BACKWARDS along the contour (aka the subpath or
976
     * set of curve segments). We stop either when we reach the beginning again,
977
     * or when we hit a non-horizontal segment. If we hit the beginning, then we
978
     * remember that the segment is 'only_horizontal'. Otherwise, we remember the
979
     * direction of this contour (UP or DOWN). */
980
0
    save_q.dir = DIR_OUT_OF_Y_RANGE;
981
0
    ll->main_dir = DIR_HORIZONTAL;
982
0
    for (; ; q.pseg = q.prev, q.prev = q.prev->prev) {
983
        /* Prepare to walk FORWARDS along the single curve segment in 'q'. */
984
0
        code = init_contour_cursor(fo, &q);
985
0
        if (code < 0)
986
0
            return code;
987
0
        for (;;) {
988
0
            code = gx_flattened_iterator__next(&q.fi);
989
0
            assert(code >= 0); /* Indicates an internal error */
990
0
            if (code < 0)
991
0
                return code;
992
0
            q.dir = compute_dir(fo, q.fi.ly0, q.fi.ly1);
993
0
            if (q.dir == DIR_DOWN || q.dir == DIR_UP)
994
0
                ll->main_dir = q.dir;
995
            /* Exit the loop when we hit the end of the single curve segment */
996
0
            if (!code)
997
0
                break;
998
0
            q.first_flattened = false;
999
0
        }
1000
        /* Thus first_flattened == true, iff the curve needed no subdivisions */
1001
0
        q.more_flattened = false;
1002
        /* ll->maindir == DIR_HORIZONTAL, iff the curve is entirely horizontal
1003
         * (or entirely out of y range). It will contain whatever the last UP or DOWN
1004
         * section was otherwise. */
1005
0
        if (ll->main_dir != DIR_HORIZONTAL) {
1006
0
            only_horizontal = false;
1007
            /* Now we know we're not entirely horizontal, we can abort this run. */
1008
0
            break;
1009
0
        }
1010
        /* If we haven't saved one yet, and we are not out of range, save this one.
1011
         * i.e. save_q and save_fi are the first 'in range' section. We can save
1012
         * time in subsequent passes through by starting here. */
1013
0
        if (!saved && q.dir != DIR_OUT_OF_Y_RANGE) {
1014
0
            save_q = q;
1015
0
            saved = true;
1016
0
        }
1017
0
        if (q.prev == q.pfirst)
1018
0
            break; /* Exit if we're back at the start of the contour */
1019
0
    }
1020
1021
    /* Second run through; this is where we actually do the hard work. */
1022
    /* Restore q if we saved it above */
1023
0
    if (saved) {
1024
0
        q = save_q;
1025
0
    }
1026
    /* q is now at the start of a run that we know will head in an
1027
     * ll->main_dir direction. Start p at the next place and walk
1028
     * forwards. */
1029
0
    for (p.prev = q.pfirst; p.prev != q.plast; p.prev = p.pseg) {
1030
0
        bool added;
1031
0
        p.pseg = p.prev->next;
1032
        /* Can we ignore this segment entirely? */
1033
0
        if (!only_horizontal && p.pseg->type != s_curve &&
1034
0
            p.prev->pt.x == p.pseg->pt.x && p.prev->pt.y == p.pseg->pt.y)
1035
0
            continue;
1036
1037
        /* Prepare to walk down 'p' */
1038
0
        code = init_contour_cursor(fo, &p);
1039
0
        if (code < 0)
1040
0
            return code;
1041
1042
0
        do {
1043
            /* Find the next flattened section that is within range */
1044
0
            do {
1045
0
                code = gx_flattened_iterator__next(&p.fi);
1046
0
                assert(code >= 0); /* Indicates an internal error */
1047
0
                if (code < 0)
1048
0
                    return code;
1049
0
                p.more_flattened = code;
1050
0
                p.dir = compute_dir(fo, p.fi.ly0, p.fi.ly1);
1051
0
            } while (p.more_flattened && p.dir == DIR_OUT_OF_Y_RANGE);
1052
1053
            /* So either we're in range, or we've reached the end of the segment (or both) */
1054
            /* FIXME: Can we break here if p.dir == DIR_OUT_OF_Y_RANGE? */
1055
1056
            /* Set ll->y_break to be the smallest line endpoint we find > ymax */
1057
0
            if (p.fi.ly0 > fo->ymax && ll->y_break > p.fi.ly0)
1058
0
                ll->y_break = p.fi.ly0;
1059
0
            if (p.fi.ly1 > fo->ymax && ll->y_break > p.fi.ly1)
1060
0
                ll->y_break = p.fi.ly1;
1061
1062
0
            added = 0;
1063
0
            if (p.dir == DIR_HORIZONTAL) {
1064
0
                if (p.monotonic_y) {
1065
0
                    if (
1066
#ifdef FILL_ZERO_WIDTH
1067
                        (fo->adjust_below | fo->adjust_above) != 0) {
1068
#else
1069
0
                        (fo->adjust_below + fo->adjust_above >= (fixed_1 - fixed_epsilon) ||
1070
0
                         fixed2int_pixround(p.pseg->pt.y - fo->adjust_below) <
1071
0
                         fixed2int_pixround(p.pseg->pt.y + fo->adjust_above))) {
1072
0
#endif
1073
                        /* Add it here to avoid double processing in process_h_segments. */
1074
0
                        code = add_y_line(p.prev, p.pseg, DIR_HORIZONTAL, ll);
1075
0
                        if (code < 0)
1076
0
                            return code;
1077
0
                        added = 1;
1078
0
                    }
1079
0
                }
1080
0
            } else {
1081
0
                if (p.fi.ly0 >= fo->ymin)
1082
0
                {
1083
0
                    if (p.dir == DIR_UP && ll->main_dir == DIR_DOWN) {
1084
                        /* p starts within range, and heads up. q was heading down. Therefore
1085
                         * they meet at a local minima. Start a pair of active lines from that. */
1086
0
                        code = start_al_pair(ll, &q, &p);
1087
0
                        if (code < 0)
1088
0
                            return code;
1089
0
                        added = 1;
1090
0
                    } else if (p.fi.ly1 < fo->ymin) {
1091
                        /* p heading downwards */
1092
0
                        if (p.monotonic_y)
1093
0
                            code = add_y_line(p.prev, p.pseg, DIR_DOWN, ll);
1094
0
                        else
1095
0
                            code = add_y_curve_part(ll, p.prev, p.pseg, DIR_DOWN, &p.fi,
1096
0
                                                    !p.first_flattened, false, p.monotonic_x);
1097
0
                        if (code < 0)
1098
0
                            return code;
1099
0
                        added = 1;
1100
0
                    }
1101
0
                } else if (p.fi.ly1 >= fo->ymin) {
1102
                    /* p heading upwards */
1103
0
                    if (p.monotonic_y)
1104
0
                        code = add_y_line(p.prev, p.pseg, DIR_UP, ll);
1105
0
                    else
1106
0
                        code = add_y_curve_part(ll, p.prev, p.pseg, DIR_UP, &p.fi,
1107
0
                                                p.more_flattened, false, p.monotonic_x);
1108
0
                    if (code < 0)
1109
0
                        return code;
1110
0
                    added = 1;
1111
0
                }
1112
0
                if (p.dir == DIR_DOWN || p.dir == DIR_UP)
1113
0
                    ll->main_dir = p.dir;
1114
0
            }
1115
0
            if (!p.monotonic_y && p.more_flattened) {
1116
0
                code = start_al_pair_from_min(ll, &p);
1117
0
                if (code < 0)
1118
0
                    return code;
1119
0
                added = 1;
1120
0
            }
1121
0
            if (p.dir == DIR_DOWN || p.dir == DIR_HORIZONTAL) {
1122
0
                q.prev = p.prev;
1123
0
                q.pseg = p.pseg;
1124
0
                q.monotonic_y = p.monotonic_y;
1125
0
                q.more_flattened = p.more_flattened;
1126
0
                q.first_flattened = p.first_flattened;
1127
0
                q.fi = p.fi;
1128
0
                q.dir = p.dir;
1129
0
            }
1130
            /* If we haven't added lines based on this segment, and there
1131
             * are more flattened lines to come from it, ensure we loop
1132
             * to get the rest of them. */
1133
            /* FIXME: Do we need '!added' here? Try removing it. */
1134
0
        } while (!added && p.more_flattened);
1135
0
    }
1136
0
    return 0;
1137
0
}
1138
1139
/*
1140
 * Construct a Y-sorted list of segments for rasterizing a path.  We assume
1141
 * the path is non-empty.  Only include non-horizontal lines or (monotonic)
1142
 * curve segments where one endpoint is locally Y-minimal, and horizontal
1143
 * lines that might color some additional pixels.
1144
 */
1145
static int
1146
add_y_list(gx_path * ppath, line_list *ll)
1147
0
{
1148
0
    subpath *psub = ppath->first_subpath;
1149
0
    int close_count = 0;
1150
0
    int code;
1151
1152
0
    ll->y_break = max_fixed;
1153
1154
0
    for (;psub; psub = (subpath *)psub->last->next) {
1155
        /* We know that pseg points to a subpath head (s_start). */
1156
0
        segment *pfirst = (segment *)psub;
1157
0
        segment *plast = psub->last, *prev;
1158
1159
0
        if (plast->type != s_line_close) {
1160
            /* Create a fake s_line_close */
1161
0
            line_close_segment *lp = &psub->closer;
1162
0
            segment *next = plast->next;
1163
1164
0
            lp->next = next;
1165
0
            lp->prev = plast;
1166
0
            plast->next = (segment *) lp;
1167
0
            if (next)
1168
0
                next->prev = (segment *) lp;
1169
0
            lp->type = s_line_close;
1170
0
            lp->pt = psub->pt;
1171
0
            lp->sub = psub;
1172
0
            psub->last = plast = (segment *) lp;
1173
0
            ll->close_count++;
1174
0
        }
1175
0
        prev = plast->prev;
1176
0
        code = scan_contour(ll, pfirst, plast, prev);
1177
0
        if (code < 0)
1178
0
            return code;
1179
0
        ll->contour_count++;
1180
0
    }
1181
0
    return close_count;
1182
0
}
1183
1184
static int
1185
step_al(active_line *alp, bool move_iterator)
1186
0
{
1187
0
    bool forth = (alp->direction == DIR_UP || !alp->fi.curve);
1188
1189
0
    if (move_iterator) {
1190
0
        int code;
1191
1192
0
        if (forth)
1193
0
            code = gx_flattened_iterator__next(&alp->fi);
1194
0
        else
1195
0
            code = gx_flattened_iterator__prev(&alp->fi);
1196
0
        if (code < 0)
1197
0
            return code;
1198
0
        alp->more_flattened = code;
1199
0
    }
1200
    /* Note that we can get alp->fi.ly0 == alp->fi.ly1
1201
       if the curve tangent is horizontal. */
1202
0
    alp->start.x = (forth ? alp->fi.lx0 : alp->fi.lx1);
1203
0
    alp->start.y = (forth ? alp->fi.ly0 : alp->fi.ly1);
1204
0
    alp->end.x = (forth ? alp->fi.lx1 : alp->fi.lx0);
1205
0
    alp->end.y = (forth ? alp->fi.ly1 : alp->fi.ly0);
1206
0
    alp->diff.x = alp->end.x - alp->start.x;
1207
0
    alp->diff.y = alp->end.y - alp->start.y;
1208
0
    SET_NUM_ADJUST(alp);
1209
0
    (alp)->y_fast_max = MAX_MINUS_NUM_ADJUST(alp) /
1210
0
      ((alp->diff.x >= 0 ? alp->diff.x : -alp->diff.x) | 1) + alp->start.y;
1211
0
    return 0;
1212
0
}
1213
1214
static int
1215
init_al(active_line *alp, const segment *s0, const segment *s1, const line_list *ll)
1216
0
{
1217
0
    const segment *ss = (alp->direction == DIR_UP ? s1 : s0);
1218
    /* Warning : p0 may be equal to &alp->end. */
1219
0
    bool curve = (ss != NULL && ss->type == s_curve);
1220
0
    int code;
1221
1222
0
    if (curve) {
1223
0
        if (alp->direction == DIR_UP) {
1224
0
            const curve_segment *cs = (const curve_segment *)s1;
1225
0
            int k = gx_curve_log2_samples(s0->pt.x, s0->pt.y, cs, ll->fo->fixed_flat);
1226
1227
0
            gx_flattened_iterator__init(&alp->fi,
1228
0
                s0->pt.x, s0->pt.y, (const curve_segment *)s1, k);
1229
0
            code = step_al(alp, true);
1230
0
            if (code < 0)
1231
0
                return code;
1232
0
            if (!ll->fo->fill_by_trapezoids) {
1233
0
                alp->monotonic_y = (s0->pt.y <= cs->p1.y && cs->p1.y <= cs->p2.y && cs->p2.y <= cs->pt.y);
1234
0
                alp->monotonic_x = (s0->pt.x <= cs->p1.x && cs->p1.x <= cs->p2.x && cs->p2.x <= cs->pt.x) ||
1235
0
                                   (s0->pt.x >= cs->p1.x && cs->p1.x >= cs->p2.x && cs->p2.x >= cs->pt.x);
1236
0
            }
1237
0
        } else {
1238
0
            const curve_segment *cs = (const curve_segment *)s0;
1239
0
            int k = gx_curve_log2_samples(s1->pt.x, s1->pt.y, cs, ll->fo->fixed_flat);
1240
0
            bool more;
1241
1242
0
            gx_flattened_iterator__init(&alp->fi,
1243
0
                s1->pt.x, s1->pt.y, (const curve_segment *)s0, k);
1244
0
            alp->more_flattened = false;
1245
0
            do {
1246
0
                code = gx_flattened_iterator__next(&alp->fi);
1247
0
                if (code < 0)
1248
0
                    return code;
1249
0
                more = code;
1250
0
                alp->more_flattened |= more;
1251
0
            } while(more);
1252
0
            gx_flattened_iterator__switch_to_backscan(&alp->fi, alp->more_flattened);
1253
0
            code = step_al(alp, false);
1254
0
            if (code < 0)
1255
0
                return code;
1256
0
            if (!ll->fo->fill_by_trapezoids) {
1257
0
                alp->monotonic_y = (s0->pt.y >= cs->p1.y && cs->p1.y >= cs->p2.y && cs->p2.y >= cs->pt.y);
1258
0
                alp->monotonic_x = (s0->pt.x <= cs->p1.x && cs->p1.x <= cs->p2.x && cs->p2.x <= cs->pt.x) ||
1259
0
                                   (s0->pt.x >= cs->p1.x && cs->p1.x >= cs->p2.x && cs->p2.x >= cs->pt.x);
1260
0
            }
1261
0
        }
1262
0
    } else {
1263
0
        gx_flattened_iterator__init_line(&alp->fi,
1264
0
                s0->pt.x, s0->pt.y, s1->pt.x, s1->pt.y);
1265
0
        code = step_al(alp, true);
1266
0
        if (code < 0)
1267
0
            return code;
1268
0
        alp->monotonic_x = alp->monotonic_y = true;
1269
0
    }
1270
0
    alp->pseg = s1;
1271
0
    return 0;
1272
0
}
1273
/*
1274
 * Internal routine to test a segment and add it to the pending list if
1275
 * appropriate.
1276
 */
1277
static int
1278
add_y_line_aux(const segment * prev_lp, const segment * lp,
1279
            const gs_fixed_point *curr, const gs_fixed_point *prev, int dir, line_list *ll)
1280
0
{
1281
0
    int code;
1282
1283
0
    active_line *alp = make_al(ll);
1284
0
    if (alp == NULL)
1285
0
        return_error(gs_error_VMerror);
1286
0
    alp->more_flattened = false;
1287
0
    switch ((alp->direction = dir)) {
1288
0
        case DIR_UP:
1289
0
            code = init_al(alp, prev_lp, lp, ll);
1290
0
            if (code < 0)
1291
0
                return code;
1292
0
            break;
1293
0
        case DIR_DOWN:
1294
0
            code = init_al(alp, lp, prev_lp, ll);
1295
0
            if (code < 0)
1296
0
                return code;
1297
0
            break;
1298
0
        case DIR_HORIZONTAL:
1299
0
            alp->start = *prev;
1300
0
            alp->end = *curr;
1301
            /* Don't need to set dx or y_fast_max */
1302
0
            alp->pseg = prev_lp;        /* may not need this either */
1303
0
            break;
1304
0
        default:                /* can't happen */
1305
0
            return_error(gs_error_unregistered);
1306
0
    }
1307
0
    insert_y_line(ll, alp);
1308
0
    return 0;
1309
0
}
1310
1311
/* ---------------- Filling loop utilities ---------------- */
1312
1313
/* Insert a newly active line in the X ordering. */
1314
static void
1315
insert_x_new(active_line * alp, line_list *ll)
1316
0
{
1317
0
    active_line *next;
1318
0
    active_line *prev = &ll->x_head;
1319
1320
0
    alp->x_current = alp->start.x;
1321
0
    alp->x_next = alp->start.x; /*      If the spot starts with a horizontal segment,
1322
                                    we need resort_x_line to work properly
1323
                                    in the very beginning. */
1324
0
    while (INCR_EXPR(x_step),
1325
0
           (next = prev->next) != 0 && x_order(next, alp) < 0
1326
0
        )
1327
0
        prev = next;
1328
0
    alp->next = next;
1329
0
    alp->prev = prev;
1330
0
    if (next != 0)
1331
0
        next->prev = alp;
1332
0
    prev->next = alp;
1333
0
}
1334
1335
/* Insert a newly active line in the h list. */
1336
/* h list isn't ordered because x intervals may overlap. */
1337
/* todo : optimize with maintaining ordered interval list;
1338
   Unite contacting inrevals, like we did in add_margin.
1339
 */
1340
static inline void
1341
insert_h_new(active_line * alp, line_list *ll)
1342
0
{
1343
0
    alp->next = ll->h_list0;
1344
0
    alp->prev = 0;
1345
0
    if (ll->h_list0 != 0)
1346
0
        ll->h_list0->prev = alp;
1347
0
    ll->h_list0 = alp;
1348
    /*
1349
     * h list keeps horizontal lines for a given y.
1350
     * There are 2 lists, corresponding to upper and lower ends
1351
     * of the Y-interval, which spot_into_trapezoids currently proceeds.
1352
     * Parts of horizontal lines, which do not contact a filled trapezoid,
1353
     * are parts of the spot bondairy. They to be marked in
1354
     * the 'sect' array.  - see process_h_lists.
1355
     */
1356
0
}
1357
1358
static inline void
1359
remove_al(const line_list *ll, active_line *alp)
1360
0
{
1361
0
    active_line *nlp = alp->next;
1362
1363
0
    alp->prev->next = nlp;
1364
0
    if (nlp)
1365
0
        nlp->prev = alp->prev;
1366
0
    if_debug1m('F', ll->memory, "[F]drop "PRI_INTPTR"\n", (intptr_t)alp);
1367
0
}
1368
1369
/*
1370
 * Handle a line segment that just ended.  Return true iff this was
1371
 * the end of a line sequence.
1372
 */
1373
static int
1374
end_x_line(active_line *alp, const line_list *ll, bool update)
1375
0
{
1376
0
    const segment *pseg = alp->pseg;
1377
    /*
1378
     * The computation of next relies on the fact that
1379
     * all subpaths have been closed.  When we cycle
1380
     * around to the other end of a subpath, we must be
1381
     * sure not to process the start/end point twice.
1382
     */
1383
0
    const segment *next =
1384
0
        (alp->direction == DIR_UP ?
1385
0
         (                      /* Upward line, go forward along path. */
1386
0
          pseg->type == s_line_close ?  /* end of subpath */
1387
0
          ((const line_close_segment *)pseg)->sub->next :
1388
0
          pseg->next) :
1389
0
         (                      /* Downward line, go backward along path. */
1390
0
          pseg->type == s_start ?       /* start of subpath */
1391
0
          ((const subpath *)pseg)->last->prev :
1392
0
          pseg->prev)
1393
0
        );
1394
0
    int code;
1395
1396
0
    if (alp->end.y < alp->start.y) {
1397
        /* fixme: The condition above causes a horizontal
1398
           part of a curve near an Y maximum to process twice :
1399
           once scanning the left spot boundary and once scanning the right one.
1400
           In both cases it will go to the H list.
1401
           However the dropout prevention logic isn't
1402
           sensitive to that, and such segments does not affect
1403
           trapezoids. Thus the resulting raster doesn't depend on that.
1404
           However it would be nice to improve someday.
1405
         */
1406
0
        remove_al(ll, alp);
1407
0
        return true;
1408
0
    } else if (alp->more_flattened)
1409
0
        return false;
1410
0
    code = init_al(alp, pseg, next, ll);
1411
0
    if (code < 0)
1412
0
        return code;
1413
0
    if (alp->start.y > alp->end.y) {
1414
        /* See comment above. */
1415
0
        remove_al(ll, alp);
1416
0
        return true;
1417
0
    }
1418
0
    alp->x_current = alp->x_next = alp->start.x;
1419
0
    print_al(ll->memory, "repl", alp);
1420
0
    return false;
1421
0
}
1422
1423
/*
1424
 * Handle the case of a slanted trapezoid with adjustment.
1425
 * To do this exactly right requires filling a central trapezoid
1426
 * (or rectangle) plus two horizontal almost-rectangles.
1427
 */
1428
static int
1429
fill_slant_adjust(const line_list *ll,
1430
        const active_line *flp, const active_line *alp, fixed y, fixed y1)
1431
0
{
1432
0
    const fill_options * const fo = ll->fo;
1433
0
    const fixed Yb = y - fo->adjust_below;
1434
0
    fixed Ya = y + fo->adjust_above;
1435
0
    fixed Y1b = y1 - fo->adjust_below;
1436
0
    const fixed Y1a = y1 + fo->adjust_above;
1437
0
    const gs_fixed_edge *plbot, *prbot, *pltop, *prtop;
1438
0
    gs_fixed_edge vert_left, slant_left, vert_right, slant_right;
1439
0
    int code;
1440
1441
0
    INCR(slant);
1442
1443
    /* Set up all the edges, even though we may not need them all. */
1444
1445
0
    slant_left.start.x = flp->start.x - fo->adjust_left;
1446
0
    slant_left.end.x = flp->end.x - fo->adjust_left;
1447
0
    slant_right.start.x = alp->start.x + fo->adjust_right;
1448
0
    slant_right.end.x = alp->end.x + fo->adjust_right;
1449
0
    if (flp->start.x < flp->end.x) {
1450
0
        vert_left.start.x = vert_left.end.x = flp->x_current - fo->adjust_left;
1451
0
        vert_left.start.y = Yb, vert_left.end.y = Ya;
1452
0
        vert_right.start.x = vert_right.end.x = alp->x_next + fo->adjust_right;
1453
0
        vert_right.start.y = Y1b, vert_right.end.y = Y1a;
1454
0
        slant_left.start.y = flp->start.y + fo->adjust_above;
1455
0
        slant_left.end.y = flp->end.y + fo->adjust_above;
1456
0
        slant_right.start.y = alp->start.y - fo->adjust_below;
1457
0
        slant_right.end.y = alp->end.y - fo->adjust_below;
1458
0
        plbot = &vert_left, prbot = &slant_right;
1459
0
        pltop = &slant_left, prtop = &vert_right;
1460
0
        if (TRY_TO_EXTEND_TRAP)
1461
0
        {
1462
0
            int x, cx, cy, dy;
1463
            /* Extend the slanted edges so they extend above/below the
1464
             * adjusted Y range. This means we could maybe use them
1465
             * directly. */
1466
0
            while (slant_right.end.y < Y1a)
1467
0
            {
1468
0
                slant_right.end.x += slant_right.end.x - slant_right.start.x;
1469
0
                slant_right.end.y += slant_right.end.y - slant_right.start.y;
1470
0
            }
1471
0
            while (slant_left.start.y > Yb)
1472
0
            {
1473
0
                slant_left.start.x -= slant_left.end.x - slant_left.start.x;
1474
0
                slant_left.start.y -= slant_left.end.y - slant_left.start.y;
1475
0
            }
1476
            /* Consider the centre of the pixel above and to the right of
1477
             * vert_right.start. If that's inside our newly extended trap
1478
             * then we can't use the extended one without changing the
1479
             * rendered result. */
1480
0
            cy = fixed_pixround(vert_right.start.y)+fixed_half;
1481
0
            cx = fixed_pixround(vert_right.start.x)+fixed_half;
1482
0
            dy = slant_right.end.y-slant_right.start.y;
1483
0
            x = vert_right.start.x +
1484
0
                (fixed)((((int64_t)(slant_right.end.x-slant_right.start.x)) *
1485
0
                         ((int64_t)(cy-vert_right.start.y)) + dy - 1) /
1486
0
                        ((int64_t)dy));
1487
0
            if ((cy >= Y1a) || (x < cx))
1488
0
            {
1489
                /* We are safe to extend the trap upwards */
1490
0
                Y1b = Y1a;
1491
0
            }
1492
            /* Consider the centre of the pixel below and to the left of
1493
             * vert_left.end. If that's inside our newly extended trap
1494
             * then we can't use the extended one without changing the
1495
             * rendered result. */
1496
0
            cy = fixed_pixround(vert_left.end.y)-fixed_half;
1497
0
            cx = fixed_pixround(vert_left.end.x)-fixed_half;
1498
0
            dy = slant_left.end.y-slant_left.start.y;
1499
0
            x = vert_left.end.x -
1500
0
                (fixed)((((int64_t)(slant_left.end.x-slant_left.start.x)) *
1501
0
                         ((int64_t)(vert_left.end.y-cy)) + dy - 1) /
1502
0
                        ((int64_t)dy));
1503
0
            if ((cy < Yb) || (x > cx))
1504
0
            {
1505
                /* We are safe to extend the trap downwards */
1506
0
                Ya = Yb;
1507
0
            }
1508
0
        }
1509
0
    } else {
1510
0
        vert_left.start.x = vert_left.end.x = flp->x_next - fo->adjust_left;
1511
0
        vert_left.start.y = Y1b, vert_left.end.y = Y1a;
1512
0
        vert_right.start.x = vert_right.end.x = alp->x_current + fo->adjust_right;
1513
0
        vert_right.start.y = Yb, vert_right.end.y = Ya;
1514
0
        slant_left.start.y = flp->start.y - fo->adjust_below;
1515
0
        slant_left.end.y = flp->end.y - fo->adjust_below;
1516
0
        slant_right.start.y = alp->start.y + fo->adjust_above;
1517
0
        slant_right.end.y = alp->end.y + fo->adjust_above;
1518
0
        plbot = &slant_left, prbot = &vert_right;
1519
0
        pltop = &vert_left, prtop = &slant_right;
1520
0
        if (TRY_TO_EXTEND_TRAP)
1521
0
        {
1522
0
            int x, cx, cy, dy;
1523
            /* Extend the slanted edges so they extend above/below the
1524
             * adjusted Y range. This means we could maybe use them
1525
             * directly. */
1526
0
            while (slant_left.end.y < Y1a)
1527
0
            {
1528
0
                slant_left.end.x += slant_left.end.x - slant_left.start.x;
1529
0
                slant_left.end.y += slant_left.end.y - slant_left.start.y;
1530
0
            }
1531
0
            while (slant_right.start.y > Yb)
1532
0
            {
1533
0
                slant_right.start.x -= slant_right.end.x-slant_right.start.x;
1534
0
                slant_right.start.y -= slant_right.end.y-slant_right.start.y;
1535
0
            }
1536
            /* Consider the centre of the pixel above and to the left of
1537
             * vert_left.start. If that's inside our newly extended trap
1538
             * then we can't use the extended one without changing the
1539
             * rendered result. */
1540
0
            cy = fixed_pixround(vert_left.start.y)+fixed_half;
1541
0
            cx = fixed_pixround(vert_left.start.x)-fixed_half;
1542
0
            dy = slant_left.end.y-slant_left.start.y;
1543
0
            x = vert_left.start.x -
1544
0
                (fixed)((((int64_t)(slant_left.start.x-slant_left.end.x)) *
1545
0
                         ((int64_t)(cy-vert_left.start.y)) + dy - 1) /
1546
0
                        ((int64_t)dy));
1547
0
            if ((cy >= Y1a) || (x > cx))
1548
0
            {
1549
                /* We are safe to extend the trap upwards */
1550
0
                Y1b = Y1a;
1551
0
            }
1552
            /* Consider the centre of the pixel below and to the left of
1553
             * vert_left.end. If that's inside our newly extended trap
1554
             * then we can't use the extended one without changing the
1555
             * rendered result. */
1556
0
            cy = fixed_pixround(vert_right.end.y)-fixed_half;
1557
0
            cx = fixed_pixround(vert_right.end.x)-fixed_half;
1558
0
            dy = slant_right.end.y-slant_right.start.y;
1559
0
            x = vert_right.end.x +
1560
0
                (fixed)((((int64_t)(slant_right.start.x-slant_right.end.x)) *
1561
0
                         ((int64_t)(vert_right.end.y-cy)) + dy - 1) /
1562
0
                        ((int64_t)dy));
1563
0
            if ((cy < Yb) || (x < cx))
1564
0
            {
1565
                /* We are safe to extend the trap downwards */
1566
0
                Ya = Yb;
1567
0
            }
1568
0
        }
1569
0
    }
1570
1571
0
    if (Ya >= Y1b) {
1572
        /*
1573
         * The upper and lower adjustment bands overlap.
1574
         * Since the entire entity is less than 2 pixels high
1575
         * in this case, we could handle it very efficiently
1576
         * with no more than 2 rectangle fills, but for right now
1577
         * we don't attempt to do this.
1578
         */
1579
0
        int iYb = fixed2int_var_pixround(Yb);
1580
0
        int iYa = fixed2int_var_pixround(Ya);
1581
0
        int iY1b = fixed2int_var_pixround(Y1b);
1582
0
        int iY1a = fixed2int_var_pixround(Y1a);
1583
1584
0
        INCR(slant_shallow);
1585
0
        if (iY1b > iYb) {
1586
0
            code = fo->fill_trap(fo->dev, plbot, prbot,
1587
0
                                 Yb, Y1b, false, fo->pdevc, fo->lop);
1588
0
            if (code < 0)
1589
0
                return code;
1590
0
        }
1591
0
        if (iYa > iY1b) {
1592
0
            int ix = fixed2int_var_pixround(vert_left.start.x);
1593
0
            int iw = fixed2int_var_pixround(vert_right.start.x) - ix;
1594
1595
0
            code = gx_fill_rectangle_device_rop(ix, iY1b, iw, iYa - iY1b,
1596
0
                        fo->pdevc, fo->dev, fo->lop);
1597
0
            if (code < 0)
1598
0
                return code;
1599
0
        }
1600
0
        if (iY1a > iYa)
1601
0
            code = fo->fill_trap(fo->dev, pltop, prtop,
1602
0
                                 Ya, Y1a, false, fo->pdevc, fo->lop);
1603
0
        else
1604
0
            code = 0;
1605
0
    } else {
1606
        /*
1607
         * Clip the trapezoid if possible.  This can save a lot
1608
         * of work when filling paths that cross band boundaries.
1609
         */
1610
0
        fixed Yac;
1611
1612
0
        if (fo->pbox->p.y < Ya) {
1613
0
            code = fo->fill_trap(fo->dev, plbot, prbot,
1614
0
                                 Yb, Ya, false, fo->pdevc, fo->lop);
1615
0
            if (code < 0)
1616
0
                return code;
1617
0
            Yac = Ya;
1618
0
        } else
1619
0
            Yac = fo->pbox->p.y;
1620
0
        if (fo->pbox->q.y > Y1b) {
1621
0
            code = fo->fill_trap(fo->dev, &slant_left, &slant_right,
1622
0
                                 Yac, Y1b, false, fo->pdevc, fo->lop);
1623
0
            if (code < 0)
1624
0
                return code;
1625
0
            code = fo->fill_trap(fo->dev, pltop, prtop,
1626
0
                                 Y1b, Y1a, false, fo->pdevc, fo->lop);
1627
0
        } else
1628
0
            code = fo->fill_trap(fo->dev, &slant_left, &slant_right,
1629
0
                                 Yac, fo->pbox->q.y, false, fo->pdevc, fo->lop);
1630
0
    }
1631
0
    return code;
1632
0
}
1633
1634
/* Re-sort the x list by moving alp backward to its proper spot. */
1635
static inline void
1636
resort_x_line(active_line * alp)
1637
0
{
1638
0
    active_line *prev = alp->prev;
1639
0
    active_line *next = alp->next;
1640
1641
0
    prev->next = next;
1642
0
    if (next)
1643
0
        next->prev = prev;
1644
0
    while (x_order(prev, alp) > 0) {
1645
0
        if_debug2('F', "[F]swap "PRI_INTPTR","PRI_INTPTR"\n",
1646
0
                   (intptr_t)alp, (intptr_t)prev);
1647
0
        next = prev, prev = prev->prev;
1648
0
    }
1649
0
    alp->next = next;
1650
0
    alp->prev = prev;
1651
    /* next might be null, if alp was in the correct spot already. */
1652
0
    if (next)
1653
0
        next->prev = alp;
1654
    /* prev can be null if the path reaches (beyond) the extent of our coordinate space */
1655
0
    if (prev)
1656
0
        prev->next = alp;
1657
0
}
1658
1659
/* Move active lines by Y. */
1660
static inline int
1661
move_al_by_y(line_list *ll, fixed y1)
1662
0
{
1663
0
    fixed x;
1664
0
    active_line *alp, *nlp;
1665
0
    int code;
1666
1667
0
    for (x = min_fixed, alp = ll->x_list; alp != 0; alp = nlp) {
1668
0
        bool notend = false;
1669
0
        alp->x_current = alp->x_next;
1670
1671
0
        nlp = alp->next;
1672
0
        if (alp->end.y == y1 && alp->more_flattened) {
1673
0
            code = step_al(alp, true);
1674
0
            if (code < 0)
1675
0
                return code;
1676
0
            alp->x_current = alp->x_next = alp->start.x;
1677
0
            notend = (alp->end.y >= alp->start.y);
1678
0
        }
1679
0
        if (alp->end.y > y1 || notend) {
1680
0
            if (alp->x_next <= x)
1681
0
                resort_x_line(alp);
1682
0
            else
1683
0
                x = alp->x_next;
1684
0
        } else {
1685
0
            code = end_x_line(alp, ll, true);
1686
0
            if (code < 0)
1687
0
                return code;
1688
0
            if (!code) {
1689
0
                if (alp->x_next <= x)
1690
0
                    resort_x_line(alp);
1691
0
                else
1692
0
                    x = alp->x_next;
1693
0
            }
1694
0
        }
1695
0
    }
1696
0
    return 0;
1697
0
}
1698
1699
/* Process horizontal segment of curves. */
1700
static inline int
1701
process_h_segments(line_list *ll, fixed y)
1702
0
{
1703
0
    active_line *alp, *nlp;
1704
0
    int inserted = 0;
1705
1706
0
    for (alp = ll->x_list; alp != 0; alp = nlp) {
1707
0
        nlp = alp->next;
1708
0
        if (alp->start.y == y && alp->end.y == y) {
1709
0
            inserted = 1;
1710
0
        }
1711
0
    }
1712
0
    return inserted;
1713
    /* After this should call move_al_by_y and step to the next band. */
1714
0
}
1715
1716
static inline int
1717
loop_fill_trap_np(const line_list *ll, const gs_fixed_edge *le, const gs_fixed_edge *re, fixed y, fixed y1)
1718
0
{
1719
0
    const fill_options * const fo = ll->fo;
1720
0
    fixed ybot = max(y, fo->pbox->p.y);
1721
0
    fixed ytop = min(y1, fo->pbox->q.y);
1722
1723
0
    if (ybot >= ytop)
1724
0
        return 0;
1725
0
    return (*fo->fill_trap)
1726
0
        (fo->dev, le, re, ybot, ytop, false, fo->pdevc, fo->lop);
1727
0
}
1728
1729
/* Define variants of the algorithm for filling a slanted trapezoid. */
1730
#define TEMPLATE_slant_into_trapezoids slant_into_trapezoids__fd
1731
0
#define FILL_DIRECT 1
1732
#include "gxfillts.h"
1733
#undef TEMPLATE_slant_into_trapezoids
1734
#undef FILL_DIRECT
1735
1736
#define TEMPLATE_slant_into_trapezoids slant_into_trapezoids__nd
1737
0
#define FILL_DIRECT 0
1738
#include "gxfillts.h"
1739
#undef TEMPLATE_slant_into_trapezoids
1740
#undef FILL_DIRECT
1741
1742
#define COVERING_PIXEL_CENTERS(y, y1, adjust_below, adjust_above)\
1743
0
    (fixed_pixround(y - adjust_below) < fixed_pixround(y1 + adjust_above))
1744
1745
/* Find an intersection within y, y1. */
1746
/* lp->x_current, lp->x_next must be set for y, y1. */
1747
static bool
1748
intersect(active_line *endp, active_line *alp, fixed y, fixed y1, fixed *p_y_new)
1749
0
{
1750
0
    fixed y_new, dy;
1751
0
    fixed dx_old = alp->x_current - endp->x_current;
1752
0
    fixed dx_den = dx_old + endp->x_next - alp->x_next;
1753
1754
0
    if (dx_den <= dx_old || dx_den == 0)
1755
0
        return false; /* Intersection isn't possible. */
1756
0
    dy = y1 - y;
1757
0
    if_debug3('F', "[F]cross: dy=%g, dx_old=%g, dx_new=%g\n",
1758
0
              fixed2float(dy), fixed2float(dx_old),
1759
0
              fixed2float(dx_den - dx_old));
1760
    /* Do the computation in single precision */
1761
    /* if the values are small enough. */
1762
0
    y_new =
1763
0
        (((ufixed)(dy | dx_old)) < (1L << (size_of(fixed) * 4 - 1)) ?
1764
0
         dy * dx_old / dx_den :
1765
0
         (INCR_EXPR(mq_cross), fixed_mult_quo(dy, dx_old, dx_den)))
1766
0
        + y;
1767
    /* The crossing value doesn't have to be */
1768
    /* very accurate, but it does have to be */
1769
    /* greater than y and less than y1. */
1770
0
    if_debug3('F', "[F]cross y=%g, y_new=%g, y1=%g\n",
1771
0
              fixed2float(y), fixed2float(y_new),
1772
0
              fixed2float(y1));
1773
0
    if (y_new <= y) {
1774
        /*
1775
         * This isn't possible.  Recompute the intersection
1776
         * accurately.
1777
         */
1778
0
        fixed ys, xs0, xs1, ye, xe0, xe1, dy, dx0, dx1;
1779
1780
0
        INCR(cross_slow);
1781
0
        if (endp->start.y < alp->start.y)
1782
0
            ys = alp->start.y,
1783
0
                xs0 = AL_X_AT_Y(endp, ys), xs1 = alp->start.x;
1784
0
        else
1785
0
            ys = endp->start.y,
1786
0
                xs0 = endp->start.x, xs1 = AL_X_AT_Y(alp, ys);
1787
0
        if (endp->end.y > alp->end.y)
1788
0
            ye = alp->end.y,
1789
0
                xe0 = AL_X_AT_Y(endp, ye), xe1 = alp->end.x;
1790
0
        else
1791
0
            ye = endp->end.y,
1792
0
                xe0 = endp->end.x, xe1 = AL_X_AT_Y(alp, ye);
1793
0
        dy = ye - ys;
1794
0
        dx0 = xe0 - xs0;
1795
0
        dx1 = xe1 - xs1;
1796
        /* We need xs0 + cross * dx0 == xs1 + cross * dx1. */
1797
0
        if (dx0 == dx1) {
1798
            /* The two lines are coincident.  Do nothing. */
1799
0
            y_new = y1;
1800
0
        } else {
1801
0
            double cross = (double)(xs0 - xs1) / (dx1 - dx0);
1802
1803
0
            y_new = (fixed)(ys + cross * dy);
1804
0
            if (y_new <= y) {
1805
                /*
1806
                 * This can only happen through some kind of
1807
                 * numeric disaster, but we have to check.
1808
                 */
1809
0
                INCR(cross_low);
1810
0
                y_new = y + fixed_epsilon;
1811
0
            }
1812
0
        }
1813
0
    }
1814
0
    *p_y_new = y_new;
1815
0
    return true;
1816
0
}
1817
1818
static inline void
1819
set_x_next(active_line *endp, active_line *alp, fixed x)
1820
0
{
1821
0
    while(endp != alp) {
1822
0
        endp->x_next = x;
1823
0
        endp = endp->next;
1824
0
    }
1825
0
}
1826
1827
static inline int
1828
coord_weight(const active_line *alp)
1829
0
{
1830
0
    return 1 + min(any_abs((int)((int64_t)alp->diff.y * 8 / alp->diff.x)), 256);
1831
0
}
1832
1833
/* Find intersections of active lines within the band.
1834
   Intersect and reorder them, and correct the bund top. */
1835
static void
1836
intersect_al(line_list *ll, fixed y, fixed *y_top, int draw, bool all_bands)
1837
0
{
1838
0
    fixed x = min_fixed, y1 = *y_top;
1839
0
    active_line *alp, *stopx = NULL;
1840
0
    active_line *endp = NULL;
1841
1842
0
    if (y == y1) {
1843
        /* Rather the intersection algorithm can handle this case with
1844
           retrieving x_next equal to x_current,
1845
           we bypass it for safety reason.
1846
         */
1847
0
    } else if (draw >= 0 || all_bands) {
1848
        /*
1849
         * Loop invariants:
1850
         *      alp = endp->next;
1851
         *      for all lines lp from stopx up to alp,
1852
         *        lp->x_next = AL_X_AT_Y(lp, y1).
1853
         */
1854
0
        for (alp = stopx = ll->x_list;
1855
0
             INCR_EXPR(find_y), alp != 0;
1856
0
             endp = alp, alp = alp->next
1857
0
            ) {
1858
0
            fixed nx = AL_X_AT_Y(alp, y1);
1859
0
            fixed y_new;
1860
1861
0
            alp->x_next = nx;
1862
            /* Check for intersecting lines. */
1863
0
            if (nx >= x)
1864
0
                x = nx;
1865
0
            else if (alp->x_current >= endp->x_current &&
1866
0
                     intersect(endp, alp, y, y1, &y_new)) {
1867
0
                if (y_new <= y1) {
1868
0
                    stopx = endp;
1869
0
                    y1 = y_new;
1870
0
                    if (endp->diff.x == 0)
1871
0
                        nx = endp->start.x;
1872
0
                    else if (alp->diff.x == 0)
1873
0
                        nx = alp->start.x;
1874
0
                    else {
1875
0
                        fixed nx0 = AL_X_AT_Y(endp, y1);
1876
0
                        fixed nx1 = AL_X_AT_Y(alp, y1);
1877
0
                        if (nx0 != nx1) {
1878
                            /* Different results due to arithmetic errors.
1879
                               Choose an imtermediate point.
1880
                               We don't like to use floating numbners here,
1881
                               but the code with int64_t isn't much better. */
1882
0
                            int64_t w0 = coord_weight(endp);
1883
0
                            int64_t w1 = coord_weight(alp);
1884
1885
0
                            nx = (fixed)((w0 * nx0 + w1 * nx1) / (w0 + w1));
1886
0
                        } else
1887
0
                            nx = nx0;
1888
0
                    }
1889
0
                    endp->x_next = alp->x_next = nx;  /* Ensure same X. */
1890
                    /* Can't guarantee same x for triple intersections here.
1891
                       Will take care below */
1892
0
                }
1893
0
                if (nx > x)
1894
0
                    x = nx;
1895
0
            }
1896
0
        }
1897
        /* Recompute next_x for lines before the intersection. */
1898
0
        for (alp = ll->x_list; alp != stopx; alp = alp->next)
1899
0
            alp->x_next = AL_X_AT_Y(alp, y1);
1900
        /* Ensure X monotonity (particularly imporoves triple intersections). */
1901
0
        if (ll->x_list != NULL) {
1902
0
            for (;;) {
1903
0
                fixed x1;
1904
0
                double sx = 0xbaadf00d; /* 'fixed' can overflow. We operate 7-bytes integers. */
1905
0
                int k = 0xbaadf00d, n;
1906
1907
0
                endp = ll->x_list;
1908
0
                x1 = endp->x_next;
1909
0
                for (alp = endp->next; alp != NULL; x1 = alp->x_next, alp = alp->next)
1910
0
                    if (alp->x_next < x1)
1911
0
                        break;
1912
0
                if (alp == NULL)
1913
0
                    break;
1914
0
                x1 = endp->x_next;
1915
0
                n = 0;
1916
0
                for (alp = endp->next; alp != NULL; alp = alp->next) {
1917
0
                     x = alp->x_next;
1918
0
                     if (x < x1) {
1919
0
                        if (n == 0) {
1920
0
                            if (endp->diff.x == 0) {
1921
0
                                k = -1;
1922
0
                                sx = x1;
1923
0
                            } else {
1924
0
                                k = coord_weight(endp);
1925
0
                                sx = (double)x1 * k;
1926
0
                            }
1927
0
                            n = 1;
1928
0
                        }
1929
0
                        n++;
1930
0
                        if (alp->diff.x == 0) {
1931
                            /* Vertical lines have a higher priority. */
1932
0
                            if (k <= -1) {
1933
0
                                sx += x;
1934
0
                                k--;
1935
0
                            } else {
1936
0
                                k = -1;
1937
0
                                sx = x;
1938
0
                            }
1939
0
                        } else if (k > 0) {
1940
0
                            int w = coord_weight(alp);
1941
1942
0
                            sx += (double)x * w;
1943
0
                            k += w;
1944
0
                        }
1945
0
                     } else {
1946
0
                        if (n > 1) {
1947
0
                            k = any_abs(k);
1948
0
                            set_x_next(endp, alp, (fixed)((sx + k / 2) / k));
1949
0
                        }
1950
0
                        x1 = alp->x_next;
1951
0
                        n = 0;
1952
0
                        endp = alp;
1953
0
                     }
1954
0
                }
1955
0
                if (n > 1) {
1956
0
                    k = any_abs(k);
1957
0
                    set_x_next(endp, alp, (fixed)((sx + k / 2) / k));
1958
0
                }
1959
0
            }
1960
0
        }
1961
0
    } else {
1962
        /* Recompute next_x for lines before the intersection. */
1963
0
        for (alp = ll->x_list; alp != stopx; alp = alp->next)
1964
0
            alp->x_next = AL_X_AT_Y(alp, y1);
1965
0
    }
1966
#ifdef DEBUG
1967
    if (gs_debug_c('F')) {
1968
        dmlprintf1(ll->memory, "[F]after loop: y1=%f\n", fixed2float(y1));
1969
        print_line_list(ll->memory, ll->x_list);
1970
    }
1971
#endif
1972
0
    *y_top = y1;
1973
0
}
1974
1975
/* ---------------- Trapezoid filling loop ---------------- */
1976
1977
/* Generate specialized algorythms for the most important cases : */
1978
1979
/* The smart winding counter advance operator : */
1980
0
#define signed_eo(a) ((a) < 0 ? -((a) & 1) : (a) > 0 ? ((a) & 1) : 0)
1981
#define ADVANCE_WINDING(inside, alp, ll) \
1982
0
                {   int k = alp->contour_count; \
1983
0
                    int v = ll->windings[k]; \
1984
0
                    inside -= signed_eo(v); \
1985
0
                    v = ll->windings[k] += alp->direction; \
1986
0
                    inside += signed_eo(v); \
1987
0
                }
1988
1989
0
#define IS_SPOTAN 0
1990
0
#define SMART_WINDING 1
1991
0
#define FILL_ADJUST 0
1992
0
#define FILL_DIRECT 1
1993
#define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__nj_fd_sw
1994
#include "gxfilltr.h"
1995
#undef IS_SPOTAN
1996
#undef SMART_WINDING
1997
#undef FILL_ADJUST
1998
#undef FILL_DIRECT
1999
#undef TEMPLATE_spot_into_trapezoids
2000
2001
0
#define IS_SPOTAN 0
2002
0
#define SMART_WINDING 1
2003
0
#define FILL_ADJUST 0
2004
0
#define FILL_DIRECT 0
2005
#define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__nj_nd_sw
2006
#include "gxfilltr.h"
2007
#undef IS_SPOTAN
2008
#undef SMART_WINDING
2009
#undef FILL_ADJUST
2010
#undef FILL_DIRECT
2011
#undef TEMPLATE_spot_into_trapezoids
2012
2013
#undef signed_eo
2014
#undef ADVANCE_WINDING
2015
/* The simple winding counter advance operator : */
2016
0
#define ADVANCE_WINDING(inside, alp, ll) inside += alp->direction
2017
2018
0
#define IS_SPOTAN 1
2019
0
#define SMART_WINDING 0
2020
0
#define FILL_ADJUST 0
2021
0
#define FILL_DIRECT 1
2022
#define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__spotan
2023
#include "gxfilltr.h"
2024
#undef IS_SPOTAN
2025
#undef SMART_WINDING
2026
#undef FILL_ADJUST
2027
#undef FILL_DIRECT
2028
#undef TEMPLATE_spot_into_trapezoids
2029
2030
0
#define IS_SPOTAN 0
2031
0
#define SMART_WINDING 0
2032
0
#define FILL_ADJUST 1
2033
0
#define FILL_DIRECT 1
2034
#define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__aj_fd
2035
#include "gxfilltr.h"
2036
#undef IS_SPOTAN
2037
#undef SMART_WINDING
2038
#undef FILL_ADJUST
2039
#undef FILL_DIRECT
2040
#undef TEMPLATE_spot_into_trapezoids
2041
2042
0
#define IS_SPOTAN 0
2043
0
#define SMART_WINDING 0
2044
0
#define FILL_ADJUST 1
2045
0
#define FILL_DIRECT 0
2046
#define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__aj_nd
2047
#include "gxfilltr.h"
2048
#undef IS_SPOTAN
2049
#undef SMART_WINDING
2050
#undef FILL_ADJUST
2051
#undef FILL_DIRECT
2052
#undef TEMPLATE_spot_into_trapezoids
2053
2054
0
#define IS_SPOTAN 0
2055
0
#define SMART_WINDING 0
2056
0
#define FILL_ADJUST 0
2057
0
#define FILL_DIRECT 1
2058
#define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__nj_fd
2059
#include "gxfilltr.h"
2060
#undef IS_SPOTAN
2061
#undef SMART_WINDING
2062
#undef FILL_ADJUST
2063
#undef FILL_DIRECT
2064
#undef TEMPLATE_spot_into_trapezoids
2065
2066
0
#define IS_SPOTAN 0
2067
0
#define SMART_WINDING 0
2068
0
#define FILL_ADJUST 0
2069
0
#define FILL_DIRECT 0
2070
#define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__nj_nd
2071
#include "gxfilltr.h"
2072
#undef IS_SPOTAN
2073
#undef SMART_WINDING
2074
#undef FILL_ADJUST
2075
#undef FILL_DIRECT
2076
#undef TEMPLATE_spot_into_trapezoids
2077
2078
#undef ADVANCE_WINDING
2079
2080
/* Main filling loop.  Takes lines off of y_list and adds them to */
2081
/* x_list as needed.  band_mask limits the size of each band, */
2082
/* by requiring that ((y1 - 1) & band_mask) == (y0 & band_mask). */
2083
static int
2084
spot_into_trapezoids(line_list *ll, fixed band_mask)
2085
0
{
2086
    /* For better performance, choose a specialized algorithm : */
2087
0
    const fill_options * const fo = ll->fo;
2088
2089
0
    if (fo->is_spotan)
2090
0
        return spot_into_trapezoids__spotan(ll, band_mask);
2091
0
    if (fo->adjust_below | fo->adjust_above | fo->adjust_left | fo->adjust_right) {
2092
0
        if (fo->fill_direct)
2093
0
            return spot_into_trapezoids__aj_fd(ll, band_mask);
2094
0
        else
2095
0
            return spot_into_trapezoids__aj_nd(ll, band_mask);
2096
0
    } else if (ll->windings != NULL) {
2097
0
        if (fo->fill_direct)
2098
0
            return spot_into_trapezoids__nj_fd_sw(ll, band_mask);
2099
0
        else
2100
0
            return spot_into_trapezoids__nj_nd_sw(ll, band_mask);
2101
0
    } else {
2102
0
        if (fo->fill_direct)
2103
0
            return spot_into_trapezoids__nj_fd(ll, band_mask);
2104
0
        else
2105
0
            return spot_into_trapezoids__nj_nd(ll, band_mask);
2106
0
    }
2107
0
}
2108
2109
/* ---------------- Range list management ---------------- */
2110
2111
/*
2112
 * We originally thought we would store fixed values in coordinate ranges,
2113
 * but it turned out we want to store integers.
2114
 */
2115
typedef int coord_value_t;
2116
0
#define MIN_COORD_VALUE min_int
2117
0
#define MAX_COORD_VALUE max_int
2118
/*
2119
 * The invariant for coord_range_ts in a coord_range_list_t:
2120
 *      if prev == 0:
2121
 *              next != 0
2122
 *              rmin == rmax == MIN_COORD_VALUE
2123
 *      else if next == 0:
2124
 *              prev != 0
2125
 *              rmin == rmax == MAX_COORD_VALUE
2126
 *      else
2127
 *              rmin < rmax
2128
 *      if prev != 0:
2129
 *              prev->next == this
2130
 *              prev->rmax < rmin
2131
 *      if next != 0:
2132
 *              next->prev = this
2133
 *              next->rmin > rmax
2134
 * A coord_range_list_t has a boundary element at each end to avoid having
2135
 * to test for null pointers in the insertion loop.  The boundary elements
2136
 * are the only empty ranges.
2137
 */
2138
typedef struct coord_range_s coord_range_t;
2139
struct coord_range_s {
2140
    coord_value_t rmin, rmax;
2141
    coord_range_t *prev, *next;
2142
    coord_range_t *alloc_next;
2143
};
2144
/* We declare coord_range_ts as simple because they only exist transiently. */
2145
gs_private_st_simple(st_coord_range, coord_range_t, "coord_range_t");
2146
2147
typedef struct coord_range_list_s {
2148
    gs_memory_t *memory;
2149
    struct rl_ {
2150
        coord_range_t *first, *next, *limit;
2151
    } local;
2152
    coord_range_t *allocated;
2153
    coord_range_t *freed;
2154
    coord_range_t *current;
2155
    coord_range_t first, last;
2156
} coord_range_list_t;
2157
2158
static coord_range_t *
2159
range_alloc(coord_range_list_t *pcrl)
2160
0
{
2161
0
    coord_range_t *pcr;
2162
2163
0
    if (pcrl->freed) {
2164
0
        pcr = pcrl->freed;
2165
0
        pcrl->freed = pcr->next;
2166
0
    } else if (pcrl->local.next < pcrl->local.limit)
2167
0
        pcr = pcrl->local.next++;
2168
0
    else {
2169
0
        pcr = gs_alloc_struct(pcrl->memory, coord_range_t, &st_coord_range,
2170
0
                              "range_alloc");
2171
0
        if (pcr == 0)
2172
0
            return 0;
2173
0
        pcr->alloc_next = pcrl->allocated;
2174
0
        pcrl->allocated = pcr;
2175
0
    }
2176
0
    return pcr;
2177
0
}
2178
2179
static void
2180
range_delete(coord_range_list_t *pcrl, coord_range_t *pcr)
2181
0
{
2182
0
    if_debug3('Q', "[Qr]delete "PRI_INTPTR": [%d,%d)\n",
2183
0
              (intptr_t)pcr, pcr->rmin, pcr->rmax);
2184
0
    pcr->prev->next = pcr->next;
2185
0
    pcr->next->prev = pcr->prev;
2186
0
    pcr->next = pcrl->freed;
2187
0
    pcrl->freed = pcr;
2188
0
}
2189
2190
static void
2191
range_list_clear(coord_range_list_t *pcrl)
2192
0
{
2193
0
    if_debug0('Q', "[Qr]clearing\n");
2194
0
    pcrl->first.next = &pcrl->last;
2195
0
    pcrl->last.prev = &pcrl->first;
2196
0
    pcrl->current = &pcrl->last;
2197
0
}
2198
2199
/* ------ "Public" procedures ------ */
2200
2201
/* Initialize a range list.  We require num_local >= 2. */
2202
static void range_list_clear(coord_range_list_t *);
2203
static void
2204
range_list_init(coord_range_list_t *pcrl, coord_range_t *pcr_local,
2205
                int num_local, gs_memory_t *mem)
2206
0
{
2207
0
    pcrl->memory = mem;
2208
0
    pcrl->local.first = pcrl->local.next = pcr_local;
2209
0
    pcrl->local.limit = pcr_local + num_local;
2210
0
    pcrl->allocated = pcrl->freed = 0;
2211
0
    pcrl->first.rmin = pcrl->first.rmax = MIN_COORD_VALUE;
2212
0
    pcrl->first.prev = 0;
2213
0
    pcrl->last.rmin = pcrl->last.rmax = MAX_COORD_VALUE;
2214
0
    pcrl->last.next = 0;
2215
0
    range_list_clear(pcrl);
2216
0
}
2217
2218
/* Reset an initialized range list to the empty state. */
2219
static void
2220
range_list_reset(coord_range_list_t *pcrl)
2221
0
{
2222
0
    if (pcrl->first.next != &pcrl->last) {
2223
0
        pcrl->last.prev->next = pcrl->freed;
2224
0
        pcrl->freed = pcrl->first.next;
2225
0
        range_list_clear(pcrl);
2226
0
    }
2227
0
}
2228
2229
/*
2230
 * Move the cursor to the beginning of a range list, in the belief that
2231
 * the next added ranges will roughly parallel the existing ones.
2232
 * (Only affects performance, not function.)
2233
 */
2234
static inline void
2235
range_list_rescan(coord_range_list_t *pcrl)
2236
0
{
2237
0
    pcrl->current = pcrl->first.next;
2238
0
}
2239
2240
/* Free a range list. */
2241
static void
2242
range_list_free(coord_range_list_t *pcrl)
2243
0
{
2244
0
    coord_range_t *pcr;
2245
2246
0
    while ((pcr = pcrl->allocated) != 0) {
2247
0
        coord_range_t *next = pcr->alloc_next;
2248
2249
0
        gs_free_object(pcrl->memory, pcr, "range_list_free");
2250
0
        pcrl->allocated = next;
2251
0
    }
2252
0
}
2253
2254
/* Add a range. */
2255
static int
2256
range_list_add(coord_range_list_t *pcrl, coord_value_t rmin, coord_value_t rmax)
2257
0
{
2258
0
    coord_range_t *pcr = pcrl->current;
2259
2260
0
    if (rmin >= rmax)
2261
0
        return 0;
2262
    /*
2263
     * Usually, ranges are added in increasing order within each scan line,
2264
     * and overlapping ranges don't differ much.  Optimize accordingly.
2265
     */
2266
0
 top:
2267
0
    if (rmax < pcr->rmin) {
2268
0
        if (rmin > pcr->prev->rmax)
2269
0
            goto ins;
2270
0
        pcr = pcr->prev;
2271
0
        goto top;
2272
0
    }
2273
0
    if (rmin > pcr->rmax) {
2274
0
        pcr = pcr->next;
2275
0
        if (rmax < pcr->rmin)
2276
0
            goto ins;
2277
0
        goto top;
2278
0
    }
2279
    /*
2280
     * Now we know that (rmin,rmax) overlaps (pcr->rmin,pcr->rmax).
2281
     * Don't delete or merge into the special min and max ranges.
2282
     */
2283
0
    while (rmin <= pcr->prev->rmax) {
2284
        /* Merge the range below pcr into this one. */
2285
0
        if (!pcr->prev->prev)
2286
0
            break;              /* don't merge into the min range */
2287
0
        pcr->rmin = pcr->prev->rmin;
2288
0
        range_delete(pcrl, pcr->prev);
2289
0
    }
2290
0
    while (rmax >= pcr->next->rmin) {
2291
        /* Merge the range above pcr into this one. */
2292
0
        if (!pcr->next->next)
2293
0
            break;              /* don't merge into the max range */
2294
0
        pcr->rmax = pcr->next->rmax;
2295
0
        range_delete(pcrl, pcr->next);
2296
0
    }
2297
    /*
2298
     * Now we know that the union of (rmin,rmax) and (pcr->rmin,pcr->rmax)
2299
     * doesn't overlap or abut either adjacent range, except that it may
2300
     * abut if the adjacent range is the special min or max range.
2301
     */
2302
0
    if (rmin < pcr->rmin) {
2303
0
        if_debug3('Q', "[Qr]update "PRI_INTPTR" => [%d,%d)\n",
2304
0
                  (intptr_t)pcr, rmin, pcr->rmax);
2305
0
        pcr->rmin = rmin;
2306
0
    }
2307
0
    if (rmax > pcr->rmax) {
2308
0
        if_debug3('Q', "[Qr]update "PRI_INTPTR" => [%d,%d)\n",
2309
0
                  (intptr_t)pcr, pcr->rmin, rmax);
2310
0
        pcr->rmax = rmax;
2311
0
    }
2312
0
    pcrl->current = pcr->next;
2313
0
    return 0;
2314
0
 ins:
2315
    /* Insert a new range below pcr. */
2316
0
    {
2317
0
        coord_range_t *prev = range_alloc(pcrl);
2318
2319
0
        if (prev == 0)
2320
0
            return_error(gs_error_VMerror);
2321
0
        if_debug3('Q', "[Qr]insert "PRI_INTPTR": [%d,%d)\n", (intptr_t)prev, rmin, rmax);
2322
0
        prev->rmin = rmin, prev->rmax = rmax;
2323
0
        (prev->prev = pcr->prev)->next = prev;
2324
0
        prev->next = pcr;
2325
0
        pcr->prev = prev;
2326
0
    }
2327
0
    pcrl->current = pcr;
2328
0
    return 0;
2329
0
}
2330
2331
/*
2332
 * Merge regions for active segments starting at a given Y, or all active
2333
 * segments, up to the end of the sampling band or the end of the segment,
2334
 * into the range list.
2335
 */
2336
static int
2337
merge_ranges(coord_range_list_t *pcrl, const line_list *ll, fixed y_min, fixed y_top)
2338
0
{
2339
0
    active_line *alp, *nlp;
2340
0
    int code = 0;
2341
2342
0
    range_list_rescan(pcrl);
2343
0
    for (alp = ll->x_list; alp != 0 && code >= 0; alp = nlp) {
2344
0
        fixed x0 = alp->x_current, x1, xt;
2345
0
        bool forth = (alp->direction == DIR_UP || !alp->fi.curve);
2346
0
        fixed xe = (forth ? alp->fi.x3 : alp->fi.x0);
2347
0
        fixed ye = (forth ? alp->fi.y3 : alp->fi.y0);
2348
2349
0
        nlp = alp->next;
2350
0
        if (alp->start.y < y_min)
2351
0
            continue;
2352
0
        if (alp->monotonic_x && alp->monotonic_y && ye <= y_top) {
2353
0
            x1 = xe;
2354
0
            if (x0 > x1)
2355
0
                xt = x0, x0 = x1, x1 = xt;
2356
0
            code = range_list_add(pcrl,
2357
0
                                  fixed2int_pixround(x0 - ll->fo->adjust_left),
2358
0
                                  fixed2int_rounded(x1 + ll->fo->adjust_right));
2359
0
            alp->more_flattened = false; /* Skip all the segments left. */
2360
0
        } else {
2361
0
            x1 = x0;
2362
0
            for (;;) {
2363
0
                if (alp->end.y <= y_top)
2364
0
                    xt = alp->end.x;
2365
0
                else
2366
0
                    xt = AL_X_AT_Y(alp, y_top);
2367
0
                x0 = min(x0, xt);
2368
0
                x1 = max(x1, xt);
2369
0
                if (!alp->more_flattened || alp->end.y > y_top)
2370
0
                    break;
2371
0
                code = step_al(alp, true);
2372
0
                if (code < 0)
2373
0
                    return code;
2374
0
                if (alp->end.y < alp->start.y) {
2375
0
                    remove_al(ll, alp); /* End of a monotonic part of a curve. */
2376
0
                    break;
2377
0
                }
2378
0
            }
2379
0
            code = range_list_add(pcrl,
2380
0
                                  fixed2int_pixround(x0 - ll->fo->adjust_left),
2381
0
                                  fixed2int_rounded(x1 + ll->fo->adjust_right));
2382
0
        }
2383
2384
0
    }
2385
0
    return code;
2386
0
}
2387
2388
/* ---------------- Scan line filling loop ---------------- */
2389
2390
/* defina specializations of the scanline algorithm. */
2391
2392
0
#define FILL_DIRECT 1
2393
#define TEMPLATE_spot_into_scanlines spot_into_scan_lines_fd
2394
#include "gxfillsl.h"
2395
#undef FILL_DIRECT
2396
#undef TEMPLATE_spot_into_scanlines
2397
2398
0
#define FILL_DIRECT 0
2399
#define TEMPLATE_spot_into_scanlines spot_into_scan_lines_nd
2400
#include "gxfillsl.h"
2401
#undef FILL_DIRECT
2402
#undef TEMPLATE_spot_into_scanlines
2403
2404
static int
2405
spot_into_scan_lines(line_list *ll, fixed band_mask)
2406
0
{
2407
0
    if (ll->fo->fill_direct)
2408
0
        return spot_into_scan_lines_fd(ll, band_mask);
2409
0
    else
2410
0
        return spot_into_scan_lines_nd(ll, band_mask);
2411
0
}