ftgrays.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  ftgrays.c                                                              */
00004 /*                                                                         */
00005 /*    A new `perfect' anti-aliasing renderer (body).                       */
00006 /*                                                                         */
00007 /*  Copyright 2000-2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009 by       */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018   /*************************************************************************/
00019   /*                                                                       */
00020   /* This file can be compiled without the rest of the FreeType engine, by */
00021   /* defining the _STANDALONE_ macro when compiling it.  You also need to  */
00022   /* put the files `ftgrays.h' and `ftimage.h' into the current            */
00023   /* compilation directory.  Typically, you could do something like        */
00024   /*                                                                       */
00025   /* - copy `src/smooth/ftgrays.c' (this file) to your current directory   */
00026   /*                                                                       */
00027   /* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */
00028   /*   same directory                                                      */
00029   /*                                                                       */
00030   /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in        */
00031   /*                                                                       */
00032   /*     cc -c -D_STANDALONE_ ftgrays.c                                    */
00033   /*                                                                       */
00034   /* The renderer can be initialized with a call to                        */
00035   /* `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated  */
00036   /* with a call to `ft_gray_raster.raster_render'.                        */
00037   /*                                                                       */
00038   /* See the comments and documentation in the file `ftimage.h' for more   */
00039   /* details on how the raster works.                                      */
00040   /*                                                                       */
00041   /*************************************************************************/
00042 
00043   /*************************************************************************/
00044   /*                                                                       */
00045   /* This is a new anti-aliasing scan-converter for FreeType 2.  The       */
00046   /* algorithm used here is _very_ different from the one in the standard  */
00047   /* `ftraster' module.  Actually, `ftgrays' computes the _exact_          */
00048   /* coverage of the outline on each pixel cell.                           */
00049   /*                                                                       */
00050   /* It is based on ideas that I initially found in Raph Levien's          */
00051   /* excellent LibArt graphics library (see http://www.levien.com/libart   */
00052   /* for more information, though the web pages do not tell anything       */
00053   /* about the renderer; you'll have to dive into the source code to       */
00054   /* understand how it works).                                             */
00055   /*                                                                       */
00056   /* Note, however, that this is a _very_ different implementation         */
00057   /* compared to Raph's.  Coverage information is stored in a very         */
00058   /* different way, and I don't use sorted vector paths.  Also, it doesn't */
00059   /* use floating point values.                                            */
00060   /*                                                                       */
00061   /* This renderer has the following advantages:                           */
00062   /*                                                                       */
00063   /* - It doesn't need an intermediate bitmap.  Instead, one can supply a  */
00064   /*   callback function that will be called by the renderer to draw gray  */
00065   /*   spans on any target surface.  You can thus do direct composition on */
00066   /*   any kind of bitmap, provided that you give the renderer the right   */
00067   /*   callback.                                                           */
00068   /*                                                                       */
00069   /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on   */
00070   /*   each pixel cell.                                                    */
00071   /*                                                                       */
00072   /* - It performs a single pass on the outline (the `standard' FT2        */
00073   /*   renderer makes two passes).                                         */
00074   /*                                                                       */
00075   /* - It can easily be modified to render to _any_ number of gray levels  */
00076   /*   cheaply.                                                            */
00077   /*                                                                       */
00078   /* - For small (< 20) pixel sizes, it is faster than the standard        */
00079   /*   renderer.                                                           */
00080   /*                                                                       */
00081   /*************************************************************************/
00082 
00083 
00084   /*************************************************************************/
00085   /*                                                                       */
00086   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
00087   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
00088   /* messages during execution.                                            */
00089   /*                                                                       */
00090 #undef  FT_COMPONENT
00091 #define FT_COMPONENT  trace_smooth
00092 
00093 
00094 #ifdef _STANDALONE_
00095 
00096 
00097   /* define this to dump debugging information */
00098 /* #define FT_DEBUG_LEVEL_TRACE */
00099 
00100 
00101 #ifdef FT_DEBUG_LEVEL_TRACE
00102 #include <stdio.h>
00103 #include <stdarg.h>
00104 #endif
00105 
00106 #include <string.h>
00107 #include <setjmp.h>
00108 #include <limits.h>
00109 #define FT_UINT_MAX  UINT_MAX
00110 
00111 #define ft_memset   memset
00112 
00113 #define ft_setjmp   setjmp
00114 #define ft_longjmp  longjmp
00115 #define ft_jmp_buf  jmp_buf
00116 
00117 
00118 #define ErrRaster_Invalid_Mode      -2
00119 #define ErrRaster_Invalid_Outline   -1
00120 #define ErrRaster_Invalid_Argument  -3
00121 #define ErrRaster_Memory_Overflow   -4
00122 
00123 #define FT_BEGIN_HEADER
00124 #define FT_END_HEADER
00125 
00126 #include "ftimage.h"
00127 #include "ftgrays.h"
00128 
00129 
00130   /* This macro is used to indicate that a function parameter is unused. */
00131   /* Its purpose is simply to reduce compiler warnings.  Note also that  */
00132   /* simply defining it as `(void)x' doesn't avoid warnings with certain */
00133   /* ANSI compilers (e.g. LCC).                                          */
00134 #define FT_UNUSED( x )  (x) = (x)
00135 
00136 
00137   /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */
00138 
00139 #ifdef FT_DEBUG_LEVEL_TRACE
00140 
00141   void
00142   FT_Message( const char*  fmt,
00143               ... )
00144   {
00145     va_list  ap;
00146 
00147 
00148     va_start( ap, fmt );
00149     vfprintf( stderr, fmt, ap );
00150     va_end( ap );
00151   }
00152 
00153   /* we don't handle tracing levels in stand-alone mode; */
00154 #ifndef FT_TRACE5
00155 #define FT_TRACE5( varformat )  FT_Message varformat
00156 #endif
00157 #ifndef FT_TRACE7
00158 #define FT_TRACE7( varformat )  FT_Message varformat
00159 #endif
00160 #ifndef FT_ERROR
00161 #define FT_ERROR( varformat )   FT_Message varformat
00162 #endif
00163 
00164 #else /* !FT_DEBUG_LEVEL_TRACE */
00165 
00166 #define FT_TRACE5( x )  do { } while ( 0 )     /* nothing */
00167 #define FT_TRACE7( x )  do { } while ( 0 )     /* nothing */
00168 #define FT_ERROR( x )   do { } while ( 0 )     /* nothing */
00169 
00170 #endif /* !FT_DEBUG_LEVEL_TRACE */
00171 
00172 
00173 #define FT_DEFINE_OUTLINE_FUNCS( class_,               \
00174                                  move_to_, line_to_,   \
00175                                  conic_to_, cubic_to_, \
00176                                  shift_, delta_ )      \
00177           static const FT_Outline_Funcs class_ =       \
00178           {                                            \
00179             move_to_,                                  \
00180             line_to_,                                  \
00181             conic_to_,                                 \
00182             cubic_to_,                                 \
00183             shift_,                                    \
00184             delta_                                     \
00185          };
00186                                           
00187 #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_,            \
00188                                 raster_new_, raster_reset_,       \
00189                                 raster_set_mode_, raster_render_, \
00190                                 raster_done_ )                    \
00191           const FT_Raster_Funcs class_ =                          \
00192           {                                                       \
00193             glyph_format_,                                        \
00194             raster_new_,                                          \
00195             raster_reset_,                                        \
00196             raster_set_mode_,                                     \
00197             raster_render_,                                       \
00198             raster_done_                                          \
00199          };
00200 
00201 #else /* !_STANDALONE_ */
00202 
00203 
00204 #include <ft2build.h>
00205 #include "ftgrays.h"
00206 #include FT_INTERNAL_OBJECTS_H
00207 #include FT_INTERNAL_DEBUG_H
00208 #include FT_OUTLINE_H
00209 
00210 #include "ftsmerrs.h"
00211 
00212 #include "ftspic.h"
00213 
00214 #define ErrRaster_Invalid_Mode      Smooth_Err_Cannot_Render_Glyph
00215 #define ErrRaster_Invalid_Outline   Smooth_Err_Invalid_Outline
00216 #define ErrRaster_Memory_Overflow   Smooth_Err_Out_Of_Memory
00217 #define ErrRaster_Invalid_Argument  Smooth_Err_Invalid_Argument
00218 
00219 #endif /* !_STANDALONE_ */
00220 
00221 #ifndef FT_MEM_SET
00222 #define FT_MEM_SET( d, s, c )  ft_memset( d, s, c )
00223 #endif
00224 
00225 #ifndef FT_MEM_ZERO
00226 #define FT_MEM_ZERO( dest, count )  FT_MEM_SET( dest, 0, count )
00227 #endif
00228 
00229   /* as usual, for the speed hungry :-) */
00230 
00231 #ifndef FT_STATIC_RASTER
00232 
00233 #define RAS_ARG   PWorker  worker
00234 #define RAS_ARG_  PWorker  worker,
00235 
00236 #define RAS_VAR   worker
00237 #define RAS_VAR_  worker,
00238 
00239 #else /* FT_STATIC_RASTER */
00240 
00241 #define RAS_ARG   /* empty */
00242 #define RAS_ARG_  /* empty */
00243 #define RAS_VAR   /* empty */
00244 #define RAS_VAR_  /* empty */
00245 
00246 #endif /* FT_STATIC_RASTER */
00247 
00248 
00249   /* must be at least 6 bits! */
00250 #define PIXEL_BITS  8
00251 
00252 #define ONE_PIXEL       ( 1L << PIXEL_BITS )
00253 #define PIXEL_MASK      ( -1L << PIXEL_BITS )
00254 #define TRUNC( x )      ( (TCoord)( (x) >> PIXEL_BITS ) )
00255 #define SUBPIXELS( x )  ( (TPos)(x) << PIXEL_BITS )
00256 #define FLOOR( x )      ( (x) & -ONE_PIXEL )
00257 #define CEILING( x )    ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
00258 #define ROUND( x )      ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
00259 
00260 #if PIXEL_BITS >= 6
00261 #define UPSCALE( x )    ( (x) << ( PIXEL_BITS - 6 ) )
00262 #define DOWNSCALE( x )  ( (x) >> ( PIXEL_BITS - 6 ) )
00263 #else
00264 #define UPSCALE( x )    ( (x) >> ( 6 - PIXEL_BITS ) )
00265 #define DOWNSCALE( x )  ( (x) << ( 6 - PIXEL_BITS ) )
00266 #endif
00267 
00268 
00269   /*************************************************************************/
00270   /*                                                                       */
00271   /*   TYPE DEFINITIONS                                                    */
00272   /*                                                                       */
00273 
00274   /* don't change the following types to FT_Int or FT_Pos, since we might */
00275   /* need to define them to "float" or "double" when experimenting with   */
00276   /* new algorithms                                                       */
00277 
00278   typedef long  TCoord;   /* integer scanline/pixel coordinate */
00279   typedef long  TPos;     /* sub-pixel coordinate              */
00280 
00281   /* determine the type used to store cell areas.  This normally takes at */
00282   /* least PIXEL_BITS*2 + 1 bits.  On 16-bit systems, we need to use      */
00283   /* `long' instead of `int', otherwise bad things happen                 */
00284 
00285 #if PIXEL_BITS <= 7
00286 
00287   typedef int  TArea;
00288 
00289 #else /* PIXEL_BITS >= 8 */
00290 
00291   /* approximately determine the size of integers using an ANSI-C header */
00292 #if FT_UINT_MAX == 0xFFFFU
00293   typedef long  TArea;
00294 #else
00295   typedef int   TArea;
00296 #endif
00297 
00298 #endif /* PIXEL_BITS >= 8 */
00299 
00300 
00301   /* maximal number of gray spans in a call to the span callback */
00302 #define FT_MAX_GRAY_SPANS  32
00303 
00304 
00305   typedef struct TCell_*  PCell;
00306 
00307   typedef struct  TCell_
00308   {
00309     TPos   x;     /* same with TWorker.ex */
00310     TCoord cover; /* same with TWorker.cover */
00311     TArea  area;
00312     PCell  next;
00313 
00314   } TCell;
00315 
00316 
00317   typedef struct  TWorker_
00318   {
00319     TCoord  ex, ey;
00320     TPos    min_ex, max_ex;
00321     TPos    min_ey, max_ey;
00322     TPos    count_ex, count_ey;
00323 
00324     TArea   area;
00325     TCoord  cover;
00326     int     invalid;
00327 
00328     PCell   cells;
00329     FT_PtrDist  max_cells;
00330     FT_PtrDist  num_cells;
00331 
00332     TCoord  cx, cy;
00333     TPos    x,  y;
00334 
00335     TPos    last_ey;
00336 
00337     FT_Vector   bez_stack[32 * 3 + 1];
00338     int         lev_stack[32];
00339 
00340     FT_Outline  outline;
00341     FT_Bitmap   target;
00342     FT_BBox     clip_box;
00343 
00344     FT_Span     gray_spans[FT_MAX_GRAY_SPANS];
00345     int         num_gray_spans;
00346 
00347     FT_Raster_Span_Func  render_span;
00348     void*                render_span_data;
00349     int                  span_y;
00350 
00351     int  band_size;
00352     int  band_shoot;
00353     int  conic_level;
00354     int  cubic_level;
00355 
00356     ft_jmp_buf  jump_buffer;
00357 
00358     void*       buffer;
00359     long        buffer_size;
00360 
00361     PCell*     ycells;
00362     TPos       ycount;
00363 
00364   } TWorker, *PWorker;
00365 
00366 
00367 #ifndef FT_STATIC_RASTER
00368 #define ras  (*worker)
00369 #else
00370   static TWorker  ras;
00371 #endif
00372 
00373 
00374   typedef struct TRaster_
00375   {
00376     void*    buffer;
00377     long     buffer_size;
00378     int      band_size;
00379     void*    memory;
00380     PWorker  worker;
00381 
00382   } TRaster, *PRaster;
00383 
00384 
00385 
00386   /*************************************************************************/
00387   /*                                                                       */
00388   /* Initialize the cells table.                                           */
00389   /*                                                                       */
00390   static void
00391   gray_init_cells( RAS_ARG_ void*  buffer,
00392                    long            byte_size )
00393   {
00394     ras.buffer      = buffer;
00395     ras.buffer_size = byte_size;
00396 
00397     ras.ycells      = (PCell*) buffer;
00398     ras.cells       = NULL;
00399     ras.max_cells   = 0;
00400     ras.num_cells   = 0;
00401     ras.area        = 0;
00402     ras.cover       = 0;
00403     ras.invalid     = 1;
00404   }
00405 
00406 
00407   /*************************************************************************/
00408   /*                                                                       */
00409   /* Compute the outline bounding box.                                     */
00410   /*                                                                       */
00411   static void
00412   gray_compute_cbox( RAS_ARG )
00413   {
00414     FT_Outline*  outline = &ras.outline;
00415     FT_Vector*   vec     = outline->points;
00416     FT_Vector*   limit   = vec + outline->n_points;
00417 
00418 
00419     if ( outline->n_points <= 0 )
00420     {
00421       ras.min_ex = ras.max_ex = 0;
00422       ras.min_ey = ras.max_ey = 0;
00423       return;
00424     }
00425 
00426     ras.min_ex = ras.max_ex = vec->x;
00427     ras.min_ey = ras.max_ey = vec->y;
00428 
00429     vec++;
00430 
00431     for ( ; vec < limit; vec++ )
00432     {
00433       TPos  x = vec->x;
00434       TPos  y = vec->y;
00435 
00436 
00437       if ( x < ras.min_ex ) ras.min_ex = x;
00438       if ( x > ras.max_ex ) ras.max_ex = x;
00439       if ( y < ras.min_ey ) ras.min_ey = y;
00440       if ( y > ras.max_ey ) ras.max_ey = y;
00441     }
00442 
00443     /* truncate the bounding box to integer pixels */
00444     ras.min_ex = ras.min_ex >> 6;
00445     ras.min_ey = ras.min_ey >> 6;
00446     ras.max_ex = ( ras.max_ex + 63 ) >> 6;
00447     ras.max_ey = ( ras.max_ey + 63 ) >> 6;
00448   }
00449 
00450 
00451   /*************************************************************************/
00452   /*                                                                       */
00453   /* Record the current cell in the table.                                 */
00454   /*                                                                       */
00455   static PCell
00456   gray_find_cell( RAS_ARG )
00457   {
00458     PCell  *pcell, cell;
00459     TPos    x = ras.ex;
00460 
00461 
00462     if ( x > ras.count_ex )
00463       x = ras.count_ex;
00464 
00465     pcell = &ras.ycells[ras.ey];
00466     for (;;)
00467     {
00468       cell = *pcell;
00469       if ( cell == NULL || cell->x > x )
00470         break;
00471 
00472       if ( cell->x == x )
00473         goto Exit;
00474 
00475       pcell = &cell->next;
00476     }
00477 
00478     if ( ras.num_cells >= ras.max_cells )
00479       ft_longjmp( ras.jump_buffer, 1 );
00480 
00481     cell        = ras.cells + ras.num_cells++;
00482     cell->x     = x;
00483     cell->area  = 0;
00484     cell->cover = 0;
00485 
00486     cell->next  = *pcell;
00487     *pcell      = cell;
00488 
00489   Exit:
00490     return cell;
00491   }
00492 
00493 
00494   static void
00495   gray_record_cell( RAS_ARG )
00496   {
00497     if ( !ras.invalid && ( ras.area | ras.cover ) )
00498     {
00499       PCell  cell = gray_find_cell( RAS_VAR );
00500 
00501 
00502       cell->area  += ras.area;
00503       cell->cover += ras.cover;
00504     }
00505   }
00506 
00507 
00508   /*************************************************************************/
00509   /*                                                                       */
00510   /* Set the current cell to a new position.                               */
00511   /*                                                                       */
00512   static void
00513   gray_set_cell( RAS_ARG_ TCoord  ex,
00514                           TCoord  ey )
00515   {
00516     /* Move the cell pointer to a new position.  We set the `invalid'      */
00517     /* flag to indicate that the cell isn't part of those we're interested */
00518     /* in during the render phase.  This means that:                       */
00519     /*                                                                     */
00520     /* . the new vertical position must be within min_ey..max_ey-1.        */
00521     /* . the new horizontal position must be strictly less than max_ex     */
00522     /*                                                                     */
00523     /* Note that if a cell is to the left of the clipping region, it is    */
00524     /* actually set to the (min_ex-1) horizontal position.                 */
00525 
00526     /* All cells that are on the left of the clipping region go to the */
00527     /* min_ex - 1 horizontal position.                                 */
00528     ey -= ras.min_ey;
00529 
00530     if ( ex > ras.max_ex )
00531       ex = ras.max_ex;
00532 
00533     ex -= ras.min_ex;
00534     if ( ex < 0 )
00535       ex = -1;
00536 
00537     /* are we moving to a different cell ? */
00538     if ( ex != ras.ex || ey != ras.ey )
00539     {
00540       /* record the current one if it is valid */
00541       if ( !ras.invalid )
00542         gray_record_cell( RAS_VAR );
00543 
00544       ras.area  = 0;
00545       ras.cover = 0;
00546     }
00547 
00548     ras.ex      = ex;
00549     ras.ey      = ey;
00550     ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey ||
00551                               ex >= ras.count_ex           );
00552   }
00553 
00554 
00555   /*************************************************************************/
00556   /*                                                                       */
00557   /* Start a new contour at a given cell.                                  */
00558   /*                                                                       */
00559   static void
00560   gray_start_cell( RAS_ARG_ TCoord  ex,
00561                             TCoord  ey )
00562   {
00563     if ( ex > ras.max_ex )
00564       ex = (TCoord)( ras.max_ex );
00565 
00566     if ( ex < ras.min_ex )
00567       ex = (TCoord)( ras.min_ex - 1 );
00568 
00569     ras.area    = 0;
00570     ras.cover   = 0;
00571     ras.ex      = ex - ras.min_ex;
00572     ras.ey      = ey - ras.min_ey;
00573     ras.last_ey = SUBPIXELS( ey );
00574     ras.invalid = 0;
00575 
00576     gray_set_cell( RAS_VAR_ ex, ey );
00577   }
00578 
00579 
00580   /*************************************************************************/
00581   /*                                                                       */
00582   /* Render a scanline as one or more cells.                               */
00583   /*                                                                       */
00584   static void
00585   gray_render_scanline( RAS_ARG_ TCoord  ey,
00586                                  TPos    x1,
00587                                  TCoord  y1,
00588                                  TPos    x2,
00589                                  TCoord  y2 )
00590   {
00591     TCoord  ex1, ex2, fx1, fx2, delta, mod, lift, rem;
00592     long    p, first, dx;
00593     int     incr;
00594 
00595 
00596     dx = x2 - x1;
00597 
00598     ex1 = TRUNC( x1 );
00599     ex2 = TRUNC( x2 );
00600     fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) );
00601     fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) );
00602 
00603     /* trivial case.  Happens often */
00604     if ( y1 == y2 )
00605     {
00606       gray_set_cell( RAS_VAR_ ex2, ey );
00607       return;
00608     }
00609 
00610     /* everything is located in a single cell.  That is easy! */
00611     /*                                                        */
00612     if ( ex1 == ex2 )
00613     {
00614       delta      = y2 - y1;
00615       ras.area  += (TArea)(( fx1 + fx2 ) * delta);
00616       ras.cover += delta;
00617       return;
00618     }
00619 
00620     /* ok, we'll have to render a run of adjacent cells on the same */
00621     /* scanline...                                                  */
00622     /*                                                              */
00623     p     = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
00624     first = ONE_PIXEL;
00625     incr  = 1;
00626 
00627     if ( dx < 0 )
00628     {
00629       p     = fx1 * ( y2 - y1 );
00630       first = 0;
00631       incr  = -1;
00632       dx    = -dx;
00633     }
00634 
00635     delta = (TCoord)( p / dx );
00636     mod   = (TCoord)( p % dx );
00637     if ( mod < 0 )
00638     {
00639       delta--;
00640       mod += (TCoord)dx;
00641     }
00642 
00643     ras.area  += (TArea)(( fx1 + first ) * delta);
00644     ras.cover += delta;
00645 
00646     ex1 += incr;
00647     gray_set_cell( RAS_VAR_ ex1, ey );
00648     y1  += delta;
00649 
00650     if ( ex1 != ex2 )
00651     {
00652       p    = ONE_PIXEL * ( y2 - y1 + delta );
00653       lift = (TCoord)( p / dx );
00654       rem  = (TCoord)( p % dx );
00655       if ( rem < 0 )
00656       {
00657         lift--;
00658         rem += (TCoord)dx;
00659       }
00660 
00661       mod -= (int)dx;
00662 
00663       while ( ex1 != ex2 )
00664       {
00665         delta = lift;
00666         mod  += rem;
00667         if ( mod >= 0 )
00668         {
00669           mod -= (TCoord)dx;
00670           delta++;
00671         }
00672 
00673         ras.area  += (TArea)(ONE_PIXEL * delta);
00674         ras.cover += delta;
00675         y1        += delta;
00676         ex1       += incr;
00677         gray_set_cell( RAS_VAR_ ex1, ey );
00678       }
00679     }
00680 
00681     delta      = y2 - y1;
00682     ras.area  += (TArea)(( fx2 + ONE_PIXEL - first ) * delta);
00683     ras.cover += delta;
00684   }
00685 
00686 
00687   /*************************************************************************/
00688   /*                                                                       */
00689   /* Render a given line as a series of scanlines.                         */
00690   /*                                                                       */
00691   static void
00692   gray_render_line( RAS_ARG_ TPos  to_x,
00693                              TPos  to_y )
00694   {
00695     TCoord  ey1, ey2, fy1, fy2, mod;
00696     TPos    dx, dy, x, x2;
00697     long    p, first;
00698     int     delta, rem, lift, incr;
00699 
00700 
00701     ey1 = TRUNC( ras.last_ey );
00702     ey2 = TRUNC( to_y );     /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
00703     fy1 = (TCoord)( ras.y - ras.last_ey );
00704     fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
00705 
00706     dx = to_x - ras.x;
00707     dy = to_y - ras.y;
00708 
00709     /* XXX: we should do something about the trivial case where dx == 0, */
00710     /*      as it happens very often!                                    */
00711 
00712     /* perform vertical clipping */
00713     {
00714       TCoord  min, max;
00715 
00716 
00717       min = ey1;
00718       max = ey2;
00719       if ( ey1 > ey2 )
00720       {
00721         min = ey2;
00722         max = ey1;
00723       }
00724       if ( min >= ras.max_ey || max < ras.min_ey )
00725         goto End;
00726     }
00727 
00728     /* everything is on a single scanline */
00729     if ( ey1 == ey2 )
00730     {
00731       gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
00732       goto End;
00733     }
00734 
00735     /* vertical line - avoid calling gray_render_scanline */
00736     incr = 1;
00737 
00738     if ( dx == 0 )
00739     {
00740       TCoord  ex     = TRUNC( ras.x );
00741       TCoord  two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 );
00742       TArea   area;
00743 
00744 
00745       first = ONE_PIXEL;
00746       if ( dy < 0 )
00747       {
00748         first = 0;
00749         incr  = -1;
00750       }
00751 
00752       delta      = (int)( first - fy1 );
00753       ras.area  += (TArea)two_fx * delta;
00754       ras.cover += delta;
00755       ey1       += incr;
00756 
00757       gray_set_cell( RAS_VAR_ ex, ey1 );
00758 
00759       delta = (int)( first + first - ONE_PIXEL );
00760       area  = (TArea)two_fx * delta;
00761       while ( ey1 != ey2 )
00762       {
00763         ras.area  += area;
00764         ras.cover += delta;
00765         ey1       += incr;
00766 
00767         gray_set_cell( RAS_VAR_ ex, ey1 );
00768       }
00769 
00770       delta      = (int)( fy2 - ONE_PIXEL + first );
00771       ras.area  += (TArea)two_fx * delta;
00772       ras.cover += delta;
00773 
00774       goto End;
00775     }
00776 
00777     /* ok, we have to render several scanlines */
00778     p     = ( ONE_PIXEL - fy1 ) * dx;
00779     first = ONE_PIXEL;
00780     incr  = 1;
00781 
00782     if ( dy < 0 )
00783     {
00784       p     = fy1 * dx;
00785       first = 0;
00786       incr  = -1;
00787       dy    = -dy;
00788     }
00789 
00790     delta = (int)( p / dy );
00791     mod   = (int)( p % dy );
00792     if ( mod < 0 )
00793     {
00794       delta--;
00795       mod += (TCoord)dy;
00796     }
00797 
00798     x = ras.x + delta;
00799     gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first );
00800 
00801     ey1 += incr;
00802     gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
00803 
00804     if ( ey1 != ey2 )
00805     {
00806       p     = ONE_PIXEL * dx;
00807       lift  = (int)( p / dy );
00808       rem   = (int)( p % dy );
00809       if ( rem < 0 )
00810       {
00811         lift--;
00812         rem += (int)dy;
00813       }
00814       mod -= (int)dy;
00815 
00816       while ( ey1 != ey2 )
00817       {
00818         delta = lift;
00819         mod  += rem;
00820         if ( mod >= 0 )
00821         {
00822           mod -= (int)dy;
00823           delta++;
00824         }
00825 
00826         x2 = x + delta;
00827         gray_render_scanline( RAS_VAR_ ey1, x,
00828                                        (TCoord)( ONE_PIXEL - first ), x2,
00829                                        (TCoord)first );
00830         x = x2;
00831 
00832         ey1 += incr;
00833         gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
00834       }
00835     }
00836 
00837     gray_render_scanline( RAS_VAR_ ey1, x,
00838                                    (TCoord)( ONE_PIXEL - first ), to_x,
00839                                    fy2 );
00840 
00841   End:
00842     ras.x       = to_x;
00843     ras.y       = to_y;
00844     ras.last_ey = SUBPIXELS( ey2 );
00845   }
00846 
00847 
00848   static void
00849   gray_split_conic( FT_Vector*  base )
00850   {
00851     TPos  a, b;
00852 
00853 
00854     base[4].x = base[2].x;
00855     b = base[1].x;
00856     a = base[3].x = ( base[2].x + b ) / 2;
00857     b = base[1].x = ( base[0].x + b ) / 2;
00858     base[2].x = ( a + b ) / 2;
00859 
00860     base[4].y = base[2].y;
00861     b = base[1].y;
00862     a = base[3].y = ( base[2].y + b ) / 2;
00863     b = base[1].y = ( base[0].y + b ) / 2;
00864     base[2].y = ( a + b ) / 2;
00865   }
00866 
00867 
00868   static void
00869   gray_render_conic( RAS_ARG_ const FT_Vector*  control,
00870                               const FT_Vector*  to )
00871   {
00872     TPos        dx, dy;
00873     int         top, level;
00874     int*        levels;
00875     FT_Vector*  arc;
00876 
00877 
00878     dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 );
00879     if ( dx < 0 )
00880       dx = -dx;
00881     dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 );
00882     if ( dy < 0 )
00883       dy = -dy;
00884     if ( dx < dy )
00885       dx = dy;
00886 
00887     level = 1;
00888     dx = dx / ras.conic_level;
00889     while ( dx > 0 )
00890     {
00891       dx >>= 2;
00892       level++;
00893     }
00894 
00895     /* a shortcut to speed things up */
00896     if ( level <= 1 )
00897     {
00898       /* we compute the mid-point directly in order to avoid */
00899       /* calling gray_split_conic()                          */
00900       TPos  to_x, to_y, mid_x, mid_y;
00901 
00902 
00903       to_x  = UPSCALE( to->x );
00904       to_y  = UPSCALE( to->y );
00905       mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
00906       mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
00907 
00908       gray_render_line( RAS_VAR_ mid_x, mid_y );
00909       gray_render_line( RAS_VAR_ to_x, to_y );
00910 
00911       return;
00912     }
00913 
00914     arc       = ras.bez_stack;
00915     levels    = ras.lev_stack;
00916     top       = 0;
00917     levels[0] = level;
00918 
00919     arc[0].x = UPSCALE( to->x );
00920     arc[0].y = UPSCALE( to->y );
00921     arc[1].x = UPSCALE( control->x );
00922     arc[1].y = UPSCALE( control->y );
00923     arc[2].x = ras.x;
00924     arc[2].y = ras.y;
00925 
00926     while ( top >= 0 )
00927     {
00928       level = levels[top];
00929       if ( level > 1 )
00930       {
00931         /* check that the arc crosses the current band */
00932         TPos  min, max, y;
00933 
00934 
00935         min = max = arc[0].y;
00936 
00937         y = arc[1].y;
00938         if ( y < min ) min = y;
00939         if ( y > max ) max = y;
00940 
00941         y = arc[2].y;
00942         if ( y < min ) min = y;
00943         if ( y > max ) max = y;
00944 
00945         if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey )
00946           goto Draw;
00947 
00948         gray_split_conic( arc );
00949         arc += 2;
00950         top++;
00951         levels[top] = levels[top - 1] = level - 1;
00952         continue;
00953       }
00954 
00955     Draw:
00956       {
00957         TPos  to_x, to_y, mid_x, mid_y;
00958 
00959 
00960         to_x  = arc[0].x;
00961         to_y  = arc[0].y;
00962         mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
00963         mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
00964 
00965         gray_render_line( RAS_VAR_ mid_x, mid_y );
00966         gray_render_line( RAS_VAR_ to_x, to_y );
00967 
00968         top--;
00969         arc -= 2;
00970       }
00971     }
00972 
00973     return;
00974   }
00975 
00976 
00977   static void
00978   gray_split_cubic( FT_Vector*  base )
00979   {
00980     TPos  a, b, c, d;
00981 
00982 
00983     base[6].x = base[3].x;
00984     c = base[1].x;
00985     d = base[2].x;
00986     base[1].x = a = ( base[0].x + c ) / 2;
00987     base[5].x = b = ( base[3].x + d ) / 2;
00988     c = ( c + d ) / 2;
00989     base[2].x = a = ( a + c ) / 2;
00990     base[4].x = b = ( b + c ) / 2;
00991     base[3].x = ( a + b ) / 2;
00992 
00993     base[6].y = base[3].y;
00994     c = base[1].y;
00995     d = base[2].y;
00996     base[1].y = a = ( base[0].y + c ) / 2;
00997     base[5].y = b = ( base[3].y + d ) / 2;
00998     c = ( c + d ) / 2;
00999     base[2].y = a = ( a + c ) / 2;
01000     base[4].y = b = ( b + c ) / 2;
01001     base[3].y = ( a + b ) / 2;
01002   }
01003 
01004 
01005   static void
01006   gray_render_cubic( RAS_ARG_ const FT_Vector*  control1,
01007                               const FT_Vector*  control2,
01008                               const FT_Vector*  to )
01009   {
01010     TPos        dx, dy, da, db;
01011     int         top, level;
01012     int*        levels;
01013     FT_Vector*  arc;
01014 
01015 
01016     dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 );
01017     if ( dx < 0 )
01018       dx = -dx;
01019     dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 );
01020     if ( dy < 0 )
01021       dy = -dy;
01022     if ( dx < dy )
01023       dx = dy;
01024     da = dx;
01025 
01026     dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x );
01027     if ( dx < 0 )
01028       dx = -dx;
01029     dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y );
01030     if ( dy < 0 )
01031       dy = -dy;
01032     if ( dx < dy )
01033       dx = dy;
01034     db = dx;
01035 
01036     level = 1;
01037     da    = da / ras.cubic_level;
01038     db    = db / ras.conic_level;
01039     while ( da > 0 || db > 0 )
01040     {
01041       da >>= 2;
01042       db >>= 3;
01043       level++;
01044     }
01045 
01046     if ( level <= 1 )
01047     {
01048       TPos   to_x, to_y, mid_x, mid_y;
01049 
01050 
01051       to_x  = UPSCALE( to->x );
01052       to_y  = UPSCALE( to->y );
01053       mid_x = ( ras.x + to_x +
01054                 3 * UPSCALE( control1->x + control2->x ) ) / 8;
01055       mid_y = ( ras.y + to_y +
01056                 3 * UPSCALE( control1->y + control2->y ) ) / 8;
01057 
01058       gray_render_line( RAS_VAR_ mid_x, mid_y );
01059       gray_render_line( RAS_VAR_ to_x, to_y );
01060       return;
01061     }
01062 
01063     arc      = ras.bez_stack;
01064     arc[0].x = UPSCALE( to->x );
01065     arc[0].y = UPSCALE( to->y );
01066     arc[1].x = UPSCALE( control2->x );
01067     arc[1].y = UPSCALE( control2->y );
01068     arc[2].x = UPSCALE( control1->x );
01069     arc[2].y = UPSCALE( control1->y );
01070     arc[3].x = ras.x;
01071     arc[3].y = ras.y;
01072 
01073     levels    = ras.lev_stack;
01074     top       = 0;
01075     levels[0] = level;
01076 
01077     while ( top >= 0 )
01078     {
01079       level = levels[top];
01080       if ( level > 1 )
01081       {
01082         /* check that the arc crosses the current band */
01083         TPos  min, max, y;
01084 
01085 
01086         min = max = arc[0].y;
01087         y = arc[1].y;
01088         if ( y < min ) min = y;
01089         if ( y > max ) max = y;
01090         y = arc[2].y;
01091         if ( y < min ) min = y;
01092         if ( y > max ) max = y;
01093         y = arc[3].y;
01094         if ( y < min ) min = y;
01095         if ( y > max ) max = y;
01096         if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
01097           goto Draw;
01098         gray_split_cubic( arc );
01099         arc += 3;
01100         top ++;
01101         levels[top] = levels[top - 1] = level - 1;
01102         continue;
01103       }
01104 
01105     Draw:
01106       {
01107         TPos  to_x, to_y, mid_x, mid_y;
01108 
01109 
01110         to_x  = arc[0].x;
01111         to_y  = arc[0].y;
01112         mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
01113         mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
01114 
01115         gray_render_line( RAS_VAR_ mid_x, mid_y );
01116         gray_render_line( RAS_VAR_ to_x, to_y );
01117         top --;
01118         arc -= 3;
01119       }
01120     }
01121 
01122     return;
01123   }
01124 
01125 
01126 
01127   static int
01128   gray_move_to( const FT_Vector*  to,
01129                 PWorker           worker )
01130   {
01131     TPos  x, y;
01132 
01133 
01134     /* record current cell, if any */
01135     gray_record_cell( RAS_VAR );
01136 
01137     /* start to a new position */
01138     x = UPSCALE( to->x );
01139     y = UPSCALE( to->y );
01140 
01141     gray_start_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) );
01142 
01143     worker->x = x;
01144     worker->y = y;
01145     return 0;
01146   }
01147 
01148 
01149   static int
01150   gray_line_to( const FT_Vector*  to,
01151                 PWorker           worker )
01152   {
01153     gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
01154     return 0;
01155   }
01156 
01157 
01158   static int
01159   gray_conic_to( const FT_Vector*  control,
01160                  const FT_Vector*  to,
01161                  PWorker           worker )
01162   {
01163     gray_render_conic( RAS_VAR_ control, to );
01164     return 0;
01165   }
01166 
01167 
01168   static int
01169   gray_cubic_to( const FT_Vector*  control1,
01170                  const FT_Vector*  control2,
01171                  const FT_Vector*  to,
01172                  PWorker           worker )
01173   {
01174     gray_render_cubic( RAS_VAR_ control1, control2, to );
01175     return 0;
01176   }
01177 
01178 
01179   static void
01180   gray_render_span( int             y,
01181                     int             count,
01182                     const FT_Span*  spans,
01183                     PWorker         worker )
01184   {
01185     unsigned char*  p;
01186     FT_Bitmap*      map = &worker->target;
01187 
01188 
01189     /* first of all, compute the scanline offset */
01190     p = (unsigned char*)map->buffer - y * map->pitch;
01191     if ( map->pitch >= 0 )
01192       p += ( map->rows - 1 ) * map->pitch;
01193 
01194     for ( ; count > 0; count--, spans++ )
01195     {
01196       unsigned char  coverage = spans->coverage;
01197 
01198 
01199       if ( coverage )
01200       {
01201         /* For small-spans it is faster to do it by ourselves than
01202          * calling `memset'.  This is mainly due to the cost of the
01203          * function call.
01204          */
01205         if ( spans->len >= 8 )
01206           FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len );
01207         else
01208         {
01209           unsigned char*  q = p + spans->x;
01210 
01211 
01212           switch ( spans->len )
01213           {
01214           case 7: *q++ = (unsigned char)coverage;
01215           case 6: *q++ = (unsigned char)coverage;
01216           case 5: *q++ = (unsigned char)coverage;
01217           case 4: *q++ = (unsigned char)coverage;
01218           case 3: *q++ = (unsigned char)coverage;
01219           case 2: *q++ = (unsigned char)coverage;
01220           case 1: *q   = (unsigned char)coverage;
01221           default:
01222             ;
01223           }
01224         }
01225       }
01226     }
01227   }
01228 
01229 
01230   static void
01231   gray_hline( RAS_ARG_ TCoord  x,
01232                        TCoord  y,
01233                        TPos    area,
01234                        TCoord  acount )
01235   {
01236     FT_Span*  span;
01237     int       count;
01238     int       coverage;
01239 
01240 
01241     /* compute the coverage line's coverage, depending on the    */
01242     /* outline fill rule                                         */
01243     /*                                                           */
01244     /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
01245     /*                                                           */
01246     coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) );
01247                                                     /* use range 0..256 */
01248     if ( coverage < 0 )
01249       coverage = -coverage;
01250 
01251     if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL )
01252     {
01253       coverage &= 511;
01254 
01255       if ( coverage > 256 )
01256         coverage = 512 - coverage;
01257       else if ( coverage == 256 )
01258         coverage = 255;
01259     }
01260     else
01261     {
01262       /* normal non-zero winding rule */
01263       if ( coverage >= 256 )
01264         coverage = 255;
01265     }
01266 
01267     y += (TCoord)ras.min_ey;
01268     x += (TCoord)ras.min_ex;
01269 
01270     /* FT_Span.x is a 16-bit short, so limit our coordinates appropriately */
01271     if ( x >= 32767 )
01272       x = 32767;
01273 
01274     /* FT_Span.y is an integer, so limit our coordinates appropriately */
01275     if ( y >= FT_INT_MAX )
01276       y = FT_INT_MAX;
01277 
01278     if ( coverage )
01279     {
01280       /* see whether we can add this span to the current list */
01281       count = ras.num_gray_spans;
01282       span  = ras.gray_spans + count - 1;
01283       if ( count > 0                          &&
01284            ras.span_y == y                    &&
01285            (int)span->x + span->len == (int)x &&
01286            span->coverage == coverage         )
01287       {
01288         span->len = (unsigned short)( span->len + acount );
01289         return;
01290       }
01291 
01292       if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS )
01293       {
01294         if ( ras.render_span && count > 0 )
01295           ras.render_span( ras.span_y, count, ras.gray_spans,
01296                            ras.render_span_data );
01297 
01298 #ifdef FT_DEBUG_LEVEL_TRACE
01299 
01300         if ( count > 0 )
01301         {
01302           int  n;
01303 
01304 
01305           FT_TRACE7(( "y = %3d ", ras.span_y ));
01306           span = ras.gray_spans;
01307           for ( n = 0; n < count; n++, span++ )
01308             FT_TRACE7(( "[%d..%d]:%02x ",
01309                         span->x, span->x + span->len - 1, span->coverage ));
01310           FT_TRACE7(( "\n" ));
01311         }
01312 
01313 #endif /* FT_DEBUG_LEVEL_TRACE */
01314 
01315         ras.num_gray_spans = 0;
01316         ras.span_y         = (int)y;
01317 
01318         count = 0;
01319         span  = ras.gray_spans;
01320       }
01321       else
01322         span++;
01323 
01324       /* add a gray span to the current list */
01325       span->x        = (short)x;
01326       span->len      = (unsigned short)acount;
01327       span->coverage = (unsigned char)coverage;
01328 
01329       ras.num_gray_spans++;
01330     }
01331   }
01332 
01333 
01334 #ifdef FT_DEBUG_LEVEL_TRACE
01335 
01336   /* to be called while in the debugger --                                */
01337   /* this function causes a compiler warning since it is unused otherwise */
01338   static void
01339   gray_dump_cells( RAS_ARG )
01340   {
01341     int  yindex;
01342 
01343 
01344     for ( yindex = 0; yindex < ras.ycount; yindex++ )
01345     {
01346       PCell  cell;
01347 
01348 
01349       printf( "%3d:", yindex );
01350 
01351       for ( cell = ras.ycells[yindex]; cell != NULL; cell = cell->next )
01352         printf( " (%3ld, c:%4ld, a:%6d)", cell->x, cell->cover, cell->area );
01353       printf( "\n" );
01354     }
01355   }
01356 
01357 #endif /* FT_DEBUG_LEVEL_TRACE */
01358 
01359 
01360   static void
01361   gray_sweep( RAS_ARG_ const FT_Bitmap*  target )
01362   {
01363     int  yindex;
01364 
01365     FT_UNUSED( target );
01366 
01367 
01368     if ( ras.num_cells == 0 )
01369       return;
01370 
01371     ras.num_gray_spans = 0;
01372 
01373     FT_TRACE7(( "gray_sweep: start\n" ));
01374 
01375     for ( yindex = 0; yindex < ras.ycount; yindex++ )
01376     {
01377       PCell   cell  = ras.ycells[yindex];
01378       TCoord  cover = 0;
01379       TCoord  x     = 0;
01380 
01381 
01382       for ( ; cell != NULL; cell = cell->next )
01383       {
01384         TPos  area;
01385 
01386 
01387         if ( cell->x > x && cover != 0 )
01388           gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
01389                       cell->x - x );
01390 
01391         cover += cell->cover;
01392         area   = cover * ( ONE_PIXEL * 2 ) - cell->area;
01393 
01394         if ( area != 0 && cell->x >= 0 )
01395           gray_hline( RAS_VAR_ cell->x, yindex, area, 1 );
01396 
01397         x = cell->x + 1;
01398       }
01399 
01400       if ( cover != 0 )
01401         gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
01402                     ras.count_ex - x );
01403     }
01404 
01405     if ( ras.render_span && ras.num_gray_spans > 0 )
01406       ras.render_span( ras.span_y, ras.num_gray_spans,
01407                        ras.gray_spans, ras.render_span_data );
01408 
01409     FT_TRACE7(( "gray_sweep: end\n" ));
01410   }
01411 
01412 
01413 #ifdef _STANDALONE_
01414 
01415   /*************************************************************************/
01416   /*                                                                       */
01417   /*  The following function should only compile in stand-alone mode,      */
01418   /*  i.e., when building this component without the rest of FreeType.     */
01419   /*                                                                       */
01420   /*************************************************************************/
01421 
01422   /*************************************************************************/
01423   /*                                                                       */
01424   /* <Function>                                                            */
01425   /*    FT_Outline_Decompose                                               */
01426   /*                                                                       */
01427   /* <Description>                                                         */
01428   /*    Walk over an outline's structure to decompose it into individual   */
01429   /*    segments and Bézier arcs.  This function is also able to emit      */
01430   /*    `move to' and `close to' operations to indicate the start and end  */
01431   /*    of new contours in the outline.                                    */
01432   /*                                                                       */
01433   /* <Input>                                                               */
01434   /*    outline        :: A pointer to the source target.                  */
01435   /*                                                                       */
01436   /*    func_interface :: A table of `emitters', i.e., function pointers   */
01437   /*                      called during decomposition to indicate path     */
01438   /*                      operations.                                      */
01439   /*                                                                       */
01440   /* <InOut>                                                               */
01441   /*    user           :: A typeless pointer which is passed to each       */
01442   /*                      emitter during the decomposition.  It can be     */
01443   /*                      used to store the state during the               */
01444   /*                      decomposition.                                   */
01445   /*                                                                       */
01446   /* <Return>                                                              */
01447   /*    Error code.  0 means success.                                      */
01448   /*                                                                       */
01449   static int
01450   FT_Outline_Decompose( const FT_Outline*        outline,
01451                         const FT_Outline_Funcs*  func_interface,
01452                         void*                    user )
01453   {
01454 #undef SCALED
01455 #define SCALED( x )  ( ( (x) << shift ) - delta )
01456 
01457     FT_Vector   v_last;
01458     FT_Vector   v_control;
01459     FT_Vector   v_start;
01460 
01461     FT_Vector*  point;
01462     FT_Vector*  limit;
01463     char*       tags;
01464 
01465     int         error;
01466 
01467     int   n;         /* index of contour in outline     */
01468     int   first;     /* index of first point in contour */
01469     char  tag;       /* current point's state           */
01470 
01471     int   shift;
01472     TPos  delta;
01473 
01474 
01475     if ( !outline || !func_interface )
01476       return ErrRaster_Invalid_Argument;
01477 
01478     shift = func_interface->shift;
01479     delta = func_interface->delta;
01480     first = 0;
01481 
01482     for ( n = 0; n < outline->n_contours; n++ )
01483     {
01484       int  last;  /* index of last point in contour */
01485 
01486 
01487       FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
01488 
01489       last  = outline->contours[n];
01490       if ( last < 0 )
01491         goto Invalid_Outline;
01492       limit = outline->points + last;
01493 
01494       v_start   = outline->points[first];
01495       v_start.x = SCALED( v_start.x );
01496       v_start.y = SCALED( v_start.y );
01497 
01498       v_last   = outline->points[last];
01499       v_last.x = SCALED( v_last.x );
01500       v_last.y = SCALED( v_last.y );
01501 
01502       v_control = v_start;
01503 
01504       point = outline->points + first;
01505       tags  = outline->tags   + first;
01506       tag   = FT_CURVE_TAG( tags[0] );
01507 
01508       /* A contour cannot start with a cubic control point! */
01509       if ( tag == FT_CURVE_TAG_CUBIC )
01510         goto Invalid_Outline;
01511 
01512       /* check first point to determine origin */
01513       if ( tag == FT_CURVE_TAG_CONIC )
01514       {
01515         /* first point is conic control.  Yes, this happens. */
01516         if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
01517         {
01518           /* start at last point if it is on the curve */
01519           v_start = v_last;
01520           limit--;
01521         }
01522         else
01523         {
01524           /* if both first and last points are conic,         */
01525           /* start at their middle and record its position    */
01526           /* for closure                                      */
01527           v_start.x = ( v_start.x + v_last.x ) / 2;
01528           v_start.y = ( v_start.y + v_last.y ) / 2;
01529 
01530           v_last = v_start;
01531         }
01532         point--;
01533         tags--;
01534       }
01535 
01536       FT_TRACE5(( "  move to (%.2f, %.2f)\n",
01537                   v_start.x / 64.0, v_start.y / 64.0 ));
01538       error = func_interface->move_to( &v_start, user );
01539       if ( error )
01540         goto Exit;
01541 
01542       while ( point < limit )
01543       {
01544         point++;
01545         tags++;
01546 
01547         tag = FT_CURVE_TAG( tags[0] );
01548         switch ( tag )
01549         {
01550         case FT_CURVE_TAG_ON:  /* emit a single line_to */
01551           {
01552             FT_Vector  vec;
01553 
01554 
01555             vec.x = SCALED( point->x );
01556             vec.y = SCALED( point->y );
01557 
01558             FT_TRACE5(( "  line to (%.2f, %.2f)\n",
01559                         vec.x / 64.0, vec.y / 64.0 ));
01560             error = func_interface->line_to( &vec, user );
01561             if ( error )
01562               goto Exit;
01563             continue;
01564           }
01565 
01566         case FT_CURVE_TAG_CONIC:  /* consume conic arcs */
01567           v_control.x = SCALED( point->x );
01568           v_control.y = SCALED( point->y );
01569 
01570         Do_Conic:
01571           if ( point < limit )
01572           {
01573             FT_Vector  vec;
01574             FT_Vector  v_middle;
01575 
01576 
01577             point++;
01578             tags++;
01579             tag = FT_CURVE_TAG( tags[0] );
01580 
01581             vec.x = SCALED( point->x );
01582             vec.y = SCALED( point->y );
01583 
01584             if ( tag == FT_CURVE_TAG_ON )
01585             {
01586               FT_TRACE5(( "  conic to (%.2f, %.2f)"
01587                           " with control (%.2f, %.2f)\n",
01588                           vec.x / 64.0, vec.y / 64.0,
01589                           v_control.x / 64.0, v_control.y / 64.0 ));
01590               error = func_interface->conic_to( &v_control, &vec, user );
01591               if ( error )
01592                 goto Exit;
01593               continue;
01594             }
01595 
01596             if ( tag != FT_CURVE_TAG_CONIC )
01597               goto Invalid_Outline;
01598 
01599             v_middle.x = ( v_control.x + vec.x ) / 2;
01600             v_middle.y = ( v_control.y + vec.y ) / 2;
01601 
01602             FT_TRACE5(( "  conic to (%.2f, %.2f)"
01603                         " with control (%.2f, %.2f)\n",
01604                         v_middle.x / 64.0, v_middle.y / 64.0,
01605                         v_control.x / 64.0, v_control.y / 64.0 ));
01606             error = func_interface->conic_to( &v_control, &v_middle, user );
01607             if ( error )
01608               goto Exit;
01609 
01610             v_control = vec;
01611             goto Do_Conic;
01612           }
01613 
01614           FT_TRACE5(( "  conic to (%.2f, %.2f)"
01615                       " with control (%.2f, %.2f)\n",
01616                       v_start.x / 64.0, v_start.y / 64.0,
01617                       v_control.x / 64.0, v_control.y / 64.0 ));
01618           error = func_interface->conic_to( &v_control, &v_start, user );
01619           goto Close;
01620 
01621         default:  /* FT_CURVE_TAG_CUBIC */
01622           {
01623             FT_Vector  vec1, vec2;
01624 
01625 
01626             if ( point + 1 > limit                             ||
01627                  FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
01628               goto Invalid_Outline;
01629 
01630             point += 2;
01631             tags  += 2;
01632 
01633             vec1.x = SCALED( point[-2].x );
01634             vec1.y = SCALED( point[-2].y );
01635 
01636             vec2.x = SCALED( point[-1].x );
01637             vec2.y = SCALED( point[-1].y );
01638 
01639             if ( point <= limit )
01640             {
01641               FT_Vector  vec;
01642 
01643 
01644               vec.x = SCALED( point->x );
01645               vec.y = SCALED( point->y );
01646 
01647               FT_TRACE5(( "  cubic to (%.2f, %.2f)"
01648                           " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
01649                           vec.x / 64.0, vec.y / 64.0,
01650                           vec1.x / 64.0, vec1.y / 64.0,
01651                           vec2.x / 64.0, vec2.y / 64.0 ));
01652               error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
01653               if ( error )
01654                 goto Exit;
01655               continue;
01656             }
01657 
01658             FT_TRACE5(( "  cubic to (%.2f, %.2f)"
01659                         " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
01660                         v_start.x / 64.0, v_start.y / 64.0,
01661                         vec1.x / 64.0, vec1.y / 64.0,
01662                         vec2.x / 64.0, vec2.y / 64.0 ));
01663             error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
01664             goto Close;
01665           }
01666         }
01667       }
01668 
01669       /* close the contour with a line segment */
01670       FT_TRACE5(( "  line to (%.2f, %.2f)\n",
01671                   v_start.x / 64.0, v_start.y / 64.0 ));
01672       error = func_interface->line_to( &v_start, user );
01673 
01674    Close:
01675       if ( error )
01676         goto Exit;
01677 
01678       first = last + 1;
01679     }
01680 
01681     FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
01682     return 0;
01683 
01684   Exit:
01685     FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error ));
01686     return error;
01687 
01688   Invalid_Outline:
01689     return ErrRaster_Invalid_Outline;
01690   }
01691 
01692 #endif /* _STANDALONE_ */
01693 
01694 
01695   typedef struct  TBand_
01696   {
01697     TPos  min, max;
01698 
01699   } TBand;
01700 
01701     FT_DEFINE_OUTLINE_FUNCS(func_interface,
01702       (FT_Outline_MoveTo_Func) gray_move_to,
01703       (FT_Outline_LineTo_Func) gray_line_to,
01704       (FT_Outline_ConicTo_Func)gray_conic_to,
01705       (FT_Outline_CubicTo_Func)gray_cubic_to,
01706       0,
01707       0
01708     )
01709 
01710   static int
01711   gray_convert_glyph_inner( RAS_ARG )
01712   {
01713 
01714     volatile int  error = 0;
01715 
01716 #ifdef FT_CONFIG_OPTION_PIC
01717       FT_Outline_Funcs func_interface;
01718       Init_Class_func_interface(&func_interface);
01719 #endif
01720 
01721     if ( ft_setjmp( ras.jump_buffer ) == 0 )
01722     {
01723       error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
01724       gray_record_cell( RAS_VAR );
01725     }
01726     else
01727       error = ErrRaster_Memory_Overflow;
01728 
01729     return error;
01730   }
01731 
01732 
01733   static int
01734   gray_convert_glyph( RAS_ARG )
01735   {
01736     TBand            bands[40];
01737     TBand* volatile  band;
01738     int volatile     n, num_bands;
01739     TPos volatile    min, max, max_y;
01740     FT_BBox*         clip;
01741 
01742 
01743     /* Set up state in the raster object */
01744     gray_compute_cbox( RAS_VAR );
01745 
01746     /* clip to target bitmap, exit if nothing to do */
01747     clip = &ras.clip_box;
01748 
01749     if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax ||
01750          ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax )
01751       return 0;
01752 
01753     if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin;
01754     if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin;
01755 
01756     if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax;
01757     if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax;
01758 
01759     ras.count_ex = ras.max_ex - ras.min_ex;
01760     ras.count_ey = ras.max_ey - ras.min_ey;
01761 
01762     /* simple heuristic used to speed up the bezier decomposition -- see */
01763     /* the code in gray_render_conic() and gray_render_cubic() for more  */
01764     /* details                                                           */
01765     ras.conic_level = 32;
01766     ras.cubic_level = 16;
01767 
01768     {
01769       int  level = 0;
01770 
01771 
01772       if ( ras.count_ex > 24 || ras.count_ey > 24 )
01773         level++;
01774       if ( ras.count_ex > 120 || ras.count_ey > 120 )
01775         level++;
01776 
01777       ras.conic_level <<= level;
01778       ras.cubic_level <<= level;
01779     }
01780 
01781     /* set up vertical bands */
01782     num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size );
01783     if ( num_bands == 0 )
01784       num_bands = 1;
01785     if ( num_bands >= 39 )
01786       num_bands = 39;
01787 
01788     ras.band_shoot = 0;
01789 
01790     min   = ras.min_ey;
01791     max_y = ras.max_ey;
01792 
01793     for ( n = 0; n < num_bands; n++, min = max )
01794     {
01795       max = min + ras.band_size;
01796       if ( n == num_bands - 1 || max > max_y )
01797         max = max_y;
01798 
01799       bands[0].min = min;
01800       bands[0].max = max;
01801       band         = bands;
01802 
01803       while ( band >= bands )
01804       {
01805         TPos  bottom, top, middle;
01806         int   error;
01807 
01808         {
01809           PCell  cells_max;
01810           int    yindex;
01811           long   cell_start, cell_end, cell_mod;
01812 
01813 
01814           ras.ycells = (PCell*)ras.buffer;
01815           ras.ycount = band->max - band->min;
01816 
01817           cell_start = sizeof ( PCell ) * ras.ycount;
01818           cell_mod   = cell_start % sizeof ( TCell );
01819           if ( cell_mod > 0 )
01820             cell_start += sizeof ( TCell ) - cell_mod;
01821 
01822           cell_end  = ras.buffer_size;
01823           cell_end -= cell_end % sizeof( TCell );
01824 
01825           cells_max = (PCell)( (char*)ras.buffer + cell_end );
01826           ras.cells = (PCell)( (char*)ras.buffer + cell_start );
01827           if ( ras.cells >= cells_max )
01828             goto ReduceBands;
01829 
01830           ras.max_cells = cells_max - ras.cells;
01831           if ( ras.max_cells < 2 )
01832             goto ReduceBands;
01833 
01834           for ( yindex = 0; yindex < ras.ycount; yindex++ )
01835             ras.ycells[yindex] = NULL;
01836         }
01837 
01838         ras.num_cells = 0;
01839         ras.invalid   = 1;
01840         ras.min_ey    = band->min;
01841         ras.max_ey    = band->max;
01842         ras.count_ey  = band->max - band->min;
01843 
01844         error = gray_convert_glyph_inner( RAS_VAR );
01845 
01846         if ( !error )
01847         {
01848           gray_sweep( RAS_VAR_ &ras.target );
01849           band--;
01850           continue;
01851         }
01852         else if ( error != ErrRaster_Memory_Overflow )
01853           return 1;
01854 
01855       ReduceBands:
01856         /* render pool overflow; we will reduce the render band by half */
01857         bottom = band->min;
01858         top    = band->max;
01859         middle = bottom + ( ( top - bottom ) >> 1 );
01860 
01861         /* This is too complex for a single scanline; there must */
01862         /* be some problems.                                     */
01863         if ( middle == bottom )
01864         {
01865 #ifdef FT_DEBUG_LEVEL_TRACE
01866           FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));
01867 #endif
01868           return 1;
01869         }
01870 
01871         if ( bottom-top >= ras.band_size )
01872           ras.band_shoot++;
01873 
01874         band[1].min = bottom;
01875         band[1].max = middle;
01876         band[0].min = middle;
01877         band[0].max = top;
01878         band++;
01879       }
01880     }
01881 
01882     if ( ras.band_shoot > 8 && ras.band_size > 16 )
01883       ras.band_size = ras.band_size / 2;
01884 
01885     return 0;
01886   }
01887 
01888 
01889   static int
01890   gray_raster_render( PRaster                  raster,
01891                       const FT_Raster_Params*  params )
01892   {
01893     const FT_Outline*  outline    = (const FT_Outline*)params->source;
01894     const FT_Bitmap*   target_map = params->target;
01895     PWorker            worker;
01896 
01897 
01898     if ( !raster || !raster->buffer || !raster->buffer_size )
01899       return ErrRaster_Invalid_Argument;
01900 
01901     if ( !outline )
01902       return ErrRaster_Invalid_Outline;
01903 
01904     /* return immediately if the outline is empty */
01905     if ( outline->n_points == 0 || outline->n_contours <= 0 )
01906       return 0;
01907 
01908     if ( !outline->contours || !outline->points )
01909       return ErrRaster_Invalid_Outline;
01910 
01911     if ( outline->n_points !=
01912            outline->contours[outline->n_contours - 1] + 1 )
01913       return ErrRaster_Invalid_Outline;
01914 
01915     worker = raster->worker;
01916 
01917     /* if direct mode is not set, we must have a target bitmap */
01918     if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )
01919     {
01920       if ( !target_map )
01921         return ErrRaster_Invalid_Argument;
01922 
01923       /* nothing to do */
01924       if ( !target_map->width || !target_map->rows )
01925         return 0;
01926 
01927       if ( !target_map->buffer )
01928         return ErrRaster_Invalid_Argument;
01929     }
01930 
01931     /* this version does not support monochrome rendering */
01932     if ( !( params->flags & FT_RASTER_FLAG_AA ) )
01933       return ErrRaster_Invalid_Mode;
01934 
01935     /* compute clipping box */
01936     if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )
01937     {
01938       /* compute clip box from target pixmap */
01939       ras.clip_box.xMin = 0;
01940       ras.clip_box.yMin = 0;
01941       ras.clip_box.xMax = target_map->width;
01942       ras.clip_box.yMax = target_map->rows;
01943     }
01944     else if ( params->flags & FT_RASTER_FLAG_CLIP )
01945       ras.clip_box = params->clip_box;
01946     else
01947     {
01948       ras.clip_box.xMin = -32768L;
01949       ras.clip_box.yMin = -32768L;
01950       ras.clip_box.xMax =  32767L;
01951       ras.clip_box.yMax =  32767L;
01952     }
01953 
01954     gray_init_cells( RAS_VAR_ raster->buffer, raster->buffer_size );
01955 
01956     ras.outline        = *outline;
01957     ras.num_cells      = 0;
01958     ras.invalid        = 1;
01959     ras.band_size      = raster->band_size;
01960     ras.num_gray_spans = 0;
01961 
01962     if ( params->flags & FT_RASTER_FLAG_DIRECT )
01963     {
01964       ras.render_span      = (FT_Raster_Span_Func)params->gray_spans;
01965       ras.render_span_data = params->user;
01966     }
01967     else
01968     {
01969       ras.target           = *target_map;
01970       ras.render_span      = (FT_Raster_Span_Func)gray_render_span;
01971       ras.render_span_data = &ras;
01972     }
01973 
01974     return gray_convert_glyph( RAS_VAR );
01975   }
01976 
01977 
01978   /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/
01979   /****                         a static object.                   *****/
01980 
01981 #ifdef _STANDALONE_
01982 
01983   static int
01984   gray_raster_new( void*       memory,
01985                    FT_Raster*  araster )
01986   {
01987     static TRaster  the_raster;
01988 
01989     FT_UNUSED( memory );
01990 
01991 
01992     *araster = (FT_Raster)&the_raster;
01993     FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
01994 
01995     return 0;
01996   }
01997 
01998 
01999   static void
02000   gray_raster_done( FT_Raster  raster )
02001   {
02002     /* nothing */
02003     FT_UNUSED( raster );
02004   }
02005 
02006 #else /* _STANDALONE_ */
02007 
02008   static int
02009   gray_raster_new( FT_Memory   memory,
02010                    FT_Raster*  araster )
02011   {
02012     FT_Error  error;
02013     PRaster   raster;
02014 
02015 
02016     *araster = 0;
02017     if ( !FT_ALLOC( raster, sizeof ( TRaster ) ) )
02018     {
02019       raster->memory = memory;
02020       *araster = (FT_Raster)raster;
02021     }
02022 
02023     return error;
02024   }
02025 
02026 
02027   static void
02028   gray_raster_done( FT_Raster  raster )
02029   {
02030     FT_Memory  memory = (FT_Memory)((PRaster)raster)->memory;
02031 
02032 
02033     FT_FREE( raster );
02034   }
02035 
02036 #endif /* _STANDALONE_ */
02037 
02038 
02039   static void
02040   gray_raster_reset( FT_Raster  raster,
02041                      char*      pool_base,
02042                      long       pool_size )
02043   {
02044     PRaster  rast = (PRaster)raster;
02045 
02046 
02047     if ( raster )
02048     {
02049       if ( pool_base && pool_size >= (long)sizeof ( TWorker ) + 2048 )
02050       {
02051         PWorker  worker = (PWorker)pool_base;
02052 
02053 
02054         rast->worker      = worker;
02055         rast->buffer      = pool_base +
02056                               ( ( sizeof ( TWorker ) + sizeof ( TCell ) - 1 ) &
02057                                 ~( sizeof ( TCell ) - 1 ) );
02058         rast->buffer_size = (long)( ( pool_base + pool_size ) -
02059                                     (char*)rast->buffer ) &
02060                                       ~( sizeof ( TCell ) - 1 );
02061         rast->band_size   = (int)( rast->buffer_size /
02062                                      ( sizeof ( TCell ) * 8 ) );
02063       }
02064       else
02065       {
02066         rast->buffer      = NULL;
02067         rast->buffer_size = 0;
02068         rast->worker      = NULL;
02069       }
02070     }
02071   }
02072 
02073 
02074   FT_DEFINE_RASTER_FUNCS(ft_grays_raster,
02075     FT_GLYPH_FORMAT_OUTLINE,
02076 
02077     (FT_Raster_New_Func)     gray_raster_new,
02078     (FT_Raster_Reset_Func)   gray_raster_reset,
02079     (FT_Raster_Set_Mode_Func)0,
02080     (FT_Raster_Render_Func)  gray_raster_render,
02081     (FT_Raster_Done_Func)    gray_raster_done
02082   )
02083 
02084 
02085 /* END */
02086 
02087 
02088 /* Local Variables: */
02089 /* coding: utf-8    */
02090 /* End:             */

Generated on Tue Jul 5 14:13:51 2011 for ROOT_528-00b_version by  doxygen 1.5.1