Line data Source code
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
122 : clip255 (int x)
123 : {
124 0 : if (x > 255)
125 0 : return 255;
126 :
127 0 : 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
156 0 : 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 0 : pixman_fixed_t y = t;
163 : uint32_t *line;
164 0 : int fill_start = -1, fill_end = -1;
165 0 : int fill_size = 0;
166 0 : uint32_t *buf = (image)->bits.bits;
167 0 : int stride = (image)->bits.rowstride;
168 0 : int width = (image)->bits.width;
169 :
170 0 : line = buf + pixman_fixed_to_int (y) * stride;
171 :
172 : for (;;)
173 0 : {
174 0 : uint8_t *ap = (uint8_t *) line;
175 : pixman_fixed_t lx, rx;
176 : int lxi, rxi;
177 :
178 : /* clip X */
179 0 : lx = l->x;
180 0 : if (lx < 0)
181 0 : lx = 0;
182 :
183 0 : rx = r->x;
184 :
185 0 : 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 0 : rx = pixman_int_to_fixed (width) - 1;
192 : }
193 :
194 : /* Skip empty (or backwards) sections */
195 0 : if (rx > lx)
196 : {
197 : int lxs, rxs;
198 :
199 : /* Find pixel bounds for span. */
200 0 : lxi = pixman_fixed_to_int (lx);
201 0 : rxi = pixman_fixed_to_int (rx);
202 :
203 : /* Sample coverage for edge pixels */
204 0 : lxs = RENDER_SAMPLES_X (lx, 8);
205 0 : rxs = RENDER_SAMPLES_X (rx, 8);
206 :
207 : /* Add coverage across row */
208 0 : if (lxi == rxi)
209 : {
210 0 : WRITE (image, ap + lxi,
211 : clip255 (READ (image, ap + lxi) + rxs - lxs));
212 : }
213 : else
214 : {
215 0 : 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 0 : lxi++;
220 :
221 : /* Don't bother trying to optimize the fill unless
222 : * the span is longer than 4 pixels. */
223 0 : if (rxi - lxi > 4)
224 : {
225 0 : if (fill_start < 0)
226 : {
227 0 : fill_start = lxi;
228 0 : fill_end = rxi;
229 0 : fill_size++;
230 : }
231 : else
232 : {
233 0 : if (lxi >= fill_end || rxi < fill_start)
234 : {
235 : /* We're beyond what we saved, just fill it */
236 0 : ADD_SATURATE_8 (ap + fill_start,
237 : fill_size * N_X_FRAC (8),
238 : fill_end - fill_start);
239 0 : fill_start = lxi;
240 0 : fill_end = rxi;
241 0 : fill_size = 1;
242 : }
243 : else
244 : {
245 : /* Update fill_start */
246 0 : if (lxi > fill_start)
247 : {
248 0 : ADD_SATURATE_8 (ap + fill_start,
249 : fill_size * N_X_FRAC (8),
250 : lxi - fill_start);
251 0 : fill_start = lxi;
252 : }
253 0 : else if (lxi < fill_start)
254 : {
255 0 : ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8),
256 : fill_start - lxi);
257 : }
258 :
259 : /* Update fill_end */
260 0 : if (rxi < fill_end)
261 : {
262 0 : ADD_SATURATE_8 (ap + rxi,
263 : fill_size * N_X_FRAC (8),
264 : fill_end - rxi);
265 0 : fill_end = rxi;
266 : }
267 0 : else if (fill_end < rxi)
268 : {
269 0 : ADD_SATURATE_8 (ap + fill_end,
270 : N_X_FRAC (8),
271 : rxi - fill_end);
272 : }
273 0 : fill_size++;
274 : }
275 : }
276 : }
277 : else
278 : {
279 0 : ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8), rxi - lxi);
280 : }
281 :
282 0 : WRITE (image, ap + rxi, clip255 (READ (image, ap + rxi) + rxs));
283 : }
284 : }
285 :
286 0 : if (y == b)
287 : {
288 : /* We're done, make sure we clean up any remaining fill. */
289 0 : if (fill_start != fill_end)
290 : {
291 0 : if (fill_size == N_Y_FRAC (8))
292 : {
293 0 : MEMSET_WRAPPED (image, ap + fill_start,
294 : 0xff, fill_end - fill_start);
295 : }
296 : else
297 : {
298 0 : ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8),
299 : fill_end - fill_start);
300 : }
301 : }
302 0 : break;
303 : }
304 :
305 0 : if (pixman_fixed_frac (y) != Y_FRAC_LAST (8))
306 : {
307 0 : RENDER_EDGE_STEP_SMALL (l);
308 0 : RENDER_EDGE_STEP_SMALL (r);
309 0 : y += STEP_Y_SMALL (8);
310 : }
311 : else
312 : {
313 0 : RENDER_EDGE_STEP_BIG (l);
314 0 : RENDER_EDGE_STEP_BIG (r);
315 0 : y += STEP_Y_BIG (8);
316 0 : if (fill_start != fill_end)
317 : {
318 0 : if (fill_size == N_Y_FRAC (8))
319 : {
320 0 : MEMSET_WRAPPED (image, ap + fill_start,
321 : 0xff, fill_end - fill_start);
322 : }
323 : else
324 : {
325 0 : ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8),
326 : fill_end - fill_start);
327 : }
328 :
329 0 : fill_start = fill_end = -1;
330 0 : fill_size = 0;
331 : }
332 :
333 0 : line += stride;
334 : }
335 : }
336 0 : }
337 :
338 : #ifndef PIXMAN_FB_ACCESSORS
339 : static
340 : #endif
341 : void
342 0 : 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 0 : switch (PIXMAN_FORMAT_BPP (image->bits.format))
349 : {
350 : case 1:
351 0 : rasterize_edges_1 (image, l, r, t, b);
352 0 : break;
353 :
354 : case 4:
355 0 : rasterize_edges_4 (image, l, r, t, b);
356 0 : break;
357 :
358 : case 8:
359 0 : rasterize_edges_8 (image, l, r, t, b);
360 0 : break;
361 :
362 : default:
363 0 : break;
364 : }
365 0 : }
366 :
367 : #ifndef PIXMAN_FB_ACCESSORS
368 :
369 : PIXMAN_EXPORT void
370 0 : 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 0 : return_if_fail (image->type == BITS);
377 0 : return_if_fail (PIXMAN_FORMAT_TYPE (image->bits.format) == PIXMAN_TYPE_A);
378 :
379 0 : if (image->bits.read_func || image->bits.write_func)
380 0 : pixman_rasterize_edges_accessors (image, l, r, t, b);
381 : else
382 0 : pixman_rasterize_edges_no_accessors (image, l, r, t, b);
383 : }
384 :
385 : #endif
|