Rev 1891 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1891 | serge | 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 |
||
25 | #endif |
||
26 | |||
27 | #include |
||
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 | 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 |
||
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 |
||
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 |
||
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); |
||
3931 | Serge | 377 | return_if_fail (PIXMAN_FORMAT_TYPE (image->bits.format) == PIXMAN_TYPE_A); |
1891 | serge | 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>>>>>>><>><>><>><> |