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