Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/claptrap-planar.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
#ifndef NDEBUG
47
    int            num_comp_lim = ct->num_comps-1;
48
#endif
49
0
    int            max_x_offset = ct->max_x_offset;
50
0
    int            max_y_offset = ct->max_y_offset;
51
0
    int            span         = ct->span;
52
0
    int            lines_in_buf = ct->lines_in_buf;
53
0
    unsigned char *linebuf      = ct->linebuf;
54
0
    int            y            = ct->y;
55
    /* Some offsets we will use repeatedly */
56
0
    int            oc           = x + comp * width;
57
    /* p != 0 if we need to be processed because a previous component shadows us.
58
     * If we're the first component then no one can shadow us. */
59
0
    int            p            = (first_comp ? 0 : *process);
60
0
    int            sx, sy, ex, ey, lo, v;
61
0
    unsigned char *pc;
62
0
    unsigned char *ppc;
63
64
0
    assert((first_comp != 1) ^ (prev_comp == -1));
65
0
    assert((last_comp != 1) ^ (comp == ct->comp_order[num_comp_lim]));
66
67
    /* Work out the search region bounds */
68
0
    sy = y - max_y_offset;
69
0
    if (clips_on_y && sy < 0)
70
0
        sy = 0;
71
0
    ey = y + max_y_offset;
72
0
    if (clips_on_y && ey >= height)
73
0
        ey = height-1;
74
0
    sx = x - max_x_offset;
75
0
    if (clips_on_x && sx < 0)
76
0
        sx = 0;
77
0
    ex = x + max_x_offset;
78
0
    if (clips_on_x && ex >= width)
79
0
        ex = width-1;
80
81
    /* We only need to check for shadowing lower components if we're
82
     * not the last last component (!last_comp). We can only need to process
83
     * here if we are not the first component (!first_comp) and
84
     * if (p != 0) then we need to search for the maximum local value
85
     * of  this component. */
86
0
    v = linebuf[line_offset + oc];
87
0
    if (!last_comp || (!first_comp && p))
88
0
    {
89
0
        int min_v, max_v;
90
91
0
        lo = sy % lines_in_buf;
92
        /* min_v only used if (!last_comp), max_v only used if (!first_comp),
93
         * but setting them unconditionally avoids warnings. */
94
0
        min_v = max_v = v;
95
0
        pc = &linebuf[lo * span + comp * width + sx];
96
0
        ex -= sx;
97
0
        for (sy = ey-sy; sy >= 0; sy--)
98
0
        {
99
0
            ppc = pc;
100
0
            for (sx = ex; sx >= 0; sx--)
101
0
            {
102
0
                int cv = *ppc++;
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
            /* Update the next components process flag if required */
125
0
            *process = np;
126
#ifdef SAVE_PROCESS_BUFFER
127
            buffer[x] = np;
128
            return;
129
#endif
130
0
        }
131
132
0
        if (!first_comp && p > v && trap_here(v, max_v, comp))
133
0
        {
134
0
            if (max_v < p)
135
0
                p = max_v;
136
0
            v = p;
137
0
        }
138
0
    }
139
0
    buffer[x] = v;
140
0
}
141
142
int ClapTrap_GetLinePlanar(ClapTrap       * gs_restrict ct,
143
                           unsigned char ** gs_restrict buffer)
144
0
{
145
0
    int max_y;
146
0
    int l_margin;
147
0
    int r_margin;
148
0
    int comp_idx;
149
0
    int prev_comp;
150
0
    int comp;
151
0
    int x;
152
0
    int line_offset;
153
0
    unsigned char *process;
154
0
    int num_comp_lim = ct->num_comps-1;
155
156
    /* Read in as many lines as we need */
157
0
    max_y = ct->y + ct->max_y_offset;
158
0
    if (max_y > ct->height-1)
159
0
        max_y = ct->height-1;
160
0
    while (ct->lines_read <= max_y)
161
0
    {
162
0
        int bufpos = ct->span * (ct->lines_read % ct->lines_in_buf);
163
0
        int code = ct->get_line(ct->get_line_arg, &ct->linebuf[bufpos]);
164
0
        if (code < 0)
165
0
            return code;
166
0
        ct->lines_read++;
167
0
    }
168
169
    /* Now we have enough information to calculate the process map for the next line of data */
170
0
    l_margin = ct->max_x_offset;
171
0
    r_margin = ct->width - ct->max_x_offset;
172
0
    if (r_margin < 0)
173
0
    {
174
0
        r_margin = 0;
175
0
        l_margin = 0;
176
0
    }
177
0
    x = (ct->y % ct->lines_in_buf);
178
0
    process = &ct->process[x * ct->width];
179
0
    line_offset = x * ct->span;
180
0
    if (ct->y < ct->max_y_offset || ct->y >= ct->height - ct->max_y_offset)
181
0
    {
182
0
        unsigned char *p = process;
183
        /* Some of our search area is off the end of the bitmap. We must be careful. */
184
0
        comp = ct->comp_order[0];
185
0
        for (x = 0; x < l_margin; x++)
186
0
        {
187
0
            process_at_pixel(ct, buffer[comp], x, 1, 1, 1, 0, -1, comp, line_offset, p++);
188
0
        }
189
0
        for (; x < r_margin; x++)
190
0
        {
191
0
            process_at_pixel(ct, buffer[comp], x, 0, 1, 1, 0, -1, comp, line_offset, p++);
192
0
        }
193
0
        for (; x < ct->width; x++)
194
0
        {
195
0
            process_at_pixel(ct, buffer[comp], x, 1, 1, 1, 0, -1, comp, line_offset, p++);
196
0
        }
197
0
        for (comp_idx = 1; comp_idx < num_comp_lim; comp_idx++)
198
0
        {
199
0
            prev_comp = comp;
200
0
            p = process;
201
0
            comp = ct->comp_order[comp_idx];
202
0
            for (x = 0; x < l_margin; x++)
203
0
            {
204
0
                process_at_pixel(ct, buffer[comp], x, 1, 1, 0, 0, prev_comp, comp, line_offset, p++);
205
0
            }
206
0
            for (; x < r_margin; x++)
207
0
            {
208
0
                process_at_pixel(ct, buffer[comp], x, 0, 1, 0, 0, prev_comp, comp, line_offset, p++);
209
0
            }
210
0
            for (; x < ct->width; x++)
211
0
            {
212
0
                process_at_pixel(ct, buffer[comp], x, 1, 1, 0, 0, prev_comp, comp, line_offset, p++);
213
0
            }
214
0
        }
215
0
        prev_comp = comp;
216
0
        p = process;
217
0
        comp = ct->comp_order[comp_idx];
218
0
        for (x = 0; x < l_margin; x++)
219
0
        {
220
0
            process_at_pixel(ct, buffer[comp], x, 1, 1, 0, 1, prev_comp, comp, line_offset, p++);
221
0
        }
222
0
        for (; x < r_margin; x++)
223
0
        {
224
0
            process_at_pixel(ct, buffer[comp], x, 0, 1, 0, 1, prev_comp, comp, line_offset, p++);
225
0
        }
226
0
        for (; x < ct->width; x++)
227
0
        {
228
0
            process_at_pixel(ct, buffer[comp], x, 1, 1, 0, 1, prev_comp, comp, line_offset, p++);
229
0
        }
230
0
    }
231
0
    else
232
0
    {
233
        /* Our search area never clips on y at least. */
234
0
        unsigned char *p = process;
235
0
        comp = ct->comp_order[0];
236
0
        for (x = 0; x < l_margin; x++)
237
0
        {
238
0
            process_at_pixel(ct, buffer[comp], x, 1, 0, 1, 0, -1, comp, line_offset, p++);
239
0
        }
240
0
        for (; x < r_margin; x++)
241
0
        {
242
0
            process_at_pixel(ct, buffer[comp], x, 0, 0, 1, 0, -1, comp, line_offset, p++);
243
0
        }
244
0
        for (; x < ct->width; x++)
245
0
        {
246
0
            process_at_pixel(ct, buffer[comp], x, 1, 0, 1, 0, -1, comp, line_offset, p++);
247
0
        }
248
0
        for (comp_idx = 1; comp_idx < num_comp_lim; comp_idx++)
249
0
        {
250
0
            prev_comp = comp;
251
0
            p = process;
252
0
            comp = ct->comp_order[comp_idx];
253
0
            for (x = 0; x < l_margin; x++)
254
0
            {
255
0
                process_at_pixel(ct, buffer[comp], x, 1, 0, 0, 0, prev_comp, comp, line_offset, p++);
256
0
            }
257
0
            for (; x < r_margin; x++)
258
0
            {
259
0
                process_at_pixel(ct, buffer[comp], x, 0, 0, 0, 0, prev_comp, comp, line_offset, p++);
260
0
            }
261
0
            for (; x < ct->width; x++)
262
0
            {
263
0
                process_at_pixel(ct, buffer[comp], x, 1, 0, 0, 0, prev_comp, comp, line_offset, p++);
264
0
            }
265
0
        }
266
0
        prev_comp = comp;
267
0
        p = process;
268
0
        comp = ct->comp_order[comp_idx];
269
0
        for (x = 0; x < l_margin; x++)
270
0
        {
271
0
            process_at_pixel(ct, buffer[comp], x, 1, 0, 0, 1, prev_comp, comp, line_offset, p++);
272
0
        }
273
0
        for (; x < r_margin; x++)
274
0
        {
275
0
            process_at_pixel(ct, buffer[comp], x, 0, 0, 0, 1, prev_comp, comp, line_offset, p++);
276
0
        }
277
0
        for (; x < ct->width; x++)
278
0
        {
279
0
            process_at_pixel(ct, buffer[comp], x, 1, 0, 0, 1, prev_comp, comp, line_offset, p++);
280
0
        }
281
0
    }
282
0
    ct->y++;
283
0
    if (ct->y == ct->height)
284
0
    {
285
0
        ct->y = 0;
286
0
        ct->lines_read = 0;
287
0
    }
288
289
0
    return 0;
290
0
}