/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 | } |