Coverage Report

Created: 2022-10-31 07:00

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