Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4680 | right-hear | 1 | #include "fitz.h" |
2 | |||
3 | #define BBOX_MIN -(1<<20) |
||
4 | #define BBOX_MAX (1<<20) |
||
5 | |||
6 | /* divide and floor towards -inf */ |
||
7 | static inline int fz_idiv(int a, int b) |
||
8 | { |
||
9 | return a < 0 ? (a - b + 1) / b : a / b; |
||
10 | } |
||
11 | |||
12 | /* If AA_BITS is defined, then we assume constant N bits of antialiasing. We |
||
13 | * will attempt to provide at least that number of bits of accuracy in the |
||
14 | * antialiasing (to a maximum of 8). If it is defined to be 0 then no |
||
15 | * antialiasing is done. If it is undefined to we will leave the antialiasing |
||
16 | * accuracy as a run time choice. |
||
17 | */ |
||
18 | |||
19 | #ifndef AA_BITS |
||
20 | #define AA_SCALE(x) ((x * fz_aa_scale) >> 8) |
||
21 | static int fz_aa_hscale = 17; |
||
22 | static int fz_aa_vscale = 15; |
||
23 | static int fz_aa_scale = 256; |
||
24 | static int fz_aa_level = 8; |
||
25 | |||
26 | #elif AA_BITS > 6 |
||
27 | #define AA_SCALE(x) (x) |
||
28 | #define fz_aa_hscale 17 |
||
29 | #define fz_aa_vscale 15 |
||
30 | #define fz_aa_level 8 |
||
31 | |||
32 | #elif AA_BITS > 4 |
||
33 | #define AA_SCALE(x) ((x * 255) >> 6) |
||
34 | #define fz_aa_hscale 8 |
||
35 | #define fz_aa_vscale 8 |
||
36 | #define fz_aa_level 6 |
||
37 | |||
38 | #elif AA_BITS > 2 |
||
39 | #define AA_SCALE(x) (x * 17) |
||
40 | #define fz_aa_hscale 5 |
||
41 | #define fz_aa_vscale 3 |
||
42 | #define fz_aa_level 4 |
||
43 | |||
44 | #elif AA_BITS > 0 |
||
45 | #define AA_SCALE(x) ((x * 255) >> 2) |
||
46 | #define fz_aa_hscale 2 |
||
47 | #define fz_aa_vscale 2 |
||
48 | #define fz_aa_level 2 |
||
49 | |||
50 | #else |
||
51 | #define AA_SCALE(x) (x * 255) |
||
52 | #define fz_aa_hscale 1 |
||
53 | #define fz_aa_vscale 1 |
||
54 | #define fz_aa_level 0 |
||
55 | |||
56 | #endif |
||
57 | |||
58 | int |
||
59 | fz_get_aa_level(void) |
||
60 | { |
||
61 | return fz_aa_level; |
||
62 | } |
||
63 | |||
64 | void |
||
65 | fz_set_aa_level(int level) |
||
66 | { |
||
67 | #ifdef AA_BITS |
||
68 | fz_warn("anti-aliasing was compiled with a fixed precision of %d bits", fz_aa_level); |
||
69 | #else |
||
70 | if (level > 6) |
||
71 | { |
||
72 | fz_aa_hscale = 17; |
||
73 | fz_aa_vscale = 15; |
||
74 | fz_aa_level = 8; |
||
75 | } |
||
76 | else if (level > 4) |
||
77 | { |
||
78 | fz_aa_hscale = 8; |
||
79 | fz_aa_vscale = 8; |
||
80 | fz_aa_level = 6; |
||
81 | } |
||
82 | else if (level > 2) |
||
83 | { |
||
84 | fz_aa_hscale = 5; |
||
85 | fz_aa_vscale = 3; |
||
86 | fz_aa_level = 4; |
||
87 | } |
||
88 | else if (level > 0) |
||
89 | { |
||
90 | fz_aa_hscale = 2; |
||
91 | fz_aa_vscale = 2; |
||
92 | fz_aa_level = 2; |
||
93 | } |
||
94 | else |
||
95 | { |
||
96 | fz_aa_hscale = 1; |
||
97 | fz_aa_vscale = 1; |
||
98 | fz_aa_level = 0; |
||
99 | } |
||
100 | fz_aa_scale = 0xFF00 / (fz_aa_hscale * fz_aa_vscale); |
||
101 | #endif |
||
102 | } |
||
103 | |||
104 | /* |
||
105 | * Global Edge List -- list of straight path segments for scan conversion |
||
106 | * |
||
107 | * Stepping along the edges is with bresenham's line algorithm. |
||
108 | * |
||
109 | * See Mike Abrash -- Graphics Programming Black Book (notably chapter 40) |
||
110 | */ |
||
111 | |||
112 | typedef struct fz_edge_s fz_edge; |
||
113 | |||
114 | struct fz_edge_s |
||
115 | { |
||
116 | int x, e, h, y; |
||
117 | int adj_up, adj_down; |
||
118 | int xmove; |
||
119 | int xdir, ydir; /* -1 or +1 */ |
||
120 | }; |
||
121 | |||
122 | struct fz_gel_s |
||
123 | { |
||
124 | fz_bbox clip; |
||
125 | fz_bbox bbox; |
||
126 | int cap, len; |
||
127 | fz_edge *edges; |
||
128 | int acap, alen; |
||
129 | fz_edge **active; |
||
130 | }; |
||
131 | |||
132 | fz_gel * |
||
133 | fz_new_gel(void) |
||
134 | { |
||
135 | fz_gel *gel; |
||
136 | |||
137 | gel = fz_malloc(sizeof(fz_gel)); |
||
138 | gel->cap = 512; |
||
139 | gel->len = 0; |
||
140 | gel->edges = fz_calloc(gel->cap, sizeof(fz_edge)); |
||
141 | |||
142 | gel->clip.x0 = gel->clip.y0 = BBOX_MAX; |
||
143 | gel->clip.x1 = gel->clip.y1 = BBOX_MIN; |
||
144 | |||
145 | gel->bbox.x0 = gel->bbox.y0 = BBOX_MAX; |
||
146 | gel->bbox.x1 = gel->bbox.y1 = BBOX_MIN; |
||
147 | |||
148 | gel->acap = 64; |
||
149 | gel->alen = 0; |
||
150 | gel->active = fz_calloc(gel->acap, sizeof(fz_edge*)); |
||
151 | |||
152 | return gel; |
||
153 | } |
||
154 | |||
155 | void |
||
156 | fz_reset_gel(fz_gel *gel, fz_bbox clip) |
||
157 | { |
||
158 | if (fz_is_infinite_rect(clip)) |
||
159 | { |
||
160 | gel->clip.x0 = gel->clip.y0 = BBOX_MAX; |
||
161 | gel->clip.x1 = gel->clip.y1 = BBOX_MIN; |
||
162 | } |
||
163 | else { |
||
164 | gel->clip.x0 = clip.x0 * fz_aa_hscale; |
||
165 | gel->clip.x1 = clip.x1 * fz_aa_hscale; |
||
166 | gel->clip.y0 = clip.y0 * fz_aa_vscale; |
||
167 | gel->clip.y1 = clip.y1 * fz_aa_vscale; |
||
168 | } |
||
169 | |||
170 | gel->bbox.x0 = gel->bbox.y0 = BBOX_MAX; |
||
171 | gel->bbox.x1 = gel->bbox.y1 = BBOX_MIN; |
||
172 | |||
173 | gel->len = 0; |
||
174 | } |
||
175 | |||
176 | void |
||
177 | fz_free_gel(fz_gel *gel) |
||
178 | { |
||
179 | fz_free(gel->active); |
||
180 | fz_free(gel->edges); |
||
181 | fz_free(gel); |
||
182 | } |
||
183 | |||
184 | fz_bbox |
||
185 | fz_bound_gel(fz_gel *gel) |
||
186 | { |
||
187 | fz_bbox bbox; |
||
188 | if (gel->len == 0) |
||
189 | return fz_empty_bbox; |
||
190 | bbox.x0 = fz_idiv(gel->bbox.x0, fz_aa_hscale); |
||
191 | bbox.y0 = fz_idiv(gel->bbox.y0, fz_aa_vscale); |
||
192 | bbox.x1 = fz_idiv(gel->bbox.x1, fz_aa_hscale) + 1; |
||
193 | bbox.y1 = fz_idiv(gel->bbox.y1, fz_aa_vscale) + 1; |
||
194 | return bbox; |
||
195 | } |
||
196 | |||
197 | enum { INSIDE, OUTSIDE, LEAVE, ENTER }; |
||
198 | |||
199 | #define clip_lerp_y(v,m,x0,y0,x1,y1,t) clip_lerp_x(v,m,y0,x0,y1,x1,t) |
||
200 | |||
201 | static int |
||
202 | clip_lerp_x(int val, int m, int x0, int y0, int x1, int y1, int *out) |
||
203 | { |
||
204 | int v0out = m ? x0 > val : x0 < val; |
||
205 | int v1out = m ? x1 > val : x1 < val; |
||
206 | |||
207 | if (v0out + v1out == 0) |
||
208 | return INSIDE; |
||
209 | |||
210 | if (v0out + v1out == 2) |
||
211 | return OUTSIDE; |
||
212 | |||
213 | if (v1out) |
||
214 | { |
||
215 | *out = y0 + (y1 - y0) * (val - x0) / (x1 - x0); |
||
216 | return LEAVE; |
||
217 | } |
||
218 | |||
219 | else |
||
220 | { |
||
221 | *out = y1 + (y0 - y1) * (val - x1) / (x0 - x1); |
||
222 | return ENTER; |
||
223 | } |
||
224 | } |
||
225 | |||
226 | static void |
||
227 | fz_insert_gel_raw(fz_gel *gel, int x0, int y0, int x1, int y1) |
||
228 | { |
||
229 | fz_edge *edge; |
||
230 | int dx, dy; |
||
231 | int winding; |
||
232 | int width; |
||
233 | int tmp; |
||
234 | |||
235 | if (y0 == y1) |
||
236 | return; |
||
237 | |||
238 | if (y0 > y1) { |
||
239 | winding = -1; |
||
240 | tmp = x0; x0 = x1; x1 = tmp; |
||
241 | tmp = y0; y0 = y1; y1 = tmp; |
||
242 | } |
||
243 | else |
||
244 | winding = 1; |
||
245 | |||
246 | if (x0 < gel->bbox.x0) gel->bbox.x0 = x0; |
||
247 | if (x0 > gel->bbox.x1) gel->bbox.x1 = x0; |
||
248 | if (x1 < gel->bbox.x0) gel->bbox.x0 = x1; |
||
249 | if (x1 > gel->bbox.x1) gel->bbox.x1 = x1; |
||
250 | |||
251 | if (y0 < gel->bbox.y0) gel->bbox.y0 = y0; |
||
252 | if (y1 > gel->bbox.y1) gel->bbox.y1 = y1; |
||
253 | |||
254 | if (gel->len + 1 == gel->cap) { |
||
255 | gel->cap = gel->cap + 512; |
||
256 | gel->edges = fz_realloc(gel->edges, gel->cap, sizeof(fz_edge)); |
||
257 | } |
||
258 | |||
259 | edge = &gel->edges[gel->len++]; |
||
260 | |||
261 | dy = y1 - y0; |
||
262 | dx = x1 - x0; |
||
263 | width = ABS(dx); |
||
264 | |||
265 | edge->xdir = dx > 0 ? 1 : -1; |
||
266 | edge->ydir = winding; |
||
267 | edge->x = x0; |
||
268 | edge->y = y0; |
||
269 | edge->h = dy; |
||
270 | edge->adj_down = dy; |
||
271 | |||
272 | /* initial error term going l->r and r->l */ |
||
273 | if (dx >= 0) |
||
274 | edge->e = 0; |
||
275 | else |
||
276 | edge->e = -dy + 1; |
||
277 | |||
278 | /* y-major edge */ |
||
279 | if (dy >= width) { |
||
280 | edge->xmove = 0; |
||
281 | edge->adj_up = width; |
||
282 | } |
||
283 | |||
284 | /* x-major edge */ |
||
285 | else { |
||
286 | edge->xmove = (width / dy) * edge->xdir; |
||
287 | edge->adj_up = width % dy; |
||
288 | } |
||
289 | } |
||
290 | |||
291 | void |
||
292 | fz_insert_gel(fz_gel *gel, float fx0, float fy0, float fx1, float fy1) |
||
293 | { |
||
294 | int x0, y0, x1, y1; |
||
295 | int d, v; |
||
296 | |||
297 | fx0 = floorf(fx0 * fz_aa_hscale); |
||
298 | fx1 = floorf(fx1 * fz_aa_hscale); |
||
299 | fy0 = floorf(fy0 * fz_aa_vscale); |
||
300 | fy1 = floorf(fy1 * fz_aa_vscale); |
||
301 | |||
302 | x0 = CLAMP(fx0, BBOX_MIN, BBOX_MAX); |
||
303 | y0 = CLAMP(fy0, BBOX_MIN, BBOX_MAX); |
||
304 | x1 = CLAMP(fx1, BBOX_MIN, BBOX_MAX); |
||
305 | y1 = CLAMP(fy1, BBOX_MIN, BBOX_MAX); |
||
306 | |||
307 | d = clip_lerp_y(gel->clip.y0, 0, x0, y0, x1, y1, &v); |
||
308 | if (d == OUTSIDE) return; |
||
309 | if (d == LEAVE) { y1 = gel->clip.y0; x1 = v; } |
||
310 | if (d == ENTER) { y0 = gel->clip.y0; x0 = v; } |
||
311 | |||
312 | d = clip_lerp_y(gel->clip.y1, 1, x0, y0, x1, y1, &v); |
||
313 | if (d == OUTSIDE) return; |
||
314 | if (d == LEAVE) { y1 = gel->clip.y1; x1 = v; } |
||
315 | if (d == ENTER) { y0 = gel->clip.y1; x0 = v; } |
||
316 | |||
317 | d = clip_lerp_x(gel->clip.x0, 0, x0, y0, x1, y1, &v); |
||
318 | if (d == OUTSIDE) { |
||
319 | x0 = x1 = gel->clip.x0; |
||
320 | } |
||
321 | if (d == LEAVE) { |
||
322 | fz_insert_gel_raw(gel, gel->clip.x0, v, gel->clip.x0, y1); |
||
323 | x1 = gel->clip.x0; |
||
324 | y1 = v; |
||
325 | } |
||
326 | if (d == ENTER) { |
||
327 | fz_insert_gel_raw(gel, gel->clip.x0, y0, gel->clip.x0, v); |
||
328 | x0 = gel->clip.x0; |
||
329 | y0 = v; |
||
330 | } |
||
331 | |||
332 | d = clip_lerp_x(gel->clip.x1, 1, x0, y0, x1, y1, &v); |
||
333 | if (d == OUTSIDE) { |
||
334 | x0 = x1 = gel->clip.x1; |
||
335 | } |
||
336 | if (d == LEAVE) { |
||
337 | fz_insert_gel_raw(gel, gel->clip.x1, v, gel->clip.x1, y1); |
||
338 | x1 = gel->clip.x1; |
||
339 | y1 = v; |
||
340 | } |
||
341 | if (d == ENTER) { |
||
342 | fz_insert_gel_raw(gel, gel->clip.x1, y0, gel->clip.x1, v); |
||
343 | x0 = gel->clip.x1; |
||
344 | y0 = v; |
||
345 | } |
||
346 | |||
347 | fz_insert_gel_raw(gel, x0, y0, x1, y1); |
||
348 | } |
||
349 | |||
350 | void |
||
351 | fz_sort_gel(fz_gel *gel) |
||
352 | { |
||
353 | fz_edge *a = gel->edges; |
||
354 | int n = gel->len; |
||
355 | |||
356 | int h, i, k; |
||
357 | fz_edge t; |
||
358 | |||
359 | h = 1; |
||
360 | if (n < 14) { |
||
361 | h = 1; |
||
362 | } |
||
363 | else { |
||
364 | while (h < n) |
||
365 | h = 3 * h + 1; |
||
366 | h /= 3; |
||
367 | h /= 3; |
||
368 | } |
||
369 | |||
370 | while (h > 0) |
||
371 | { |
||
372 | for (i = 0; i < n; i++) { |
||
373 | t = a[i]; |
||
374 | k = i - h; |
||
375 | /* TODO: sort on y major, x minor */ |
||
376 | while (k >= 0 && a[k].y > t.y) { |
||
377 | a[k + h] = a[k]; |
||
378 | k -= h; |
||
379 | } |
||
380 | a[k + h] = t; |
||
381 | } |
||
382 | |||
383 | h /= 3; |
||
384 | } |
||
385 | } |
||
386 | |||
387 | int |
||
388 | fz_is_rect_gel(fz_gel *gel) |
||
389 | { |
||
390 | /* a rectangular path is converted into two vertical edges of identical height */ |
||
391 | if (gel->len == 2) |
||
392 | { |
||
393 | fz_edge *a = gel->edges + 0; |
||
394 | fz_edge *b = gel->edges + 1; |
||
395 | return a->y == b->y && a->h == b->h && |
||
396 | a->xmove == 0 && a->adj_up == 0 && |
||
397 | b->xmove == 0 && b->adj_up == 0; |
||
398 | } |
||
399 | return 0; |
||
400 | } |
||
401 | |||
402 | /* |
||
403 | * Active Edge List -- keep track of active edges while sweeping |
||
404 | */ |
||
405 | |||
406 | static void |
||
407 | sort_active(fz_edge **a, int n) |
||
408 | { |
||
409 | int h, i, k; |
||
410 | fz_edge *t; |
||
411 | |||
412 | h = 1; |
||
413 | if (n < 14) { |
||
414 | h = 1; |
||
415 | } |
||
416 | else { |
||
417 | while (h < n) |
||
418 | h = 3 * h + 1; |
||
419 | h /= 3; |
||
420 | h /= 3; |
||
421 | } |
||
422 | |||
423 | while (h > 0) |
||
424 | { |
||
425 | for (i = 0; i < n; i++) { |
||
426 | t = a[i]; |
||
427 | k = i - h; |
||
428 | while (k >= 0 && a[k]->x > t->x) { |
||
429 | a[k + h] = a[k]; |
||
430 | k -= h; |
||
431 | } |
||
432 | a[k + h] = t; |
||
433 | } |
||
434 | |||
435 | h /= 3; |
||
436 | } |
||
437 | } |
||
438 | |||
439 | static void |
||
440 | insert_active(fz_gel *gel, int y, int *e) |
||
441 | { |
||
442 | /* insert edges that start here */ |
||
443 | while (*e < gel->len && gel->edges[*e].y == y) { |
||
444 | if (gel->alen + 1 == gel->acap) { |
||
445 | int newcap = gel->acap + 64; |
||
446 | fz_edge **newactive = fz_realloc(gel->active, newcap, sizeof(fz_edge*)); |
||
447 | gel->active = newactive; |
||
448 | gel->acap = newcap; |
||
449 | } |
||
450 | gel->active[gel->alen++] = &gel->edges[(*e)++]; |
||
451 | } |
||
452 | |||
453 | /* shell-sort the edges by increasing x */ |
||
454 | sort_active(gel->active, gel->alen); |
||
455 | } |
||
456 | |||
457 | static void |
||
458 | advance_active(fz_gel *gel) |
||
459 | { |
||
460 | fz_edge *edge; |
||
461 | int i = 0; |
||
462 | |||
463 | while (i < gel->alen) |
||
464 | { |
||
465 | edge = gel->active[i]; |
||
466 | |||
467 | edge->h --; |
||
468 | |||
469 | /* terminator! */ |
||
470 | if (edge->h == 0) { |
||
471 | gel->active[i] = gel->active[--gel->alen]; |
||
472 | } |
||
473 | |||
474 | else { |
||
475 | edge->x += edge->xmove; |
||
476 | edge->e += edge->adj_up; |
||
477 | if (edge->e > 0) { |
||
478 | edge->x += edge->xdir; |
||
479 | edge->e -= edge->adj_down; |
||
480 | } |
||
481 | i ++; |
||
482 | } |
||
483 | } |
||
484 | } |
||
485 | |||
486 | /* |
||
487 | * Anti-aliased scan conversion. |
||
488 | */ |
||
489 | |||
490 | static inline void add_span_aa(int *list, int x0, int x1, int xofs) |
||
491 | { |
||
492 | int x0pix, x0sub; |
||
493 | int x1pix, x1sub; |
||
494 | |||
495 | if (x0 == x1) |
||
496 | return; |
||
497 | |||
498 | /* x between 0 and width of bbox */ |
||
499 | x0 -= xofs; |
||
500 | x1 -= xofs; |
||
501 | |||
502 | x0pix = x0 / fz_aa_hscale; |
||
503 | x0sub = x0 % fz_aa_hscale; |
||
504 | x1pix = x1 / fz_aa_hscale; |
||
505 | x1sub = x1 % fz_aa_hscale; |
||
506 | |||
507 | if (x0pix == x1pix) |
||
508 | { |
||
509 | list[x0pix] += x1sub - x0sub; |
||
510 | list[x0pix+1] += x0sub - x1sub; |
||
511 | } |
||
512 | |||
513 | else |
||
514 | { |
||
515 | list[x0pix] += fz_aa_hscale - x0sub; |
||
516 | list[x0pix+1] += x0sub; |
||
517 | list[x1pix] += x1sub - fz_aa_hscale; |
||
518 | list[x1pix+1] += -x1sub; |
||
519 | } |
||
520 | } |
||
521 | |||
522 | static inline void non_zero_winding_aa(fz_gel *gel, int *list, int xofs) |
||
523 | { |
||
524 | int winding = 0; |
||
525 | int x = 0; |
||
526 | int i; |
||
527 | for (i = 0; i < gel->alen; i++) |
||
528 | { |
||
529 | if (!winding && (winding + gel->active[i]->ydir)) |
||
530 | x = gel->active[i]->x; |
||
531 | if (winding && !(winding + gel->active[i]->ydir)) |
||
532 | add_span_aa(list, x, gel->active[i]->x, xofs); |
||
533 | winding += gel->active[i]->ydir; |
||
534 | } |
||
535 | } |
||
536 | |||
537 | static inline void even_odd_aa(fz_gel *gel, int *list, int xofs) |
||
538 | { |
||
539 | int even = 0; |
||
540 | int x = 0; |
||
541 | int i; |
||
542 | for (i = 0; i < gel->alen; i++) |
||
543 | { |
||
544 | if (!even) |
||
545 | x = gel->active[i]->x; |
||
546 | else |
||
547 | add_span_aa(list, x, gel->active[i]->x, xofs); |
||
548 | even = !even; |
||
549 | } |
||
550 | } |
||
551 | |||
552 | static inline void undelta_aa(unsigned char * restrict out, int * restrict in, int n) |
||
553 | { |
||
554 | int d = 0; |
||
555 | while (n--) |
||
556 | { |
||
557 | d += *in++; |
||
558 | *out++ = AA_SCALE(d); |
||
559 | } |
||
560 | } |
||
561 | |||
562 | static inline void blit_aa(fz_pixmap *dst, int x, int y, |
||
563 | unsigned char *mp, int w, unsigned char *color) |
||
564 | { |
||
565 | unsigned char *dp; |
||
566 | dp = dst->samples + ( (y - dst->y) * dst->w + (x - dst->x) ) * dst->n; |
||
567 | if (color) |
||
568 | fz_paint_span_with_color(dp, mp, dst->n, w, color); |
||
569 | else |
||
570 | fz_paint_span(dp, mp, 1, w, 255); |
||
571 | } |
||
572 | |||
573 | static void |
||
574 | fz_scan_convert_aa(fz_gel *gel, int eofill, fz_bbox clip, |
||
575 | fz_pixmap *dst, unsigned char *color) |
||
576 | { |
||
577 | unsigned char *alphas; |
||
578 | int *deltas; |
||
579 | int y, e; |
||
580 | int yd, yc; |
||
581 | |||
582 | int xmin = fz_idiv(gel->bbox.x0, fz_aa_hscale); |
||
583 | int xmax = fz_idiv(gel->bbox.x1, fz_aa_hscale) + 1; |
||
584 | |||
585 | int xofs = xmin * fz_aa_hscale; |
||
586 | |||
587 | int skipx = clip.x0 - xmin; |
||
588 | int clipn = clip.x1 - clip.x0; |
||
589 | |||
590 | if (gel->len == 0) |
||
591 | return; |
||
592 | |||
593 | assert(clip.x0 >= xmin); |
||
594 | assert(clip.x1 <= xmax); |
||
595 | |||
596 | alphas = fz_malloc(xmax - xmin + 1); |
||
597 | deltas = fz_malloc((xmax - xmin + 1) * sizeof(int)); |
||
598 | memset(deltas, 0, (xmax - xmin + 1) * sizeof(int)); |
||
599 | |||
600 | e = 0; |
||
601 | y = gel->edges[0].y; |
||
602 | yc = fz_idiv(y, fz_aa_vscale); |
||
603 | yd = yc; |
||
604 | |||
605 | while (gel->alen > 0 || e < gel->len) |
||
606 | { |
||
607 | yc = fz_idiv(y, fz_aa_vscale); |
||
608 | if (yc != yd) |
||
609 | { |
||
610 | if (yd >= clip.y0 && yd < clip.y1) |
||
611 | { |
||
612 | undelta_aa(alphas, deltas, skipx + clipn); |
||
613 | blit_aa(dst, xmin + skipx, yd, alphas + skipx, clipn, color); |
||
614 | memset(deltas, 0, (skipx + clipn) * sizeof(int)); |
||
615 | } |
||
616 | } |
||
617 | yd = yc; |
||
618 | |||
619 | insert_active(gel, y, &e); |
||
620 | |||
621 | if (yd >= clip.y0 && yd < clip.y1) |
||
622 | { |
||
623 | if (eofill) |
||
624 | even_odd_aa(gel, deltas, xofs); |
||
625 | else |
||
626 | non_zero_winding_aa(gel, deltas, xofs); |
||
627 | } |
||
628 | |||
629 | advance_active(gel); |
||
630 | |||
631 | if (gel->alen > 0) |
||
632 | y ++; |
||
633 | else if (e < gel->len) |
||
634 | y = gel->edges[e].y; |
||
635 | } |
||
636 | |||
637 | if (yd >= clip.y0 && yd < clip.y1) |
||
638 | { |
||
639 | undelta_aa(alphas, deltas, skipx + clipn); |
||
640 | blit_aa(dst, xmin + skipx, yd, alphas + skipx, clipn, color); |
||
641 | } |
||
642 | |||
643 | fz_free(deltas); |
||
644 | fz_free(alphas); |
||
645 | } |
||
646 | |||
647 | /* |
||
648 | * Sharp (not anti-aliased) scan conversion |
||
649 | */ |
||
650 | |||
651 | static inline void blit_sharp(int x0, int x1, int y, |
||
652 | fz_bbox clip, fz_pixmap *dst, unsigned char *color) |
||
653 | { |
||
654 | unsigned char *dp; |
||
655 | x0 = CLAMP(x0, dst->x, dst->x + dst->w); |
||
656 | x1 = CLAMP(x1, dst->x, dst->x + dst->w); |
||
657 | if (x0 < x1) |
||
658 | { |
||
659 | dp = dst->samples + ( (y - dst->y) * dst->w + (x0 - dst->x) ) * dst->n; |
||
660 | if (color) |
||
661 | fz_paint_solid_color(dp, dst->n, x1 - x0, color); |
||
662 | else |
||
663 | fz_paint_solid_alpha(dp, x1 - x0, 255); |
||
664 | } |
||
665 | } |
||
666 | |||
667 | static inline void non_zero_winding_sharp(fz_gel *gel, int y, |
||
668 | fz_bbox clip, fz_pixmap *dst, unsigned char *color) |
||
669 | { |
||
670 | int winding = 0; |
||
671 | int x = 0; |
||
672 | int i; |
||
673 | for (i = 0; i < gel->alen; i++) |
||
674 | { |
||
675 | if (!winding && (winding + gel->active[i]->ydir)) |
||
676 | x = gel->active[i]->x; |
||
677 | if (winding && !(winding + gel->active[i]->ydir)) |
||
678 | blit_sharp(x, gel->active[i]->x, y, clip, dst, color); |
||
679 | winding += gel->active[i]->ydir; |
||
680 | } |
||
681 | } |
||
682 | |||
683 | static inline void even_odd_sharp(fz_gel *gel, int y, |
||
684 | fz_bbox clip, fz_pixmap *dst, unsigned char *color) |
||
685 | { |
||
686 | int even = 0; |
||
687 | int x = 0; |
||
688 | int i; |
||
689 | for (i = 0; i < gel->alen; i++) |
||
690 | { |
||
691 | if (!even) |
||
692 | x = gel->active[i]->x; |
||
693 | else |
||
694 | blit_sharp(x, gel->active[i]->x, y, clip, dst, color); |
||
695 | even = !even; |
||
696 | } |
||
697 | } |
||
698 | |||
699 | static void |
||
700 | fz_scan_convert_sharp(fz_gel *gel, int eofill, fz_bbox clip, |
||
701 | fz_pixmap *dst, unsigned char *color) |
||
702 | { |
||
703 | int e = 0; |
||
704 | int y = gel->edges[0].y; |
||
705 | |||
706 | while (gel->alen > 0 || e < gel->len) |
||
707 | { |
||
708 | insert_active(gel, y, &e); |
||
709 | |||
710 | if (y >= clip.y0 && y < clip.y1) |
||
711 | { |
||
712 | if (eofill) |
||
713 | even_odd_sharp(gel, y, clip, dst, color); |
||
714 | else |
||
715 | non_zero_winding_sharp(gel, y, clip, dst, color); |
||
716 | } |
||
717 | |||
718 | advance_active(gel); |
||
719 | |||
720 | if (gel->alen > 0) |
||
721 | y ++; |
||
722 | else if (e < gel->len) |
||
723 | y = gel->edges[e].y; |
||
724 | } |
||
725 | } |
||
726 | |||
727 | void |
||
728 | fz_scan_convert(fz_gel *gel, int eofill, fz_bbox clip, |
||
729 | fz_pixmap *dst, unsigned char *color) |
||
730 | { |
||
731 | if (fz_aa_level > 0) |
||
732 | fz_scan_convert_aa(gel, eofill, clip, dst, color); |
||
733 | else |
||
734 | fz_scan_convert_sharp(gel, eofill, clip, dst, color); |
||
735 | }>>>>>>>>>>>=>>>>>>>>>>>>>>>>>20) |