LCOV - code coverage report
Current view: top level - evg - ftgrays.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 318 320 99.4 %
Date: 2021-04-29 23:48:07 Functions: 13 13 100.0 %

          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 */

Generated by: LCOV version 1.13