misc/libfreetype/src/smooth/ftgrays.c
branchwebgl
changeset 9521 8054d9d775fd
parent 9282 92af50454cf2
parent 9519 b8b5c82eb61b
child 9950 2759212a27de
equal deleted inserted replaced
9282:92af50454cf2 9521:8054d9d775fd
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  ftgrays.c                                                              */
       
     4 /*                                                                         */
       
     5 /*    A new `perfect' anti-aliasing renderer (body).                       */
       
     6 /*                                                                         */
       
     7 /*  Copyright 2000-2003, 2005-2011 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 file can be compiled without the rest of the FreeType engine, by */
       
    21   /* defining the _STANDALONE_ macro when compiling it.  You also need to  */
       
    22   /* put the files `ftgrays.h' and `ftimage.h' into the current            */
       
    23   /* compilation directory.  Typically, you could do something like        */
       
    24   /*                                                                       */
       
    25   /* - copy `src/smooth/ftgrays.c' (this file) to your current directory   */
       
    26   /*                                                                       */
       
    27   /* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */
       
    28   /*   same directory                                                      */
       
    29   /*                                                                       */
       
    30   /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in        */
       
    31   /*                                                                       */
       
    32   /*     cc -c -D_STANDALONE_ ftgrays.c                                    */
       
    33   /*                                                                       */
       
    34   /* The renderer can be initialized with a call to                        */
       
    35   /* `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated  */
       
    36   /* with a call to `ft_gray_raster.raster_render'.                        */
       
    37   /*                                                                       */
       
    38   /* See the comments and documentation in the file `ftimage.h' for more   */
       
    39   /* details on how the raster works.                                      */
       
    40   /*                                                                       */
       
    41   /*************************************************************************/
       
    42 
       
    43   /*************************************************************************/
       
    44   /*                                                                       */
       
    45   /* This is a new anti-aliasing scan-converter for FreeType 2.  The       */
       
    46   /* algorithm used here is _very_ different from the one in the standard  */
       
    47   /* `ftraster' module.  Actually, `ftgrays' computes the _exact_          */
       
    48   /* coverage of the outline on each pixel cell.                           */
       
    49   /*                                                                       */
       
    50   /* It is based on ideas that I initially found in Raph Levien's          */
       
    51   /* excellent LibArt graphics library (see http://www.levien.com/libart   */
       
    52   /* for more information, though the web pages do not tell anything       */
       
    53   /* about the renderer; you'll have to dive into the source code to       */
       
    54   /* understand how it works).                                             */
       
    55   /*                                                                       */
       
    56   /* Note, however, that this is a _very_ different implementation         */
       
    57   /* compared to Raph's.  Coverage information is stored in a very         */
       
    58   /* different way, and I don't use sorted vector paths.  Also, it doesn't */
       
    59   /* use floating point values.                                            */
       
    60   /*                                                                       */
       
    61   /* This renderer has the following advantages:                           */
       
    62   /*                                                                       */
       
    63   /* - It doesn't need an intermediate bitmap.  Instead, one can supply a  */
       
    64   /*   callback function that will be called by the renderer to draw gray  */
       
    65   /*   spans on any target surface.  You can thus do direct composition on */
       
    66   /*   any kind of bitmap, provided that you give the renderer the right   */
       
    67   /*   callback.                                                           */
       
    68   /*                                                                       */
       
    69   /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on   */
       
    70   /*   each pixel cell.                                                    */
       
    71   /*                                                                       */
       
    72   /* - It performs a single pass on the outline (the `standard' FT2        */
       
    73   /*   renderer makes two passes).                                         */
       
    74   /*                                                                       */
       
    75   /* - It can easily be modified to render to _any_ number of gray levels  */
       
    76   /*   cheaply.                                                            */
       
    77   /*                                                                       */
       
    78   /* - For small (< 20) pixel sizes, it is faster than the standard        */
       
    79   /*   renderer.                                                           */
       
    80   /*                                                                       */
       
    81   /*************************************************************************/
       
    82 
       
    83 
       
    84   /*************************************************************************/
       
    85   /*                                                                       */
       
    86   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
       
    87   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
       
    88   /* messages during execution.                                            */
       
    89   /*                                                                       */
       
    90 #undef  FT_COMPONENT
       
    91 #define FT_COMPONENT  trace_smooth
       
    92 
       
    93 
       
    94 #ifdef _STANDALONE_
       
    95 
       
    96 
       
    97   /* define this to dump debugging information */
       
    98 /* #define FT_DEBUG_LEVEL_TRACE */
       
    99 
       
   100 
       
   101 #ifdef FT_DEBUG_LEVEL_TRACE
       
   102 #include <stdio.h>
       
   103 #include <stdarg.h>
       
   104 #endif
       
   105 
       
   106 #include <stddef.h>
       
   107 #include <string.h>
       
   108 #include <setjmp.h>
       
   109 #include <limits.h>
       
   110 #define FT_UINT_MAX  UINT_MAX
       
   111 #define FT_INT_MAX   INT_MAX
       
   112 
       
   113 #define ft_memset   memset
       
   114 
       
   115 #define ft_setjmp   setjmp
       
   116 #define ft_longjmp  longjmp
       
   117 #define ft_jmp_buf  jmp_buf
       
   118 
       
   119 typedef ptrdiff_t  FT_PtrDist;
       
   120 
       
   121 
       
   122 #define ErrRaster_Invalid_Mode      -2
       
   123 #define ErrRaster_Invalid_Outline   -1
       
   124 #define ErrRaster_Invalid_Argument  -3
       
   125 #define ErrRaster_Memory_Overflow   -4
       
   126 
       
   127 #define FT_BEGIN_HEADER
       
   128 #define FT_END_HEADER
       
   129 
       
   130 #include "ftimage.h"
       
   131 #include "ftgrays.h"
       
   132 
       
   133 
       
   134   /* This macro is used to indicate that a function parameter is unused. */
       
   135   /* Its purpose is simply to reduce compiler warnings.  Note also that  */
       
   136   /* simply defining it as `(void)x' doesn't avoid warnings with certain */
       
   137   /* ANSI compilers (e.g. LCC).                                          */
       
   138 #define FT_UNUSED( x )  (x) = (x)
       
   139 
       
   140 
       
   141   /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */
       
   142 
       
   143 #ifdef FT_DEBUG_LEVEL_TRACE
       
   144 
       
   145   void
       
   146   FT_Message( const char*  fmt,
       
   147               ... )
       
   148   {
       
   149     va_list  ap;
       
   150 
       
   151 
       
   152     va_start( ap, fmt );
       
   153     vfprintf( stderr, fmt, ap );
       
   154     va_end( ap );
       
   155   }
       
   156 
       
   157   /* we don't handle tracing levels in stand-alone mode; */
       
   158 #ifndef FT_TRACE5
       
   159 #define FT_TRACE5( varformat )  FT_Message varformat
       
   160 #endif
       
   161 #ifndef FT_TRACE7
       
   162 #define FT_TRACE7( varformat )  FT_Message varformat
       
   163 #endif
       
   164 #ifndef FT_ERROR
       
   165 #define FT_ERROR( varformat )   FT_Message varformat
       
   166 #endif
       
   167 
       
   168 #else /* !FT_DEBUG_LEVEL_TRACE */
       
   169 
       
   170 #define FT_TRACE5( x )  do { } while ( 0 )     /* nothing */
       
   171 #define FT_TRACE7( x )  do { } while ( 0 )     /* nothing */
       
   172 #define FT_ERROR( x )   do { } while ( 0 )     /* nothing */
       
   173 
       
   174 #endif /* !FT_DEBUG_LEVEL_TRACE */
       
   175 
       
   176 
       
   177 #define FT_DEFINE_OUTLINE_FUNCS( class_,               \
       
   178                                  move_to_, line_to_,   \
       
   179                                  conic_to_, cubic_to_, \
       
   180                                  shift_, delta_ )      \
       
   181           static const FT_Outline_Funcs class_ =       \
       
   182           {                                            \
       
   183             move_to_,                                  \
       
   184             line_to_,                                  \
       
   185             conic_to_,                                 \
       
   186             cubic_to_,                                 \
       
   187             shift_,                                    \
       
   188             delta_                                     \
       
   189          };
       
   190 
       
   191 #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_,            \
       
   192                                 raster_new_, raster_reset_,       \
       
   193                                 raster_set_mode_, raster_render_, \
       
   194                                 raster_done_ )                    \
       
   195           const FT_Raster_Funcs class_ =                          \
       
   196           {                                                       \
       
   197             glyph_format_,                                        \
       
   198             raster_new_,                                          \
       
   199             raster_reset_,                                        \
       
   200             raster_set_mode_,                                     \
       
   201             raster_render_,                                       \
       
   202             raster_done_                                          \
       
   203          };
       
   204 
       
   205 #else /* !_STANDALONE_ */
       
   206 
       
   207 
       
   208 #include <ft2build.h>
       
   209 #include "ftgrays.h"
       
   210 #include FT_INTERNAL_OBJECTS_H
       
   211 #include FT_INTERNAL_DEBUG_H
       
   212 #include FT_OUTLINE_H
       
   213 
       
   214 #include "ftsmerrs.h"
       
   215 
       
   216 #include "ftspic.h"
       
   217 
       
   218 #define ErrRaster_Invalid_Mode      Smooth_Err_Cannot_Render_Glyph
       
   219 #define ErrRaster_Invalid_Outline   Smooth_Err_Invalid_Outline
       
   220 #define ErrRaster_Memory_Overflow   Smooth_Err_Out_Of_Memory
       
   221 #define ErrRaster_Invalid_Argument  Smooth_Err_Invalid_Argument
       
   222 
       
   223 #endif /* !_STANDALONE_ */
       
   224 
       
   225 #ifndef FT_MEM_SET
       
   226 #define FT_MEM_SET( d, s, c )  ft_memset( d, s, c )
       
   227 #endif
       
   228 
       
   229 #ifndef FT_MEM_ZERO
       
   230 #define FT_MEM_ZERO( dest, count )  FT_MEM_SET( dest, 0, count )
       
   231 #endif
       
   232 
       
   233   /* as usual, for the speed hungry :-) */
       
   234 
       
   235 #ifndef FT_STATIC_RASTER
       
   236 
       
   237 #define RAS_ARG   PWorker  worker
       
   238 #define RAS_ARG_  PWorker  worker,
       
   239 
       
   240 #define RAS_VAR   worker
       
   241 #define RAS_VAR_  worker,
       
   242 
       
   243 #else /* FT_STATIC_RASTER */
       
   244 
       
   245 #define RAS_ARG   /* empty */
       
   246 #define RAS_ARG_  /* empty */
       
   247 #define RAS_VAR   /* empty */
       
   248 #define RAS_VAR_  /* empty */
       
   249 
       
   250 #endif /* FT_STATIC_RASTER */
       
   251 
       
   252 
       
   253   /* must be at least 6 bits! */
       
   254 #define PIXEL_BITS  8
       
   255 
       
   256 #define ONE_PIXEL       ( 1L << PIXEL_BITS )
       
   257 #define PIXEL_MASK      ( -1L << PIXEL_BITS )
       
   258 #define TRUNC( x )      ( (TCoord)( (x) >> PIXEL_BITS ) )
       
   259 #define SUBPIXELS( x )  ( (TPos)(x) << PIXEL_BITS )
       
   260 #define FLOOR( x )      ( (x) & -ONE_PIXEL )
       
   261 #define CEILING( x )    ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
       
   262 #define ROUND( x )      ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
       
   263 
       
   264 #if PIXEL_BITS >= 6
       
   265 #define UPSCALE( x )    ( (x) << ( PIXEL_BITS - 6 ) )
       
   266 #define DOWNSCALE( x )  ( (x) >> ( PIXEL_BITS - 6 ) )
       
   267 #else
       
   268 #define UPSCALE( x )    ( (x) >> ( 6 - PIXEL_BITS ) )
       
   269 #define DOWNSCALE( x )  ( (x) << ( 6 - PIXEL_BITS ) )
       
   270 #endif
       
   271 
       
   272 
       
   273   /*************************************************************************/
       
   274   /*                                                                       */
       
   275   /*   TYPE DEFINITIONS                                                    */
       
   276   /*                                                                       */
       
   277 
       
   278   /* don't change the following types to FT_Int or FT_Pos, since we might */
       
   279   /* need to define them to "float" or "double" when experimenting with   */
       
   280   /* new algorithms                                                       */
       
   281 
       
   282   typedef long  TCoord;   /* integer scanline/pixel coordinate */
       
   283   typedef long  TPos;     /* sub-pixel coordinate              */
       
   284 
       
   285   /* determine the type used to store cell areas.  This normally takes at */
       
   286   /* least PIXEL_BITS*2 + 1 bits.  On 16-bit systems, we need to use      */
       
   287   /* `long' instead of `int', otherwise bad things happen                 */
       
   288 
       
   289 #if PIXEL_BITS <= 7
       
   290 
       
   291   typedef int  TArea;
       
   292 
       
   293 #else /* PIXEL_BITS >= 8 */
       
   294 
       
   295   /* approximately determine the size of integers using an ANSI-C header */
       
   296 #if FT_UINT_MAX == 0xFFFFU
       
   297   typedef long  TArea;
       
   298 #else
       
   299   typedef int   TArea;
       
   300 #endif
       
   301 
       
   302 #endif /* PIXEL_BITS >= 8 */
       
   303 
       
   304 
       
   305   /* maximal number of gray spans in a call to the span callback */
       
   306 #define FT_MAX_GRAY_SPANS  32
       
   307 
       
   308 
       
   309   typedef struct TCell_*  PCell;
       
   310 
       
   311   typedef struct  TCell_
       
   312   {
       
   313     TPos   x;     /* same with TWorker.ex */
       
   314     TCoord cover; /* same with TWorker.cover */
       
   315     TArea  area;
       
   316     PCell  next;
       
   317 
       
   318   } TCell;
       
   319 
       
   320 
       
   321   typedef struct  TWorker_
       
   322   {
       
   323     TCoord  ex, ey;
       
   324     TPos    min_ex, max_ex;
       
   325     TPos    min_ey, max_ey;
       
   326     TPos    count_ex, count_ey;
       
   327 
       
   328     TArea   area;
       
   329     TCoord  cover;
       
   330     int     invalid;
       
   331 
       
   332     PCell   cells;
       
   333     FT_PtrDist  max_cells;
       
   334     FT_PtrDist  num_cells;
       
   335 
       
   336     TCoord  cx, cy;
       
   337     TPos    x,  y;
       
   338 
       
   339     TPos    last_ey;
       
   340 
       
   341     FT_Vector   bez_stack[32 * 3 + 1];
       
   342     int         lev_stack[32];
       
   343 
       
   344     FT_Outline  outline;
       
   345     FT_Bitmap   target;
       
   346     FT_BBox     clip_box;
       
   347 
       
   348     FT_Span     gray_spans[FT_MAX_GRAY_SPANS];
       
   349     int         num_gray_spans;
       
   350 
       
   351     FT_Raster_Span_Func  render_span;
       
   352     void*                render_span_data;
       
   353     int                  span_y;
       
   354 
       
   355     int  band_size;
       
   356     int  band_shoot;
       
   357 
       
   358     ft_jmp_buf  jump_buffer;
       
   359 
       
   360     void*       buffer;
       
   361     long        buffer_size;
       
   362 
       
   363     PCell*     ycells;
       
   364     TPos       ycount;
       
   365 
       
   366   } TWorker, *PWorker;
       
   367 
       
   368 
       
   369 #ifndef FT_STATIC_RASTER
       
   370 #define ras  (*worker)
       
   371 #else
       
   372   static TWorker  ras;
       
   373 #endif
       
   374 
       
   375 
       
   376   typedef struct TRaster_
       
   377   {
       
   378     void*    buffer;
       
   379     long     buffer_size;
       
   380     int      band_size;
       
   381     void*    memory;
       
   382     PWorker  worker;
       
   383 
       
   384   } TRaster, *PRaster;
       
   385 
       
   386 
       
   387 
       
   388   /*************************************************************************/
       
   389   /*                                                                       */
       
   390   /* Initialize the cells table.                                           */
       
   391   /*                                                                       */
       
   392   static void
       
   393   gray_init_cells( RAS_ARG_ void*  buffer,
       
   394                    long            byte_size )
       
   395   {
       
   396     ras.buffer      = buffer;
       
   397     ras.buffer_size = byte_size;
       
   398 
       
   399     ras.ycells      = (PCell*) buffer;
       
   400     ras.cells       = NULL;
       
   401     ras.max_cells   = 0;
       
   402     ras.num_cells   = 0;
       
   403     ras.area        = 0;
       
   404     ras.cover       = 0;
       
   405     ras.invalid     = 1;
       
   406   }
       
   407 
       
   408 
       
   409   /*************************************************************************/
       
   410   /*                                                                       */
       
   411   /* Compute the outline bounding box.                                     */
       
   412   /*                                                                       */
       
   413   static void
       
   414   gray_compute_cbox( RAS_ARG )
       
   415   {
       
   416     FT_Outline*  outline = &ras.outline;
       
   417     FT_Vector*   vec     = outline->points;
       
   418     FT_Vector*   limit   = vec + outline->n_points;
       
   419 
       
   420 
       
   421     if ( outline->n_points <= 0 )
       
   422     {
       
   423       ras.min_ex = ras.max_ex = 0;
       
   424       ras.min_ey = ras.max_ey = 0;
       
   425       return;
       
   426     }
       
   427 
       
   428     ras.min_ex = ras.max_ex = vec->x;
       
   429     ras.min_ey = ras.max_ey = vec->y;
       
   430 
       
   431     vec++;
       
   432 
       
   433     for ( ; vec < limit; vec++ )
       
   434     {
       
   435       TPos  x = vec->x;
       
   436       TPos  y = vec->y;
       
   437 
       
   438 
       
   439       if ( x < ras.min_ex ) ras.min_ex = x;
       
   440       if ( x > ras.max_ex ) ras.max_ex = x;
       
   441       if ( y < ras.min_ey ) ras.min_ey = y;
       
   442       if ( y > ras.max_ey ) ras.max_ey = y;
       
   443     }
       
   444 
       
   445     /* truncate the bounding box to integer pixels */
       
   446     ras.min_ex = ras.min_ex >> 6;
       
   447     ras.min_ey = ras.min_ey >> 6;
       
   448     ras.max_ex = ( ras.max_ex + 63 ) >> 6;
       
   449     ras.max_ey = ( ras.max_ey + 63 ) >> 6;
       
   450   }
       
   451 
       
   452 
       
   453   /*************************************************************************/
       
   454   /*                                                                       */
       
   455   /* Record the current cell in the table.                                 */
       
   456   /*                                                                       */
       
   457   static PCell
       
   458   gray_find_cell( RAS_ARG )
       
   459   {
       
   460     PCell  *pcell, cell;
       
   461     TPos    x = ras.ex;
       
   462 
       
   463 
       
   464     if ( x > ras.count_ex )
       
   465       x = ras.count_ex;
       
   466 
       
   467     pcell = &ras.ycells[ras.ey];
       
   468     for (;;)
       
   469     {
       
   470       cell = *pcell;
       
   471       if ( cell == NULL || cell->x > x )
       
   472         break;
       
   473 
       
   474       if ( cell->x == x )
       
   475         goto Exit;
       
   476 
       
   477       pcell = &cell->next;
       
   478     }
       
   479 
       
   480     if ( ras.num_cells >= ras.max_cells )
       
   481       ft_longjmp( ras.jump_buffer, 1 );
       
   482 
       
   483     cell        = ras.cells + ras.num_cells++;
       
   484     cell->x     = x;
       
   485     cell->area  = 0;
       
   486     cell->cover = 0;
       
   487 
       
   488     cell->next  = *pcell;
       
   489     *pcell      = cell;
       
   490 
       
   491   Exit:
       
   492     return cell;
       
   493   }
       
   494 
       
   495 
       
   496   static void
       
   497   gray_record_cell( RAS_ARG )
       
   498   {
       
   499     if ( !ras.invalid && ( ras.area | ras.cover ) )
       
   500     {
       
   501       PCell  cell = gray_find_cell( RAS_VAR );
       
   502 
       
   503 
       
   504       cell->area  += ras.area;
       
   505       cell->cover += ras.cover;
       
   506     }
       
   507   }
       
   508 
       
   509 
       
   510   /*************************************************************************/
       
   511   /*                                                                       */
       
   512   /* Set the current cell to a new position.                               */
       
   513   /*                                                                       */
       
   514   static void
       
   515   gray_set_cell( RAS_ARG_ TCoord  ex,
       
   516                           TCoord  ey )
       
   517   {
       
   518     /* Move the cell pointer to a new position.  We set the `invalid'      */
       
   519     /* flag to indicate that the cell isn't part of those we're interested */
       
   520     /* in during the render phase.  This means that:                       */
       
   521     /*                                                                     */
       
   522     /* . the new vertical position must be within min_ey..max_ey-1.        */
       
   523     /* . the new horizontal position must be strictly less than max_ex     */
       
   524     /*                                                                     */
       
   525     /* Note that if a cell is to the left of the clipping region, it is    */
       
   526     /* actually set to the (min_ex-1) horizontal position.                 */
       
   527 
       
   528     /* All cells that are on the left of the clipping region go to the */
       
   529     /* min_ex - 1 horizontal position.                                 */
       
   530     ey -= ras.min_ey;
       
   531 
       
   532     if ( ex > ras.max_ex )
       
   533       ex = ras.max_ex;
       
   534 
       
   535     ex -= ras.min_ex;
       
   536     if ( ex < 0 )
       
   537       ex = -1;
       
   538 
       
   539     /* are we moving to a different cell ? */
       
   540     if ( ex != ras.ex || ey != ras.ey )
       
   541     {
       
   542       /* record the current one if it is valid */
       
   543       if ( !ras.invalid )
       
   544         gray_record_cell( RAS_VAR );
       
   545 
       
   546       ras.area  = 0;
       
   547       ras.cover = 0;
       
   548     }
       
   549 
       
   550     ras.ex      = ex;
       
   551     ras.ey      = ey;
       
   552     ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey ||
       
   553                               ex >= ras.count_ex           );
       
   554   }
       
   555 
       
   556 
       
   557   /*************************************************************************/
       
   558   /*                                                                       */
       
   559   /* Start a new contour at a given cell.                                  */
       
   560   /*                                                                       */
       
   561   static void
       
   562   gray_start_cell( RAS_ARG_ TCoord  ex,
       
   563                             TCoord  ey )
       
   564   {
       
   565     if ( ex > ras.max_ex )
       
   566       ex = (TCoord)( ras.max_ex );
       
   567 
       
   568     if ( ex < ras.min_ex )
       
   569       ex = (TCoord)( ras.min_ex - 1 );
       
   570 
       
   571     ras.area    = 0;
       
   572     ras.cover   = 0;
       
   573     ras.ex      = ex - ras.min_ex;
       
   574     ras.ey      = ey - ras.min_ey;
       
   575     ras.last_ey = SUBPIXELS( ey );
       
   576     ras.invalid = 0;
       
   577 
       
   578     gray_set_cell( RAS_VAR_ ex, ey );
       
   579   }
       
   580 
       
   581 
       
   582   /*************************************************************************/
       
   583   /*                                                                       */
       
   584   /* Render a scanline as one or more cells.                               */
       
   585   /*                                                                       */
       
   586   static void
       
   587   gray_render_scanline( RAS_ARG_ TCoord  ey,
       
   588                                  TPos    x1,
       
   589                                  TCoord  y1,
       
   590                                  TPos    x2,
       
   591                                  TCoord  y2 )
       
   592   {
       
   593     TCoord  ex1, ex2, fx1, fx2, delta, mod, lift, rem;
       
   594     long    p, first, dx;
       
   595     int     incr;
       
   596 
       
   597 
       
   598     dx = x2 - x1;
       
   599 
       
   600     ex1 = TRUNC( x1 );
       
   601     ex2 = TRUNC( x2 );
       
   602     fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) );
       
   603     fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) );
       
   604 
       
   605     /* trivial case.  Happens often */
       
   606     if ( y1 == y2 )
       
   607     {
       
   608       gray_set_cell( RAS_VAR_ ex2, ey );
       
   609       return;
       
   610     }
       
   611 
       
   612     /* everything is located in a single cell.  That is easy! */
       
   613     /*                                                        */
       
   614     if ( ex1 == ex2 )
       
   615     {
       
   616       delta      = y2 - y1;
       
   617       ras.area  += (TArea)(( fx1 + fx2 ) * delta);
       
   618       ras.cover += delta;
       
   619       return;
       
   620     }
       
   621 
       
   622     /* ok, we'll have to render a run of adjacent cells on the same */
       
   623     /* scanline...                                                  */
       
   624     /*                                                              */
       
   625     p     = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
       
   626     first = ONE_PIXEL;
       
   627     incr  = 1;
       
   628 
       
   629     if ( dx < 0 )
       
   630     {
       
   631       p     = fx1 * ( y2 - y1 );
       
   632       first = 0;
       
   633       incr  = -1;
       
   634       dx    = -dx;
       
   635     }
       
   636 
       
   637     delta = (TCoord)( p / dx );
       
   638     mod   = (TCoord)( p % dx );
       
   639     if ( mod < 0 )
       
   640     {
       
   641       delta--;
       
   642       mod += (TCoord)dx;
       
   643     }
       
   644 
       
   645     ras.area  += (TArea)(( fx1 + first ) * delta);
       
   646     ras.cover += delta;
       
   647 
       
   648     ex1 += incr;
       
   649     gray_set_cell( RAS_VAR_ ex1, ey );
       
   650     y1  += delta;
       
   651 
       
   652     if ( ex1 != ex2 )
       
   653     {
       
   654       p    = ONE_PIXEL * ( y2 - y1 + delta );
       
   655       lift = (TCoord)( p / dx );
       
   656       rem  = (TCoord)( p % dx );
       
   657       if ( rem < 0 )
       
   658       {
       
   659         lift--;
       
   660         rem += (TCoord)dx;
       
   661       }
       
   662 
       
   663       mod -= (int)dx;
       
   664 
       
   665       while ( ex1 != ex2 )
       
   666       {
       
   667         delta = lift;
       
   668         mod  += rem;
       
   669         if ( mod >= 0 )
       
   670         {
       
   671           mod -= (TCoord)dx;
       
   672           delta++;
       
   673         }
       
   674 
       
   675         ras.area  += (TArea)(ONE_PIXEL * delta);
       
   676         ras.cover += delta;
       
   677         y1        += delta;
       
   678         ex1       += incr;
       
   679         gray_set_cell( RAS_VAR_ ex1, ey );
       
   680       }
       
   681     }
       
   682 
       
   683     delta      = y2 - y1;
       
   684     ras.area  += (TArea)(( fx2 + ONE_PIXEL - first ) * delta);
       
   685     ras.cover += delta;
       
   686   }
       
   687 
       
   688 
       
   689   /*************************************************************************/
       
   690   /*                                                                       */
       
   691   /* Render a given line as a series of scanlines.                         */
       
   692   /*                                                                       */
       
   693   static void
       
   694   gray_render_line( RAS_ARG_ TPos  to_x,
       
   695                              TPos  to_y )
       
   696   {
       
   697     TCoord  ey1, ey2, fy1, fy2, mod;
       
   698     TPos    dx, dy, x, x2;
       
   699     long    p, first;
       
   700     int     delta, rem, lift, incr;
       
   701 
       
   702 
       
   703     ey1 = TRUNC( ras.last_ey );
       
   704     ey2 = TRUNC( to_y );     /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
       
   705     fy1 = (TCoord)( ras.y - ras.last_ey );
       
   706     fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
       
   707 
       
   708     dx = to_x - ras.x;
       
   709     dy = to_y - ras.y;
       
   710 
       
   711     /* XXX: we should do something about the trivial case where dx == 0, */
       
   712     /*      as it happens very often!                                    */
       
   713 
       
   714     /* perform vertical clipping */
       
   715     {
       
   716       TCoord  min, max;
       
   717 
       
   718 
       
   719       min = ey1;
       
   720       max = ey2;
       
   721       if ( ey1 > ey2 )
       
   722       {
       
   723         min = ey2;
       
   724         max = ey1;
       
   725       }
       
   726       if ( min >= ras.max_ey || max < ras.min_ey )
       
   727         goto End;
       
   728     }
       
   729 
       
   730     /* everything is on a single scanline */
       
   731     if ( ey1 == ey2 )
       
   732     {
       
   733       gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
       
   734       goto End;
       
   735     }
       
   736 
       
   737     /* vertical line - avoid calling gray_render_scanline */
       
   738     incr = 1;
       
   739 
       
   740     if ( dx == 0 )
       
   741     {
       
   742       TCoord  ex     = TRUNC( ras.x );
       
   743       TCoord  two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 );
       
   744       TArea   area;
       
   745 
       
   746 
       
   747       first = ONE_PIXEL;
       
   748       if ( dy < 0 )
       
   749       {
       
   750         first = 0;
       
   751         incr  = -1;
       
   752       }
       
   753 
       
   754       delta      = (int)( first - fy1 );
       
   755       ras.area  += (TArea)two_fx * delta;
       
   756       ras.cover += delta;
       
   757       ey1       += incr;
       
   758 
       
   759       gray_set_cell( RAS_VAR_ ex, ey1 );
       
   760 
       
   761       delta = (int)( first + first - ONE_PIXEL );
       
   762       area  = (TArea)two_fx * delta;
       
   763       while ( ey1 != ey2 )
       
   764       {
       
   765         ras.area  += area;
       
   766         ras.cover += delta;
       
   767         ey1       += incr;
       
   768 
       
   769         gray_set_cell( RAS_VAR_ ex, ey1 );
       
   770       }
       
   771 
       
   772       delta      = (int)( fy2 - ONE_PIXEL + first );
       
   773       ras.area  += (TArea)two_fx * delta;
       
   774       ras.cover += delta;
       
   775 
       
   776       goto End;
       
   777     }
       
   778 
       
   779     /* ok, we have to render several scanlines */
       
   780     p     = ( ONE_PIXEL - fy1 ) * dx;
       
   781     first = ONE_PIXEL;
       
   782     incr  = 1;
       
   783 
       
   784     if ( dy < 0 )
       
   785     {
       
   786       p     = fy1 * dx;
       
   787       first = 0;
       
   788       incr  = -1;
       
   789       dy    = -dy;
       
   790     }
       
   791 
       
   792     delta = (int)( p / dy );
       
   793     mod   = (int)( p % dy );
       
   794     if ( mod < 0 )
       
   795     {
       
   796       delta--;
       
   797       mod += (TCoord)dy;
       
   798     }
       
   799 
       
   800     x = ras.x + delta;
       
   801     gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first );
       
   802 
       
   803     ey1 += incr;
       
   804     gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
       
   805 
       
   806     if ( ey1 != ey2 )
       
   807     {
       
   808       p     = ONE_PIXEL * dx;
       
   809       lift  = (int)( p / dy );
       
   810       rem   = (int)( p % dy );
       
   811       if ( rem < 0 )
       
   812       {
       
   813         lift--;
       
   814         rem += (int)dy;
       
   815       }
       
   816       mod -= (int)dy;
       
   817 
       
   818       while ( ey1 != ey2 )
       
   819       {
       
   820         delta = lift;
       
   821         mod  += rem;
       
   822         if ( mod >= 0 )
       
   823         {
       
   824           mod -= (int)dy;
       
   825           delta++;
       
   826         }
       
   827 
       
   828         x2 = x + delta;
       
   829         gray_render_scanline( RAS_VAR_ ey1, x,
       
   830                                        (TCoord)( ONE_PIXEL - first ), x2,
       
   831                                        (TCoord)first );
       
   832         x = x2;
       
   833 
       
   834         ey1 += incr;
       
   835         gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
       
   836       }
       
   837     }
       
   838 
       
   839     gray_render_scanline( RAS_VAR_ ey1, x,
       
   840                                    (TCoord)( ONE_PIXEL - first ), to_x,
       
   841                                    fy2 );
       
   842 
       
   843   End:
       
   844     ras.x       = to_x;
       
   845     ras.y       = to_y;
       
   846     ras.last_ey = SUBPIXELS( ey2 );
       
   847   }
       
   848 
       
   849 
       
   850   static void
       
   851   gray_split_conic( FT_Vector*  base )
       
   852   {
       
   853     TPos  a, b;
       
   854 
       
   855 
       
   856     base[4].x = base[2].x;
       
   857     b = base[1].x;
       
   858     a = base[3].x = ( base[2].x + b ) / 2;
       
   859     b = base[1].x = ( base[0].x + b ) / 2;
       
   860     base[2].x = ( a + b ) / 2;
       
   861 
       
   862     base[4].y = base[2].y;
       
   863     b = base[1].y;
       
   864     a = base[3].y = ( base[2].y + b ) / 2;
       
   865     b = base[1].y = ( base[0].y + b ) / 2;
       
   866     base[2].y = ( a + b ) / 2;
       
   867   }
       
   868 
       
   869 
       
   870   static void
       
   871   gray_render_conic( RAS_ARG_ const FT_Vector*  control,
       
   872                               const FT_Vector*  to )
       
   873   {
       
   874     TPos        dx, dy;
       
   875     int         top, level;
       
   876     int*        levels;
       
   877     FT_Vector*  arc;
       
   878 
       
   879 
       
   880     arc      = ras.bez_stack;
       
   881     arc[0].x = UPSCALE( to->x );
       
   882     arc[0].y = UPSCALE( to->y );
       
   883     arc[1].x = UPSCALE( control->x );
       
   884     arc[1].y = UPSCALE( control->y );
       
   885     arc[2].x = ras.x;
       
   886     arc[2].y = ras.y;
       
   887 
       
   888     dx = FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x );
       
   889     dy = FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y );
       
   890     if ( dx < dy )
       
   891       dx = dy;
       
   892 
       
   893     level = 0;
       
   894     while ( dx > ONE_PIXEL / 6 )
       
   895     {
       
   896       dx >>= 2;
       
   897       level++;
       
   898     }
       
   899 
       
   900     levels    = ras.lev_stack;
       
   901     levels[0] = level;
       
   902     top       = 0;
       
   903 
       
   904     do
       
   905     {
       
   906       level = levels[top];
       
   907       if ( level > 1 )
       
   908       {
       
   909         /* check that the arc crosses the current band */
       
   910         TPos  min, max, y;
       
   911 
       
   912 
       
   913         min = max = arc[0].y;
       
   914 
       
   915         y = arc[1].y;
       
   916         if ( y < min ) min = y;
       
   917         if ( y > max ) max = y;
       
   918 
       
   919         y = arc[2].y;
       
   920         if ( y < min ) min = y;
       
   921         if ( y > max ) max = y;
       
   922 
       
   923         if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey )
       
   924           goto Draw;
       
   925 
       
   926         gray_split_conic( arc );
       
   927         arc += 2;
       
   928         top++;
       
   929         levels[top] = levels[top - 1] = level - 1;
       
   930         continue;
       
   931       }
       
   932 
       
   933     Draw:
       
   934       gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
       
   935       top--;
       
   936       arc -= 2;
       
   937 
       
   938     } while ( top >= 0 );
       
   939   }
       
   940 
       
   941 
       
   942   static void
       
   943   gray_split_cubic( FT_Vector*  base )
       
   944   {
       
   945     TPos  a, b, c, d;
       
   946 
       
   947 
       
   948     base[6].x = base[3].x;
       
   949     c = base[1].x;
       
   950     d = base[2].x;
       
   951     base[1].x = a = ( base[0].x + c ) / 2;
       
   952     base[5].x = b = ( base[3].x + d ) / 2;
       
   953     c = ( c + d ) / 2;
       
   954     base[2].x = a = ( a + c ) / 2;
       
   955     base[4].x = b = ( b + c ) / 2;
       
   956     base[3].x = ( a + b ) / 2;
       
   957 
       
   958     base[6].y = base[3].y;
       
   959     c = base[1].y;
       
   960     d = base[2].y;
       
   961     base[1].y = a = ( base[0].y + c ) / 2;
       
   962     base[5].y = b = ( base[3].y + d ) / 2;
       
   963     c = ( c + d ) / 2;
       
   964     base[2].y = a = ( a + c ) / 2;
       
   965     base[4].y = b = ( b + c ) / 2;
       
   966     base[3].y = ( a + b ) / 2;
       
   967   }
       
   968 
       
   969 
       
   970   static void
       
   971   gray_render_cubic( RAS_ARG_ const FT_Vector*  control1,
       
   972                               const FT_Vector*  control2,
       
   973                               const FT_Vector*  to )
       
   974   {
       
   975     FT_Vector*  arc;
       
   976 
       
   977 
       
   978     arc      = ras.bez_stack;
       
   979     arc[0].x = UPSCALE( to->x );
       
   980     arc[0].y = UPSCALE( to->y );
       
   981     arc[1].x = UPSCALE( control2->x );
       
   982     arc[1].y = UPSCALE( control2->y );
       
   983     arc[2].x = UPSCALE( control1->x );
       
   984     arc[2].y = UPSCALE( control1->y );
       
   985     arc[3].x = ras.x;
       
   986     arc[3].y = ras.y;
       
   987 
       
   988     for (;;)
       
   989     {
       
   990       /* Check that the arc crosses the current band. */
       
   991       TPos  min, max, y;
       
   992 
       
   993 
       
   994       min = max = arc[0].y;
       
   995 
       
   996       y = arc[1].y;
       
   997       if ( y < min )
       
   998         min = y;
       
   999       if ( y > max )
       
  1000         max = y;
       
  1001 
       
  1002       y = arc[2].y;
       
  1003       if ( y < min )
       
  1004         min = y;
       
  1005       if ( y > max )
       
  1006         max = y;
       
  1007 
       
  1008       y = arc[3].y;
       
  1009       if ( y < min )
       
  1010         min = y;
       
  1011       if ( y > max )
       
  1012         max = y;
       
  1013 
       
  1014       if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey )
       
  1015         goto Draw;
       
  1016 
       
  1017       /* Decide whether to split or draw. See `Rapid Termination          */
       
  1018       /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */
       
  1019       /* F. Hain, at                                                      */
       
  1020       /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */
       
  1021 
       
  1022       {
       
  1023         TPos  dx, dy, dx_, dy_;
       
  1024         TPos  dx1, dy1, dx2, dy2;
       
  1025         TPos  L, s, s_limit;
       
  1026 
       
  1027 
       
  1028         /* dx and dy are x and y components of the P0-P3 chord vector. */
       
  1029         dx = arc[3].x - arc[0].x;
       
  1030         dy = arc[3].y - arc[0].y;
       
  1031 
       
  1032         /* L is an (under)estimate of the Euclidean distance P0-P3.       */
       
  1033         /*                                                                */
       
  1034         /* If dx >= dy, then r = sqrt(dx^2 + dy^2) can be overestimated   */
       
  1035         /* with least maximum error by                                    */
       
  1036         /*                                                                */
       
  1037         /*   r_upperbound = dx + (sqrt(2) - 1) * dy  ,                    */
       
  1038         /*                                                                */
       
  1039         /* where sqrt(2) - 1 can be (over)estimated by 107/256, giving an */
       
  1040         /* error of no more than 8.4%.                                    */
       
  1041         /*                                                                */
       
  1042         /* Similarly, some elementary calculus shows that r can be        */
       
  1043         /* underestimated with least maximum error by                     */
       
  1044         /*                                                                */
       
  1045         /*   r_lowerbound = sqrt(2 + sqrt(2)) / 2 * dx                    */
       
  1046         /*                  + sqrt(2 - sqrt(2)) / 2 * dy  .               */
       
  1047         /*                                                                */
       
  1048         /* 236/256 and 97/256 are (under)estimates of the two algebraic   */
       
  1049         /* numbers, giving an error of no more than 8.1%.                 */
       
  1050 
       
  1051         dx_ = FT_ABS( dx );
       
  1052         dy_ = FT_ABS( dy );
       
  1053 
       
  1054         /* This is the same as                     */
       
  1055         /*                                         */
       
  1056         /*   L = ( 236 * FT_MAX( dx_, dy_ )        */
       
  1057         /*       + 97 * FT_MIN( dx_, dy_ ) ) >> 8; */
       
  1058         L = ( dx_ > dy_ ? 236 * dx_ +  97 * dy_
       
  1059                         :  97 * dx_ + 236 * dy_ ) >> 8;
       
  1060 
       
  1061         /* Avoid possible arithmetic overflow below by splitting. */
       
  1062         if ( L > 32767 )
       
  1063           goto Split;
       
  1064 
       
  1065         /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */
       
  1066         s_limit = L * (TPos)( ONE_PIXEL / 6 );
       
  1067 
       
  1068         /* s is L * the perpendicular distance from P1 to the line P0-P3. */
       
  1069         dx1 = arc[1].x - arc[0].x;
       
  1070         dy1 = arc[1].y - arc[0].y;
       
  1071         s = FT_ABS( dy * dx1 - dx * dy1 );
       
  1072 
       
  1073         if ( s > s_limit )
       
  1074           goto Split;
       
  1075 
       
  1076         /* s is L * the perpendicular distance from P2 to the line P0-P3. */
       
  1077         dx2 = arc[2].x - arc[0].x;
       
  1078         dy2 = arc[2].y - arc[0].y;
       
  1079         s = FT_ABS( dy * dx2 - dx * dy2 );
       
  1080 
       
  1081         if ( s > s_limit )
       
  1082           goto Split;
       
  1083 
       
  1084         /* If P1 or P2 is outside P0-P3, split the curve. */
       
  1085         if ( dy * dy1 + dx * dx1 < 0                                     ||
       
  1086              dy * dy2 + dx * dx2 < 0                                     ||
       
  1087              dy * (arc[3].y - arc[1].y) + dx * (arc[3].x - arc[1].x) < 0 ||
       
  1088              dy * (arc[3].y - arc[2].y) + dx * (arc[3].x - arc[2].x) < 0 )
       
  1089           goto Split;
       
  1090 
       
  1091         /* No reason to split. */
       
  1092         goto Draw;
       
  1093       }
       
  1094 
       
  1095     Split:
       
  1096       gray_split_cubic( arc );
       
  1097       arc += 3;
       
  1098       continue;
       
  1099 
       
  1100     Draw:
       
  1101       gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
       
  1102 
       
  1103       if ( arc == ras.bez_stack )
       
  1104         return;
       
  1105 
       
  1106       arc -= 3;
       
  1107     }
       
  1108   }
       
  1109 
       
  1110 
       
  1111   static int
       
  1112   gray_move_to( const FT_Vector*  to,
       
  1113                 PWorker           worker )
       
  1114   {
       
  1115     TPos  x, y;
       
  1116 
       
  1117 
       
  1118     /* record current cell, if any */
       
  1119     gray_record_cell( RAS_VAR );
       
  1120 
       
  1121     /* start to a new position */
       
  1122     x = UPSCALE( to->x );
       
  1123     y = UPSCALE( to->y );
       
  1124 
       
  1125     gray_start_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) );
       
  1126 
       
  1127     worker->x = x;
       
  1128     worker->y = y;
       
  1129     return 0;
       
  1130   }
       
  1131 
       
  1132 
       
  1133   static int
       
  1134   gray_line_to( const FT_Vector*  to,
       
  1135                 PWorker           worker )
       
  1136   {
       
  1137     gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
       
  1138     return 0;
       
  1139   }
       
  1140 
       
  1141 
       
  1142   static int
       
  1143   gray_conic_to( const FT_Vector*  control,
       
  1144                  const FT_Vector*  to,
       
  1145                  PWorker           worker )
       
  1146   {
       
  1147     gray_render_conic( RAS_VAR_ control, to );
       
  1148     return 0;
       
  1149   }
       
  1150 
       
  1151 
       
  1152   static int
       
  1153   gray_cubic_to( const FT_Vector*  control1,
       
  1154                  const FT_Vector*  control2,
       
  1155                  const FT_Vector*  to,
       
  1156                  PWorker           worker )
       
  1157   {
       
  1158     gray_render_cubic( RAS_VAR_ control1, control2, to );
       
  1159     return 0;
       
  1160   }
       
  1161 
       
  1162 
       
  1163   static void
       
  1164   gray_render_span( int             y,
       
  1165                     int             count,
       
  1166                     const FT_Span*  spans,
       
  1167                     PWorker         worker )
       
  1168   {
       
  1169     unsigned char*  p;
       
  1170     FT_Bitmap*      map = &worker->target;
       
  1171 
       
  1172 
       
  1173     /* first of all, compute the scanline offset */
       
  1174     p = (unsigned char*)map->buffer - y * map->pitch;
       
  1175     if ( map->pitch >= 0 )
       
  1176       p += (unsigned)( ( map->rows - 1 ) * map->pitch );
       
  1177 
       
  1178     for ( ; count > 0; count--, spans++ )
       
  1179     {
       
  1180       unsigned char  coverage = spans->coverage;
       
  1181 
       
  1182 
       
  1183       if ( coverage )
       
  1184       {
       
  1185         /* For small-spans it is faster to do it by ourselves than
       
  1186          * calling `memset'.  This is mainly due to the cost of the
       
  1187          * function call.
       
  1188          */
       
  1189         if ( spans->len >= 8 )
       
  1190           FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len );
       
  1191         else
       
  1192         {
       
  1193           unsigned char*  q = p + spans->x;
       
  1194 
       
  1195 
       
  1196           switch ( spans->len )
       
  1197           {
       
  1198           case 7: *q++ = (unsigned char)coverage;
       
  1199           case 6: *q++ = (unsigned char)coverage;
       
  1200           case 5: *q++ = (unsigned char)coverage;
       
  1201           case 4: *q++ = (unsigned char)coverage;
       
  1202           case 3: *q++ = (unsigned char)coverage;
       
  1203           case 2: *q++ = (unsigned char)coverage;
       
  1204           case 1: *q   = (unsigned char)coverage;
       
  1205           default:
       
  1206             ;
       
  1207           }
       
  1208         }
       
  1209       }
       
  1210     }
       
  1211   }
       
  1212 
       
  1213 
       
  1214   static void
       
  1215   gray_hline( RAS_ARG_ TCoord  x,
       
  1216                        TCoord  y,
       
  1217                        TPos    area,
       
  1218                        TCoord  acount )
       
  1219   {
       
  1220     FT_Span*  span;
       
  1221     int       count;
       
  1222     int       coverage;
       
  1223 
       
  1224 
       
  1225     /* compute the coverage line's coverage, depending on the    */
       
  1226     /* outline fill rule                                         */
       
  1227     /*                                                           */
       
  1228     /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
       
  1229     /*                                                           */
       
  1230     coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) );
       
  1231                                                     /* use range 0..256 */
       
  1232     if ( coverage < 0 )
       
  1233       coverage = -coverage;
       
  1234 
       
  1235     if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL )
       
  1236     {
       
  1237       coverage &= 511;
       
  1238 
       
  1239       if ( coverage > 256 )
       
  1240         coverage = 512 - coverage;
       
  1241       else if ( coverage == 256 )
       
  1242         coverage = 255;
       
  1243     }
       
  1244     else
       
  1245     {
       
  1246       /* normal non-zero winding rule */
       
  1247       if ( coverage >= 256 )
       
  1248         coverage = 255;
       
  1249     }
       
  1250 
       
  1251     y += (TCoord)ras.min_ey;
       
  1252     x += (TCoord)ras.min_ex;
       
  1253 
       
  1254     /* FT_Span.x is a 16-bit short, so limit our coordinates appropriately */
       
  1255     if ( x >= 32767 )
       
  1256       x = 32767;
       
  1257 
       
  1258     /* FT_Span.y is an integer, so limit our coordinates appropriately */
       
  1259     if ( y >= FT_INT_MAX )
       
  1260       y = FT_INT_MAX;
       
  1261 
       
  1262     if ( coverage )
       
  1263     {
       
  1264       /* see whether we can add this span to the current list */
       
  1265       count = ras.num_gray_spans;
       
  1266       span  = ras.gray_spans + count - 1;
       
  1267       if ( count > 0                          &&
       
  1268            ras.span_y == y                    &&
       
  1269            (int)span->x + span->len == (int)x &&
       
  1270            span->coverage == coverage         )
       
  1271       {
       
  1272         span->len = (unsigned short)( span->len + acount );
       
  1273         return;
       
  1274       }
       
  1275 
       
  1276       if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS )
       
  1277       {
       
  1278         if ( ras.render_span && count > 0 )
       
  1279           ras.render_span( ras.span_y, count, ras.gray_spans,
       
  1280                            ras.render_span_data );
       
  1281 
       
  1282 #ifdef FT_DEBUG_LEVEL_TRACE
       
  1283 
       
  1284         if ( count > 0 )
       
  1285         {
       
  1286           int  n;
       
  1287 
       
  1288 
       
  1289           FT_TRACE7(( "y = %3d ", ras.span_y ));
       
  1290           span = ras.gray_spans;
       
  1291           for ( n = 0; n < count; n++, span++ )
       
  1292             FT_TRACE7(( "[%d..%d]:%02x ",
       
  1293                         span->x, span->x + span->len - 1, span->coverage ));
       
  1294           FT_TRACE7(( "\n" ));
       
  1295         }
       
  1296 
       
  1297 #endif /* FT_DEBUG_LEVEL_TRACE */
       
  1298 
       
  1299         ras.num_gray_spans = 0;
       
  1300         ras.span_y         = (int)y;
       
  1301 
       
  1302         count = 0;
       
  1303         span  = ras.gray_spans;
       
  1304       }
       
  1305       else
       
  1306         span++;
       
  1307 
       
  1308       /* add a gray span to the current list */
       
  1309       span->x        = (short)x;
       
  1310       span->len      = (unsigned short)acount;
       
  1311       span->coverage = (unsigned char)coverage;
       
  1312 
       
  1313       ras.num_gray_spans++;
       
  1314     }
       
  1315   }
       
  1316 
       
  1317 
       
  1318 #ifdef FT_DEBUG_LEVEL_TRACE
       
  1319 
       
  1320   /* to be called while in the debugger --                                */
       
  1321   /* this function causes a compiler warning since it is unused otherwise */
       
  1322   static void
       
  1323   gray_dump_cells( RAS_ARG )
       
  1324   {
       
  1325     int  yindex;
       
  1326 
       
  1327 
       
  1328     for ( yindex = 0; yindex < ras.ycount; yindex++ )
       
  1329     {
       
  1330       PCell  cell;
       
  1331 
       
  1332 
       
  1333       printf( "%3d:", yindex );
       
  1334 
       
  1335       for ( cell = ras.ycells[yindex]; cell != NULL; cell = cell->next )
       
  1336         printf( " (%3ld, c:%4ld, a:%6d)", cell->x, cell->cover, cell->area );
       
  1337       printf( "\n" );
       
  1338     }
       
  1339   }
       
  1340 
       
  1341 #endif /* FT_DEBUG_LEVEL_TRACE */
       
  1342 
       
  1343 
       
  1344   static void
       
  1345   gray_sweep( RAS_ARG_ const FT_Bitmap*  target )
       
  1346   {
       
  1347     int  yindex;
       
  1348 
       
  1349     FT_UNUSED( target );
       
  1350 
       
  1351 
       
  1352     if ( ras.num_cells == 0 )
       
  1353       return;
       
  1354 
       
  1355     ras.num_gray_spans = 0;
       
  1356 
       
  1357     FT_TRACE7(( "gray_sweep: start\n" ));
       
  1358 
       
  1359     for ( yindex = 0; yindex < ras.ycount; yindex++ )
       
  1360     {
       
  1361       PCell   cell  = ras.ycells[yindex];
       
  1362       TCoord  cover = 0;
       
  1363       TCoord  x     = 0;
       
  1364 
       
  1365 
       
  1366       for ( ; cell != NULL; cell = cell->next )
       
  1367       {
       
  1368         TPos  area;
       
  1369 
       
  1370 
       
  1371         if ( cell->x > x && cover != 0 )
       
  1372           gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
       
  1373                       cell->x - x );
       
  1374 
       
  1375         cover += cell->cover;
       
  1376         area   = cover * ( ONE_PIXEL * 2 ) - cell->area;
       
  1377 
       
  1378         if ( area != 0 && cell->x >= 0 )
       
  1379           gray_hline( RAS_VAR_ cell->x, yindex, area, 1 );
       
  1380 
       
  1381         x = cell->x + 1;
       
  1382       }
       
  1383 
       
  1384       if ( cover != 0 )
       
  1385         gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
       
  1386                     ras.count_ex - x );
       
  1387     }
       
  1388 
       
  1389     if ( ras.render_span && ras.num_gray_spans > 0 )
       
  1390       ras.render_span( ras.span_y, ras.num_gray_spans,
       
  1391                        ras.gray_spans, ras.render_span_data );
       
  1392 
       
  1393     FT_TRACE7(( "gray_sweep: end\n" ));
       
  1394   }
       
  1395 
       
  1396 
       
  1397 #ifdef _STANDALONE_
       
  1398 
       
  1399   /*************************************************************************/
       
  1400   /*                                                                       */
       
  1401   /*  The following function should only compile in stand-alone mode,      */
       
  1402   /*  i.e., when building this component without the rest of FreeType.     */
       
  1403   /*                                                                       */
       
  1404   /*************************************************************************/
       
  1405 
       
  1406   /*************************************************************************/
       
  1407   /*                                                                       */
       
  1408   /* <Function>                                                            */
       
  1409   /*    FT_Outline_Decompose                                               */
       
  1410   /*                                                                       */
       
  1411   /* <Description>                                                         */
       
  1412   /*    Walk over an outline's structure to decompose it into individual   */
       
  1413   /*    segments and Bézier arcs.  This function is also able to emit      */
       
  1414   /*    `move to' and `close to' operations to indicate the start and end  */
       
  1415   /*    of new contours in the outline.                                    */
       
  1416   /*                                                                       */
       
  1417   /* <Input>                                                               */
       
  1418   /*    outline        :: A pointer to the source target.                  */
       
  1419   /*                                                                       */
       
  1420   /*    func_interface :: A table of `emitters', i.e., function pointers   */
       
  1421   /*                      called during decomposition to indicate path     */
       
  1422   /*                      operations.                                      */
       
  1423   /*                                                                       */
       
  1424   /* <InOut>                                                               */
       
  1425   /*    user           :: A typeless pointer which is passed to each       */
       
  1426   /*                      emitter during the decomposition.  It can be     */
       
  1427   /*                      used to store the state during the               */
       
  1428   /*                      decomposition.                                   */
       
  1429   /*                                                                       */
       
  1430   /* <Return>                                                              */
       
  1431   /*    Error code.  0 means success.                                      */
       
  1432   /*                                                                       */
       
  1433   static int
       
  1434   FT_Outline_Decompose( const FT_Outline*        outline,
       
  1435                         const FT_Outline_Funcs*  func_interface,
       
  1436                         void*                    user )
       
  1437   {
       
  1438 #undef SCALED
       
  1439 #define SCALED( x )  ( ( (x) << shift ) - delta )
       
  1440 
       
  1441     FT_Vector   v_last;
       
  1442     FT_Vector   v_control;
       
  1443     FT_Vector   v_start;
       
  1444 
       
  1445     FT_Vector*  point;
       
  1446     FT_Vector*  limit;
       
  1447     char*       tags;
       
  1448 
       
  1449     int         error;
       
  1450 
       
  1451     int   n;         /* index of contour in outline     */
       
  1452     int   first;     /* index of first point in contour */
       
  1453     char  tag;       /* current point's state           */
       
  1454 
       
  1455     int   shift;
       
  1456     TPos  delta;
       
  1457 
       
  1458 
       
  1459     if ( !outline || !func_interface )
       
  1460       return ErrRaster_Invalid_Argument;
       
  1461 
       
  1462     shift = func_interface->shift;
       
  1463     delta = func_interface->delta;
       
  1464     first = 0;
       
  1465 
       
  1466     for ( n = 0; n < outline->n_contours; n++ )
       
  1467     {
       
  1468       int  last;  /* index of last point in contour */
       
  1469 
       
  1470 
       
  1471       FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
       
  1472 
       
  1473       last  = outline->contours[n];
       
  1474       if ( last < 0 )
       
  1475         goto Invalid_Outline;
       
  1476       limit = outline->points + last;
       
  1477 
       
  1478       v_start   = outline->points[first];
       
  1479       v_start.x = SCALED( v_start.x );
       
  1480       v_start.y = SCALED( v_start.y );
       
  1481 
       
  1482       v_last   = outline->points[last];
       
  1483       v_last.x = SCALED( v_last.x );
       
  1484       v_last.y = SCALED( v_last.y );
       
  1485 
       
  1486       v_control = v_start;
       
  1487 
       
  1488       point = outline->points + first;
       
  1489       tags  = outline->tags   + first;
       
  1490       tag   = FT_CURVE_TAG( tags[0] );
       
  1491 
       
  1492       /* A contour cannot start with a cubic control point! */
       
  1493       if ( tag == FT_CURVE_TAG_CUBIC )
       
  1494         goto Invalid_Outline;
       
  1495 
       
  1496       /* check first point to determine origin */
       
  1497       if ( tag == FT_CURVE_TAG_CONIC )
       
  1498       {
       
  1499         /* first point is conic control.  Yes, this happens. */
       
  1500         if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
       
  1501         {
       
  1502           /* start at last point if it is on the curve */
       
  1503           v_start = v_last;
       
  1504           limit--;
       
  1505         }
       
  1506         else
       
  1507         {
       
  1508           /* if both first and last points are conic,         */
       
  1509           /* start at their middle and record its position    */
       
  1510           /* for closure                                      */
       
  1511           v_start.x = ( v_start.x + v_last.x ) / 2;
       
  1512           v_start.y = ( v_start.y + v_last.y ) / 2;
       
  1513 
       
  1514           v_last = v_start;
       
  1515         }
       
  1516         point--;
       
  1517         tags--;
       
  1518       }
       
  1519 
       
  1520       FT_TRACE5(( "  move to (%.2f, %.2f)\n",
       
  1521                   v_start.x / 64.0, v_start.y / 64.0 ));
       
  1522       error = func_interface->move_to( &v_start, user );
       
  1523       if ( error )
       
  1524         goto Exit;
       
  1525 
       
  1526       while ( point < limit )
       
  1527       {
       
  1528         point++;
       
  1529         tags++;
       
  1530 
       
  1531         tag = FT_CURVE_TAG( tags[0] );
       
  1532         switch ( tag )
       
  1533         {
       
  1534         case FT_CURVE_TAG_ON:  /* emit a single line_to */
       
  1535           {
       
  1536             FT_Vector  vec;
       
  1537 
       
  1538 
       
  1539             vec.x = SCALED( point->x );
       
  1540             vec.y = SCALED( point->y );
       
  1541 
       
  1542             FT_TRACE5(( "  line to (%.2f, %.2f)\n",
       
  1543                         vec.x / 64.0, vec.y / 64.0 ));
       
  1544             error = func_interface->line_to( &vec, user );
       
  1545             if ( error )
       
  1546               goto Exit;
       
  1547             continue;
       
  1548           }
       
  1549 
       
  1550         case FT_CURVE_TAG_CONIC:  /* consume conic arcs */
       
  1551           v_control.x = SCALED( point->x );
       
  1552           v_control.y = SCALED( point->y );
       
  1553 
       
  1554         Do_Conic:
       
  1555           if ( point < limit )
       
  1556           {
       
  1557             FT_Vector  vec;
       
  1558             FT_Vector  v_middle;
       
  1559 
       
  1560 
       
  1561             point++;
       
  1562             tags++;
       
  1563             tag = FT_CURVE_TAG( tags[0] );
       
  1564 
       
  1565             vec.x = SCALED( point->x );
       
  1566             vec.y = SCALED( point->y );
       
  1567 
       
  1568             if ( tag == FT_CURVE_TAG_ON )
       
  1569             {
       
  1570               FT_TRACE5(( "  conic to (%.2f, %.2f)"
       
  1571                           " with control (%.2f, %.2f)\n",
       
  1572                           vec.x / 64.0, vec.y / 64.0,
       
  1573                           v_control.x / 64.0, v_control.y / 64.0 ));
       
  1574               error = func_interface->conic_to( &v_control, &vec, user );
       
  1575               if ( error )
       
  1576                 goto Exit;
       
  1577               continue;
       
  1578             }
       
  1579 
       
  1580             if ( tag != FT_CURVE_TAG_CONIC )
       
  1581               goto Invalid_Outline;
       
  1582 
       
  1583             v_middle.x = ( v_control.x + vec.x ) / 2;
       
  1584             v_middle.y = ( v_control.y + vec.y ) / 2;
       
  1585 
       
  1586             FT_TRACE5(( "  conic to (%.2f, %.2f)"
       
  1587                         " with control (%.2f, %.2f)\n",
       
  1588                         v_middle.x / 64.0, v_middle.y / 64.0,
       
  1589                         v_control.x / 64.0, v_control.y / 64.0 ));
       
  1590             error = func_interface->conic_to( &v_control, &v_middle, user );
       
  1591             if ( error )
       
  1592               goto Exit;
       
  1593 
       
  1594             v_control = vec;
       
  1595             goto Do_Conic;
       
  1596           }
       
  1597 
       
  1598           FT_TRACE5(( "  conic to (%.2f, %.2f)"
       
  1599                       " with control (%.2f, %.2f)\n",
       
  1600                       v_start.x / 64.0, v_start.y / 64.0,
       
  1601                       v_control.x / 64.0, v_control.y / 64.0 ));
       
  1602           error = func_interface->conic_to( &v_control, &v_start, user );
       
  1603           goto Close;
       
  1604 
       
  1605         default:  /* FT_CURVE_TAG_CUBIC */
       
  1606           {
       
  1607             FT_Vector  vec1, vec2;
       
  1608 
       
  1609 
       
  1610             if ( point + 1 > limit                             ||
       
  1611                  FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
       
  1612               goto Invalid_Outline;
       
  1613 
       
  1614             point += 2;
       
  1615             tags  += 2;
       
  1616 
       
  1617             vec1.x = SCALED( point[-2].x );
       
  1618             vec1.y = SCALED( point[-2].y );
       
  1619 
       
  1620             vec2.x = SCALED( point[-1].x );
       
  1621             vec2.y = SCALED( point[-1].y );
       
  1622 
       
  1623             if ( point <= limit )
       
  1624             {
       
  1625               FT_Vector  vec;
       
  1626 
       
  1627 
       
  1628               vec.x = SCALED( point->x );
       
  1629               vec.y = SCALED( point->y );
       
  1630 
       
  1631               FT_TRACE5(( "  cubic to (%.2f, %.2f)"
       
  1632                           " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
       
  1633                           vec.x / 64.0, vec.y / 64.0,
       
  1634                           vec1.x / 64.0, vec1.y / 64.0,
       
  1635                           vec2.x / 64.0, vec2.y / 64.0 ));
       
  1636               error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
       
  1637               if ( error )
       
  1638                 goto Exit;
       
  1639               continue;
       
  1640             }
       
  1641 
       
  1642             FT_TRACE5(( "  cubic to (%.2f, %.2f)"
       
  1643                         " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
       
  1644                         v_start.x / 64.0, v_start.y / 64.0,
       
  1645                         vec1.x / 64.0, vec1.y / 64.0,
       
  1646                         vec2.x / 64.0, vec2.y / 64.0 ));
       
  1647             error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
       
  1648             goto Close;
       
  1649           }
       
  1650         }
       
  1651       }
       
  1652 
       
  1653       /* close the contour with a line segment */
       
  1654       FT_TRACE5(( "  line to (%.2f, %.2f)\n",
       
  1655                   v_start.x / 64.0, v_start.y / 64.0 ));
       
  1656       error = func_interface->line_to( &v_start, user );
       
  1657 
       
  1658    Close:
       
  1659       if ( error )
       
  1660         goto Exit;
       
  1661 
       
  1662       first = last + 1;
       
  1663     }
       
  1664 
       
  1665     FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
       
  1666     return 0;
       
  1667 
       
  1668   Exit:
       
  1669     FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error ));
       
  1670     return error;
       
  1671 
       
  1672   Invalid_Outline:
       
  1673     return ErrRaster_Invalid_Outline;
       
  1674   }
       
  1675 
       
  1676 #endif /* _STANDALONE_ */
       
  1677 
       
  1678 
       
  1679   typedef struct  TBand_
       
  1680   {
       
  1681     TPos  min, max;
       
  1682 
       
  1683   } TBand;
       
  1684 
       
  1685     FT_DEFINE_OUTLINE_FUNCS(func_interface,
       
  1686       (FT_Outline_MoveTo_Func) gray_move_to,
       
  1687       (FT_Outline_LineTo_Func) gray_line_to,
       
  1688       (FT_Outline_ConicTo_Func)gray_conic_to,
       
  1689       (FT_Outline_CubicTo_Func)gray_cubic_to,
       
  1690       0,
       
  1691       0
       
  1692     )
       
  1693 
       
  1694   static int
       
  1695   gray_convert_glyph_inner( RAS_ARG )
       
  1696   {
       
  1697 
       
  1698     volatile int  error = 0;
       
  1699 
       
  1700 #ifdef FT_CONFIG_OPTION_PIC
       
  1701       FT_Outline_Funcs func_interface;
       
  1702       Init_Class_func_interface(&func_interface);
       
  1703 #endif
       
  1704 
       
  1705     if ( ft_setjmp( ras.jump_buffer ) == 0 )
       
  1706     {
       
  1707       error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
       
  1708       gray_record_cell( RAS_VAR );
       
  1709     }
       
  1710     else
       
  1711       error = ErrRaster_Memory_Overflow;
       
  1712 
       
  1713     return error;
       
  1714   }
       
  1715 
       
  1716 
       
  1717   static int
       
  1718   gray_convert_glyph( RAS_ARG )
       
  1719   {
       
  1720     TBand            bands[40];
       
  1721     TBand* volatile  band;
       
  1722     int volatile     n, num_bands;
       
  1723     TPos volatile    min, max, max_y;
       
  1724     FT_BBox*         clip;
       
  1725 
       
  1726 
       
  1727     /* Set up state in the raster object */
       
  1728     gray_compute_cbox( RAS_VAR );
       
  1729 
       
  1730     /* clip to target bitmap, exit if nothing to do */
       
  1731     clip = &ras.clip_box;
       
  1732 
       
  1733     if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax ||
       
  1734          ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax )
       
  1735       return 0;
       
  1736 
       
  1737     if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin;
       
  1738     if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin;
       
  1739 
       
  1740     if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax;
       
  1741     if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax;
       
  1742 
       
  1743     ras.count_ex = ras.max_ex - ras.min_ex;
       
  1744     ras.count_ey = ras.max_ey - ras.min_ey;
       
  1745 
       
  1746     /* set up vertical bands */
       
  1747     num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size );
       
  1748     if ( num_bands == 0 )
       
  1749       num_bands = 1;
       
  1750     if ( num_bands >= 39 )
       
  1751       num_bands = 39;
       
  1752 
       
  1753     ras.band_shoot = 0;
       
  1754 
       
  1755     min   = ras.min_ey;
       
  1756     max_y = ras.max_ey;
       
  1757 
       
  1758     for ( n = 0; n < num_bands; n++, min = max )
       
  1759     {
       
  1760       max = min + ras.band_size;
       
  1761       if ( n == num_bands - 1 || max > max_y )
       
  1762         max = max_y;
       
  1763 
       
  1764       bands[0].min = min;
       
  1765       bands[0].max = max;
       
  1766       band         = bands;
       
  1767 
       
  1768       while ( band >= bands )
       
  1769       {
       
  1770         TPos  bottom, top, middle;
       
  1771         int   error;
       
  1772 
       
  1773         {
       
  1774           PCell  cells_max;
       
  1775           int    yindex;
       
  1776           long   cell_start, cell_end, cell_mod;
       
  1777 
       
  1778 
       
  1779           ras.ycells = (PCell*)ras.buffer;
       
  1780           ras.ycount = band->max - band->min;
       
  1781 
       
  1782           cell_start = sizeof ( PCell ) * ras.ycount;
       
  1783           cell_mod   = cell_start % sizeof ( TCell );
       
  1784           if ( cell_mod > 0 )
       
  1785             cell_start += sizeof ( TCell ) - cell_mod;
       
  1786 
       
  1787           cell_end  = ras.buffer_size;
       
  1788           cell_end -= cell_end % sizeof( TCell );
       
  1789 
       
  1790           cells_max = (PCell)( (char*)ras.buffer + cell_end );
       
  1791           ras.cells = (PCell)( (char*)ras.buffer + cell_start );
       
  1792           if ( ras.cells >= cells_max )
       
  1793             goto ReduceBands;
       
  1794 
       
  1795           ras.max_cells = cells_max - ras.cells;
       
  1796           if ( ras.max_cells < 2 )
       
  1797             goto ReduceBands;
       
  1798 
       
  1799           for ( yindex = 0; yindex < ras.ycount; yindex++ )
       
  1800             ras.ycells[yindex] = NULL;
       
  1801         }
       
  1802 
       
  1803         ras.num_cells = 0;
       
  1804         ras.invalid   = 1;
       
  1805         ras.min_ey    = band->min;
       
  1806         ras.max_ey    = band->max;
       
  1807         ras.count_ey  = band->max - band->min;
       
  1808 
       
  1809         error = gray_convert_glyph_inner( RAS_VAR );
       
  1810 
       
  1811         if ( !error )
       
  1812         {
       
  1813           gray_sweep( RAS_VAR_ &ras.target );
       
  1814           band--;
       
  1815           continue;
       
  1816         }
       
  1817         else if ( error != ErrRaster_Memory_Overflow )
       
  1818           return 1;
       
  1819 
       
  1820       ReduceBands:
       
  1821         /* render pool overflow; we will reduce the render band by half */
       
  1822         bottom = band->min;
       
  1823         top    = band->max;
       
  1824         middle = bottom + ( ( top - bottom ) >> 1 );
       
  1825 
       
  1826         /* This is too complex for a single scanline; there must */
       
  1827         /* be some problems.                                     */
       
  1828         if ( middle == bottom )
       
  1829         {
       
  1830 #ifdef FT_DEBUG_LEVEL_TRACE
       
  1831           FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));
       
  1832 #endif
       
  1833           return 1;
       
  1834         }
       
  1835 
       
  1836         if ( bottom-top >= ras.band_size )
       
  1837           ras.band_shoot++;
       
  1838 
       
  1839         band[1].min = bottom;
       
  1840         band[1].max = middle;
       
  1841         band[0].min = middle;
       
  1842         band[0].max = top;
       
  1843         band++;
       
  1844       }
       
  1845     }
       
  1846 
       
  1847     if ( ras.band_shoot > 8 && ras.band_size > 16 )
       
  1848       ras.band_size = ras.band_size / 2;
       
  1849 
       
  1850     return 0;
       
  1851   }
       
  1852 
       
  1853 
       
  1854   static int
       
  1855   gray_raster_render( PRaster                  raster,
       
  1856                       const FT_Raster_Params*  params )
       
  1857   {
       
  1858     const FT_Outline*  outline    = (const FT_Outline*)params->source;
       
  1859     const FT_Bitmap*   target_map = params->target;
       
  1860     PWorker            worker;
       
  1861 
       
  1862 
       
  1863     if ( !raster || !raster->buffer || !raster->buffer_size )
       
  1864       return ErrRaster_Invalid_Argument;
       
  1865 
       
  1866     if ( !outline )
       
  1867       return ErrRaster_Invalid_Outline;
       
  1868 
       
  1869     /* return immediately if the outline is empty */
       
  1870     if ( outline->n_points == 0 || outline->n_contours <= 0 )
       
  1871       return 0;
       
  1872 
       
  1873     if ( !outline->contours || !outline->points )
       
  1874       return ErrRaster_Invalid_Outline;
       
  1875 
       
  1876     if ( outline->n_points !=
       
  1877            outline->contours[outline->n_contours - 1] + 1 )
       
  1878       return ErrRaster_Invalid_Outline;
       
  1879 
       
  1880     worker = raster->worker;
       
  1881 
       
  1882     /* if direct mode is not set, we must have a target bitmap */
       
  1883     if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )
       
  1884     {
       
  1885       if ( !target_map )
       
  1886         return ErrRaster_Invalid_Argument;
       
  1887 
       
  1888       /* nothing to do */
       
  1889       if ( !target_map->width || !target_map->rows )
       
  1890         return 0;
       
  1891 
       
  1892       if ( !target_map->buffer )
       
  1893         return ErrRaster_Invalid_Argument;
       
  1894     }
       
  1895 
       
  1896     /* this version does not support monochrome rendering */
       
  1897     if ( !( params->flags & FT_RASTER_FLAG_AA ) )
       
  1898       return ErrRaster_Invalid_Mode;
       
  1899 
       
  1900     /* compute clipping box */
       
  1901     if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )
       
  1902     {
       
  1903       /* compute clip box from target pixmap */
       
  1904       ras.clip_box.xMin = 0;
       
  1905       ras.clip_box.yMin = 0;
       
  1906       ras.clip_box.xMax = target_map->width;
       
  1907       ras.clip_box.yMax = target_map->rows;
       
  1908     }
       
  1909     else if ( params->flags & FT_RASTER_FLAG_CLIP )
       
  1910       ras.clip_box = params->clip_box;
       
  1911     else
       
  1912     {
       
  1913       ras.clip_box.xMin = -32768L;
       
  1914       ras.clip_box.yMin = -32768L;
       
  1915       ras.clip_box.xMax =  32767L;
       
  1916       ras.clip_box.yMax =  32767L;
       
  1917     }
       
  1918 
       
  1919     gray_init_cells( RAS_VAR_ raster->buffer, raster->buffer_size );
       
  1920 
       
  1921     ras.outline        = *outline;
       
  1922     ras.num_cells      = 0;
       
  1923     ras.invalid        = 1;
       
  1924     ras.band_size      = raster->band_size;
       
  1925     ras.num_gray_spans = 0;
       
  1926 
       
  1927     if ( params->flags & FT_RASTER_FLAG_DIRECT )
       
  1928     {
       
  1929       ras.render_span      = (FT_Raster_Span_Func)params->gray_spans;
       
  1930       ras.render_span_data = params->user;
       
  1931     }
       
  1932     else
       
  1933     {
       
  1934       ras.target           = *target_map;
       
  1935       ras.render_span      = (FT_Raster_Span_Func)gray_render_span;
       
  1936       ras.render_span_data = &ras;
       
  1937     }
       
  1938 
       
  1939     return gray_convert_glyph( RAS_VAR );
       
  1940   }
       
  1941 
       
  1942 
       
  1943   /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/
       
  1944   /****                         a static object.                   *****/
       
  1945 
       
  1946 #ifdef _STANDALONE_
       
  1947 
       
  1948   static int
       
  1949   gray_raster_new( void*       memory,
       
  1950                    FT_Raster*  araster )
       
  1951   {
       
  1952     static TRaster  the_raster;
       
  1953 
       
  1954     FT_UNUSED( memory );
       
  1955 
       
  1956 
       
  1957     *araster = (FT_Raster)&the_raster;
       
  1958     FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
       
  1959 
       
  1960     return 0;
       
  1961   }
       
  1962 
       
  1963 
       
  1964   static void
       
  1965   gray_raster_done( FT_Raster  raster )
       
  1966   {
       
  1967     /* nothing */
       
  1968     FT_UNUSED( raster );
       
  1969   }
       
  1970 
       
  1971 #else /* !_STANDALONE_ */
       
  1972 
       
  1973   static int
       
  1974   gray_raster_new( FT_Memory   memory,
       
  1975                    FT_Raster*  araster )
       
  1976   {
       
  1977     FT_Error  error;
       
  1978     PRaster   raster = NULL;
       
  1979 
       
  1980 
       
  1981     *araster = 0;
       
  1982     if ( !FT_ALLOC( raster, sizeof ( TRaster ) ) )
       
  1983     {
       
  1984       raster->memory = memory;
       
  1985       *araster = (FT_Raster)raster;
       
  1986     }
       
  1987 
       
  1988     return error;
       
  1989   }
       
  1990 
       
  1991 
       
  1992   static void
       
  1993   gray_raster_done( FT_Raster  raster )
       
  1994   {
       
  1995     FT_Memory  memory = (FT_Memory)((PRaster)raster)->memory;
       
  1996 
       
  1997 
       
  1998     FT_FREE( raster );
       
  1999   }
       
  2000 
       
  2001 #endif /* !_STANDALONE_ */
       
  2002 
       
  2003 
       
  2004   static void
       
  2005   gray_raster_reset( FT_Raster  raster,
       
  2006                      char*      pool_base,
       
  2007                      long       pool_size )
       
  2008   {
       
  2009     PRaster  rast = (PRaster)raster;
       
  2010 
       
  2011 
       
  2012     if ( raster )
       
  2013     {
       
  2014       if ( pool_base && pool_size >= (long)sizeof ( TWorker ) + 2048 )
       
  2015       {
       
  2016         PWorker  worker = (PWorker)pool_base;
       
  2017 
       
  2018 
       
  2019         rast->worker      = worker;
       
  2020         rast->buffer      = pool_base +
       
  2021                               ( ( sizeof ( TWorker ) + sizeof ( TCell ) - 1 ) &
       
  2022                                 ~( sizeof ( TCell ) - 1 ) );
       
  2023         rast->buffer_size = (long)( ( pool_base + pool_size ) -
       
  2024                                     (char*)rast->buffer ) &
       
  2025                                       ~( sizeof ( TCell ) - 1 );
       
  2026         rast->band_size   = (int)( rast->buffer_size /
       
  2027                                      ( sizeof ( TCell ) * 8 ) );
       
  2028       }
       
  2029       else
       
  2030       {
       
  2031         rast->buffer      = NULL;
       
  2032         rast->buffer_size = 0;
       
  2033         rast->worker      = NULL;
       
  2034       }
       
  2035     }
       
  2036   }
       
  2037 
       
  2038 
       
  2039   FT_DEFINE_RASTER_FUNCS(ft_grays_raster,
       
  2040     FT_GLYPH_FORMAT_OUTLINE,
       
  2041 
       
  2042     (FT_Raster_New_Func)     gray_raster_new,
       
  2043     (FT_Raster_Reset_Func)   gray_raster_reset,
       
  2044     (FT_Raster_Set_Mode_Func)0,
       
  2045     (FT_Raster_Render_Func)  gray_raster_render,
       
  2046     (FT_Raster_Done_Func)    gray_raster_done
       
  2047   )
       
  2048 
       
  2049 
       
  2050 /* END */
       
  2051 
       
  2052 
       
  2053 /* Local Variables: */
       
  2054 /* coding: utf-8    */
       
  2055 /* End:             */