1 /* Copyright (C) 2015-2018 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., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, 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. */
process_at_pixel(ClapTrap * gs_restrict ct,unsigned char * gs_restrict buffer,int x,int clips_on_x,int clips_on_y,int first_comp,int last_comp,int prev_comp,int comp,int line_offset,unsigned char * process)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 {
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 int width = ct->width;
45 int height = ct->height;
46 int num_comps = ct->num_comps;
47 int max_x_offset = ct->max_x_offset;
48 int max_y_offset = ct->max_y_offset;
49 int span = ct->span;
50 int lines_in_buf = ct->lines_in_buf;
51 unsigned char *linebuf = ct->linebuf;
52 int y = ct->y;
53 /* Some offsets we will use repeatedly */
54 int o = x * num_comps;
55 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 int p = (first_comp ? 0 : *process);
59 int sx, sy, ex, ey, lo, v;
60 unsigned char *pc;
61 unsigned char *ppc;
62
63 assert((first_comp != 1) ^ (prev_comp == -1));
64 assert((last_comp != 1) ^ (comp == ct->comp_order[num_comps-1]));
65
66 /* Work out the search region bounds */
67 sy = y - max_y_offset;
68 if (clips_on_y && sy < 0)
69 sy = 0;
70 ey = y + max_y_offset;
71 if (clips_on_y && ey >= height)
72 ey = height-1;
73 sx = x - max_x_offset;
74 if (clips_on_x && sx < 0)
75 sx = 0;
76 ex = x + max_x_offset;
77 if (clips_on_x && ex >= width)
78 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 v = linebuf[line_offset + oc];
86 if (!last_comp || (!first_comp && p))
87 {
88 int min_v, max_v;
89
90 lo = sy % lines_in_buf;
91 if (!first_comp)
92 max_v = v;
93 if (!last_comp)
94 min_v = v;
95 pc = &linebuf[lo * span + sx * num_comps + comp];
96 ex -= sx;
97 for (sy = ey-sy; sy >= 0; sy--)
98 {
99 ppc = pc;
100 for (sx = ex; sx >= 0; sx--)
101 {
102 int cv = *ppc;
103 ppc += num_comps;
104 if (!first_comp && cv > max_v)
105 max_v = cv;
106 else if (!last_comp && cv < min_v)
107 min_v = cv;
108 }
109 pc += span;
110 lo++;
111 if (lo == lines_in_buf)
112 {
113 pc -= span * lines_in_buf;
114 }
115 }
116 /* If we're not the last component, and we meet the criteria
117 * the next component needs processing. */
118 if (!last_comp)
119 {
120 /* Process flag for next component inherits from this one */
121 int np = p;
122 if (v > np && shadow_here(v, min_v, comp))
123 np = v;
124
125 *process = np;
126 #ifdef SAVE_PROCESS_BUFFER
127 buffer[oc] = np;
128 return;
129 #endif
130 }
131
132 if (!first_comp && p > v && trap_here(v, max_v, comp))
133 {
134 if (max_v < p)
135 p = max_v;
136 v = p;
137 }
138 }
139 buffer[oc] = v;
140 }
141
ClapTrap_GetLine(ClapTrap * gs_restrict ct,unsigned char * gs_restrict buffer)142 int ClapTrap_GetLine(ClapTrap * gs_restrict ct,
143 unsigned char * gs_restrict buffer)
144 {
145 int max_y;
146 int l_margin;
147 int r_margin;
148 int comp_idx;
149 int prev_comp;
150 int comp;
151 int x;
152 int line_offset;
153 unsigned char *process;
154
155 /* Read in as many lines as we need */
156 max_y = ct->y + ct->max_y_offset;
157 if (max_y > ct->height-1)
158 max_y = ct->height-1;
159 while (ct->lines_read <= max_y)
160 {
161 int bufpos = ct->span * (ct->lines_read % ct->lines_in_buf);
162 int code = ct->get_line(ct->get_line_arg, &ct->linebuf[bufpos]);
163 if (code < 0)
164 return code;
165 ct->lines_read++;
166 }
167
168 /* Now we have enough information to calculate the process map for the next line of data */
169 l_margin = ct->max_x_offset;
170 r_margin = ct->width - ct->max_x_offset;
171 if (r_margin < 0)
172 {
173 r_margin = 0;
174 l_margin = 0;
175 }
176 x = (ct->y % ct->lines_in_buf);
177 process = &ct->process[x * ct->width];
178 line_offset = x * ct->span;
179 if (ct->y < ct->max_y_offset || ct->y >= ct->height - ct->max_y_offset)
180 {
181 unsigned char *p = process;
182 /* Some of our search area is off the end of the bitmap. We must be careful. */
183 comp = ct->comp_order[0];
184 for (x = 0; x < l_margin; x++)
185 {
186 process_at_pixel(ct, buffer, x, 1, 1, 1, 0, -1, comp, line_offset, p++);
187 }
188 for (; x < r_margin; x++)
189 {
190 process_at_pixel(ct, buffer, x, 0, 1, 1, 0, -1, comp, line_offset, p++);
191 }
192 for (; x < ct->width; x++)
193 {
194 process_at_pixel(ct, buffer, x, 1, 1, 1, 0, -1, comp, line_offset, p++);
195 }
196 for (comp_idx = 1; comp_idx < ct->num_comps-1; comp_idx++)
197 {
198 p = process;
199 prev_comp = comp;
200 comp = ct->comp_order[comp_idx];
201 for (x = 0; x < l_margin; x++)
202 {
203 process_at_pixel(ct, buffer, x, 1, 1, 0, 0, prev_comp, comp, line_offset, p++);
204 }
205 for (; x < r_margin; x++)
206 {
207 process_at_pixel(ct, buffer, x, 0, 1, 0, 0, prev_comp, comp, line_offset, p++);
208 }
209 for (; x < ct->width; x++)
210 {
211 process_at_pixel(ct, buffer, x, 1, 1, 0, 0, prev_comp, comp, line_offset, p++);
212 }
213 }
214 p = process;
215 prev_comp = comp;
216 comp = ct->comp_order[comp_idx];
217 for (x = 0; x < l_margin; x++)
218 {
219 process_at_pixel(ct, buffer, x, 1, 1, 0, 1, prev_comp, comp, line_offset, p++);
220 }
221 for (; x < r_margin; x++)
222 {
223 process_at_pixel(ct, buffer, x, 0, 1, 0, 1, prev_comp, comp, line_offset, p++);
224 }
225 for (; x < ct->width; x++)
226 {
227 process_at_pixel(ct, buffer, x, 1, 1, 0, 1, prev_comp, comp, line_offset, p++);
228 }
229 }
230 else
231 {
232 unsigned char *p = process;
233 /* Our search area never clips on y at least. */
234 comp = ct->comp_order[0];
235 for (x = 0; x < l_margin; x++)
236 {
237 process_at_pixel(ct, buffer, x, 1, 0, 1, 0, -1, comp, line_offset, p++);
238 }
239 for (; x < r_margin; x++)
240 {
241 process_at_pixel(ct, buffer, x, 0, 0, 1, 0, -1, comp, line_offset, p++);
242 }
243 for (; x < ct->width; x++)
244 {
245 process_at_pixel(ct, buffer, x, 1, 0, 1, 0, -1, comp, line_offset, p++);
246 }
247 for (comp_idx = 1; comp_idx < ct->num_comps-1; comp_idx++)
248 {
249 p = process;
250 prev_comp = comp;
251 comp = ct->comp_order[comp_idx];
252 for (x = 0; x < l_margin; x++)
253 {
254 process_at_pixel(ct, buffer, x, 1, 0, 0, 0, prev_comp, comp, line_offset, p++);
255 }
256 for (; x < r_margin; x++)
257 {
258 process_at_pixel(ct, buffer, x, 0, 0, 0, 0, prev_comp, comp, line_offset, p++);
259 }
260 for (; x < ct->width; x++)
261 {
262 process_at_pixel(ct, buffer, x, 1, 0, 0, 0, prev_comp, comp, line_offset, p++);
263 }
264 }
265 p = process;
266 prev_comp = comp;
267 comp = ct->comp_order[comp_idx];
268 for (x = 0; x < l_margin; x++)
269 {
270 process_at_pixel(ct, buffer, x, 1, 0, 0, 1, prev_comp, comp, line_offset, p++);
271 }
272 for (; x < r_margin; x++)
273 {
274 process_at_pixel(ct, buffer, x, 0, 0, 0, 1, prev_comp, comp, line_offset, p++);
275 }
276 for (; x < ct->width; x++)
277 {
278 process_at_pixel(ct, buffer, x, 1, 0, 0, 1, prev_comp, comp, line_offset, p++);
279 }
280 }
281 ct->y++;
282 if (ct->y == ct->height)
283 {
284 ct->y = 0;
285 ct->lines_read = 0;
286 }
287
288 return 0;
289 }
290