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