Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gxfillsl.h
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Configurable algorithm for filling a path by scanlines. */
18
19
/*
20
 * Since we need several statically defined variants of this agorithm,
21
 * we store it in .h file and include it several times into gxfill.c .
22
 * Configuration macros (template arguments) are :
23
 *
24
 *  FILL_DIRECT - See LOOP_FILL_RECTANGLE_DIRECT.
25
 *  TEMPLATE_spot_into_scanlines - the name of the procedure to generate.
26
*/
27
28
#if defined(TEMPLATE_spot_into_scanlines) && defined(INCR) && defined(LOOP_FILL_RECTANGLE_DIRECT)
29
30
static int
31
TEMPLATE_spot_into_scanlines (line_list *ll, fixed band_mask)
32
0
{
33
0
    const fill_options fo = *ll->fo;
34
0
    active_line *yll = ll->y_list;
35
0
    fixed y_limit = fo.ymax;
36
    /*
37
     * The meaning of adjust_below (B) and adjust_above (A) is that the
38
     * pixels that would normally be painted at coordinate Y get "smeared"
39
     * to coordinates Y-B through Y+A-epsilon, inclusive.  This is
40
     * equivalent to saying that the pixels actually painted at coordinate Y
41
     * are those contributed by scan lines Y-A+epsilon through Y+B,
42
     * inclusive.  (A = B = 0 is a special case, equivalent to B = 0, A =
43
     * epsilon.)
44
     */
45
0
    fixed y_frac_min =
46
0
        (fo.adjust_above == fixed_0 ? fixed_half :
47
0
         fixed_half + fixed_epsilon - fo.adjust_above);
48
0
    fixed y_frac_max =
49
0
        fixed_half + fo.adjust_below;
50
0
    int y0 = fixed2int(min_fixed);
51
0
    fixed y_bot = min_fixed; /* normally int2fixed(y0) + y_frac_min */
52
0
    fixed y_top = min_fixed; /* normally int2fixed(y0) + y_frac_max */
53
0
    fixed y = min_fixed;
54
0
    coord_range_list_t rlist;
55
0
    coord_range_t rlocal[MAX_LOCAL_ACTIVE];
56
0
    int code = 0;
57
58
0
    if (yll == 0)   /* empty list */
59
0
        return 0;
60
0
    range_list_init(&rlist, rlocal, countof(rlocal), ll->memory);
61
0
    ll->x_list = 0;
62
0
    ll->x_head.x_current = min_fixed; /* stop backward scan */
63
0
    do {
64
0
        active_line *alp, *nlp;
65
0
        fixed x;
66
0
        bool new_band;
67
68
0
        INCR(iter);
69
70
0
        code = move_al_by_y(ll, y); /* Skip horizontal pieces. */
71
0
        if (code < 0)
72
0
            return code;
73
        /*
74
         * Find the next sampling point, either the bottom of a sampling
75
         * band or a line start.
76
         */
77
78
0
        if (ll->x_list == 0)
79
0
            y = (yll == 0 ? ll->y_break : yll->start.y);
80
0
        else {
81
0
            y = y_bot + fixed_1;
82
0
            if (yll != 0)
83
0
                y = min(y, yll->start.y);
84
0
            for (alp = ll->x_list; alp != 0; alp = alp->next) {
85
0
                fixed yy = max(alp->fi.y3, alp->fi.y0);
86
87
0
                yy = max(yy, alp->end.y); /* Non-monotonic curves may have an inner extreme. */
88
0
                y = min(y, yy);
89
0
            }
90
0
        }
91
92
        /* Move newly active lines from y to x list. */
93
94
0
        while (yll != 0 && yll->start.y == y) {
95
0
            active_line *ynext = yll->next; /* insert smashes next/prev links */
96
97
0
            if (yll->direction == DIR_HORIZONTAL) {
98
0
                insert_h_new(yll, ll);
99
0
            } else
100
0
                insert_x_new(yll, ll);
101
0
            yll = ynext;
102
0
        }
103
104
        /* Update active lines to y. */
105
106
0
        x = min_fixed;
107
0
        for (alp = ll->x_list; alp != 0; alp = nlp) {
108
0
            fixed nx;
109
110
0
            nlp = alp->next;
111
0
          e:if (alp->end.y <= y || alp->start.y == alp->end.y) {
112
0
                if (end_x_line(alp, ll, true))
113
0
                    continue;
114
0
                if (alp->more_flattened)
115
0
                    if (alp->end.y <= y || alp->start.y == alp->end.y) {
116
0
                        code = step_al(alp, true);
117
0
                        if (code < 0)
118
0
                            return code;
119
0
                    }
120
0
                goto e;
121
0
            }
122
0
            nx = alp->x_current = (alp->start.y >= y ? alp->start.x : AL_X_AT_Y(alp, y));
123
0
            if (nx < x) {
124
                /* Move this line backward in the list. */
125
0
                active_line *ilp = alp;
126
127
0
                while (nx < (ilp = ilp->prev)->x_current)
128
0
                    DO_NOTHING;
129
                /* Now ilp->x_current <= nx < ilp->next->x_cur. */
130
0
                alp->prev->next = alp->next;
131
0
                if (alp->next)
132
0
                    alp->next->prev = alp->prev;
133
0
                if (ilp->next)
134
0
                    ilp->next->prev = alp;
135
0
                alp->next = ilp->next;
136
0
                ilp->next = alp;
137
0
                alp->prev = ilp;
138
0
                continue;
139
0
            }
140
0
            x = nx;
141
0
        }
142
143
0
        if (y > y_top || y >= y_limit) {
144
            /* We're beyond the end of the previous sampling band. */
145
0
            const coord_range_t *pcr;
146
147
            /* Fill the ranges for y0. */
148
149
0
            for (pcr = rlist.first.next; pcr != &rlist.last;
150
0
                 pcr = pcr->next
151
0
                 ) {
152
0
                int x0 = pcr->rmin, x1 = pcr->rmax;
153
154
0
                if_debug4m('Q', ll->memory, "[Qr]draw "PRI_INTPTR": [%d,%d),%d\n",
155
0
                           (intptr_t)pcr, x0, x1, y0);
156
0
                code = LOOP_FILL_RECTANGLE_DIRECT(&fo, x0, y0, x1 - x0, 1);
157
0
                if_debug3m('F', ll->memory, "[F]drawing [%d:%d),%d\n", x0, x1, y0);
158
0
                if (code < 0)
159
0
                    goto done;
160
0
            }
161
0
            range_list_reset(&rlist);
162
163
            /* Check whether we've reached the maximum y. */
164
165
0
            if (y >= y_limit)
166
0
                break;
167
168
            /* Reset the sampling band. */
169
170
0
            y0 = fixed2int(y);
171
0
            if (fixed_fraction(y) < y_frac_min)
172
0
                --y0;
173
0
            y_bot = int2fixed(y0) + y_frac_min;
174
0
            y_top = int2fixed(y0) + y_frac_max;
175
0
            new_band = true;
176
0
        } else
177
0
            new_band = false;
178
179
0
        if (y <= y_top) {
180
            /*
181
             * We're within the same Y pixel.  Merge regions for segments
182
             * starting here (at y), up to y_top or the end of the segment.
183
             * If this is the first sampling within the band, run the
184
             * fill/eofill algorithm.
185
             */
186
0
            fixed y_min;
187
188
0
            if (new_band) {
189
0
                int inside = 0;
190
191
0
                INCR(band);
192
0
                for (alp = ll->x_list; alp != 0; alp = alp->next) {
193
0
                    int x0 = fixed2int_pixround(alp->x_current - fo.adjust_left);
194
195
0
                    for (;;) {
196
                        /* We're inside a filled region. */
197
0
                        print_al(ll->memory, "step", alp);
198
0
                        INCR(band_step);
199
0
                        inside += alp->direction;
200
0
                        if (!INSIDE_PATH_P(inside, fo.rule))
201
0
                            break;
202
                        /*
203
                         * Since we're dealing with closed paths, the test
204
                         * for alp == 0 shouldn't be needed, but we may have
205
                         * omitted lines that are to the right of the
206
                         * clipping region.
207
                         */
208
0
                        if ((alp = alp->next) == 0)
209
0
                            goto out;
210
0
                    }
211
                    /* We just went from inside to outside, so fill the region. */
212
0
                    code = range_list_add(&rlist, x0,
213
0
                                          fixed2int_rounded(alp->x_current +
214
0
                                                            fo.adjust_right));
215
0
                    if (code < 0)
216
0
                        goto done;
217
0
                }
218
0
            out:
219
0
                y_min = min_fixed;
220
0
            } else
221
0
                y_min = y;
222
223
            /* Process horizontal segments */
224
225
0
            for (alp = ll->h_list0; alp != NULL; alp = alp->next) {
226
0
                fixed x0 = min(alp->start.x, alp->end.x);
227
0
                fixed x1 = max(alp->start.x, alp->end.x);
228
229
0
                code = range_list_add(&rlist, fixed2int_rounded(x0 - fo.adjust_left),
230
0
                                              fixed2int_rounded(x1 + fo.adjust_right));
231
0
                if (code < 0)
232
0
                    goto done;
233
0
            }
234
235
0
            code = merge_ranges(&rlist, ll, y_min, y_top);
236
0
        } /* else y < y_bot + 1, do nothing */
237
0
        ll->h_list0 = NULL;
238
0
    } while (code >= 0);
239
0
 done:
240
0
    range_list_free(&rlist);
241
0
    return code;
242
0
}
Unexecuted instantiation: gxfill.c:spot_into_scan_lines_fd
Unexecuted instantiation: gxfill.c:spot_into_scan_lines_nd
243
244
#else
245
int dummy;
246
#endif