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