Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/claptrap.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2015-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
#include <stdlib.h>
17
#include <string.h>
18
#include <assert.h>
19
20
#include "claptrap.h"
21
#include "claptrap-impl.h"
22
23
/* This is the actual guts of the per-pixel processing.
24
 * We use a static inline, so the compiler can optimise
25
 * out as many of the tests as possible. */
26
inline static void process_at_pixel(ClapTrap      * gs_restrict ct,
27
                                    unsigned char * gs_restrict buffer,
28
                                    int            x,
29
                                    int            clips_on_x,
30
                                    int            clips_on_y,
31
                                    int            first_comp,
32
                                    int            last_comp,
33
                                    int            prev_comp,
34
                                    int            comp,
35
                                    int            line_offset,
36
                                    unsigned char *process)
37
0
{
38
    /* We look at the pixel values on comp.
39
     * We look at the process values passed into us from prev_comp, and pass out
40
     * into comp.
41
     */
42
43
    /* Use local vars to avoid pointer aliasing */
44
0
    int            width        = ct->width;
45
0
    int            height       = ct->height;
46
0
    int            num_comps    = ct->num_comps;
47
0
    int            max_x_offset = ct->max_x_offset;
48
0
    int            max_y_offset = ct->max_y_offset;
49
0
    int            span         = ct->span;
50
0
    int            lines_in_buf = ct->lines_in_buf;
51
0
    unsigned char *linebuf      = ct->linebuf;
52
0
    int            y            = ct->y;
53
    /* Some offsets we will use repeatedly */
54
0
    int            o            = x * num_comps;
55
0
    int            oc           = o + comp;
56
    /* p != 0 if we need to be processed because a previous component shadows us.
57
     * If we're the first component then no one can shadow us. */
58
0
    int            p            = (first_comp ? 0 : *process);
59
0
    int            sx, sy, ex, ey, lo, v;
60
0
    unsigned char *pc;
61
0
    unsigned char *ppc;
62
63
0
    assert((first_comp != 1) ^ (prev_comp == -1));
64
0
    assert((last_comp != 1) ^ (comp == ct->comp_order[num_comps-1]));
65
66
    /* Work out the search region bounds */
67
0
    sy = y - max_y_offset;
68
0
    if (clips_on_y && sy < 0)
69
0
        sy = 0;
70
0
    ey = y + max_y_offset;
71
0
    if (clips_on_y && ey >= height)
72
0
        ey = height-1;
73
0
    sx = x - max_x_offset;
74
0
    if (clips_on_x && sx < 0)
75
0
        sx = 0;
76
0
    ex = x + max_x_offset;
77
0
    if (clips_on_x && ex >= width)
78
0
        ex = width-1;
79
80
    /* We only need to check for shadowing lower components if we're
81
     * not the last last component (!last_comp). We can only need to process
82
     * here if we are not the first component (!first_comp) and
83
     * if (p != 0) then we need to search for the maximum local value
84
     * of  this component. */
85
0
    v = linebuf[line_offset + oc];
86
0
    if (!last_comp || (!first_comp && p))
87
0
    {
88
0
        int min_v, max_v;
89
90
0
        lo = sy % lines_in_buf;
91
        /* min_v only used if (!last_comp), max_v only used if (!first_comp),
92
         * but setting them unconditionally avoids warnings. */
93
0
        min_v = max_v = v;
94
0
        pc = &linebuf[lo * span + sx * num_comps + comp];
95
0
        ex -= sx;
96
0
        for (sy = ey-sy; sy >= 0; sy--)
97
0
        {
98
0
            ppc = pc;
99
0
            for (sx = ex; sx >= 0; sx--)
100
0
            {
101
0
                int cv = *ppc;
102
0
                ppc += num_comps;
103
0
                if (!first_comp && cv > max_v)
104
0
                    max_v = cv;
105
0
                else if (!last_comp && cv < min_v)
106
0
                    min_v = cv;
107
0
            }
108
0
            pc += span;
109
0
            lo++;
110
0
            if (lo == lines_in_buf)
111
0
            {
112
0
                pc -= span * lines_in_buf;
113
0
            }
114
0
        }
115
        /* If we're not the last component, and we meet the criteria
116
         * the next component needs processing. */
117
0
        if (!last_comp)
118
0
        {
119
            /* Process flag for next component inherits from this one */
120
0
            int np = p;
121
0
            if (v > np && shadow_here(v, min_v, comp))
122
0
                np = v;
123
124
0
            *process = np;
125
#ifdef SAVE_PROCESS_BUFFER
126
            buffer[oc] = np;
127
            return;
128
#endif
129
0
        }
130
131
0
        if (!first_comp && p > v && trap_here(v, max_v, comp))
132
0
        {
133
0
            if (max_v < p)
134
0
                p = max_v;
135
0
            v = p;
136
0
        }
137
0
    }
138
0
    buffer[oc] = v;
139
0
}
140
141
int ClapTrap_GetLine(ClapTrap      * gs_restrict ct,
142
                     unsigned char * gs_restrict buffer)
143
0
{
144
0
    int max_y;
145
0
    int l_margin;
146
0
    int r_margin;
147
0
    int comp_idx;
148
0
    int prev_comp;
149
0
    int comp;
150
0
    int x;
151
0
    int line_offset;
152
0
    unsigned char *process;
153
154
    /* Read in as many lines as we need */
155
0
    max_y = ct->y + ct->max_y_offset;
156
0
    if (max_y > ct->height-1)
157
0
        max_y = ct->height-1;
158
0
    while (ct->lines_read <= max_y)
159
0
    {
160
0
        int bufpos = ct->span * (ct->lines_read % ct->lines_in_buf);
161
0
        int code = ct->get_line(ct->get_line_arg, &ct->linebuf[bufpos]);
162
0
        if (code < 0)
163
0
            return code;
164
0
        ct->lines_read++;
165
0
    }
166
167
    /* Now we have enough information to calculate the process map for the next line of data */
168
0
    l_margin = ct->max_x_offset;
169
0
    r_margin = ct->width - ct->max_x_offset;
170
0
    if (r_margin < 0)
171
0
    {
172
0
        r_margin = 0;
173
0
        l_margin = 0;
174
0
    }
175
0
    x = (ct->y % ct->lines_in_buf);
176
0
    process = &ct->process[x * ct->width];
177
0
    line_offset = x * ct->span;
178
0
    if (ct->y < ct->max_y_offset || ct->y >= ct->height - ct->max_y_offset)
179
0
    {
180
0
        unsigned char *p = process;
181
        /* Some of our search area is off the end of the bitmap. We must be careful. */
182
0
        comp = ct->comp_order[0];
183
0
        for (x = 0; x < l_margin; x++)
184
0
        {
185
0
            process_at_pixel(ct, buffer, x, 1, 1, 1, 0, -1, comp, line_offset, p++);
186
0
        }
187
0
        for (; x < r_margin; x++)
188
0
        {
189
0
            process_at_pixel(ct, buffer, x, 0, 1, 1, 0, -1, comp, line_offset, p++);
190
0
        }
191
0
        for (; x < ct->width; x++)
192
0
        {
193
0
            process_at_pixel(ct, buffer, x, 1, 1, 1, 0, -1, comp, line_offset, p++);
194
0
        }
195
0
        for (comp_idx = 1; comp_idx < ct->num_comps-1; comp_idx++)
196
0
        {
197
0
            p = process;
198
0
            prev_comp = comp;
199
0
            comp = ct->comp_order[comp_idx];
200
0
            for (x = 0; x < l_margin; x++)
201
0
            {
202
0
                process_at_pixel(ct, buffer, x, 1, 1, 0, 0, prev_comp, comp, line_offset, p++);
203
0
            }
204
0
            for (; x < r_margin; x++)
205
0
            {
206
0
                process_at_pixel(ct, buffer, x, 0, 1, 0, 0, prev_comp, comp, line_offset, p++);
207
0
            }
208
0
            for (; x < ct->width; x++)
209
0
            {
210
0
                process_at_pixel(ct, buffer, x, 1, 1, 0, 0, prev_comp, comp, line_offset, p++);
211
0
            }
212
0
        }
213
0
        p = process;
214
0
        prev_comp = comp;
215
0
        comp = ct->comp_order[comp_idx];
216
0
        for (x = 0; x < l_margin; x++)
217
0
        {
218
0
            process_at_pixel(ct, buffer, x, 1, 1, 0, 1, prev_comp, comp, line_offset, p++);
219
0
        }
220
0
        for (; x < r_margin; x++)
221
0
        {
222
0
            process_at_pixel(ct, buffer, x, 0, 1, 0, 1, prev_comp, comp, line_offset, p++);
223
0
        }
224
0
        for (; x < ct->width; x++)
225
0
        {
226
0
            process_at_pixel(ct, buffer, x, 1, 1, 0, 1, prev_comp, comp, line_offset, p++);
227
0
        }
228
0
    }
229
0
    else
230
0
    {
231
0
        unsigned char *p = process;
232
        /* Our search area never clips on y at least. */
233
0
        comp = ct->comp_order[0];
234
0
        for (x = 0; x < l_margin; x++)
235
0
        {
236
0
            process_at_pixel(ct, buffer, x, 1, 0, 1, 0, -1, comp, line_offset, p++);
237
0
        }
238
0
        for (; x < r_margin; x++)
239
0
        {
240
0
            process_at_pixel(ct, buffer, x, 0, 0, 1, 0, -1, comp, line_offset, p++);
241
0
        }
242
0
        for (; x < ct->width; x++)
243
0
        {
244
0
            process_at_pixel(ct, buffer, x, 1, 0, 1, 0, -1, comp, line_offset, p++);
245
0
        }
246
0
        for (comp_idx = 1; comp_idx < ct->num_comps-1; comp_idx++)
247
0
        {
248
0
            p = process;
249
0
            prev_comp = comp;
250
0
            comp = ct->comp_order[comp_idx];
251
0
            for (x = 0; x < l_margin; x++)
252
0
            {
253
0
                process_at_pixel(ct, buffer, x, 1, 0, 0, 0, prev_comp, comp, line_offset, p++);
254
0
            }
255
0
            for (; x < r_margin; x++)
256
0
            {
257
0
                process_at_pixel(ct, buffer, x, 0, 0, 0, 0, prev_comp, comp, line_offset, p++);
258
0
            }
259
0
            for (; x < ct->width; x++)
260
0
            {
261
0
                process_at_pixel(ct, buffer, x, 1, 0, 0, 0, prev_comp, comp, line_offset, p++);
262
0
            }
263
0
        }
264
0
        p = process;
265
0
        prev_comp = comp;
266
0
        comp = ct->comp_order[comp_idx];
267
0
        for (x = 0; x < l_margin; x++)
268
0
        {
269
0
            process_at_pixel(ct, buffer, x, 1, 0, 0, 1, prev_comp, comp, line_offset, p++);
270
0
        }
271
0
        for (; x < r_margin; x++)
272
0
        {
273
0
            process_at_pixel(ct, buffer, x, 0, 0, 0, 1, prev_comp, comp, line_offset, p++);
274
0
        }
275
0
        for (; x < ct->width; x++)
276
0
        {
277
0
            process_at_pixel(ct, buffer, x, 1, 0, 0, 1, prev_comp, comp, line_offset, p++);
278
0
        }
279
0
    }
280
0
    ct->y++;
281
0
    if (ct->y == ct->height)
282
0
    {
283
0
        ct->y = 0;
284
0
        ct->lines_read = 0;
285
0
    }
286
287
0
    return 0;
288
0
}