Line data Source code
1 : /***************************************************************************/
2 : /* */
3 : /* ftgrays.c */
4 : /* */
5 : /* A new `perfect' anti-aliasing renderer (body). */
6 : /* */
7 : /* Copyright 2000-2001, 2002 by */
8 : /* David Turner, Robert Wilhelm, and Werner Lemberg. */
9 : /* */
10 : /* This file is part of the FreeType project, and may only be used, */
11 : /* modified, and distributed under the terms of the FreeType project */
12 : /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 : /* this file you indicate that you have read the license and */
14 : /* understand and accept it fully. */
15 : /* */
16 : /***************************************************************************/
17 :
18 : /*************************************************************************/
19 : /* */
20 : /* This is a new anti-aliasing scan-converter for FreeType 2. The */
21 : /* algorithm used here is _very_ different from the one in the standard */
22 : /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */
23 : /* coverage of the outline on each pixel cell. */
24 : /* */
25 : /* It is based on ideas that I initially found in Raph Levien's */
26 : /* excellent LibArt graphics library (see http://www.levien.com/libart */
27 : /* for more information, though the web pages do not tell anything */
28 : /* about the renderer; you'll have to dive into the source code to */
29 : /* understand how it works). */
30 : /* */
31 : /* Note, however, that this is a _very_ different implementation */
32 : /* compared to Raph's. Coverage information is stored in a very */
33 : /* different way, and I don't use sorted vector paths. Also, it doesn't */
34 : /* use floating point values. */
35 : /* */
36 : /* This renderer has the following advantages: */
37 : /* */
38 : /* - It doesn't need an intermediate bitmap. Instead, one can supply a */
39 : /* callback function that will be called by the renderer to draw gray */
40 : /* spans on any target surface. You can thus do direct composition on */
41 : /* any kind of bitmap, provided that you give the renderer the right */
42 : /* callback. */
43 : /* */
44 : /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */
45 : /* each pixel cell. */
46 : /* */
47 : /* - It performs a single pass on the outline (the `standard' FT2 */
48 : /* renderer makes two passes). */
49 : /* */
50 : /* - It can easily be modified to render to _any_ number of gray levels */
51 : /* cheaply. */
52 : /* */
53 : /* - For small (< 20) pixel sizes, it is faster than the standard */
54 : /* renderer. */
55 : /* */
56 : /*************************************************************************/
57 :
58 :
59 : /*
60 : GPAC version modifications:
61 : * removed all cubic/quadratic support (present in GPAC path objects)
62 : * moved span data memory to dynamic allocation
63 : * bypassed Y-sorting of cells by using an array of scanlines: a bit more consuming
64 : in memory, but faster cell sorting (X-sorting only)
65 : * deferred coverage push for 3D
66 : */
67 :
68 : #include "rast_soft.h"
69 :
70 :
71 17000694 : void gray_record_cell( TRaster *raster )
72 : {
73 17000694 : if (( raster->area | raster->cover) && (raster->ey<raster->max_ey)) {
74 15322069 : long y = raster->ey - raster->min_ey;
75 15322069 : if (y>=0) {
76 : AACell *cell;
77 14922953 : AAScanline *sl = &raster->scanlines[y];
78 :
79 14922953 : if (sl->num >= sl->alloc) {
80 190374 : sl->cells = (AACell*)gf_realloc(sl->cells, sizeof(AACell)* (sl->alloc + AA_CELL_STEP_ALLOC));
81 190374 : sl->alloc += AA_CELL_STEP_ALLOC;
82 : }
83 14922953 : cell = &sl->cells[sl->num];
84 14922953 : sl->num++;
85 : /*clip cell */
86 14922953 : if (raster->ex<raster->min_ex) cell->x = (TCoord) -1;
87 14593729 : else if (raster->ex>raster->max_ex) cell->x = (TCoord) (raster->max_ex - raster->min_ex);
88 14122405 : else cell->x = (TCoord)(raster->ex - raster->min_ex);
89 14922953 : cell->area = raster->area;
90 14922953 : cell->cover = raster->cover;
91 14922953 : cell->idx1 = raster->idx1;
92 14922953 : cell->idx2 = raster->idx2;
93 :
94 14922953 : if (raster->first_scanline > (u32) y)
95 1761587 : raster->first_scanline = y;
96 : }
97 : }
98 17000694 : }
99 :
100 2703 : void gray_set_cell( TRaster *raster, TCoord ex, TCoord ey )
101 : {
102 16901860 : if ((raster->ex != ex) || (raster->ey != ey)) {
103 16310340 : gray_record_cell(raster);
104 16310340 : raster->ex = ex;
105 16310340 : raster->ey = ey;
106 16310340 : raster->area = 0;
107 16310340 : raster->cover = 0;
108 : }
109 2703 : }
110 :
111 :
112 18782000 : static GFINLINE void evg_translate_point(GF_Matrix2D *mx, EVG_Vector *pt, TPos *x, TPos *y)
113 : {
114 : Fixed _x, _y;
115 18782000 : _x = pt->x;
116 18782000 : _y = pt->y;
117 18782000 : gf_mx2d_apply_coords(mx, &_x, &_y);
118 : #ifdef GPAC_FIXED_POINT
119 : *x = UPSCALE(_x);
120 : *y = UPSCALE(_y);
121 : #else
122 18782000 : *x = (s32) (_x * ONE_PIXEL);
123 18782000 : *y = (s32) (_y * ONE_PIXEL);
124 : #endif
125 18782000 : }
126 :
127 458453 : static GFINLINE int gray_move_to( EVG_Vector* to, EVG_Raster raster)
128 : {
129 : TPos x, y;
130 : TCoord ex, ey;
131 :
132 : /* record current cell, if any */
133 458453 : gray_record_cell(raster);
134 :
135 458453 : evg_translate_point(raster->mx, to, &x, &y);
136 :
137 458453 : ex = TRUNC(x);
138 458453 : ey = TRUNC(y);
139 458453 : if ( ex < raster->min_ex ) ex = (TCoord)(raster->min_ex - 1);
140 458453 : raster->area = 0;
141 458453 : raster->cover = 0;
142 : gray_set_cell( raster, ex, ey );
143 458453 : if (ey<0) ey=0;
144 458453 : raster->last_ey = SUBPIXELS( ey );
145 :
146 458453 : raster->x = x;
147 458453 : raster->y = y;
148 458453 : return 0;
149 : }
150 :
151 : /*************************************************************************/
152 : /* */
153 : /* Render a scanline as one or more cells. */
154 : /* */
155 20880606 : static void gray_render_scanline( TRaster *raster, TCoord ey, TPos x1, TCoord y1, TPos x2, TCoord y2)
156 : {
157 : TCoord ex1, ex2, fx1, fx2, delta;
158 : long p, first;
159 : long dx;
160 : int incr, mod;
161 :
162 20880606 : dx = x2 - x1;
163 20880606 : ex1 = TRUNC( x1 ); /* if (ex1 >= raster->max_ex) ex1 = raster->max_ex-1; */
164 20880606 : ex2 = TRUNC( x2 ); /* if (ex2 >= raster->max_ex) ex2 = raster->max_ex-1; */
165 20880606 : if (ex1<0) {
166 : ex1=0;
167 : fx1 = (TCoord) 0;
168 : } else {
169 20804088 : fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) );
170 : }
171 20880606 : if (ex2<0) {
172 : ex2=0;
173 : fx2 = (TCoord) 0;
174 : } else {
175 20804394 : fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) );
176 : }
177 : /* trivial case. Happens often */
178 20880606 : if ( y1 == y2 ) {
179 : gray_set_cell( raster, ex2, ey );
180 : return;
181 : }
182 :
183 : /* everything is located in a single cell. That is easy! */
184 19768592 : if ( ex1 == ex2 ) {
185 15226643 : delta = y2 - y1;
186 15226643 : raster->area += (TArea)( fx1 + fx2 ) * delta;
187 15226643 : raster->cover += delta;
188 15226643 : return;
189 : }
190 :
191 : /* ok, we'll have to render a run of adjacent cells on the same */
192 : /* scanline... */
193 4541949 : p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
194 : first = ONE_PIXEL;
195 : incr = 1;
196 :
197 4541949 : if ( dx < 0 ) {
198 2278180 : p = fx1 * ( y2 - y1 );
199 : first = 0;
200 : incr = -1;
201 2278180 : dx = -dx;
202 : }
203 4541949 : delta = (TCoord)( p / dx );
204 4541949 : mod = (TCoord)( p % dx );
205 4541949 : if ( mod < 0 ) {
206 2031985 : delta--;
207 2031985 : mod += (TCoord)dx;
208 : }
209 4541949 : raster->area += (TArea)( fx1 + first ) * delta;
210 4541949 : raster->cover += delta;
211 :
212 4541949 : ex1 += incr;
213 : gray_set_cell( raster, ex1, ey );
214 4541949 : y1 += delta;
215 :
216 4541949 : if ( ex1 != ex2 ) {
217 : int lift, rem;
218 540436 : p = ONE_PIXEL * ( y2 - y1 + delta );
219 540436 : lift = (TCoord)( p / dx );
220 540436 : rem = (TCoord)( p % dx );
221 540436 : if ( rem < 0 ) {
222 266863 : lift--;
223 266863 : rem += (TCoord)dx;
224 : }
225 540436 : mod -= (int) dx;
226 :
227 1950912 : while ( ex1 != ex2 ) {
228 : delta = lift;
229 870040 : mod += rem;
230 870040 : if ( mod >= 0 ) {
231 421188 : mod -= (TCoord)dx;
232 421188 : delta++;
233 : }
234 :
235 870040 : raster->area += (TArea)ONE_PIXEL * delta;
236 870040 : raster->cover += delta;
237 870040 : y1 += delta;
238 870040 : ex1 += incr;
239 : gray_set_cell( raster, ex1, ey );
240 : }
241 : }
242 4541949 : delta = y2 - y1;
243 4541949 : raster->area += (TArea)( fx2 + ONE_PIXEL - first ) * delta;
244 4541949 : raster->cover += delta;
245 : }
246 :
247 :
248 : /*************************************************************************/
249 : /* */
250 : /* Render a given line as a series of scanlines. */
251 18368158 : void gray_render_line(TRaster *raster, TPos to_x, TPos to_y)
252 : {
253 : TCoord min, max;
254 : TCoord ey1, ey2, fy1, fy2;
255 : TPos x, x2;
256 : long dx, dy;
257 : long p, first;
258 : int delta, rem, mod, lift, incr;
259 :
260 :
261 18368158 : ey1 = TRUNC( raster->last_ey );
262 18368158 : ey2 = TRUNC( to_y ); /* if (ey2 >= raster->max_ey) ey2 = raster->max_ey-1; */
263 18368158 : if (ey2<0) ey2=0;
264 18368158 : fy1 = (TCoord)( raster->y - raster->last_ey );
265 18368158 : fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
266 :
267 18368158 : dx = to_x - raster->x;
268 18368158 : dy = to_y - raster->y;
269 :
270 : /* perform vertical clipping */
271 : min = ey1;
272 : max = ey2;
273 18368158 : if ( ey1 > ey2 ) {
274 : min = ey2;
275 : max = ey1;
276 : }
277 34827021 : if ( min >= raster->max_ey || max < raster->min_ey ) goto End;
278 :
279 : /* everything is on a single scanline */
280 15919012 : if ( ey1 == ey2 ) {
281 12741212 : gray_render_scanline( raster, ey1, raster->x, fy1, to_x, fy2 );
282 12741212 : goto End;
283 : }
284 : /* vertical line - avoid calling gray_render_scanline */
285 : incr = 1;
286 3177800 : if (dx == 0 ) {
287 612903 : TCoord ex = TRUNC( raster->x );
288 : TCoord tdiff;
289 612903 : if (ex<0) {
290 : ex = 0;
291 : tdiff=0;
292 : } else {
293 599942 : tdiff = raster->x - SUBPIXELS( ex );
294 : }
295 612903 : TCoord two_fx = (TCoord)( ( tdiff ) << 1 );
296 : TPos area;
297 :
298 : first = ONE_PIXEL;
299 612903 : if ( dy < 0 ) {
300 : first = 0;
301 : incr = -1;
302 : }
303 :
304 612903 : delta = (int)( first - fy1 );
305 612903 : raster->area += (TArea)two_fx * delta;
306 612903 : raster->cover += delta;
307 612903 : ey1 += incr;
308 :
309 : gray_set_cell( raster, ex, ey1 );
310 :
311 612903 : delta = (int)( first + first - ONE_PIXEL );
312 612903 : area = (TArea)two_fx * delta;
313 4955107 : while ( ey1 != ey2 ) {
314 3729301 : raster->area += area;
315 3729301 : raster->cover += delta;
316 3729301 : ey1 += incr;
317 : gray_set_cell( raster, ex, ey1 );
318 : }
319 612903 : delta = (int)( fy2 - ONE_PIXEL + first );
320 612903 : raster->area += (TArea)two_fx * delta;
321 612903 : raster->cover += delta;
322 612903 : goto End;
323 : }
324 : /* ok, we have to render several scanlines */
325 2564897 : p = ( ONE_PIXEL - fy1 ) * dx;
326 : first = ONE_PIXEL;
327 : incr = 1;
328 :
329 2564897 : if ( dy < 0 ) {
330 1292002 : p = fy1 * dx;
331 : first = 0;
332 : incr = -1;
333 1292002 : dy = -dy;
334 : }
335 :
336 2564897 : delta = (int)( p / dy );
337 2564897 : mod = (int)( p % dy );
338 2564897 : if ( mod < 0 ) {
339 1186715 : delta--;
340 1186715 : mod += (TCoord)dy;
341 : }
342 2564897 : x = raster->x + delta;
343 2564897 : gray_render_scanline( raster, ey1, raster->x, fy1, x, (TCoord)first );
344 :
345 2564897 : ey1 += incr;
346 2564897 : gray_set_cell( raster, TRUNC( x ), ey1 );
347 :
348 2564897 : if ( ey1 != ey2 ) {
349 585532 : p = ONE_PIXEL * dx;
350 585532 : lift = (int)( p / dy );
351 585532 : rem = (int)( p % dy );
352 585532 : if ( rem < 0 ) {
353 276885 : lift--;
354 276885 : rem += (int)dy;
355 : }
356 585532 : mod -= (int)dy;
357 :
358 4180664 : while ( ey1 != ey2 ) {
359 : delta = lift;
360 3009600 : mod += rem;
361 3009600 : if ( mod >= 0 ) {
362 1409167 : mod -= (int)dy;
363 1409167 : delta++;
364 : }
365 :
366 3009600 : x2 = x + delta;
367 3009600 : gray_render_scanline( raster, ey1, x, (TCoord)( ONE_PIXEL - first ), x2, (TCoord)first );
368 : x = x2;
369 :
370 3009600 : ey1 += incr;
371 3009600 : gray_set_cell( raster, TRUNC( x ), ey1 );
372 : }
373 : }
374 :
375 2564897 : gray_render_scanline( raster, ey1, x, (TCoord)( ONE_PIXEL - first ), to_x, fy2 );
376 :
377 20817304 : End:
378 18368158 : raster->x = to_x;
379 18368158 : raster->y = to_y;
380 18368158 : raster->last_ey = SUBPIXELS( ey2 );
381 18368158 : }
382 :
383 :
384 :
385 227995 : static int EVG_Outline_Decompose(EVG_Outline *outline, TRaster *user)
386 : {
387 : EVG_Vector v_start;
388 : int n; /* index of contour in outline */
389 : int first; /* index of first point in contour */
390 : TPos _x, _y;
391 :
392 : first = 0;
393 686448 : for ( n = 0; n < outline->n_contours; n++ ) {
394 : EVG_Vector *point;
395 : EVG_Vector *limit;
396 : int last; /* index of last point in contour */
397 458453 : last = outline->contours[n];
398 458453 : limit = outline->points + last;
399 458453 : v_start = outline->points[first];
400 : point = outline->points + first;
401 458453 : gray_move_to(&v_start, user);
402 18782000 : while ( point < limit ) {
403 17865094 : point++;
404 17865094 : evg_translate_point(user->mx, point, &_x, &_y);
405 17865094 : gray_render_line(user, _x, _y);
406 : }
407 : /* close the contour with a line segment */
408 458453 : evg_translate_point(user->mx, &v_start, &_x, &_y);
409 458453 : gray_render_line(user, _x, _y);
410 458453 : first = last + 1;
411 : }
412 227995 : return 0;
413 : }
414 :
415 :
416 :
417 : #define SWAP_CELLS( a, b, temp ) { \
418 : temp = *(a); \
419 : *(a) = *(b); \
420 : *(b) = temp; \
421 : }
422 :
423 :
424 : /* This is a non-recursive quicksort that directly process our cells */
425 : /* array. It should be faster than calling the stdlib qsort(), and we */
426 : /* can even tailor our insertion threshold... */
427 :
428 : #define QSORT_THRESHOLD 9 /* below this size, a sub-array will be sorted */
429 : /* through a normal insertion sort */
430 :
431 3009289 : void gray_quick_sort( AACell *cells, int count )
432 : {
433 : AACell *stack[80]; /* should be enough ;-) */
434 : AACell **top; /* top of stack */
435 : AACell *base, *limit;
436 : AACell temp;
437 :
438 3009289 : limit = cells + count;
439 : base = cells;
440 : top = stack;
441 :
442 : for (;;) {
443 3906125 : int len = (int)( limit - base );
444 : AACell *i, *j;
445 3906125 : if ( len > QSORT_THRESHOLD ) {
446 : AACell *pivot;
447 : /* we use base + len/2 as the pivot */
448 448418 : pivot = base + len / 2;
449 448418 : SWAP_CELLS( base, pivot, temp );
450 :
451 448418 : i = base + 1;
452 448418 : j = limit - 1;
453 :
454 : /* now ensure that *i <= *base <= *j */
455 448418 : if(j->x < i->x)
456 132677 : SWAP_CELLS( i, j, temp );
457 :
458 448418 : if(base->x < i->x)
459 91491 : SWAP_CELLS( base, i, temp );
460 :
461 448418 : if(j->x < base->x)
462 121869 : SWAP_CELLS( base, j, temp );
463 :
464 880542 : for (;;) {
465 1328960 : int x = base->x;
466 4122548 : do i++;
467 4122548 : while( i->x < x );
468 4435810 : do j--;
469 4435810 : while( x < j->x );
470 :
471 1328960 : if ( i > j )
472 : break;
473 :
474 880542 : SWAP_CELLS( i, j, temp );
475 : }
476 :
477 448418 : SWAP_CELLS( base, j, temp );
478 :
479 : /* now, push the largest sub-array */
480 448418 : if ( j - base > limit - i ) {
481 192474 : top[0] = base;
482 192474 : top[1] = j;
483 : base = i;
484 : } else {
485 255944 : top[0] = i;
486 255944 : top[1] = limit;
487 : limit = j;
488 : }
489 448418 : top += 2;
490 : } else {
491 : /* the sub-array is small, perform insertion sort */
492 : j = base;
493 3457707 : i = j + 1;
494 :
495 14432514 : for ( ; i < limit; j = i, i++ ) {
496 9459547 : for ( ; j[1].x < j->x; j-- ) {
497 13324627 : SWAP_CELLS( j + 1, j, temp );
498 13324627 : if ( j == base )
499 : break;
500 : }
501 : }
502 3457707 : if ( top > stack ) {
503 448418 : top -= 2;
504 448418 : base = top[0];
505 448418 : limit = top[1];
506 : } else
507 : break;
508 : }
509 : }
510 3009289 : }
511 :
512 15406993 : static void gray_hline( TRaster *raster, TCoord x, TCoord y, TPos area, int acount, Bool zero_non_zero_rule, u32 idx1, u32 idx2)
513 : {
514 : int coverage;
515 : EVG_Span* span;
516 : int count;
517 :
518 15406993 : x += (TCoord)raster->min_ex;
519 15406993 : if (x>=raster->max_ex) return;
520 15191042 : y += (TCoord)raster->min_ey;
521 :
522 : /* compute the coverage line's coverage, depending on the */
523 : /* outline fill rule */
524 : /* */
525 : /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
526 : /* */
527 15191042 : coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) );
528 : /* use range 0..256 */
529 15191042 : if ( coverage < 0 )
530 8741767 : coverage = -coverage;
531 :
532 15191042 : if (zero_non_zero_rule) {
533 : /* normal non-zero winding rule */
534 6627163 : if ( coverage >= 256 )
535 : coverage = 255;
536 : } else {
537 8563879 : coverage &= 511;
538 :
539 8563879 : if ( coverage > 256 )
540 2511 : coverage = 512 - coverage;
541 8561368 : else if ( coverage == 256 )
542 : coverage = 255;
543 : }
544 :
545 12912082 : if (!coverage)
546 : return;
547 :
548 : /* see if we can add this span to the current list */
549 13776317 : count = raster->num_gray_spans;
550 13776317 : span = raster->gray_spans + count - 1;
551 24639329 : if ( count > 0 &&
552 20538879 : (int)span->x + span->len == (int)x &&
553 9675867 : span->coverage == coverage )
554 : {
555 392171 : span->len = (unsigned short)( span->len + acount );
556 392171 : return;
557 : }
558 :
559 13384146 : if ((u32) count >= raster->max_gray_spans) {
560 12936 : raster->render_span(y, count, raster->gray_spans, raster->render_span_data );
561 12936 : raster->num_gray_spans = 0;
562 :
563 12936 : span = raster->gray_spans;
564 : } else {
565 13371210 : if (count==raster->alloc_gray_spans) {
566 14 : raster->alloc_gray_spans*=2;
567 14 : raster->gray_spans = gf_realloc(raster->gray_spans, sizeof(EVG_Span)*raster->alloc_gray_spans);
568 14 : span = raster->gray_spans + count - 1;
569 : }
570 13371210 : span++;
571 : }
572 :
573 : /* add a gray span to the current list */
574 13384146 : span->x = (short)x;
575 13384146 : span->len = (unsigned short)acount;
576 13384146 : span->coverage = (unsigned char)coverage;
577 13384146 : span->idx1 = idx1;
578 13384146 : span->idx2 = idx2;
579 13384146 : raster->num_gray_spans++;
580 : }
581 :
582 3035249 : void gray_sweep_line( TRaster *raster, AAScanline *sl, int y, Bool zero_non_zero_rule)
583 : {
584 : TCoord cover;
585 : AACell *start, *cur;
586 :
587 3035249 : cur = sl->cells;
588 : cover = 0;
589 3035249 : raster->num_gray_spans = 0;
590 :
591 18687514 : while (sl->num) {
592 : TCoord x;
593 : TArea area;
594 : start = cur;
595 12617016 : x = start->x;
596 12617016 : area = start->area;
597 12617016 : cover += start->cover;
598 : /* accumulate all start cells */
599 27539969 : while(--sl->num) {
600 11887704 : ++cur ;
601 11887704 : if (cur->x != start->x )
602 : break;
603 :
604 2305937 : area += cur->area;
605 2305937 : cover += cur->cover;
606 : }
607 :
608 : /* if the start cell has a non-null area, we must draw an */
609 : /* individual gray pixel there */
610 12617016 : if ( area && x >= 0 ) {
611 11850408 : gray_hline( raster, x, y, cover * ( ONE_PIXEL * 2 ) - area, 1, zero_non_zero_rule, start->idx1, start->idx2);
612 11850408 : x++;
613 : }
614 12617016 : if ( x < 0 ) x = 0;
615 :
616 : /* draw a gray span between the start cell and the current one */
617 12617016 : if ( cur->x > x )
618 3556585 : gray_hline( raster, x, y, cover * ( ONE_PIXEL * 2 ), cur->x - x, zero_non_zero_rule, cur->idx1, cur->idx2);
619 : }
620 3035249 : raster->render_span((int) (y + raster->min_ey), raster->num_gray_spans, raster->gray_spans, raster->render_span_data );
621 3035249 : }
622 :
623 :
624 227995 : int evg_raster_render(GF_EVGSurface *surf)
625 : {
626 : Bool zero_non_zero_rule;
627 : u32 i, size_y;
628 227995 : EVG_Raster raster = surf->raster;
629 227995 : EVG_Outline* outline = (EVG_Outline*)&surf->ftoutline;
630 :
631 : /* return immediately if the outline is empty */
632 227995 : if ( outline->n_points == 0 || outline->n_contours <= 0 ) return 0;
633 :
634 227995 : raster->render_span = (EVG_Raster_Span_Func) surf->gray_spans;
635 227995 : raster->render_span_data = surf;
636 :
637 : /* Set up state in the raster object */
638 227995 : raster->min_ex = surf->clip_xMin;
639 227995 : raster->min_ey = surf->clip_yMin;
640 227995 : raster->max_ex = surf->clip_xMax;
641 227995 : raster->max_ey = surf->clip_yMax;
642 :
643 227995 : raster->mx = surf->mx;
644 :
645 227995 : size_y = (u32) (raster->max_ey - raster->min_ey);
646 227995 : if (raster->max_lines < size_y) {
647 1586 : raster->scanlines = (AAScanline*)gf_realloc(raster->scanlines, sizeof(AAScanline)*size_y);
648 1586 : memset(&raster->scanlines[raster->max_lines], 0, sizeof(AAScanline)*(size_y-raster->max_lines) );
649 1586 : raster->max_lines = size_y;
650 : }
651 :
652 227995 : raster->ex = (int) (raster->max_ex+1);
653 227995 : raster->ey = (int) (raster->max_ey+1);
654 227995 : raster->cover = 0;
655 227995 : raster->area = 0;
656 227995 : raster->first_scanline = raster->max_ey;
657 :
658 227995 : EVG_Outline_Decompose(outline, raster);
659 227995 : gray_record_cell( raster );
660 :
661 : /*store odd/even rule*/
662 227995 : zero_non_zero_rule = (outline->flags & GF_PATH_FILL_ZERO_NONZERO) ? GF_TRUE : GF_FALSE;
663 :
664 : /* sort each scanline and render it*/
665 6313931 : for (i=raster->first_scanline; i<size_y; i++) {
666 6085936 : AAScanline *sl = &raster->scanlines[i];
667 6085936 : if (sl->num) {
668 2915368 : if (sl->num>1) gray_quick_sort(sl->cells, sl->num);
669 2915368 : gray_sweep_line(raster, sl, i, zero_non_zero_rule);
670 2915368 : sl->num = 0;
671 : }
672 : }
673 :
674 : return 0;
675 : }
676 :
677 :
678 :
679 :
680 1251 : EVG_Raster evg_raster_new()
681 : {
682 : TRaster *raster;
683 1251 : GF_SAFEALLOC(raster , TRaster);
684 1251 : if (!raster) return NULL;
685 1251 : raster->max_gray_spans = raster->alloc_gray_spans = FT_MAX_GRAY_SPANS;
686 1251 : raster->gray_spans = gf_malloc(sizeof(EVG_Span)* raster->max_gray_spans);
687 1251 : if (!raster->gray_spans) {
688 0 : gf_free(raster);
689 0 : return NULL;
690 : }
691 : return raster;
692 : }
693 :
694 1251 : void evg_raster_del(EVG_Raster raster)
695 : {
696 : u32 i;
697 115030 : for (i=0; i<raster->max_lines; i++) {
698 113779 : gf_free(raster->scanlines[i].cells);
699 113779 : if (raster->scanlines[i].pixels)
700 2075 : gf_free(raster->scanlines[i].pixels);
701 : }
702 1251 : gf_free(raster->gray_spans);
703 :
704 1251 : gf_free(raster->scanlines);
705 1251 : gf_free(raster);
706 1251 : }
707 :
708 : /* END */
|