1 /*
2 * Copyright © 2004 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Keith Packard makes no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28
29 #include "pixman-private.h"
30 #include "pixman-accessor.h"
31
32 /*
33 * Step across a small sample grid gap
34 */
35 #define RENDER_EDGE_STEP_SMALL(edge) \
36 { \
37 edge->x += edge->stepx_small; \
38 edge->e += edge->dx_small; \
39 if (edge->e > 0) \
40 { \
41 edge->e -= edge->dy; \
42 edge->x += edge->signdx; \
43 } \
44 }
45
46 /*
47 * Step across a large sample grid gap
48 */
49 #define RENDER_EDGE_STEP_BIG(edge) \
50 { \
51 edge->x += edge->stepx_big; \
52 edge->e += edge->dx_big; \
53 if (edge->e > 0) \
54 { \
55 edge->e -= edge->dy; \
56 edge->x += edge->signdx; \
57 } \
58 }
59
60 #ifdef PIXMAN_FB_ACCESSORS
61 #define PIXMAN_RASTERIZE_EDGES pixman_rasterize_edges_accessors
62 #else
63 #define PIXMAN_RASTERIZE_EDGES pixman_rasterize_edges_no_accessors
64 #endif
65
66 /*
67 * 4 bit alpha
68 */
69
70 #define N_BITS 4
71 #define RASTERIZE_EDGES rasterize_edges_4
72
73 #ifndef WORDS_BIGENDIAN
74 #define SHIFT_4(o) ((o) << 2)
75 #else
76 #define SHIFT_4(o) ((1 - (o)) << 2)
77 #endif
78
79 #define GET_4(x, o) (((x) >> SHIFT_4 (o)) & 0xf)
80 #define PUT_4(x, o, v) \
81 (((x) & ~(0xf << SHIFT_4 (o))) | (((v) & 0xf) << SHIFT_4 (o)))
82
83 #define DEFINE_ALPHA(line, x) \
84 uint8_t *__ap = (uint8_t *) line + ((x) >> 1); \
85 int __ao = (x) & 1
86
87 #define STEP_ALPHA ((__ap += __ao), (__ao ^= 1))
88
89 #define ADD_ALPHA(a) \
90 { \
91 uint8_t __o = READ (image, __ap); \
92 uint8_t __a = (a) + GET_4 (__o, __ao); \
93 WRITE (image, __ap, PUT_4 (__o, __ao, __a | (0 - ((__a) >> 4)))); \
94 }
95
96 #include "pixman-edge-imp.h"
97
98 #undef ADD_ALPHA
99 #undef STEP_ALPHA
100 #undef DEFINE_ALPHA
101 #undef RASTERIZE_EDGES
102 #undef N_BITS
103
104
105 /*
106 * 1 bit alpha
107 */
108
109 #define N_BITS 1
110 #define RASTERIZE_EDGES rasterize_edges_1
111
112 #include "pixman-edge-imp.h"
113
114 #undef RASTERIZE_EDGES
115 #undef N_BITS
116
117 /*
118 * 8 bit alpha
119 */
120
121 static force_inline uint8_t
clip255(int x)122 clip255 (int x)
123 {
124 if (x > 255)
125 return 255;
126
127 return x;
128 }
129
130 #define ADD_SATURATE_8(buf, val, length) \
131 do \
132 { \
133 int i__ = (length); \
134 uint8_t *buf__ = (buf); \
135 int val__ = (val); \
136 \
137 while (i__--) \
138 { \
139 WRITE (image, (buf__), clip255 (READ (image, (buf__)) + (val__))); \
140 (buf__)++; \
141 } \
142 } while (0)
143
144 /*
145 * We want to detect the case where we add the same value to a long
146 * span of pixels. The triangles on the end are filled in while we
147 * count how many sub-pixel scanlines contribute to the middle section.
148 *
149 * +--------------------------+
150 * fill_height =| \ /
151 * +------------------+
152 * |================|
153 * fill_start fill_end
154 */
155 static void
rasterize_edges_8(pixman_image_t * image,pixman_edge_t * l,pixman_edge_t * r,pixman_fixed_t t,pixman_fixed_t b)156 rasterize_edges_8 (pixman_image_t *image,
157 pixman_edge_t * l,
158 pixman_edge_t * r,
159 pixman_fixed_t t,
160 pixman_fixed_t b)
161 {
162 pixman_fixed_t y = t;
163 uint32_t *line;
164 int fill_start = -1, fill_end = -1;
165 int fill_size = 0;
166 uint32_t *buf = (image)->bits.bits;
167 int stride = (image)->bits.rowstride;
168 int width = (image)->bits.width;
169
170 line = buf + pixman_fixed_to_int (y) * stride;
171
172 for (;;)
173 {
174 uint8_t *ap = (uint8_t *) line;
175 pixman_fixed_t lx, rx;
176 int lxi, rxi;
177
178 /* clip X */
179 lx = l->x;
180 if (lx < 0)
181 lx = 0;
182
183 rx = r->x;
184
185 if (pixman_fixed_to_int (rx) >= width)
186 {
187 /* Use the last pixel of the scanline, covered 100%.
188 * We can't use the first pixel following the scanline,
189 * because accessing it could result in a buffer overrun.
190 */
191 rx = pixman_int_to_fixed (width) - 1;
192 }
193
194 /* Skip empty (or backwards) sections */
195 if (rx > lx)
196 {
197 int lxs, rxs;
198
199 /* Find pixel bounds for span. */
200 lxi = pixman_fixed_to_int (lx);
201 rxi = pixman_fixed_to_int (rx);
202
203 /* Sample coverage for edge pixels */
204 lxs = RENDER_SAMPLES_X (lx, 8);
205 rxs = RENDER_SAMPLES_X (rx, 8);
206
207 /* Add coverage across row */
208 if (lxi == rxi)
209 {
210 WRITE (image, ap + lxi,
211 clip255 (READ (image, ap + lxi) + rxs - lxs));
212 }
213 else
214 {
215 WRITE (image, ap + lxi,
216 clip255 (READ (image, ap + lxi) + N_X_FRAC (8) - lxs));
217
218 /* Move forward so that lxi/rxi is the pixel span */
219 lxi++;
220
221 /* Don't bother trying to optimize the fill unless
222 * the span is longer than 4 pixels. */
223 if (rxi - lxi > 4)
224 {
225 if (fill_start < 0)
226 {
227 fill_start = lxi;
228 fill_end = rxi;
229 fill_size++;
230 }
231 else
232 {
233 if (lxi >= fill_end || rxi < fill_start)
234 {
235 /* We're beyond what we saved, just fill it */
236 ADD_SATURATE_8 (ap + fill_start,
237 fill_size * N_X_FRAC (8),
238 fill_end - fill_start);
239 fill_start = lxi;
240 fill_end = rxi;
241 fill_size = 1;
242 }
243 else
244 {
245 /* Update fill_start */
246 if (lxi > fill_start)
247 {
248 ADD_SATURATE_8 (ap + fill_start,
249 fill_size * N_X_FRAC (8),
250 lxi - fill_start);
251 fill_start = lxi;
252 }
253 else if (lxi < fill_start)
254 {
255 ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8),
256 fill_start - lxi);
257 }
258
259 /* Update fill_end */
260 if (rxi < fill_end)
261 {
262 ADD_SATURATE_8 (ap + rxi,
263 fill_size * N_X_FRAC (8),
264 fill_end - rxi);
265 fill_end = rxi;
266 }
267 else if (fill_end < rxi)
268 {
269 ADD_SATURATE_8 (ap + fill_end,
270 N_X_FRAC (8),
271 rxi - fill_end);
272 }
273 fill_size++;
274 }
275 }
276 }
277 else
278 {
279 ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8), rxi - lxi);
280 }
281
282 WRITE (image, ap + rxi, clip255 (READ (image, ap + rxi) + rxs));
283 }
284 }
285
286 if (y == b)
287 {
288 /* We're done, make sure we clean up any remaining fill. */
289 if (fill_start != fill_end)
290 {
291 if (fill_size == N_Y_FRAC (8))
292 {
293 MEMSET_WRAPPED (image, ap + fill_start,
294 0xff, fill_end - fill_start);
295 }
296 else
297 {
298 ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8),
299 fill_end - fill_start);
300 }
301 }
302 break;
303 }
304
305 if (pixman_fixed_frac (y) != Y_FRAC_LAST (8))
306 {
307 RENDER_EDGE_STEP_SMALL (l);
308 RENDER_EDGE_STEP_SMALL (r);
309 y += STEP_Y_SMALL (8);
310 }
311 else
312 {
313 RENDER_EDGE_STEP_BIG (l);
314 RENDER_EDGE_STEP_BIG (r);
315 y += STEP_Y_BIG (8);
316 if (fill_start != fill_end)
317 {
318 if (fill_size == N_Y_FRAC (8))
319 {
320 MEMSET_WRAPPED (image, ap + fill_start,
321 0xff, fill_end - fill_start);
322 }
323 else
324 {
325 ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8),
326 fill_end - fill_start);
327 }
328
329 fill_start = fill_end = -1;
330 fill_size = 0;
331 }
332
333 line += stride;
334 }
335 }
336 }
337
338 #ifndef PIXMAN_FB_ACCESSORS
339 static
340 #endif
341 void
PIXMAN_RASTERIZE_EDGES(pixman_image_t * image,pixman_edge_t * l,pixman_edge_t * r,pixman_fixed_t t,pixman_fixed_t b)342 PIXMAN_RASTERIZE_EDGES (pixman_image_t *image,
343 pixman_edge_t * l,
344 pixman_edge_t * r,
345 pixman_fixed_t t,
346 pixman_fixed_t b)
347 {
348 switch (PIXMAN_FORMAT_BPP (image->bits.format))
349 {
350 case 1:
351 rasterize_edges_1 (image, l, r, t, b);
352 break;
353
354 case 4:
355 rasterize_edges_4 (image, l, r, t, b);
356 break;
357
358 case 8:
359 rasterize_edges_8 (image, l, r, t, b);
360 break;
361
362 default:
363 break;
364 }
365 }
366
367 #ifndef PIXMAN_FB_ACCESSORS
368
369 PIXMAN_EXPORT void
pixman_rasterize_edges(pixman_image_t * image,pixman_edge_t * l,pixman_edge_t * r,pixman_fixed_t t,pixman_fixed_t b)370 pixman_rasterize_edges (pixman_image_t *image,
371 pixman_edge_t * l,
372 pixman_edge_t * r,
373 pixman_fixed_t t,
374 pixman_fixed_t b)
375 {
376 return_if_fail (image->type == BITS);
377 return_if_fail (PIXMAN_FORMAT_TYPE (image->bits.format) == PIXMAN_TYPE_A);
378
379 if (image->bits.read_func || image->bits.write_func)
380 pixman_rasterize_edges_accessors (image, l, r, t, b);
381 else
382 pixman_rasterize_edges_no_accessors (image, l, r, t, b);
383 }
384
385 #endif
386