shithub: freetype+ttf2subf

Download patch

ref: 4fce93e0cb5294786c482c8cbb9233070349686f
parent: 112be4c60984f57718c1da09ff93278df156a41d
author: David Turner <[email protected]>
date: Wed May 3 14:15:40 EDT 2000

still working on that damn rasterizer bug !! ;-)

git/fs: mount .git/fs: mount/attach disallowed
--- a/demos/Makefile
+++ b/demos/Makefile
@@ -190,6 +190,9 @@
   $(OBJ_)ftrast.$O: $(SRC_DIR_)ftrast.c
 	  $(COMPILE) $T$@ $<
 
+  $(OBJ_)ftrast2.$O: $(SRC_DIR_)ftrast2.c
+	  $(COMPILE) $T$@ $<
+
   $(OBJ_)fttry.$O: $(SRC_DIR_)fttry.c
 	  $(COMPILE) $T$@ $<
 
@@ -264,8 +267,8 @@
 	  $(LINK)
 
 
-  $(BIN_)ftview$E: $(OBJ_)ftview.$O $(FTLIB) $(GRAPH_LIB) $(COMMON_OBJ) $(OBJ_)ftrast.$O
-	  $(GRAPH_LINK)
+  $(BIN_)ftview$E: $(OBJ_)ftview.$O $(FTLIB) $(GRAPH_LIB) $(COMMON_OBJ) $(OBJ_)ftrast2.$O
+	  $(GRAPH_LINK) $(OBJ_)ftrast2.$O
 
   $(BIN_)ftstring$E: $(OBJ_)ftstring.$O $(FTLIB) $(GRAPH_LIB) $(COMMON_OBJ)
 	  $(GRAPH_LINK)
--- a/demos/src/ftrast.c
+++ b/demos/src/ftrast.c
@@ -23,6 +23,75 @@
 #include "ftrast.h"
 #include <ftcalc.h>      /* for FT_MulDiv only */
 
+  /*************************************************************************/
+  /*                                                                       */
+  /* A simple technical note on how the raster works:                      */
+  /*                                                                       */
+  /*   Converting an outline into a bitmap is achieved in several steps    */
+  /*   which are:                                                          */
+  /*                                                                       */
+  /*   1 - Decomposing the outline into successive `profiles'.  Each       */
+  /*       profile is simply an array of scanline intersections on a given */
+  /*       dimension.  A profile's main attributes are                     */
+  /*                                                                       */
+  /*       o its scanline position boundaries, i.e. `Ymin' and `Ymax'.     */
+  /*                                                                       */
+  /*       o an array of intersection coordinates for each scanline        */
+  /*         between `Ymin' and `Ymax'.                                    */
+  /*                                                                       */
+  /*       o a direction, indicating wether is was built going `up' or     */
+  /*         `down', as this is very important for filling rules.          */
+  /*                                                                       */
+  /*   2 - Sweeping the target map's scanlines in order to compute segment */
+  /*       `spans' which are then filled.  Additionaly, this pass performs */
+  /*       drop-out control.                                               */
+  /*                                                                       */
+  /*   The outline data is parsed during step 1 only.  The profiles are    */
+  /*   built from the bottom of the render pool, used as a stack.  The     */
+  /*   following graphics shows the profile list under construction:       */
+  /*                                                                       */
+  /*     ____________________________________________________________ _ _  */
+  /*    |         |                   |         |                 |        */
+  /*    | profile | coordinates for   | profile | coordinates for |-->     */
+  /*    |    1    |  profile 1        |    2    |  profile 2      |-->     */
+  /*    |_________|___________________|_________|_________________|__ _ _  */
+  /*                                                                       */
+  /*    ^                                                         ^        */
+  /*    |                                                         |        */
+  /*    start of render pool                                   top         */
+  /*                                                                       */
+  /*   The top of the profile stack is kept in the `top' variable.         */
+  /*                                                                       */
+  /*   As you can see, a profile record is pushed on top of the render     */
+  /*   pool, which is then followed by its coordinates/intersections.  If  */
+  /*   a change of direction is detected in the outline, a new profile is  */
+  /*   generated until the end of the outline.                             */
+  /*                                                                       */
+  /*   Note that when all profiles have been generated, the function       */
+  /*   Finalize_Profile_Table() is used to record, for each profile, its   */
+  /*   bottom-most scanline as well as the scanline above its upmost       */
+  /*   boundary.  These positions are called `y-turns' because they (sort  */
+  /*   of) correspond to local extrema.  They are stored in a sorted list  */
+  /*   built from the top of the render pool as a downwards stack:         */
+  /*                                                                       */
+  /*      _ _ _______________________________________                      */
+  /*                            |                    |                     */
+  /*                         <--| sorted list of     |                     */
+  /*                         <--|  extrema scanlines |                     */
+  /*      _ _ __________________|____________________|                     */
+  /*                                                                       */
+  /*                            ^                    ^                     */
+  /*                            |                    |                     */
+  /*                       maxBuff             sizeBuff = end of pool      */
+  /*                                                                       */
+  /*   This list is later used during the sweep phase in order to          */
+  /*   optimize performance (see technical note on the sweep below).       */
+  /*                                                                       */
+  /*   Of course, the raster detects whether the two stacks collide and    */
+  /*   handles the situation propertly.                                    */
+  /*                                                                       */
+  /*************************************************************************/
+
   /****************************************************************/
   /****************************************************************/
   /**                                                            **/
--- /dev/null
+++ b/demos/src/ftrast2.c
@@ -1,0 +1,3971 @@
+/*******************************************************************
+ *
+ *  ftraster.c                                                  2.0
+ *
+ *  The FreeType glyph rasterizer (body).
+ *
+ *  Copyright 1996-1998 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ *  This file is part of the FreeType project, and may only be used
+ *  modified and distributed under the terms of the FreeType project
+ *  license, LICENSE.TXT. By continuing to use, modify, or distribute
+ *  this file you indicate that you have read the license and
+ *  understand and accept it fully.
+ *
+ *  The "raster" component implements FreeType's scan-line converter,
+ *  the one used to generate bitmaps and pixmaps from vectorial outlines
+ *  descriptions.
+ *
+ *  It has been rewritten entirely for FreeType 2.0, in order to become
+ *  completely independent of the rest of the library. It should now be
+ *  possible to include it more easily in all kinds of libraries and
+ *  applications, which do not necessarily need the font engines and
+ *  API.
+ *
+ *  This version features :
+ *
+ *   - support for third-order bezier arcs
+ *
+ *   - improved performance of the 5-levels anti-aliasing algorithm
+ *
+ *   - 17-levels anti-aliasing for smoother curves, though the
+ *     difference isn't always noticeable, depending on your palette
+ *
+ *   - an API to decompose a raster outline into a path (i.e. into
+ *     a series of segments and arcs).
+ *
+ ******************************************************************/
+
+#include "ftraster.h"
+#include <freetype.h>  /* for FT_Outline_Decompose */
+
+#ifndef EXPORT_FUNC
+#define EXPORT_FUNC  /* nothing */
+#endif
+
+
+#ifndef _xxFREETYPE_
+
+/**************************************************************************/
+/*                                                                        */
+/* The following defines are used when the raster is compiled as a        */
+/* stand-alone object. Each of them is commented, and you're free to      */
+/* toggle them to suit your needs..                                       */
+/*                                                                        */
+
+/**************************************************************************/
+/*                                                                        */
+/* FT_RASTER_OPTION_ANTI_ALIAS                                            */
+/*                                                                        */
+/*   Define this configuration macro if you want to support anti-aliasing */
+/*                                                                        */
+#define FT_RASTER_OPTION_ANTI_ALIAS
+
+/**************************************************************************/
+/*                                                                        */
+/* FT_RASTER_OPTION_CONIC_BEZIERS                                         */
+/*                                                                        */
+/*   Define this configuration macro if your source outlines contain      */
+/*   second-order Bezier arcs. Typically, these are TrueType outlines..   */
+/*                                                                        */
+#define FT_RASTER_CONIC_BEZIERS
+
+/**************************************************************************/
+/*                                                                        */
+/* FT_RASTER_OPTION_CUBIC_BEZIERS                                         */
+/*                                                                        */
+/*   Define this configuration macro if your source outlines contain      */
+/*   third-order Bezier arcs. Typically, these are Type1 outlines..       */
+/*                                                                        */
+#define FT_RASTER_CUBIC_BEZIERS
+
+/**************************************************************************/
+/*                                                                        */
+/* FT_RASTER_ANTI_ALIAS_5                                                 */
+/*                                                                        */
+/*   Define this configuration macro if you want to enable the 5-grays    */
+/*   anti-aliasing mode.. Ignored if FT_RASTER_OPTION_ANTI_ALIAS isn't    */
+/*   defined..                                                            */
+/*                                                                        */
+#define FT_RASTER_ANTI_ALIAS_5
+
+/**************************************************************************/
+/*                                                                        */
+/* FT_RASTER_ANTI_ALIAS_17                                                */
+/*                                                                        */
+/*   Define this configuration macro if you want to enable the 17-grays   */
+/*   anti-aliasing mode.. Ignored if FT_RASTER_OPTION_ANTI_ALIAS isn't    */
+/*   defined..                                                            */
+/*                                                                        */
+#define FT_RASTER_ANTI_ALIAS_17
+
+/**************************************************************************/
+/*                                                                        */
+/* FT_RASTER_LITTLE_ENDIAN                                                */
+/* FT_RASTER_BIG_ENDIAN                                                   */
+/*                                                                        */
+/*   The default anti-alias routines are processor-independent, but slow. */
+/*   Define one of these macros to suit your own system, and enjoy        */
+/*   greatly improved rendering speed                                     */
+/*                                                                        */
+
+/* #define FT_RASTER_LITTLE_ENDIAN */
+/* #define FT_RASTER_BIG_ENDIAN    */
+
+#else  /* _FREETYPE_ */
+
+/**************************************************************************/
+/*                                                                        */
+/* The following defines are used when the raster is compiled within      */
+/* the FreeType base layer. Don't change these unless you really know     */
+/* what you're doing..                                                    */
+/*                                                                        */
+
+#ifdef FT_CONFIG_OPTION_ANTI_ALIAS
+#define FT_RASTER_OPTION_ANTI_ALIAS
+#endif
+
+#define FT_RASTER_CONIC_BEZIERS
+#define FT_RASTER_CUBIC_BEZIERS
+
+#define FT_RASTER_ANTI_ALIAS_5
+#undef  FT_RASTER_ANTI_ALIAS_17
+
+#ifdef FT_CONFIG_OPTION_LITTLE_ENDIAN
+#define FT_RASTER_LITTLE_ENDIAN
+#endif
+
+#ifdef FT_CONFIG_OPTION_BIG_ENDIAN
+#define FT_RASTER_BIG_ENDIAN
+#endif
+
+#endif /* _FREETYPE_ */
+
+
+/* FT_RASTER_ANY_ENDIAN indicates that no endianess was defined */
+/* through one of the configuration macros                      */
+/*                                                              */
+#if !defined(FT_RASTER_LITTLE_ENDIAN) && !defined(FT_RASTER_BIG_ENDIAN)
+#define FT_RASTER_ANY_ENDIAN
+#endif
+
+
+/* The rasterizer is a very general purpose component, please leave */
+/* the following redefinitions there (you never know your target    */
+/* environment).                                                    */
+
+#ifndef TRUE
+#define TRUE   1
+#endif
+
+#ifndef FALSE
+#define FALSE  0
+#endif
+
+#ifndef NULL
+#define NULL  (void*)0
+#endif
+
+
+#undef  FAILURE
+#define FAILURE  TRUE
+
+#undef  SUCCESS
+#define SUCCESS  FALSE
+
+
+/* Please don't touch the following macros. Their importance is historical */
+/* to FreeType, but they have some nice effects, like getting rid of all   */
+/* '->' symbols when accessing the raster object.. (replacing them with    */
+/* a simple '.' )                                                          */
+
+/* used in function signatures to define the _first_ argument */
+#define  RAS_ARGS  FT_Raster  raster,
+#define  RAS_ARG   FT_Raster  raster
+
+/* used to call a function within this component, first parameter */
+#define  RAS_VARS  raster,
+#define  RAS_VAR   raster
+
+/* used to access the current raster object, with a '.' instead of a '->' */
+#define  ras       (*raster)
+
+
+/* For anti-aliasing modes, we use a 2 or 4 lines intermediate bitmap which */
+/* is filtered repeatedly to render each pixmap row. The following macro    */
+/* defines this buffer's size in bytes (which is part of raster objects)    */
+#define ANTI_ALIAS_BUFFER_SIZE   2048
+
+
+/* Error codes returned by the scan-line converter/raster */
+
+#define ErrRaster_Ok                      0
+#define ErrRaster_Uninitialised_Object    1
+#define ErrRaster_Overflow                2
+#define ErrRaster_Negative_Height         3
+#define ErrRaster_Invalid_Outline         4
+#define ErrRaster_Invalid_Map             5
+#define ErrRaster_AntiAlias_Unsupported   6
+#define ErrRaster_Invalid_Pool            7
+#define ErrRaster_Unimplemented           8
+#define ErrRaster_Bad_Palette_Count       9
+
+
+#define SET_High_Precision(p)  Set_High_Precision( RAS_VARS p )
+
+/* Fast MulDiv, as 'b' is always < 64, don't use intermediate precision */
+#define FMulDiv( a, b, c )  ( (a) * (b) / (c) )
+
+
+/* Define DEBUG_RASTER if you want to generate a debug version of the  */
+/* rasterizer.  This will progressively draw the glyphs while all the  */
+/* computation are done directly on the graphics screen (the glyphs    */
+/* will be inverted).                                                  */
+
+/* Note that DEBUG_RASTER should only be used for debugging with b/w   */
+/* rendering, not with gray levels.                                    */
+
+/* The definition of DEBUG_RASTER should appear in the file            */
+/* "ftconfig.h".                                                       */
+
+#ifdef DEBUG_RASTER
+  extern char*  vio;  /* A pointer to VRAM or display buffer */
+#endif
+
+
+#define MaxBezier  32   /* The maximum number of stacked Bezier curves. */
+                        /* Setting this constant to more than 32 is a   */
+                        /* pure waste of space.                         */
+
+#define Pixel_Bits  6   /* fractional bits of *input* coordinates   */
+                        /* We always use 26.6, but hackers are free */
+                        /* to experiment with different values      */
+
+
+  /* The type of the pixel coordinates used within the render pool during   */
+  /* scan-line conversion. We use longs to store either 26.6 or 22.10 fixed */
+  /* float values, depending on the "precision" we want to use (resp. low   */
+  /* or high). These are ideals in order to subdivise bezier arcs in halves */
+  /* though simple additions and shifts.                                    */
+
+  typedef  long   TPos, *PPos;
+
+
+  /* The type of a scanline position/coordinate within a map */
+  typedef  int    TScan, *PScan;
+
+
+
+
+  /* boolean type */
+  typedef  char   TBool;
+  
+  /* unsigned char type and array */
+  typedef  unsigned char   TByte, *PByte;
+
+  /* unsigned short type and array */
+  typedef  unsigned short  UShort, *PUShort;
+
+  /* flow */
+  enum _TFlow
+  {
+    FT_Flow_Error = 0,
+    FT_Flow_Down  = -1,
+    FT_Flow_Up    = 1
+  };
+
+
+  /* states/directions of each line, arc and profile */
+  enum  _TDirection
+  {
+    Unknown,
+    Ascending,
+    Descending,
+    Flat
+  };
+  typedef enum _TDirection  TDirection;
+
+
+  struct  _TProfile;
+  typedef struct _TProfile  TProfile;
+  typedef TProfile*         PProfile;
+
+  struct  _TProfile
+  {                                                                     
+    TPos      X;           /* current coordinate during sweep          */
+    PProfile  link;        /* link to next profile - various purpose   */
+    PPos      offset;      /* start of profile's data in render pool   */
+    int       flow;        /* Profile orientation: Asc/Descending      */
+    TScan     height;      /* profile's height in scanlines            */
+    TScan     start;       /* profile's starting scanline              */
+
+    TScan     countL;      /* number of lines to step before this      */
+                           /* profile becomes drawable                 */
+
+    PProfile  next;        /* next profile in same contour, used       */
+                           /* during drop-out control                  */
+  };
+
+  typedef PProfile   TProfileList;
+  typedef PProfile*  PProfileList;
+
+
+  /* Simple record used to implement a stack of bands, required */
+  /* by the sub-banding mechanism                               */
+  /*                                                            */
+  struct  _TBand
+  {
+    TScan  y_min;   /* band's minimum */
+    TScan  y_max;   /* band's maximum */
+  };
+
+  typedef struct _TBand  TBand;
+
+
+/* The size in _TPos_ of a profile record in the render pool */
+#define AlignProfileSize  ((sizeof(TProfile)+sizeof(TPos)-1) / sizeof(TPos))
+
+
+  /* prototypes used for sweep function dispatch */
+  typedef void  Function_Sweep_Init( RAS_ARGS int*  min, int*  max );
+
+  typedef void  Function_Sweep_Span( RAS_ARGS  TScan  y,
+                                               TPos   x1,
+                                               TPos   x2 );
+
+  typedef int   Function_Test_Pixel( RAS_ARGS TScan  y,
+                                              int    x );
+                                              
+  typedef void  Function_Set_Pixel( RAS_ARGS  TScan  y,
+                                              int    x,
+                                              int    color );
+
+  typedef void  Function_Sweep_Step( RAS_ARG );
+
+
+/* compute lowest integer coordinate below a given x */
+#define FLOOR( x )    ( (x) & ras.precision_mask )
+
+/* compute highest integer coordinate above a given x */
+#define CEILING( x )  ( ((x) + ras.precision - 1) & ras.precision_mask )
+
+/* get integer coordinate of a given 26.6 or 22.10 'x' coordinate - no round */
+#define TRUNC( x )    ( (signed long)(x) >> ras.precision_bits )
+
+/* get the fractional part of a given coordinate */
+#define FRAC( x )     ( (x) & (ras.precision - 1) )
+
+/* scale an 'input coordinate' (as found in FT_Outline structures) into */
+/* a 'work coordinate', which depends on current resolution and render  */
+/* mode..                                                               */
+#define SCALED( x )   ( ((x) << ras.scale_shift) - ras.precision_half )
+
+
+/* DEBUG_PSET is used to plot a single pixel in VRam during debug mode */
+#ifdef DEBUG_RASTER
+#define DEBUG_PSET  Pset()
+#else
+#define DEBUG_PSET  
+#endif
+
+  struct  _TPoint
+  {
+    TPos  x, y;
+  };
+  typedef struct _TPoint  TPoint;
+
+
+  /* Note that I have moved the location of some fields in the */
+  /* structure to ensure that the most used variables are used */
+  /* at the top.  Thus, their offset can be coded with less    */
+  /* opcodes, and it results in a smaller executable.          */
+
+  struct  FT_RasterRec_
+  {
+    PPos      cursor;              /* Current cursor in render pool  */
+
+    PPos      pool;                /* The render pool base address   */
+    PPos      pool_size;           /* The render pool's size         */
+    PPos      pool_limit;          /* Limit of profiles zone in pool */
+
+    int       bit_width;            /* target bitmap width  */
+    PByte     bit_buffer;           /* target bitmap buffer */
+    PByte     pix_buffer;           /* target pixmap buffer */
+
+    TPoint    last;
+    long      minY, maxY;
+
+    int       error;
+
+    int       precision_bits;       /* precision related variables */
+    int       precision;
+    int       precision_half;
+    long      precision_mask;
+    int       precision_shift;
+    int       precision_step;
+    int       precision_jitter;
+
+    FT_Outline*  outline;
+    
+    int       n_points;             /* number of points in current glyph   */
+    int       n_contours;           /* number of contours in current glyph */
+    int       n_turns;              /* number of Y-turns in outline        */
+
+    TPoint*   arc;                  /* current Bezier arc pointer */
+
+    int       num_profs;            /* current number of profiles */
+
+    TBool      fresh;                /* signals a fresh new profile which */ 
+                                    /* 'start' field must be completed   */
+    TBool      joint;                /* signals that the last arc ended   */
+                                    /* exactly on a scanline.  Allows    */
+                                    /* removal of doublets               */
+    PProfile  cur_prof;             /* current profile                   */
+    PProfile  start_prof;           /* head of linked list of profiles   */
+    PProfile  first_prof;           /* contour's first profile in case   */
+                                    /* of impact                         */
+    TDirection state;               /* rendering state */
+   
+    FT_Bitmap  target;              /* description of target bit/pixmap */
+
+    int       trace_bit;            /* current offset in target bitmap */
+    int       trace_pix;            /* current offset in target pixmap */
+
+    int       trace_incr;           /* sweep's increment in target bitmap */
+
+    int       gray_min_x;           /* current min x during gray rendering */
+    int       gray_max_x;           /* current max x during gray rendering */
+
+    /* dispatch variables */
+
+    Function_Sweep_Init*  Proc_Sweep_Init;
+    Function_Sweep_Span*  Proc_Sweep_Span;
+    Function_Sweep_Step*  Proc_Sweep_Step;
+    Function_Test_Pixel*  Proc_Test_Pixel;
+    Function_Set_Pixel*   Proc_Set_Pixel;
+
+    int       scale_shift;      /* == 0  for bitmaps           */
+                                /* == 1  for 5-levels pixmaps  */
+                                /* == 2  for 17-levels pixmaps */
+
+    TByte      dropout_mode;     /* current drop_out control method */
+
+    TBool      second_pass;      /* indicates wether a horizontal pass      */
+                                /* should be performed to control drop-out */
+                                /* accurately when calling Render_Glyph.   */
+                                /* Note that there is no horizontal pass   */
+                                /* during gray rendering.                  */
+
+    TBool      flipped;          /* this flag is set during the rendering to */
+                                /* indicate the second pass..               */
+                                
+    TBand     band_stack[16];       /* band stack used for sub-banding */
+    int       band_top;             /* band stack top                  */
+
+    TPoint    arcs[ 2*MaxBezier+1 ];      /* The Bezier stack */
+
+    void*     memory;
+   
+#if defined(FT_RASTER_OPTION_ANTI_ALIAS)
+
+    long      grays[20];        /* Palette of gray levels used for render */
+
+    int       gray_width;       /* length in bytes of the onochrome        */
+                                /* intermediate scanline of gray_lines.    */
+                                /* Each gray pixel takes 2 or 4 bits long  */
+
+                        /* The gray_lines must hold 2 lines, thus with size */
+                        /* in bytes of at least 'gray_width*2'              */
+
+    int       grays_count;      /* number of entries in the palette */
+
+    char      gray_lines[ANTI_ALIAS_BUFFER_SIZE];       
+                                /* Intermediate table used to render the   */
+                                /* graylevels pixmaps.                     */
+                                /* gray_lines is a buffer holding 2 or 4   */
+                                /* monochrome scanlines                    */
+
+    int       count_table[256];     /* Look-up table used to quickly count */
+                                    /* set bits in a gray 2x2 cell         */
+#endif
+  };
+
+
+
+#ifdef DEBUG_RASTER
+
+  /************************************************/
+  /*                                              */
+  /* Pset:                                        */
+  /*                                              */
+  /*  Used for debugging only.  Plots a point     */
+  /*  in VRAM during rendering (not afterwards).  */
+  /*                                              */
+  /* NOTE:  This procedure relies on the value    */
+  /*        of cProfile->start, which may not     */
+  /*        be set when Pset is called sometimes. */
+  /*        This will usually result in a dot     */
+  /*        plotted on the first screen scanline  */
+  /*        (far away its original position).     */
+  /*                                              */
+  /*        This "bug" reflects nothing wrong     */
+  /*        in the current implementation, and    */
+  /*        the bitmap is rendered correctly,     */
+  /*        so don't panic if you see 'flying'    */
+  /*        dots in debugging mode.               */
+  /*                                              */
+  /*  - David                                     */
+  /*                                              */
+  /************************************************/
+
+  static void  Pset( RAS_ARG )
+  {
+    long  o;
+    long  x;
+
+    x = ras.cursor[-1];
+
+    switch ( ras.cur_prof->flow )
+    {
+    case FT_Flow_Up:
+      o = Vio_ScanLineWidth *
+         ( ras.cursor - ras.cur_prof->offset + ras.cur_prof->start ) +
+         ( x / (ras.precision*8) );
+      break;
+
+    case FT_Flow_Down:
+      o = Vio_ScanLineWidth *
+         ( ras.cur_prof->start - ras.cursor + ras.cur_prof->offset ) +
+         ( x / (ras.precision*8) );
+      break;
+    }
+
+    if ( o > 0 )
+      Vio[o] |= (unsigned)0x80 >> ( (x/ras.precision) & 7 );
+  }
+
+
+  static void  Clear_Band( RAS_ARGS Int  y1, Int  y2 )
+  {
+    MEM_Set( Vio + y1*Vio_ScanLineWidth, (y2-y1+1)*Vio_ScanLineWidth, 0 );
+  }
+
+#endif /* DEBUG_RASTER */
+
+
+/************************************************************************/
+/*                                                                      */
+/* <Function>   Set_High_Precision                                      */
+/*                                                                      */
+/* <Description> Sets precision variables according to param flag.      */
+/*                                                                      */
+/* <Input>       High ::  set to True for high precision (typically for */
+/*                       ppem < 18), false otherwise.                   */
+/*                                                                      */
+/************************************************************************/
+
+  static 
+  void  Set_High_Precision( RAS_ARGS int  High )
+  {
+    if ( High )
+    {
+      ras.precision_bits   = 10;
+      ras.precision_step   = 128;
+      ras.precision_jitter = 24;
+    }
+    else
+    {
+      ras.precision_bits   = 6;
+      ras.precision_step   = 32;
+      ras.precision_jitter = 2;
+    }
+
+    ras.precision       = 1 << ras.precision_bits;
+    ras.precision_half  = ras.precision / 2;
+    ras.precision_shift = ras.precision_bits - Pixel_Bits;
+    ras.precision_mask  = -ras.precision;
+  }
+
+
+/**************************************************************************/
+/*                                                                        */
+/* <Function>   New_Profile                                               */
+/*                                                                        */
+/* <Description> Creates a new Profile in the render pool.                */
+/*                                                                        */
+/* <Input>                                                                */
+/*    aState  ::  state/orientation of the new Profile                    */
+/*                                                                        */
+/* <Return>                                                               */
+/*    SUCCESS or FAILURE                                                  */
+/*                                                                        */
+/**************************************************************************/
+
+  static 
+  TBool  New_Profile( RAS_ARGS TDirection  direction )
+  {
+    if ( ras.start_prof == NULL )
+    {
+      ras.cur_prof   = (PProfile)ras.cursor;
+      ras.start_prof = ras.cur_prof;
+      ras.cursor    += AlignProfileSize;
+    }
+
+    if ( ras.cursor >= ras.pool_limit )
+    {
+      ras.error = ErrRaster_Overflow;
+      return FAILURE;
+    }
+
+    switch ( direction )
+    {
+    case Ascending:
+      ras.cur_prof->flow = FT_Flow_Up;
+      break;
+
+    case Descending:
+      ras.cur_prof->flow = FT_Flow_Down;
+      break;
+
+    default:
+      ras.error = ErrRaster_Invalid_Map;
+      return FAILURE;
+    }
+
+    {
+      PProfile  cur = ras.cur_prof;
+      
+      cur->start  = 0;
+      cur->height = 0;
+      cur->offset = ras.cursor;
+      cur->link   = (PProfile)0;
+      cur->next   = (PProfile)0;
+    }
+
+    if ( ras.first_prof == NULL )
+      ras.first_prof = ras.cur_prof;
+
+    ras.state  = direction;
+    ras.fresh  = TRUE;
+    ras.joint  = FALSE;
+
+    return SUCCESS;
+  }
+
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function> End_Profile                                                   */
+/*                                                                          */
+/* <Description> Finalizes the current Profile.                             */
+/*                                                                          */
+/* <Return>                                                                 */
+/*    SUCCESS or FAILURE                                                    */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  TBool  End_Profile( RAS_ARG )
+  {
+    int  h;
+
+    h = ras.cursor - ras.cur_prof->offset;
+
+    if ( h < 0 )
+    {
+      ras.error = ErrRaster_Negative_Height;
+      return FAILURE;
+    }
+
+    if ( h > 0 )
+    {
+      PProfile  old, new;
+      
+      old          = ras.cur_prof;
+      old->height  = h;
+      ras.cur_prof = new = (PProfile)ras.cursor;
+
+      ras.cursor  += AlignProfileSize;
+
+      new->height  = 0;
+      new->offset  = ras.cursor;
+      old->next    = new;
+
+      ras.num_profs++;
+    }
+
+    if ( ras.cursor >= ras.pool_limit )
+    {
+      ras.error = ErrRaster_Overflow;
+      return FAILURE;
+    }
+
+    ras.joint = FALSE;
+
+    return SUCCESS;
+  }
+
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Insert_Y_Turn                                               */
+/*                                                                          */
+/* <Description>                                                            */
+/*     Insert a salient into the sorted list placed on top                  */
+/*     of the render pool                                                   */
+/*                                                                          */
+/* <Input>                                                                  */
+/*     y   ::  new scanline position                                        */
+/*                                                                          */
+/****************************************************************************/
+
+  static  
+  TBool  Insert_Y_Turn( RAS_ARGS  TScan  y )
+  {
+    PPos   y_turns;
+    TScan  y2;
+    int    n;
+
+    n       = ras.n_turns-1;
+    y_turns = ras.pool_size - ras.n_turns;
+
+    /* look for first y value that is <= */
+    while ( n >= 0 && y < y_turns[n] )
+      n--;
+
+    /* if it is <, simply insert it, ignore if == */
+    if ( n >= 0 && y > y_turns[n] )
+      while (n >= 0)
+      {
+        y2 = y_turns[n];
+        y_turns[n] = y;
+        y = y2;
+        n--;
+      }
+
+    if (n < 0)
+    {
+      ras.pool_limit--;
+      ras.n_turns++;
+      ras.pool_size[-ras.n_turns ] = y;
+
+      if ( ras.pool_limit <= ras.cursor )
+      {
+        ras.error = ErrRaster_Overflow;
+        return FAILURE;
+      }
+    }
+    return SUCCESS;
+  }
+
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Finalize_Profile_Table                                      */
+/*                                                                          */
+/* <Description>                                                            */
+/*     Adjusts all links in the Profiles list.                              */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  TBool  Finalize_Profile_Table( RAS_ARG )
+  {
+    int       n, bottom, top;
+    PProfile  p;
+
+
+    n = ras.num_profs;
+
+    if ( n > 1 )
+    {
+      p = ras.start_prof;
+      while ( n > 0 )
+      {
+        if (n > 1)
+          p->link = (PProfile)( p->offset + p->height );
+        else
+          p->link = NULL;
+
+        switch (p->flow)
+        {
+          case FT_Flow_Down:
+            bottom     = p->start - p->height+1;
+            top        = p->start;
+            p->start   = bottom;
+            p->offset += p->height-1;
+            break;
+
+          case FT_Flow_Up:
+          default:
+            bottom = p->start;
+            top    = p->start + p->height-1;
+        }
+
+        if ( Insert_Y_Turn( RAS_VARS  bottom ) ||
+             Insert_Y_Turn( RAS_VARS  top+1 )  )
+          return FAILURE;
+
+        p = p->link;
+        n--;
+      }
+    }
+    else
+      ras.start_prof = NULL;
+      
+    return SUCCESS;
+  }
+
+
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Line_Up                                                     */
+/*                                                                          */
+/* <Description>                                                            */
+/*     Computes the scan-line intersections of an ascending line segment    */
+/*     and stores them in the render pool.                                  */
+/*                                                                          */
+/* <Input>                                                                  */
+/*     x1  :: start x coordinate                                            */
+/*     y1  :: start y coordinates                                           */
+/*     x2  :: end x coordinate                                              */
+/*     y2  :: end y coordinate                                              */
+/*   miny  :: minimum vertical grid coordinate                              */
+/*   maxy  :: maximum vertical grid coordinate                              */
+/*                                                                          */
+/* <Return>                                                                 */
+/*     SUCCESS or FAILURE.                                                  */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  TBool  Line_Up( RAS_ARGS TPos  x1,   TPos  y1, 
+                          TPos  x2,   TPos  y2,
+                          TPos  miny, TPos  maxy )
+  {
+    TPos   Dx, Dy;
+    int    e1, e2, f1, f2, size;
+    TPos   Ix, Rx, Ax;
+
+    PPos  top;
+
+
+    Dx = x2 - x1;
+    Dy = y2 - y1;
+
+    if ( Dy <= 0 || y2 < miny || y1 > maxy )
+      return SUCCESS;
+
+    if ( y1 < miny )
+    {
+      x1 += FMulDiv( Dx, miny - y1, Dy );
+      e1  = TRUNC( miny );
+      f1  = 0;
+    }
+    else
+    {
+      e1 = TRUNC( y1 );
+      f1 = FRAC( y1 );
+    }
+
+    if ( y2 > maxy )
+    {
+      /* x2 += FMulDiv( Dx, maxy-y2, Dy );  UNNECESSARY */
+      e2  = TRUNC( maxy );
+      f2  = 0;
+    }
+    else
+    {
+      e2 = TRUNC( y2 );
+      f2 = FRAC( y2 );
+    }
+
+    if ( f1 > 0 )
+    {
+      if ( e1 == e2 ) return SUCCESS;
+      else
+      {
+        x1 += FMulDiv( Dx, ras.precision - f1, Dy );
+        e1 += 1;
+      }
+    }
+    else
+      if ( ras.joint )
+      {
+        ras.cursor--;
+        ras.joint = FALSE;
+      }
+
+    ras.joint = ( f2 == 0 );
+
+    if ( ras.fresh )
+    {
+      ras.cur_prof->start = e1;
+      ras.fresh           = FALSE;
+    }
+
+    size = e2 - e1 + 1;
+    if ( ras.cursor + size >= ras.pool_limit )
+    {
+      ras.error = ErrRaster_Overflow;
+      return FAILURE;
+    }
+
+    if ( Dx > 0 )
+    {
+      Ix = (ras.precision*Dx) / Dy;
+      Rx = (ras.precision*Dx) % Dy;
+      Dx = 1;
+    }
+    else
+    {
+      Ix = -( (ras.precision*-Dx) / Dy );
+      Rx =    (ras.precision*-Dx) % Dy;
+      Dx = -1;
+    }
+
+    Ax  = -Dy;
+    top = ras.cursor;
+
+    while ( size > 0 ) 
+    {
+      *top++ = x1;
+
+      DEBUG_PSET;
+
+      x1 += Ix;
+      Ax += Rx;
+      if ( Ax >= 0 )
+      {
+        Ax -= Dy;
+        x1 += Dx;
+      }
+      size--;
+    }
+
+    ras.cursor = top;
+    return SUCCESS;
+  }
+
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Line_Down                                                   */
+/*                                                                          */
+/* <Description>                                                            */
+/*     Computes the scan-line intersections of a descending line segment    */
+/*     and stores them in the render pool.                                  */
+/*                                                                          */
+/* <Input>                                                                  */
+/*     x1  :: start x coordinate                                            */
+/*     y1  :: start y coordinates                                           */
+/*     x2  :: end x coordinate                                              */
+/*     y2  :: end y coordinate                                              */
+/*   miny  :: minimum vertical grid coordinate                              */
+/*   maxy  :: maximum vertical grid coordinate                              */
+/*                                                                          */
+/* <Return>                                                                 */
+/*     SUCCESS or FAILURE.                                                  */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  TBool  Line_Down( RAS_ARGS TPos  x1,   TPos  y1, 
+                            TPos  x2,   TPos  y2,
+                            TPos  miny, TPos  maxy )
+  {
+    TBool result, fresh;
+
+    fresh  = ras.fresh;
+    result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
+
+    if ( fresh && !ras.fresh ) 
+      ras.cur_prof->start = -ras.cur_prof->start;
+
+    return result;
+  }
+
+
+
+
+#ifdef FT_RASTER_CONIC_BEZIERS
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Split_Conic                                                 */
+/*                                                                          */
+/* <Description>                                                            */
+/*     Subdivides one second-order Bezier arc into two joint sub-arcs in    */
+/*     the Bezier stack.                                                    */
+/*                                                                          */
+/* <Note>                                                                   */
+/*     This routine is the "beef" of the component. It is one of _the_      */
+/*     inner loops that should be optimized like hell to get the best       */
+/*     performance..                                                        */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  void  Split_Conic( TPoint*  base )
+  {
+    TPos   a, b;
+
+    base[4].x = base[2].x;
+    b = base[1].x;
+    a = base[3].x = ( base[2].x + b )/2;
+    b = base[1].x = ( base[0].x + b )/2;
+    base[2].x = (a+b)/2;
+
+    base[4].y = base[2].y;
+    b = base[1].y;
+    a = base[3].y = ( base[2].y + b )/2;
+    b = base[1].y = ( base[0].y + b )/2;
+    base[2].y = (a+b)/2;
+  }
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Push_Conic                                                  */
+/*                                                                          */
+/* <Description> Clears the Bezier stack and pushes a new arc on top of it  */
+/*                                                                          */
+/* <Input>                                                                  */
+/*    p2  :: pointer to second (control) point                              */
+/*    p3  :: pointer to third  (end) point                                  */
+/*                                                                          */
+/* <Note>                                                                   */
+/*     The first point is taken as "raster->last", so it doesn't appear     */
+/*     in the signature..                                                   */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  void  Push_Conic( RAS_ARGS FT_Vector*  p2,
+                             FT_Vector*  p3 )
+  {
+#undef  STORE
+#define STORE( _arc, point )                      \
+            {                                     \
+              TPos  x = SCALED(point->x);         \
+              TPos  y = SCALED(point->y);         \
+              if (ras.flipped)                    \
+              {                                   \
+                _arc.x = y;                       \
+                _arc.y = x;                       \
+              }                                   \
+              else                                \
+              {                                   \
+                _arc.x = x;                       \
+                _arc.y = y;                       \
+              }                                   \
+            }
+
+    TPoint*  arc;
+    ras.arc = arc = ras.arcs;
+
+    arc[2] = ras.last;
+    STORE( arc[1], p2 );
+    STORE( arc[0], p3 );
+#undef  STORE
+  }
+
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Conic_Up                                                    */
+/*                                                                          */
+/* <Description>                                                            */
+/*     Computes the scan-line intersections of an ascending second-order    */
+/*     Bezier arc and stores them in the render pool. The arc is taken      */
+/*     from the top of the stack..                                          */
+/*                                                                          */
+/* <Input>                                                                  */
+/*     miny     :: minimum vertical grid coordinate                         */
+/*     maxy     :: maximum vertical grid coordinate                         */
+/*                                                                          */
+/* <Return>                                                                 */
+/*     SUCCESS or FAILURE                                                   */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  TBool  Conic_Up( RAS_ARGS TPos  miny, TPos  maxy )
+  {
+    TPos  y1, y2, e, e2, e0;
+    int   f1;
+
+    TPoint*  arc;
+    TPoint*  start_arc;
+
+    PPos top;
+
+
+    arc = ras.arc;
+    y1  = arc[2].y;
+    y2  = arc[0].y;
+    top = ras.cursor; 
+
+    if ( y2 < miny || y1 > maxy )
+      goto Fin;
+    
+    e2 = FLOOR( y2 );
+
+    if ( e2 > maxy )
+      e2 = maxy;
+
+    e0 = miny;
+
+    if ( y1 < miny )
+      e = miny;
+    else
+    {
+      e  = CEILING( y1 );
+      f1 = FRAC( y1 );
+      e0 = e;
+
+      if ( f1 == 0 )
+      {
+        if ( ras.joint )
+        {
+          top--;
+          ras.joint = FALSE;
+        }
+
+        *top++ = arc[2].x;
+
+        DEBUG_PSET;
+
+        e += ras.precision;
+      }
+    }
+
+    if ( ras.fresh )
+    {
+      ras.cur_prof->start = TRUNC( e0 );
+      ras.fresh = FALSE;
+    }
+
+    if ( e2 < e )
+      goto Fin;
+
+    if ( ( top+TRUNC(e2-e)+1 ) >= ras.pool_limit )
+    {
+      ras.cursor = top;
+      ras.error  = ErrRaster_Overflow;
+      return FAILURE;
+    }
+
+    start_arc = arc;
+
+    while ( arc >= start_arc && e <= e2 )
+    {
+      ras.joint = FALSE;
+
+      y2 = arc[0].y;
+
+      if ( y2 > e )
+      {
+        y1 = arc[2].y;
+        if ( y2 - y1 >= ras.precision_step )
+        {
+          Split_Conic( arc );
+          arc += 2;
+        }
+        else
+        {
+          *top++ = arc[2].x + 
+                   FMulDiv( arc[0].x-arc[2].x, 
+                            e  - y1, 
+                            y2 - y1 );
+          DEBUG_PSET;
+            
+          arc -= 2;
+          e   += ras.precision;
+        }
+      }
+      else
+      {
+        if ( y2 == e )
+        {
+          ras.joint  = TRUE;
+          *top++     = arc[0].x;
+        
+          DEBUG_PSET;
+        
+          e += ras.precision;
+        }
+        arc -= 2;
+      }
+    }
+
+  Fin:
+    ras.cursor = top;
+    ras.arc   -= 2;
+    return SUCCESS;
+  }
+
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Conic_Down                                                  */
+/*                                                                          */
+/* <Description>                                                            */
+/*     Computes the scan-line intersections of a descending second-order    */
+/*     Bezier arc and stores them in the render pool. The arc is taken      */
+/*     from the top of the stack..                                          */
+/*                                                                          */
+/* <Input>                                                                  */
+/*     miny     :: minimum vertical grid coordinate                         */
+/*     maxy     :: maximum vertical grid coordinate                         */
+/*                                                                          */
+/* <Return>                                                                 */
+/*     SUCCESS or FAILURE                                                   */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  TBool  Conic_Down( RAS_ARGS TPos  miny, TPos  maxy )
+  {
+    TPoint*  arc = ras.arc;
+    TBool     result, fresh;
+
+
+    arc[0].y = -arc[0].y;
+    arc[1].y = -arc[1].y; 
+    arc[2].y = -arc[2].y;
+
+    fresh = ras.fresh;
+
+    result = Conic_Up( RAS_VARS -maxy, -miny );
+
+    if ( fresh && !ras.fresh )
+      ras.cur_prof->start = -ras.cur_prof->start;
+
+    arc[0].y = -arc[0].y;
+    return result;
+  }
+
+#endif /* FT_RASTER_CONIC_BEZIERS */
+
+
+
+#ifdef FT_RASTER_CUBIC_BEZIERS
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Split_Cubic                                                 */
+/*                                                                          */
+/* <Description>                                                            */
+/*     Subdivides a third-order Bezier arc into two joint sub-arcs in the   */
+/*     Bezier stack.                                                        */
+/*                                                                          */
+/* <Note>                                                                   */
+/*     This routine is the "beef" of the component. It is one of _the_      */
+/*     inner loops that should be optimized like hell to get the best       */
+/*     performance..                                                        */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  void  Split_Cubic( TPoint*  base )
+  {
+    TPos   a, b, c, d;
+
+    base[6].x = base[3].x;
+    c = base[1].x;
+    d = base[2].x;
+    base[1].x = a = ( base[0].x + c )/2;
+    base[5].x = b = ( base[3].x + d )/2;
+    c = (c+d)/2;
+    base[2].x = a = (a+c)/2;
+    base[4].x = b = (b+c)/2;
+    base[3].x = (a+b)/2;
+    
+    base[6].y = base[3].y;
+    c = base[1].y;
+    d = base[2].y;
+    base[1].y = a = ( base[0].y + c )/2;
+    base[5].y = b = ( base[3].y + d )/2;
+    c = (c+d)/2;
+    base[2].y = a = (a+c)/2;
+    base[4].y = b = (b+c)/2;
+    base[3].y = (a+b)/2;
+  }
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Push_Cubic                                                  */
+/*                                                                          */
+/* <Description>                                                            */
+/*     Clears the bezier stack and pushes a new third-order bezier arc      */
+/*     on top of it                                                         */
+/*                                                                          */
+/* <Input>                                                                  */
+/*     p2  :: pointer to second point (control)                             */
+/*     p3  :: pointer to third point  (control)                             */
+/*     p4  :: pointer to last point  (end)                                  */
+/*                                                                          */
+/* <Note>                                                                   */
+/*     The first point is taken as "raster->last", so it doesn't appear     */
+/*     in the signature..                                                   */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  void  Push_Cubic( RAS_ARGS FT_Vector*  p2,
+                             FT_Vector*  p3,
+                             FT_Vector*  p4 )
+  {
+#undef  STORE
+#define STORE( _arc, point )                      \
+            {                                     \
+              TPos  x = SCALED(point->x);         \
+              TPos  y = SCALED(point->y);         \
+              if (ras.flipped)                    \
+              {                                   \
+                _arc.x = y;                       \
+                _arc.y = x;                       \
+              }                                   \
+              else                                \
+              {                                   \
+                _arc.x = x;                       \
+                _arc.y = y;                       \
+              }                                   \
+            }
+
+    TPoint*  arc;
+    ras.arc = arc = ras.arcs;
+
+    arc[3] = ras.last;
+    STORE( arc[2], p2 );
+    STORE( arc[1], p3 );
+    STORE( arc[0], p4 );
+
+#undef STORE
+  }
+
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Cubic_Up                                                    */
+/*                                                                          */
+/* <Description>                                                            */
+/*     Computes the scan-line intersections of an ascending third-order     */
+/*     bezier arc and stores them in the render pool                        */
+/*                                                                          */
+/* <Input>                                                                  */
+/*     miny     :: minimum vertical grid coordinate                         */
+/*     maxy     :: maximum vertical grid coordinate                         */
+/*                                                                          */
+/* <Return>                                                                 */
+/*     SUCCESS or FAILURE                                                   */
+/*                                                                          */
+/****************************************************************************/
+  static
+  TBool  Cubic_Up( RAS_ARGS TPos  miny, TPos  maxy )
+  {
+    TPos  y1, y2, e, e2, e0;
+    int   f1;
+
+    TPoint*  arc;
+    TPoint*  start_arc;
+
+    TPos*    top;
+
+
+    arc = ras.arc;
+    y1  = arc[3].y;
+    y2  = arc[0].y;
+    top = ras.cursor; 
+
+    if ( y2 < miny || y1 > maxy )
+      goto Fin;
+    
+    e2 = FLOOR( y2 );
+
+    if ( e2 > maxy )
+      e2 = maxy;
+
+    e0 = miny;
+
+    if ( y1 < miny )
+      e = miny;
+    else
+    {
+      e  = CEILING( y1 );
+      f1 = FRAC( y1 );
+      e0 = e;
+
+      if ( f1 == 0 )
+      {
+        if ( ras.joint )
+        {
+          top--;
+          ras.joint = FALSE;
+        }
+
+        *top++ = arc[3].x;
+
+        DEBUG_PSET;
+
+        e += ras.precision;
+      }
+    }
+
+    if ( ras.fresh )
+    {
+      ras.cur_prof->start = TRUNC( e0 );
+      ras.fresh = FALSE;
+    }
+
+    if ( e2 < e )
+      goto Fin;
+
+    if ( ( top+TRUNC(e2-e)+1 ) >= ras.pool_limit )
+    {
+      ras.cursor = top;
+      ras.error  = ErrRaster_Overflow;
+      return FAILURE;
+    }
+
+    start_arc = arc;
+
+    while ( arc >= start_arc && e <= e2 )
+    {
+      ras.joint = FALSE;
+
+      y2 = arc[0].y;
+
+      if ( y2 > e )
+      {
+        y1 = arc[3].y;
+        if ( y2 - y1 >= ras.precision_step )
+        {
+          Split_Cubic( arc );
+          arc += 3;
+        }
+        else
+        {
+          *top++ = arc[3].x + 
+                   FMulDiv( arc[0].x-arc[3].x, 
+                            e  - y1, 
+                            y2 - y1 );
+          DEBUG_PSET;
+            
+          arc -= 3;
+          e   += ras.precision;
+        }
+      }
+      else
+      {
+        if ( y2 == e )
+        {
+          ras.joint  = TRUE;
+          *top++     = arc[0].x;
+        
+          DEBUG_PSET;
+        
+          e += ras.precision;
+        }
+        arc -= 3;
+      }
+    }
+
+  Fin:
+    ras.cursor = top;
+    ras.arc   -= 3;
+    return SUCCESS;
+  }
+
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Cubic_Down                                                  */
+/*                                                                          */
+/* <Description>                                                            */
+/*     Computes the scan-line intersections of a descending third-order     */
+/*     bezier arc and stores them in the render pool                        */
+/*                                                                          */
+/* <Input>                                                                  */
+/*     miny     :: minimum vertical grid coordinate                         */
+/*     maxy     :: maximum vertical grid coordinate                         */
+/*                                                                          */
+/* <Return>                                                                 */
+/*     SUCCESS or FAILURE                                                   */
+/*                                                                          */
+/****************************************************************************/
+  static 
+  TBool  Cubic_Down( RAS_ARGS TPos  miny, TPos  maxy )
+  {
+    TPoint*  arc = ras.arc;
+    TBool     result, fresh;
+
+
+    arc[0].y = -arc[0].y;
+    arc[1].y = -arc[1].y; 
+    arc[2].y = -arc[2].y;
+    arc[3].y = -arc[3].y;
+
+    fresh = ras.fresh;
+
+    result = Cubic_Up( RAS_VARS -maxy, -miny );
+
+    if ( fresh && !ras.fresh )
+      ras.cur_prof->start = -ras.cur_prof->start;
+
+    arc[0].y = -arc[0].y;
+    return result;
+  }
+
+#endif /* FT_RASTER_CUBIC_BEZIERS */
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Check_Contour                                               */
+/*                                                                          */
+/* <Description>                                                            */
+/*     perform some check at contour closure.                               */
+/*                                                                          */
+/* <Return>                                                                 */
+/*     SUCCESS or FAILURE                                                   */
+/*                                                                          */
+/****************************************************************************/
+
+  static  
+  TBool  Check_Contour( RAS_ARG )
+  {
+    PProfile  lastProfile;
+      
+    /* We must now see if the extreme arcs join or not */
+    if ( ( FRAC( ras.last.y ) == 0     &&
+           ras.last.y >= ras.minY      &&
+           ras.last.y <= ras.maxY )    )
+    {
+      if ( ras.first_prof && ras.first_prof->flow == ras.cur_prof->flow )
+        ras.cursor--;
+    }
+    
+    lastProfile = ras.cur_prof;
+    if ( End_Profile( RAS_VAR ) ) return FAILURE;
+    
+    /* close the 'next profile in contour' linked list */
+    lastProfile->next = ras.first_prof;
+    
+    return SUCCESS;
+  }
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Move_To                                                     */
+/*                                                                          */
+/* <Description>                                                            */
+/*     This function injects a new contour in the render pool..             */
+/*                                                                          */
+/* <Input>                                                                  */
+/*     to       :: pointer to the contour's first point                     */
+/*     raster   :: a pointer to the current raster object                   */
+/*                                                                          */
+/* <Return>                                                                 */
+/*     Error code, 0 means success                                          */
+/*                                                                          */
+/* <Note>                                                                   */
+/*     This function is used as a "FTRasterMoveTo_Func" by the outline      */
+/*     decomposer..                                                         */
+/*                                                                          */
+/****************************************************************************/
+
+  static
+  int  Move_To( FT_Vector*  to,
+                FT_Raster   raster )
+  {
+    /* if there was already a contour being built, perform some checks */
+    if ( ras.start_prof )
+      if ( Check_Contour( RAS_VAR ) )
+        return FAILURE;
+
+    /* set the "current last point" */
+    if (ras.flipped)
+    {
+      ras.last.x = SCALED( to->y );
+      ras.last.y = SCALED( to->x );
+    }
+    else
+    {
+      ras.last.x = SCALED( to->x );
+      ras.last.y = SCALED( to->y );
+    }
+
+    ras.state      = Unknown;
+    ras.first_prof = NULL;
+    
+    return SUCCESS;
+  }
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Line_To                                                     */
+/*                                                                          */
+/* <Description>                                                            */
+/*     This function injects a new line segment in the render pool and      */
+/*     adjusts the profiles list accordingly..                              */
+/*                                                                          */
+/* <Input>                                                                  */
+/*     to       :: pointer to the target position                           */
+/*     raster   :: a pointer to the current raster object                   */
+/*                                                                          */
+/* <Return>                                                                 */
+/*     Error code, 0 means success                                          */
+/*                                                                          */
+/* <Note>                                                                   */
+/*     This function is used as a "FTRasterLineTo_Func" by the outline      */
+/*     decomposer..                                                         */
+/*                                                                          */
+/****************************************************************************/
+  
+  static 
+  int  Line_To( FT_Vector*  to,
+                FT_Raster   raster )
+  {
+    TPos  x;
+    TPos  y;
+    
+    if ( ras.flipped )
+    {
+      x = SCALED(to->y);
+      y = SCALED(to->x);
+    }
+    else
+    {
+      x = SCALED(to->x);
+      y = SCALED(to->y);
+    }
+    
+    /* First, detect a change of direction */
+
+    switch ( ras.state )
+    {
+    case Unknown:
+      if ( y > ras.last.y )
+      {
+        if ( New_Profile( RAS_VARS  Ascending ) ) return FAILURE;
+      }
+      else
+      {
+        if ( y < ras.last.y )
+          if ( New_Profile( RAS_VARS  Descending ) ) return FAILURE;
+      }
+      break;
+
+    case Ascending:
+      if ( y < ras.last.y )
+      {
+        if ( End_Profile( RAS_VAR ) ||
+             New_Profile( RAS_VARS  Descending ) ) return FAILURE;
+      }
+      break;
+
+    case Descending:
+      if ( y > ras.last.y )
+      {
+        if ( End_Profile( RAS_VAR ) ||
+             New_Profile( RAS_VARS  Ascending ) ) return FAILURE;
+      }
+      break;
+
+    default:
+      ;
+    }
+
+    /* Then compute the lines */
+
+    switch ( ras.state )
+    {
+    case Ascending:
+      if ( Line_Up ( RAS_VARS  ras.last.x, ras.last.y,
+                               x, y, ras.minY, ras.maxY ) )
+        return FAILURE;
+      break;
+
+    case Descending:
+      if ( Line_Down( RAS_VARS ras.last.x, ras.last.y,
+                               x, y, ras.minY, ras.maxY ) )
+        return FAILURE;
+      break;
+
+    default:
+      ;
+    }
+
+    ras.last.x = x;
+    ras.last.y = y;
+
+    return SUCCESS;
+  }
+
+#ifdef FT_RASTER_CONIC_BEZIERS
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Conic_To                                                    */
+/*                                                                          */
+/* <Description>                                                            */
+/*      Injects a new conic bezier arc and adjusts the profile list         */
+/*      accordingly.                                                        */
+/*                                                                          */
+/* <Input>                                                                  */
+/*      control  :: pointer to intermediate control point                   */
+/*      to       :: pointer to end point                                    */
+/*      raster   :: handle to current raster object                         */
+/*                                                                          */
+/* <Return>                                                                 */
+/*     Error code, 0 means success                                          */
+/*                                                                          */
+/* <Note>                                                                   */
+/*     This function is used as a "FTRasterConicTo_Func" by the outline     */
+/*     decomposer..                                                         */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  int  Conic_To( FT_Vector*  control,
+                 FT_Vector*  to,
+                 FT_Raster   raster )
+  {
+    TPos        y1, y2, y3, x3;
+    TDirection  state_bez;
+
+
+    Push_Conic( RAS_VARS  control, to );
+
+    do
+    {
+      y1 = ras.arc[2].y;
+      y2 = ras.arc[1].y;
+      y3 = ras.arc[0].y;
+      x3 = ras.arc[0].x;
+
+      /* first, categorize the bezier arc */
+
+      if( y1 == y3 )
+      {
+        if ( y2 == y1 )
+          state_bez = Flat;
+        else
+          state_bez = Unknown;
+      }
+      else if ( y1 < y3 )
+      {
+        if ( y2 < y1 || y2 > y3 )
+          state_bez = Unknown;
+        else
+          state_bez = Ascending;
+      }
+      else
+      {
+        if ( y2 < y3 || y2 > y1 )
+          state_bez = Unknown;
+        else
+          state_bez = Descending;
+      }
+
+      /* split non-monotonic arcs, ignore flat ones, or */
+      /* computes the up and down ones                  */
+
+      switch ( state_bez )
+      {
+      case Flat:
+        ras.arc -= 2;
+        break;
+
+      case Unknown:
+        Split_Conic( ras.arc );
+        ras.arc += 2;
+        break;
+
+      default:
+        /* detect a change of direction */
+
+        if ( ras.state != state_bez )
+        {
+          if ( ras.state != Unknown )
+            if ( End_Profile( RAS_VAR ) ) return FAILURE;
+
+          if ( New_Profile( RAS_VARS state_bez ) ) return FAILURE;
+        }
+
+        /* compute intersections */
+        switch ( ras.state )
+        {
+        case Ascending:
+          if ( Conic_Up ( RAS_VARS ras.minY, ras.maxY ) )
+            return FAILURE;
+          break;
+
+        case Descending:
+          if ( Conic_Down( RAS_VARS ras.minY, ras.maxY ) )
+            return FAILURE;
+          break;
+
+        default:
+          ;
+        }
+      }
+    } while ( ras.arc >= ras.arcs );
+
+    ras.last.x = x3;
+    ras.last.y = y3;
+
+    return 0;
+  }
+
+#else
+  static 
+  int  Conic_To( FT_Vector*  control,
+                 FT_Vector*  to,
+                 FT_Raster   raster )
+  {
+    (void)control;
+    (void)to;
+    (void)raster;
+    
+    return ErrRaster_Invalid_Outline;
+  }
+#endif /* CONIC_BEZIERS */
+
+
+#ifdef FT_RASTER_CUBIC_BEZIERS
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Cubic_To                                                    */
+/*                                                                          */
+/* <Description>                                                            */
+/*      Injects a new cubic bezier arc and adjusts the profile list         */
+/*      accordingly.                                                        */
+/*                                                                          */
+/* <Input>                                                                  */
+/*      control1 :: pointer to first control point                          */
+/*      control2 :: pointer to second control point                         */
+/*      to       :: pointer to end point                                    */
+/*      raster   :: handle to current raster object                         */
+/*                                                                          */
+/* <Return>                                                                 */
+/*     Error code, 0 means success                                          */
+/*                                                                          */
+/* <Note>                                                                   */
+/*     This function is used as a "FTRasterCubicTo_Func" by the outline     */
+/*     decomposer..                                                         */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  int  Cubic_To( FT_Vector*  control1,
+                 FT_Vector*  control2,
+                 FT_Vector*  to,
+                 FT_Raster   raster )
+  {
+    TPos        y1, y2, y3, y4, x4;
+    TDirection  state_bez;
+
+   
+    Push_Cubic( RAS_VARS  control1, control2, to );
+
+    do
+    {
+      y1 = ras.arc[3].y;
+      y2 = ras.arc[2].y;
+      y3 = ras.arc[1].y;
+      y4 = ras.arc[0].y;
+      x4 = ras.arc[0].x;
+
+      /* first, categorize the bezier arc */
+      if ( y1 == y4 )
+      {
+        if ( y1 == y2 && y1 == y3 )
+          state_bez = Flat;
+        else
+          state_bez = Unknown;
+      }
+      else if ( y1 < y4 )
+      {
+        if ( y2 < y1 || y2 > y4 || y3 < y1 || y3 > y4 )
+          state_bez = Unknown;
+        else
+          state_bez = Ascending;
+      }
+      else
+      {
+        if ( y2 < y4 || y2 > y1 || y3 < y4 || y3 > y1 )
+          state_bez = Unknown;
+        else
+          state_bez = Descending;
+      }
+
+      /* split non-monotonic arcs, ignore flat ones, or */
+      /* computes the up and down ones                  */
+
+      switch ( state_bez )
+      {
+      case Flat:
+        ras.arc -= 3;
+        break;
+
+      case Unknown:
+        Split_Cubic( ras.arc );
+        ras.arc += 3;
+        break;
+
+      default:
+        /* detect a change of direction */
+
+        if ( ras.state != state_bez )
+        {
+          if ( ras.state != Unknown )
+            if ( End_Profile( RAS_VAR ) ) return FAILURE;
+
+          if ( New_Profile( RAS_VARS state_bez ) ) return FAILURE;
+        }
+
+        /* compute */
+
+        switch ( ras.state )
+        {
+        case Ascending:
+          if ( Cubic_Up ( RAS_VARS ras.minY, ras.maxY ) )
+            return FAILURE;
+          break;
+
+        case Descending:
+          if ( Cubic_Down( RAS_VARS ras.minY, ras.maxY ) )
+            return FAILURE;
+          break;
+
+        default:
+          ;
+        }
+      }
+    } while ( ras.arc >= ras.arcs );
+
+    ras.last.x = x4;
+    ras.last.y = y4;
+
+    return 0;
+  }
+
+#else
+  int  Cubic_To( FT_Vector*  control1,
+                 FT_Vector*  control2,
+                 FT_Vector*  to,
+                 FT_Raster   raster )
+  {
+    (void)control1;
+    (void)control2;
+    (void)to;
+    (void)raster;
+    
+    return ErrRaster_Invalid_Outline;
+  }
+#endif /* CUBIC_BEZIERS */
+
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Convert_Glyph                                               */
+/*                                                                          */
+/* <Description>                                                            */
+/*     Converts a glyph into a series of segments and arcs and makes        */
+/*     a profiles list with them..                                          */
+/*                                                                          */
+/* <Input>                                                                  */
+/*     outline  :: glyph outline                                            */
+/*                                                                          */
+/* <Return>                                                                 */
+/*     SUCCESS or FAILURE                                                   */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  TBool  Convert_Glyph( RAS_ARGS  FT_Outline*  outline )
+  {
+    static
+    FT_Outline_Funcs  interface =
+    {
+      (FT_Outline_MoveTo_Func)Move_To,
+      (FT_Outline_LineTo_Func)Line_To,
+      (FT_Outline_ConicTo_Func)Conic_To,
+      (FT_Outline_CubicTo_Func)Cubic_To
+    };
+
+    /* Set up state in the raster object */
+    ras.start_prof = NULL;
+    ras.joint      = FALSE;
+    ras.fresh      = FALSE;
+
+    ras.pool_limit  = ras.pool_size - AlignProfileSize;
+
+    ras.n_turns = 0;
+
+    ras.cur_prof         = (PProfile)ras.cursor;
+    ras.cur_prof->offset = ras.cursor;
+    ras.num_profs        = 0;
+
+    /* Now decompose curve */
+    if ( FT_Outline_Decompose( outline, &interface, &ras ) ) return FAILURE;
+    /* XXX : the error condition is in ras.error */
+
+    /* Check the last contour if needed */
+    if ( Check_Contour( RAS_VAR ) ) return FAILURE;
+    
+    /* Finalize profiles list */
+    return Finalize_Profile_Table( RAS_VAR );
+  }
+
+
+/************************************************/
+/*                                              */
+/*  Init_Linked                                 */
+/*                                              */
+/*    Inits an empty linked list.               */
+/*                                              */
+/************************************************/
+
+  static void  Init_Linked( TProfileList*  l )
+  {
+    *l = NULL;
+  }
+
+
+/************************************************/
+/*                                              */
+/*  InsNew :                                    */
+/*                                              */
+/*    Inserts a new Profile in a linked list.   */
+/*                                              */
+/************************************************/
+
+  static void  InsNew( PProfileList  list,
+                       PProfile      profile )
+  {
+    PProfile  *old, current;
+    TPos       x;
+
+
+    old     = list;
+    current = *old;
+    x       = profile->X;
+
+    while ( current )
+    {
+      if ( x < current->X )
+        break;
+      old     = &current->link;
+      current = *old;
+    }
+
+    profile->link = current;
+    *old          = profile;
+  }
+
+
+/*************************************************/
+/*                                               */
+/*  DelOld :                                     */
+/*                                               */
+/*    Removes an old Profile from a linked list. */
+/*                                               */
+/*************************************************/
+
+  static void  DelOld( PProfileList  list,
+                       PProfile      profile )
+  {
+    PProfile  *old, current;
+
+
+    old     = list;
+    current = *old;
+
+    while ( current )
+    {
+      if ( current == profile )
+      {
+        *old = current->link;
+        return;
+      }
+
+      old     = &current->link;
+      current = *old;
+    }
+
+    /* we should never get there, unless the Profile was not part of */
+    /* the list.                                                     */
+  }
+
+/************************************************/
+/*                                              */
+/*  Update :                                    */
+/*                                              */
+/*    Update all X offsets of a drawing list    */
+/*                                              */
+/************************************************/
+
+  static void  Update( PProfile  first )
+  {
+    PProfile  current = first;
+
+    while (current)
+    {
+      current->X       = *current->offset;
+      current->offset += current->flow;
+      current->height--;
+      current = current->link;
+    }
+  }
+
+/************************************************/
+/*                                              */
+/*  Sort :                                      */
+/*                                              */
+/*    Sorts a trace list.  In 95%, the list     */
+/*    is already sorted.  We need an algorithm  */
+/*    which is fast in this case.  Bubble sort  */
+/*    is enough and simple.                     */
+/*                                              */
+/************************************************/
+
+  static void  Sort( PProfileList  list )
+  {
+    PProfile  *old, current, next;
+
+
+    /* First, set the new X coordinate of each profile */
+    Update( *list );
+
+    /* Then sort them */
+    old     = list;
+    current = *old;
+
+    if ( !current )
+      return;
+
+    next = current->link;
+
+    while ( next )
+    {
+      if ( current->X <= next->X )
+      {
+        old     = &current->link;
+        current = *old;
+
+        if ( !current )
+          return;
+      }
+      else
+      {
+        *old          = next;
+        current->link = next->link;
+        next->link    = current;
+
+        old     = list;
+        current = *old;
+      }
+
+      next = current->link;
+    }
+  }
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**************************************************************************/
+/********                                                         *********/
+/********            Vertical Bitmap Sweep Routines               *********/
+/********                                                         *********/
+/**************************************************************************/
+/**************************************************************************/
+/**************************************************************************/
+
+
+/***********************************************************************/
+/*                                                                     */
+/* <Function> Vertical_Sweep_Init                                      */
+/*                                                                     */
+/* <Description>                                                       */
+/*     Initialise the vertical bitmap sweep. Called by the generic     */
+/*     sweep/draw routine before its loop..                            */
+/*                                                                     */
+/* <Input>                                                             */
+/*    min  :: address of current minimum scanline                      */
+/*    max  :: address of current maximum scanline                      */
+/*                                                                     */
+/***********************************************************************/
+
+  static 
+  void  Vertical_Sweep_Init( RAS_ARGS int*  min, int*  max )
+  {
+    long  pitch = ras.target.pitch;
+    
+    ras.trace_incr = -pitch;
+    ras.trace_bit  = -*min*pitch;
+    if (pitch > 0)
+      ras.trace_bit += (ras.target.rows-1)*pitch;
+      
+    ras.gray_min_x = 0;
+    ras.gray_max_x = 0;
+  }
+
+/***********************************************************************/
+/*                                                                     */
+/* <Function> Vertical_Sweep_Span                                      */
+/*                                                                     */
+/* <Description>                                                       */
+/*     draws a single horizontal bitmap span during the vertical       */
+/*     bitmap sweep.                                                   */
+/*                                                                     */
+/* <Input>                                                             */
+/*     y  :: current scanline                                          */
+/*     x1 :: left span edge                                            */
+/*     x2 :: right span edge                                           */
+/*                                                                     */
+/***********************************************************************/
+
+  static void  Vertical_Sweep_Span( RAS_ARGS TScan  y,
+                                             TPos   x1,
+                                             TPos   x2 )
+  {
+    TPos   e1, e2;
+    int    c1, c2;
+    TByte   f1, f2;
+    TByte*  target;
+
+    /* Drop-out control */
+
+    e1 = TRUNC( CEILING( x1 ) );
+    if ( x2-x1-ras.precision <= ras.precision_jitter )
+      e2 = e1;
+    else
+      e2 = TRUNC( FLOOR( x2 ) );
+
+    if ( e1 <= e2 && e2 >= 0 && e1 < ras.bit_width )
+    {
+      if ( e1 < 0 )              e1 = 0;
+      if ( e2 >= ras.bit_width ) e2 = ras.bit_width-1;
+
+      c1 = e1 >> 3;
+      c2 = e2 >> 3;
+
+      f1 =  ((unsigned char)0xFF >> (e1 & 7));
+      f2 = ~((unsigned char)0x7F >> (e2 & 7));
+
+      target = ras.bit_buffer + ras.trace_bit + c1;
+      c2 -= c1;
+
+      if ( c2 > 0 )
+      {
+        target[0] |= f1;
+
+        /* memset is slower than the following code on many platforms   */
+        /* this is due to the fact that, in the vast majority of cases, */
+        /* the span length in bytes is relatively small..               */
+        c2--;
+        while (c2 > 0)
+        {
+          * ++target = 0xFF;
+          c2--;
+        }
+        target[1] |= f2;
+      }
+      else
+        *target |= ( f1 & f2 );
+    }
+  }
+
+/***********************************************************************/
+/*                                                                     */
+/* <Function> Vertical_Test_Pixel                                      */
+/*                                                                     */
+/* <Description>                                                       */
+/*     test a pixel 'light' during the vertical bitmap sweep. Used     */
+/*     during drop-out control only..                                  */
+/*                                                                     */
+/* <Input>                                                             */
+/*     y  :: current scanline                                          */
+/*     x  :: current x coordinate                                      */
+/*                                                                     */
+/***********************************************************************/
+
+  static 
+  int  Vertical_Test_Pixel( RAS_ARGS TScan  y,
+                                     int    x )
+  {
+    int c1 = x >> 3;
+
+    return ( x >= 0 && x < ras.bit_width && 
+             ras.bit_buffer[ras.trace_bit + c1] & (0x80 >> (x & 7)) );
+  }
+
+/***********************************************************************/
+/*                                                                     */
+/* <Function> Vertical_Set_Pixel                                       */
+/*                                                                     */
+/* <Description>                                                       */
+/*     Sets a single pixel in a bitmap during the vertical sweep.      */
+/*     Used during drop-out control..                                  */
+/*                                                                     */
+/* <Input>                                                             */
+/*     y  :: current scanline                                          */
+/*     x  :: current x coordinate                                      */
+/* color  :: ignored by this function                                  */
+/*                                                                     */
+/***********************************************************************/
+
+  static 
+  void  Vertical_Set_Pixel( RAS_ARGS  int  y,
+                                      int  x,
+                                      int  color )
+  {
+    (void)color;  /* unused here */
+
+    if ( x >= 0 && x < ras.bit_width )
+    {
+      int c1 = x >> 3;
+
+      if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
+      if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1;
+
+      ras.bit_buffer[ras.trace_bit+c1] |= (char)(0x80 >> (x & 7));
+    }
+  }
+
+/***********************************************************************/
+/*                                                                     */
+/* <Function> Vertical_Sweep_Step                                      */
+/*                                                                     */
+/* <Description>                                                       */
+/*     Called whenever the sweep jumps to anothr scanline.             */
+/*     Only updates the pointers in the vertical bitmap sweep          */
+/*                                                                     */
+/***********************************************************************/
+
+  static
+  void Vertical_Sweep_Step( RAS_ARG )
+  {
+    ras.trace_bit += ras.trace_incr;
+  }
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**************************************************************************/
+/********                                                         *********/
+/********           Horizontal Bitmap Sweep Routines              *********/
+/********                                                         *********/
+/**************************************************************************/
+/**************************************************************************/
+/**************************************************************************/
+
+/***********************************************************************/
+/*                                                                     */
+/* <Function> Horizontal_Sweep_Init                                    */
+/*                                                                     */
+/* <Description>                                                       */
+/*     Initialise the horizontal bitmap sweep. Called by the generic   */
+/*     sweep/draw routine before its loop..                            */
+/*                                                                     */
+/* <Input>                                                             */
+/*    min  :: address of current minimum pixel column                  */
+/*    max  :: address of current maximum pixel column                  */
+/*                                                                     */
+/***********************************************************************/
+
+  static void  Horizontal_Sweep_Init( RAS_ARGS int*  min, int*  max )
+  {
+    /* nothing, really */
+  }
+
+
+/***********************************************************************/
+/*                                                                     */
+/* <Function> Horizontal_Sweep_Span                                    */
+/*                                                                     */
+/* <Description>                                                       */
+/*     draws a single vertical bitmap span during the horizontal       */
+/*     bitmap sweep. Actually, this function is only used to           */
+/*     check for weird drop-out cases..                                */
+/*                                                                     */
+/* <Input>                                                             */
+/*     y  :: current pixel column                                      */
+/*     x1 :: top    span edge                                          */
+/*     x2 :: bottom span edge                                          */
+/*                                                                     */
+/***********************************************************************/
+
+  static void  Horizontal_Sweep_Span( RAS_ARGS TScan  y,
+                                               TPos   x1,
+                                               TPos   x2 )
+  {
+    TPos  e1, e2;
+    PByte bits;
+    TByte  f1;
+
+
+    /* During the horizontal sweep, we only take care of drop-outs */
+    if ( x2-x1 < ras.precision )
+    {
+      e1 = CEILING( x1 );
+      e2 = FLOOR( x2 );
+      
+      if ( e1 == e2 )
+      {
+        bits = ras.bit_buffer + (y >> 3);
+        f1   = (TByte)(0x80 >> (y & 7));
+        
+        e1 = TRUNC( e1 );
+
+        if ( e1 >= 0 && e1 < ras.target.rows )
+        {
+          long  pitch = ras.target.pitch;
+          
+          bits -= e1*pitch;
+          if (pitch > 0)
+            bits += (ras.target.rows-1)*pitch;
+            
+          bits[0] |= f1;
+        }
+      }
+    }
+  }
+
+
+/***********************************************************************/
+/*                                                                     */
+/* <Function> Horizontal_Test_Pixel                                    */
+/*                                                                     */
+/* <Description>                                                       */
+/*     test a pixel 'light' during the horizontal bitmap sweep. Used   */
+/*     during drop-out control only..                                  */
+/*                                                                     */
+/* <Input>                                                             */
+/*     y  :: current pixel column                                      */
+/*     x  :: current row/scanline                                      */
+/*                                                                     */
+/***********************************************************************/
+
+  static
+  int   Horizontal_Test_Pixel( RAS_ARGS  int  y,
+                                         int  x )
+  {
+    char*  bits  = (char*)ras.bit_buffer + (y >> 3);
+    int    f1    = (TByte)(0x80 >> (y & 7));
+    long   pitch = ras.target.pitch;
+    
+    bits -= x*pitch;
+    if (pitch > 0)
+      bits += (ras.target.rows-1)*pitch;
+      
+    return ( x >= 0 && x < ras.target.rows && (bits[0] & f1) );
+  }
+
+/***********************************************************************/
+/*                                                                     */
+/* <Function> Horizontal_Set_Pixel                                     */
+/*                                                                     */
+/* <Description>                                                       */
+/*     Sets a single pixel in a bitmap during the horizontal sweep.    */
+/*     Used during drop-out control..                                  */
+/*                                                                     */
+/* <Input>                                                             */
+/*     y  :: current pixel column                                      */
+/*     x  :: current row/scanline                                      */
+/* color  :: ignored by this function                                  */
+/*                                                                     */
+/***********************************************************************/
+
+  static
+  void  Horizontal_Set_Pixel( RAS_ARGS  int  y,
+                                        int  x,
+                                        int  color )
+  {
+    char*  bits  = (char*)ras.bit_buffer + (y >> 3);
+    int    f1    = (TByte)(0x80 >> (y  & 7));
+    long   pitch = ras.target.pitch;
+
+    (void)color;   /* unused here */
+
+    bits -= x*pitch;
+    if (pitch > 0)
+      bits += (ras.target.rows-1)*pitch;
+      
+    if ( x >= 0 && x < ras.target.rows )
+      bits[0] |= f1;
+  }
+
+/***********************************************************************/
+/*                                                                     */
+/* <Function> Horizontal_Sweep_Step                                    */
+/*                                                                     */
+/* <Description>                                                       */
+/*     Called whenever the sweep jumps to another pixel column.        */
+/*                                                                     */
+/***********************************************************************/
+
+  static void Horizontal_Sweep_Step( RAS_ARG )
+  {
+    /* Nothing, really */
+  }
+
+
+/**************************************************************************/
+/**************************************************************************/
+/**************************************************************************/
+/********                                                         *********/
+/********      Anti-Aliased Vertical Bitmap Sweep Routines        *********/
+/********                                                         *********/
+/**************************************************************************/
+/**************************************************************************/
+/**************************************************************************/
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIAS
+
+#ifdef FT_RASTER_ANTI_ALIAS_5
+/***********************************************************************/
+/*                                                                     */
+/*  Vertical Gray Sweep Procedure Set :                                */
+/*                                                                     */
+/*  These two routines are used during the vertical gray-levels        */
+/*  sweep phase by the generic Draw_Sweep() function.                  */
+/*                                                                     */
+/*                                                                     */
+/*  NOTES:                                                             */
+/*                                                                     */
+/*  - The target pixmap's width *must* be a multiple of 4.             */
+/*                                                                     */
+/*  - you have to use the function Vertical_Sweep_Span() for           */
+/*    the gray span call.                                              */
+/*                                                                     */
+/***********************************************************************/
+
+  static void  Vertical_Gray5_Sweep_Init( RAS_ARGS int*  min, int*  max )
+  {
+    long  pitch;
+    
+    *min = *min & -2;
+    *max = ( *max+3 ) & -2;
+
+    ras.trace_bit = 0;
+
+    pitch          = ras.target.pitch;
+    ras.trace_incr = -pitch;
+    ras.trace_pix  = - (*min/2)*pitch;
+    if (pitch > 0)
+      ras.trace_pix += (ras.target.rows-1)*pitch;
+      
+    ras.gray_min_x =  32000;
+    ras.gray_max_x = -32000;
+  }
+
+
+  static void  Vertical_Gray5_Sweep_Span( RAS_ARGS TScan  y,
+                                                   TPos   x1,
+                                                   TPos   x2 )
+  {
+    static
+    const unsigned int  LMask[17] =
+#ifdef FT_RASTER_LITTLE_ENDIAN
+             { 0xF0F0F0F0, 0xF0F0F070, 0xF0F0F030, 0xF0F0F010,
+               0xF0F0F000, 0xF0F07000, 0xF0F03000, 0xF0F01000,
+               0xF0F00000, 0xF0700000, 0xF0300000, 0xF0100000,
+               0xF0000000, 0x70000000, 0x30000000, 0x10000000,
+               0x00000000 };
+#else
+             { 0xF0F0F0F0, 0x70F0F0F0, 0x30F0F0F0, 0x10F0F0F0,
+               0x00F0F0F0, 0x0070F0F0, 0x0030F0F0, 0x0010F0F0,
+               0x0000F0F0, 0x000070F0, 0x000030F0, 0x000010F0,
+               0x000000F0, 0x00000070, 0x00000030, 0x00000010,
+               0x00000000 };
+#endif
+
+    TPos   e1, e2;
+    int    c1, c2;
+    TByte*  target;
+
+    unsigned int    f1, f2;
+    unsigned int    shift, fill;
+
+    /* Drop-out control */
+
+    e1 = TRUNC( CEILING( x1 ) );
+    if ( x2-x1 <= ras.precision+ras.precision_jitter )
+      e2 = e1;
+    else
+      e2 = FLOOR ( x2 );
+
+    e2 = TRUNC( e2 );
+ 
+    if ( e1 <= e2 && e2 >= 0 && e1 < ras.bit_width )
+    {
+      if ( e1 < 0 )              e1 = 0;
+      if ( e2 >= ras.bit_width ) e2 = ras.bit_width-1;
+
+      shift = (y & 1)*4;
+
+      c1 = e1 >> 4;
+      c2 = e2 >> 4;
+
+      fill = LMask[0];
+      f1   = LMask[ e1 & 15 ];
+      f2   = fill ^ LMask[ 1+(e2 & 15) ];
+
+      f1   >>= shift;
+      f2   >>= shift;
+      fill >>= shift;
+
+      if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
+      if ( ras.gray_max_x < c2 ) ras.gray_max_x = c2;
+
+      target = ras.bit_buffer + c1*4;
+      c2 -= c1;
+
+      if (c2 > 0)
+      {
+        int*  slice = (int*)target;
+        
+        slice[0] |= f1;
+        c2--;
+        while (c2 > 0)
+        {
+          * ++slice |= fill;
+          c2--;
+        }
+        slice[1] |= f2;
+      }
+      else
+        ((int*)target)[0] |= ( f1 & f2 );
+    }
+  }
+
+
+  static 
+  int  Vertical_Gray5_Test_Pixel( RAS_ARGS int  y,
+                                           int  x )
+  {
+    int c1    = x >> 2;
+    int f1    = x  & 3;
+    int mask  = (0x80 >> f1) >> ((y & 1)*4);
+
+    return ( x >= 0                    && 
+             x < ras.bit_width         && 
+             ras.bit_buffer[c1] & mask );
+  }
+
+
+  static 
+  void  Vertical_Gray5_Set_Pixel( RAS_ARGS  int  y,
+                                            int  x,
+                                            int  color )
+  {
+    (void)color;  /* unused here */
+
+    if ( x >= 0 && x < ras.bit_width )
+    {
+      int c1   = x >> 2;
+      int f1   = x  & 3;
+      int mask = (0x80 >> f1) >> ((y & 1)*4);
+  
+      if ( ras.gray_min_x > c1/4 ) ras.gray_min_x = c1/4;
+      if ( ras.gray_max_x < c1/4 ) ras.gray_max_x = c1/4;
+
+      ras.bit_buffer[c1] |= mask;
+    }
+  }
+
+
+  static void  Vertical_Gray5_Sweep_Step( RAS_ARG )
+  {
+    int    c1;
+    PByte  pix, bit;
+    int*   count = ras.count_table;
+    long*  grays;
+
+
+    ras.trace_bit++;
+
+    if ( ras.trace_bit > 1 )
+    {
+      pix   = ras.pix_buffer + ras.trace_pix + ras.gray_min_x*8;
+      grays = ras.grays;
+
+      if ( ras.gray_max_x >= 0 )
+      {
+        if ( ras.gray_max_x*8 >= ras.target.width ) 
+          ras.gray_max_x = (ras.target.width+7)/8-1;
+
+        if ( ras.gray_min_x < 0 ) 
+          ras.gray_min_x = 0;
+
+        bit = ras.bit_buffer + ras.gray_min_x*4;
+        c1  = (ras.gray_max_x - ras.gray_min_x + 1);
+
+        while ( c1 >= 0 )
+        {
+          if ( *(short*)bit )
+          {
+#if defined( FT_RASTER_LITTLE_ENDIAN )
+            /* little endian storage */
+            *((long*)pix) = (count[bit[1]] << 16) | count[bit[0]];
+#elif defined( FT_RASTER_BIG_ENDIAN )
+            /* big-endian storage */
+            *((long*)pix) = (count[bit[0]] << 16) | count[bit[1]];
+#else
+            /* endian-independent storage */
+            int  c;
+            c = count[bit[1]];
+            pix[4] = (TByte)(c >> 8);
+            pix[5] = (TByte)(c & 0xFF);
+            c = count[bit[0]];
+            pix[6] = (TByte)(c >> 8);
+            pix[7] = (TByte)(c & 0xFF);
+#endif
+            *(short*)bit = 0;
+          }
+
+          bit += 2;
+          
+          if ( *(short*)bit )
+          {
+#if defined( FT_RASTER_LITTLE_ENDIAN )
+            /* little endian storage */
+            *((long*)pix + 1)= (count[bit[1]] << 16) | count[bit[0]];
+#elif defined( FT_RASTER_BIG_ENDIAN )
+            /* big-endian storage */
+            *((long*)pix + 1) = (count[bit[0]] << 16) | count[bit[1]];
+#else
+            /* endian-independent storage */
+            int  c;
+            c = count[bit[1]];
+            pix[0] = (TByte)(c >> 8);
+            pix[1] = (TByte)(c & 0xFF);
+            c = count[bit[0]];
+            pix[2] = (TByte)(c >> 8);
+            pix[3] = (TByte)(c & 0xFF);
+#endif
+            *(short*)bit = 0;
+          }
+          pix += 8;
+          bit += 2;
+          c1 --;
+        }
+      }
+     
+      ras.trace_bit  = 0;
+      ras.trace_pix += ras.trace_incr;
+
+      ras.gray_min_x =  32000;
+      ras.gray_max_x = -32000;
+    }
+  }
+
+
+
+  static void  Horizontal_Gray5_Sweep_Span( RAS_ARGS TScan  y,
+                                                     TPos   x1,
+                                                     TPos   x2 )
+  {
+    /* nothing, really */
+    (void)y;
+    (void)x1;
+    (void)x2;
+  }
+
+
+  static
+  int   Horizontal_Gray5_Test_Pixel( RAS_ARGS  TScan  y,
+                                               int    x )
+  {
+    /* don't do anything here */
+    (void)x;
+    (void)y;
+    
+    return 0;
+  }
+
+
+  static
+  void  Horizontal_Gray5_Set_Pixel( RAS_ARGS  TScan  y,
+                                              int    x,
+                                              int    color )
+  {
+    char*  pixel;
+
+    x = x/2;
+      
+    if (x < ras.target.rows)
+    {
+      long  pitch;
+      
+      pixel = (char*)ras.pix_buffer + (y/2);
+      pitch = ras.target.pitch;
+      pixel -= x*pitch;
+      if (pitch > 0)
+        pixel += (ras.target.rows-1)*pitch;
+        
+      if (pixel[0] == ras.grays[0])
+        pixel[0] = (char)ras.grays[1+color];
+    }
+  }
+#endif /* FT_RASTER_ANTI_ALIAS_5 */
+  
+#ifdef FT_RASTER_ANTI_ALIAS_17
+/***********************************************************************/
+/*                                                                     */
+/*  Vertical Gray Sweep Procedure Set :                                */
+/*                                                                     */
+/*  These two routines are used during the vertical gray-levels        */
+/*  sweep phase by the generic Draw_Sweep() function.                  */
+/*                                                                     */
+/*                                                                     */
+/*  NOTES:                                                             */
+/*                                                                     */
+/*  - The target pixmap's width *must* be a multiple of 4.             */
+/*                                                                     */
+/*  - you have to use the function Vertical_Sweep_Span() for           */
+/*    the gray span call.                                              */
+/*                                                                     */
+/***********************************************************************/
+
+  static void  Vertical_Gray17_Sweep_Init( RAS_ARGS int*  min, int*  max )
+  {
+    long  pitch = ras.target.pitch;
+    
+    *min = *min & -4;
+    *max = ( *max+7 ) & -4;
+
+    ras.trace_bit = 0;
+    ras.trace_incr = -pitch;
+    ras.trace_bit  = - (*min/4)*pitch;
+    if (pitch > 0)
+      ras.trace_bit += (ras.target.rows-1)*pitch;
+
+    ras.gray_min_x =  32000;
+    ras.gray_max_x = -32000;
+  }
+
+
+  static void  Vertical_Gray17_Sweep_Span( RAS_ARGS TScan  y,
+                                                    TPos   x1,
+                                                    TPos   x2 )
+  {
+    static
+    const unsigned int  LMask[9] =
+#ifdef FT_RASTER_LITTLE_ENDIAN
+             { 0xF000F000, 0xF0007000, 0xF0003000, 0xF0001000,
+               0xF0000000, 0x70000000, 0x30000000, 0x10000000,
+               0x00000000 };
+#else
+             { 0xF000F000, 0x7000F000, 0x3000F000, 0x1000F000,
+               0x0000F000, 0x00007000, 0x00003000, 0x00001000,
+               0x00000000 };
+#endif
+
+    TPos   e1, e2;
+    int    c1, c2;
+    TByte*  target;
+
+    unsigned int    f1, f2;
+    unsigned int    shift, fill;
+
+    /* Drop-out control */
+
+    e1 = TRUNC( CEILING( x1 ) );
+    if ( x2-x1 <= ras.precision+ras.precision_jitter )
+      e2 = e1;
+    else
+      e2 = FLOOR ( x2 );
+    e2 = TRUNC( e2 );
+ 
+    if ( e1 <= e2 && e2 >= 0 && e1 < ras.bit_width )
+    {
+      if ( e1 < 0 )              e1 = 0;
+      if ( e2 >= ras.bit_width ) e2 = ras.bit_width-1;
+
+      shift = (y & 3)*4;
+
+      c1 = e1 >> 3;
+      c2 = e2 >> 3;
+
+      fill = LMask[0];
+      f1   = LMask[ e1 & 7 ];
+      f2   = fill ^ LMask[ 1+(e2 & 7) ];
+
+      f1   >>= shift;
+      f2   >>= shift;
+      fill >>= shift;
+
+      if ( ras.gray_min_x > c1/2 ) ras.gray_min_x = c1/2;
+      if ( ras.gray_max_x < c2/2 ) ras.gray_max_x = c2/2;
+
+      target = ras.bit_buffer + c1*4;
+      c2 -= c1;
+
+      if (c2 > 0)
+      {
+        int*  slice = (int*)target;
+
+        slice[0] |= f1;
+        c2--;
+        while (c2 > 0)
+        {
+          * ++slice |= fill;
+          c2--;
+        }
+        slice[1] |= f2;
+      }
+      else
+        ((int*)target)[0] |= ( f1 & f2 );
+    }
+  }
+
+
+  static 
+  int  Vertical_Gray17_Test_Pixel( RAS_ARGS int  y,
+                                            int  x )
+  {
+    int c1    = x >> 2;
+    int f1    = x  & 3;
+    int mask  = (0x8000 >> f1) >> ((y & 3)*4);
+
+    return ( x >= 0                    && 
+             x < ras.bit_width         && 
+             ((short*)ras.bit_buffer)[c1] & mask );
+  }
+
+
+  static 
+  void  Vertical_Gray17_Set_Pixel( RAS_ARGS  int  y,
+                                             int  x,
+                                             int  color )
+  {
+    (void)color;  /* unused here */
+
+    if ( x >= 0 && x < ras.bit_width )
+    {
+      int c1   = x >> 2;
+      int f1   = x  & 3;
+      int mask = (0x8000 >> f1) >> ((y & 3)*4);
+  
+      if ( ras.gray_min_x > c1/4 ) ras.gray_min_x = c1/4;
+      if ( ras.gray_max_x < c1/4 ) ras.gray_max_x = c1/4;
+
+      ((short*)ras.bit_buffer)[c1] |= mask;
+    }
+  }
+
+
+  static void  Vertical_Gray17_Sweep_Step( RAS_ARG )
+  {
+    int    c1;
+    PByte  pix, bit;
+    long*  grays;
+
+
+    ras.trace_bit++;
+
+    if ( ras.trace_bit > 3 )
+    {
+      pix   = ras.pix_buffer + ras.trace_pix + ras.gray_min_x*4;
+      grays = ras.grays;
+
+      if ( ras.gray_max_x >= 0 )
+      {
+        if ( ras.gray_max_x >= ras.target.width/4 ) 
+          ras.gray_max_x = (ras.target.width+3)/4-1;
+
+        if ( ras.gray_min_x < 0 ) 
+          ras.gray_min_x = 0;
+
+        bit = ras.bit_buffer + ras.gray_min_x*8;
+        c1  = (ras.gray_max_x - ras.gray_min_x + 1);
+
+        while ( c1 >= 0 )
+        {
+          if ( *(long*)bit || *(long*)(bit+4) )
+          {
+            int*  table = ras.count_table;
+
+#if defined( FT_RASTER_LITTLE_ENDIAN )
+            /* little-endian specific storage */
+            *(long*)pix =   grays[ table[ bit[0] ] +
+                                   table[ bit[1] ] ]         |
+                                      
+                          ( grays[ table[ bit[2] ] +
+                                   table[ bit[3] ] ] << 8 )  |
+                                   
+                          ( grays[ table[ bit[4] ] +
+                                   table[ bit[5] ] ] << 16 ) |
+                                   
+                          ( grays[ table[ bit[6] ] +
+                                   table[ bit[7] ] ] << 24 );
+
+#elif defined( FT_RASTER_BIG_ENDIAN )
+            /* big-endian specific storage */
+            *(long*)pix = ( grays[ table[ bit[0] ] +
+                                   table[ bit[1] ] ] << 24    |
+                                      
+                          ( grays[ table[ bit[2] ] +
+                                   table[ bit[3] ] ] << 16 )  |
+                                   
+                          ( grays[ table[ bit[4] ] +
+                                   table[ bit[5] ] ] << 8 ) |
+                                   
+                          ( grays[ table[ bit[6] ] +
+                                   table[ bit[7] ] ]  );
+#else
+            /* endianess-independent storage */
+            pix[0] = grays[ table[bit[0]] + table[bit[1]] ];
+            pix[1] = grays[ table[bit[2]] + table[bit[3]] ];
+            pix[2] = grays[ table[bit[4]] + table[bit[5]] ];
+            pix[3] = grays[ table[bit[6]] + table[bit[7]] ];
+#endif
+            *(long*)( bit ) = 0;
+            *(long*)(bit+4) = 0;
+          }
+          pix += 4;
+          bit += 8;
+          c1 --;
+        }
+      }
+      ras.trace_bit   = 0;
+      ras.trace_pix  += ras.trace_incr;
+
+      ras.gray_min_x =  32000;
+      ras.gray_max_x = -32000;
+    }
+  }
+
+
+
+  static void  Horizontal_Gray17_Sweep_Span( RAS_ARGS TScan  y,
+                                                      TPos   x1,
+                                                      TPos   x2 )
+  {
+    /* nothing, really */
+    (void)y;
+    (void)x1;
+    (void)x2;
+  }
+
+
+  static
+  int   Horizontal_Gray17_Test_Pixel( RAS_ARGS  TScan  y,
+                                                int    x )
+  {
+    /* don't do anything here */
+    (void)x;
+    (void)y;
+    
+    return 0;
+  }
+
+
+  static
+  void  Horizontal_Gray17_Set_Pixel( RAS_ARGS  TScan  y,
+                                               int    x,
+                                               int    color )
+  {
+    char*  pixel;
+
+    x = x/4;
+      
+    if (x < ras.target.rows)
+    {
+      long  pitch = ras.target.pitch;
+      
+      pixel  = (char*)ras.pix_buffer + (y/4);
+      pixel -= x*pitch;
+      if (pitch > 0)
+        pixel += (ras.target.rows-1)*pitch;
+        
+      if (pixel[0] == ras.grays[0])
+        pixel[0] = ras.grays[1+color];
+    }
+  }
+#endif /* FT_RASTER_ANTI_ALIAS_17 */
+  
+#endif /* FT_RASTER_OPTION_ANTI_ALIAS */
+
+/********************************************************************/
+/*                                                                  */
+/*  Generic Sweep Drawing routine                                   */
+/*                                                                  */
+/********************************************************************/
+
+  static TBool  Draw_Sweep( RAS_ARG )
+  {
+    TScan  y, y_change, y_height;
+
+    PProfile  P, Q, P_Left, P_Right;
+
+    TScan   min_Y, max_Y, top, bottom, dropouts;
+
+    TPos x1, x2, e1, e2;
+
+    TProfileList  wait;
+    TProfileList  draw;
+
+    /* Init empty linked lists */
+
+    Init_Linked( &wait );
+    Init_Linked( &draw );
+
+    /* first, compute min and max Y */
+
+    P     = ras.start_prof;
+    max_Y = TRUNC( ras.minY );
+    min_Y = TRUNC( ras.maxY );
+
+    while ( P )
+    {
+      Q = P->link;
+
+      bottom = P->start;
+      top    = P->start + P->height-1;
+
+      if ( min_Y > bottom ) min_Y = bottom;
+      if ( max_Y < top    ) max_Y = top;
+
+      P->X = 0;
+      InsNew( &wait, P );
+
+      P = Q;
+    }
+
+    /* Check the Y-turns */
+    if ( ras.n_turns == 0 )
+    {
+      ras.error = ErrRaster_Invalid_Outline;
+      return FAILURE;
+    }
+
+    /* Now inits the sweep */
+
+    ras.Proc_Sweep_Init( RAS_VARS  &min_Y, &max_Y );
+
+    /* Then compute the distance of each profile from min_Y */
+
+    P = wait;
+
+    while ( P )
+    {
+      P->countL = P->start - min_Y;
+      P = P->link;
+    }
+
+    /* Let's go */
+
+    y        = min_Y;
+    y_height = 0;
+
+    if ( ras.n_turns > 0 &&
+         ras.pool_size[-ras.n_turns] == min_Y )
+      ras.n_turns--;
+
+    while (ras.n_turns > 0)
+    {
+      PProfile  prof = wait;
+      
+      /* look in the wait list for new activations */
+      while (prof)
+      {
+        PProfile  next = prof->link;
+        
+        prof->countL -= y_height;
+        if ( prof->countL == 0 )
+        {
+          DelOld( &wait, prof );
+          InsNew( &draw, prof );
+        }
+        prof = next;
+      }
+
+      /* Sort the drawing lists */
+      Sort( &draw );
+
+      y_change = ras.pool_size[-ras.n_turns--];
+      y_height = y_change - y;
+
+      while ( y < y_change )
+      {
+        int       window;
+        PProfile  left;
+
+        /* Let's trace */
+  
+        dropouts = 0;
+
+        if (!draw)
+          goto Next_Line;
+          
+        left   = draw;
+        window = left->flow;
+        prof   = left->link;
+
+        while (prof)
+        {
+          PProfile  next = prof->link;
+          
+          window += prof->flow;
+          
+          if ( window == 0 )
+          {
+            x1 = left->X;
+            x2 = prof->X;
+#if 1
+            if ( x1 > x2 )
+            {
+              TPos  xs = x1;
+              x1 = x2;
+              x2 = xs;
+            }
+#endif
+            if ( x2-x1 <= ras.precision && ras.dropout_mode )
+            {
+#if 1
+              e1 = CEILING( x1 );
+              e2 = FLOOR( x2 );
+#else
+              e1 = FLOOR(x1);
+              e2 = CEILING(x2);
+#endif
+              if ( e1 > e2 || e2 == e1+ ras.precision )
+              {
+                /* a drop out was detected */
+   
+                left->X = x1;
+                prof->X = x2;
+
+                /* mark profiles for drop-out processing */
+                left->countL = 1;
+                prof->countL = 2;
+                dropouts++;
+                goto Skip_To_Next;
+              }
+            }
+
+            ras.Proc_Sweep_Span( RAS_VARS  y, x1, x2 );
+   
+   Skip_To_Next:
+            left = next;
+          }       
+          prof = next;
+        }
+
+        /* now perform the dropouts _after_ the span drawing   */
+        /* drop-outs processing has been moved out of the loop */
+        /* for performance tuning                              */
+        if (dropouts > 0)
+          goto Scan_DropOuts;
+
+   Next_Line:
+
+        ras.Proc_Sweep_Step( RAS_VAR );
+
+        y++;
+
+        if ( y < y_change )
+          Sort( &draw );
+      }
+
+      /* Now finalize the profiles that needs it */
+
+      {
+        PProfile  prof, next;
+        prof = draw;
+        while (prof)
+        {
+          next = prof->link;
+          if (prof->height == 0)
+            DelOld( &draw, prof );
+          prof = next;
+        }
+      }
+    }
+
+    /* for gray-scaling, flushes the bitmap scanline cache */
+    while (y <= max_Y)
+    {
+        ras.Proc_Sweep_Step( RAS_VAR );
+        y++;
+    }
+
+    return SUCCESS;
+
+
+Scan_DropOuts :
+    P_Left = draw;
+    while (dropouts > 0)
+    {
+      TPos      e1,   e2;
+      PProfile  left, right;
+    
+      while (P_Left->countL != 1) P_Left = P_Left->link;
+      P_Right = P_Left->link;
+      while (P_Right->countL != 2) P_Right = P_Right->link;
+       
+      P_Left->countL  = 0;
+      P_Right->countL = 0;
+
+      /* Now perform the dropout control */      
+      x1 = P_Left->X;
+      x2 = P_Right->X;
+
+      left  = ( ras.flipped ? P_Right : P_Left  );
+      right = ( ras.flipped ? P_Left  : P_Right );
+      
+      e1 = CEILING( x1 );
+      e2 = FLOOR  ( x2 );
+
+      if ( e1 > e2 )
+      {
+        if ( e1 == e2 + ras.precision )
+        {
+          switch ( ras.dropout_mode )
+          {
+          case 1:
+            e1 = e2;
+            break;
+
+          case 4:
+            e1 = CEILING( (x1+x2+1) / 2 );
+            break;
+
+          case 2:
+          case 5:
+          /* Drop-out Control Rule #4 */
+  
+          /* The spec is not very clear regarding rule #4.  It      */
+          /* presents a method that is way too costly to implement  */
+          /* while the general idea seems to get rid of 'stubs'.    */
+          /*                                                        */
+          /* Here, we only get rid of stubs recognized when:        */
+          /*                                                        */
+          /*  upper stub:                                           */
+          /*                                                        */
+          /*   - P_Left and P_Right are in the same contour         */
+          /*   - P_Right is the successor of P_Left in that contour */
+          /*   - y is the top of P_Left and P_Right                 */
+          /*                                                        */
+          /*  lower stub:                                           */
+          /*                                                        */
+          /*   - P_Left and P_Right are in the same contour         */
+          /*   - P_Left is the successor of P_Right in that contour */
+          /*   - y is the bottom of P_Left                          */
+          /*                                                        */
+
+            /* upper stub test */
+            if ( ( left->next == right && left->height <= 0 ) ||
+
+            /* lower stub test */
+                 ( right->next == left && left->start == y )  ||
+
+            /* check that the rightmost pixel isn't set */
+                 ras.Proc_Test_Pixel( RAS_VARS  y, TRUNC(e1))       )
+              goto Next_Dropout;
+
+            if ( ras.dropout_mode == 2 )
+              e1 = e2;
+            else
+              e1 = CEILING( (x1+x2+1)/2 );
+                    
+            break;
+
+          default:
+            goto Next_Dropout;  /* Unsupported mode */
+          }
+        }
+        else
+          goto Next_Dropout;
+      }
+
+      ras.Proc_Set_Pixel( RAS_VARS y, 
+                                   TRUNC(e1), 
+                                   (x2-x1 >= ras.precision_half) & 1 );
+    Next_Dropout:
+    
+      dropouts--;
+    }
+    goto Next_Line;
+  }
+
+
+
+/****************************************************************************/
+/*                                                                          */
+/* Function:    Render_Single_Pass                                          */
+/*                                                                          */
+/* Description: Performs one sweep with sub-banding.                        */
+/*                                                                          */
+/* Input:       _XCoord, _YCoord : x and y coordinates arrays               */
+/*                                                                          */
+/* Returns:     SUCCESS on success                                          */
+/*              FAILURE if any error was encountered during render.         */
+/*                                                                          */
+/****************************************************************************/
+
+  static 
+  int  Render_Single_Pass( RAS_ARGS  int  flipped )
+  {
+    int  i, j, k;
+
+    ras.flipped = flipped;
+
+    while ( ras.band_top >= 0 )
+    {
+      ras.maxY = ((long)ras.band_stack[ras.band_top].y_max <<
+                    (ras.scale_shift+6))-1;
+
+      ras.minY = (long)ras.band_stack[ras.band_top].y_min <<
+                    (ras.scale_shift+6);
+
+      ras.cursor = ras.pool;
+      ras.error  = 0;
+
+      if ( Convert_Glyph( RAS_VARS  ras.outline ) )
+      {
+        if ( ras.error != ErrRaster_Overflow ) return FAILURE;
+        ras.error = ErrRaster_Ok;
+
+        /* sub-banding */
+
+#ifdef DEBUG_RASTER
+        ClearBand( RAS_VARS  TRUNC( ras.minY ), TRUNC( ras.maxY ) );
+#endif
+
+        i = ras.band_stack[ras.band_top].y_min;
+        j = ras.band_stack[ras.band_top].y_max;
+
+        k = ( j-i ) >> 1;
+
+        if ( ras.band_top >= 7 || k == 0 )
+        {
+          ras.band_top     = 0;
+          ras.error = ErrRaster_Invalid_Outline;
+          return ras.error;
+        }
+
+        ras.band_stack[ras.band_top+1].y_min = i + k;
+        ras.band_stack[ras.band_top+1].y_max = j;
+
+        ras.band_stack[ras.band_top].y_max = i + k;
+
+        ras.band_top++;
+      }
+      else
+      {
+        if ( ras.start_prof )
+          if ( Draw_Sweep( RAS_VAR ) ) return ras.error;
+        ras.band_top--;
+      }
+    }
+
+    return 0;  /* success */
+  }
+
+
+#if 0
+  void  Compute_BBox( FT_Outline*  outline,
+                      FT_BBox*     bbox )
+  {
+    int         n;
+    FT_Vector*  vec;
+    
+    vec   = outline->points;
+    bbox->xMin = bbox->xMax = vec->x;
+    bbox->yMin = bbox->yMax = vec->y;
+
+    n = outline->n_points-1;
+    while ( n > 0 )
+    {
+      FT_Pos  x, y;
+      
+      vec++;     
+       
+      x = vec->x;
+      if ( bbox->xMin > x ) bbox->xMin = x;
+      if ( bbox->xMax < x ) bbox->xMax = x;
+      
+      y = vec->y;
+      if ( bbox->yMin > y ) bbox->yMin = y;
+      if ( bbox->yMax < y ) bbox->yMax = y;
+      
+      n--;
+    }
+  }
+#endif
+
+  static
+  int  Raster_Render1( FT_Raster       raster )
+  {
+    int  error;
+    long byte_len;
+
+    byte_len = ras.target.pitch;
+    if (byte_len < 0) byte_len = -byte_len;
+    
+    if ( ras.target.width > byte_len*8 )
+      return ErrRaster_Invalid_Map;
+    
+    ras.scale_shift  = (ras.precision_bits-6);
+
+    /* Vertical Sweep */
+    ras.band_top            = 0;
+    ras.band_stack[0].y_min = 0;
+    ras.band_stack[0].y_max = ras.target.rows;
+
+    ras.Proc_Sweep_Init = Vertical_Sweep_Init;
+    ras.Proc_Sweep_Span = Vertical_Sweep_Span;
+    ras.Proc_Sweep_Step = Vertical_Sweep_Step;
+    ras.Proc_Test_Pixel = Vertical_Test_Pixel;
+    ras.Proc_Set_Pixel  = Vertical_Set_Pixel;
+
+    ras.bit_width  = ras.target.width;
+    ras.bit_buffer = (unsigned char*)ras.target.buffer;
+
+    if ( (error = Render_Single_Pass( RAS_VARS 0 )) != 0 )
+      return error;
+
+    /* Horizontal Sweep */
+
+    if ( ras.second_pass && ras.dropout_mode != 0 )
+    {
+      ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
+      ras.Proc_Sweep_Span = Horizontal_Sweep_Span;
+      ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
+      ras.Proc_Test_Pixel = Horizontal_Test_Pixel;
+      ras.Proc_Set_Pixel  = Horizontal_Set_Pixel;
+
+      ras.band_top            = 0;
+      ras.band_stack[0].y_min = 0;
+      ras.band_stack[0].y_max = ras.target.width - 1;
+
+      if ( (error = Render_Single_Pass( RAS_VARS  1 )) != 0 )
+        return error;
+    }
+
+    return ErrRaster_Ok;
+  }
+
+
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIAS
+  static
+  int  Raster_Render8( FT_Raster       raster )
+  {
+    int  error;
+    long byte_len;
+    
+    byte_len = ras.target.pitch;
+    if (byte_len < 0) byte_len = -byte_len;
+    
+    if ( ras.target.width > byte_len )
+      return ErrRaster_Invalid_Map;
+
+    /* Vertical Sweep */
+    ras.band_top            = 0;
+    ras.band_stack[0].y_min = 0;
+    ras.band_stack[0].y_max = ras.target.rows;
+
+#if !defined(FT_RASTER_ANTI_ALIAS_5) && !defined(FT_RASTER_ANTI_ALIAS_17)
+    return ErrRaster_Unimplemented;
+#endif
+
+#ifdef FT_RASTER_ANTI_ALIAS_5
+    if ( ras.grays_count == 5 )
+    {
+      ras.scale_shift  = (ras.precision_bits-5);
+      ras.bit_width    = ras.gray_width/2;
+      if ( ras.bit_width > (ras.target.width+3)/4 )
+        ras.bit_width = (ras.target.width+3)/4;
+    
+      ras.bit_width  = ras.bit_width * 8;
+      ras.bit_buffer = (unsigned char*)ras.gray_lines;
+      ras.pix_buffer = (unsigned char*)ras.target.buffer;
+    
+      ras.Proc_Sweep_Init = Vertical_Gray5_Sweep_Init;
+      ras.Proc_Sweep_Span = Vertical_Gray5_Sweep_Span;
+      ras.Proc_Sweep_Step = Vertical_Gray5_Sweep_Step;
+      ras.Proc_Test_Pixel = Vertical_Gray5_Test_Pixel;
+      ras.Proc_Set_Pixel  = Vertical_Gray5_Set_Pixel;
+    }
+#endif
+
+#ifdef FT_RASTER_ANTI_ALIAS_17
+    if ( ras.grays_count == 17 )
+    {
+      ras.scale_shift  = (ras.precision_bits-4);
+      ras.bit_width    = ras.gray_width/4;
+      if ( ras.bit_width > (ras.target.width+1)/2 )
+        ras.bit_width = (ras.target.width+1)/2;
+    
+      ras.bit_width  = ras.bit_width * 8;
+      ras.bit_buffer = (unsigned char*)ras.gray_lines;
+      ras.pix_buffer = (unsigned char*)ras.target.buffer;
+    
+      ras.Proc_Sweep_Init = Vertical_Gray17_Sweep_Init;
+      ras.Proc_Sweep_Span = Vertical_Gray17_Sweep_Span;
+      ras.Proc_Sweep_Step = Vertical_Gray17_Sweep_Step;
+      ras.Proc_Test_Pixel = Vertical_Gray17_Test_Pixel;
+      ras.Proc_Set_Pixel  = Vertical_Gray17_Set_Pixel;
+    }
+#endif
+
+    error = Render_Single_Pass( RAS_VARS  0 );
+    if (error)
+      return error;
+
+    /* Horizontal Sweep */
+
+    if ( ras.second_pass && ras.dropout_mode != 0 )
+    {
+#ifdef FT_RASTER_ANTI_ALIAS_5
+      if ( ras.grays_count == 5 )
+      {
+        ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
+        ras.Proc_Sweep_Span = Horizontal_Gray5_Sweep_Span;
+        ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
+        ras.Proc_Test_Pixel = Horizontal_Gray5_Test_Pixel;
+        ras.Proc_Set_Pixel  = Horizontal_Gray5_Set_Pixel;
+      }
+#endif
+      
+#ifdef FT_RASTER_ANTI_ALIAS_17
+      if ( ras.grays_count == 17 )
+      {
+        ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
+        ras.Proc_Sweep_Span = Horizontal_Gray17_Sweep_Span;
+        ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
+        ras.Proc_Test_Pixel = Horizontal_Gray17_Test_Pixel;
+        ras.Proc_Set_Pixel  = Horizontal_Gray17_Set_Pixel;
+      }
+#endif
+      ras.band_top            = 0;
+      ras.band_stack[0].y_min = 0;
+      ras.band_stack[0].y_max = ras.target.width-1;
+
+      error = Render_Single_Pass( RAS_VARS  1 );
+      if (error)
+        return error;
+    }
+
+    return ErrRaster_Ok;
+  }
+
+#else  /* ANTI_ALIAS */
+
+  static
+  int  Raster_Render8( FT_Raster       raster )
+  {
+    return ErrRaster_Unimplemented;
+  }
+
+#endif /* FT_RASTER_OPTION_ANTI_ALIAS */
+
+
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIAS
+/****************************************************************************/
+/*                                                                          */
+/* <Function>   Reset_Palette_5                                             */
+/*                                                                          */
+/* <Description> Resets lookup table when the 5-gray-levels palette changes */
+/*                                                                          */
+/****************************************************************************/
+
+static
+void  Reset_Palette_5( RAS_ARG )
+{
+  int  i;
+
+  for ( i = 0; i < 256; i++ )
+  {
+    int  cnt1, cnt2;
+    
+    cnt1 = ((i & 128) >> 7) +
+           ((i & 64)  >> 6) +
+           ((i & 8)   >> 3) +
+           ((i & 4)   >> 2);
+           
+    cnt2 = ((i & 32) >> 5) +
+           ((i & 16) >> 4) +
+           ((i & 2)  >> 1) +
+            (i & 1);
+
+  /*                                                                 */
+  /* Note that when the endianess isn't specified through one of the */
+  /* configuration, we use the big-endian storage in 'count_table'   */
+  /*                                                                 */
+
+#if defined( FT_RASTER_LITTLE_ENDIAN )
+    ras.count_table[i] = (ras.grays[cnt2] << 8) | ras.grays[cnt1];
+#else
+    ras.count_table[i] = (ras.grays[cnt1] << 8) | ras.grays[cnt2];
+#endif
+  }
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* <Function>    Reset_Palette_17                                           */
+/*                                                                          */
+/* <Description> Resets lookup table when 17-gray-levels palette changes    */
+/*                                                                          */
+/****************************************************************************/
+
+#ifdef FT_RASTER_ANTI_ALIAS_17
+static
+void  Reset_Palette_17( RAS_ARG )
+{
+  int  i;
+
+  for ( i = 0; i < 256; i++ )
+    ras.count_table[i] = 
+           ((i & 128) >> 7) +
+           ((i & 64)  >> 6) +
+           ((i & 8)   >> 3) +
+           ((i & 4)   >> 2) +
+           ((i & 32)  >> 5) +
+           ((i & 16)  >> 4) +
+           ((i & 2)   >> 1) +
+            (i & 1);
+}
+#endif /* ANTI_ALIAS_17 */
+
+#endif /* TT_RASTER_OPTION_ANTI_ALIAS */
+
+
+
+  /**********************************************************************/
+  /*                                                                    */
+  /* <Function> FT_Raster_SetPalette                                    */
+  /*                                                                    */
+  /* <Description>                                                      */
+  /*     Set the pixmap rendering palette. anti-aliasing modes are      */
+  /*     implemented/possible, they differ from the number of           */
+  /*     entries in the palette.                                        */
+  /*                                                                    */
+  /* <Input>                                                            */
+  /*     count   :: the number of palette entries. Valid values are     */
+  /*                2, 5 and 17, which are the number of intermediate   */
+  /*                gray levels supported                               */
+  /*                                                                    */
+  /*     palette :: an array of 'count' chars giving the 8-bit palette  */
+  /*                of intermediate "gray" levels for anti-aliased      */
+  /*                rendering.                                          */
+  /*                                                                    */
+  /*         In all modes, palette[0] corresponds to the background,    */
+  /*         while palette[count-1] to the foreground. Hence, a count   */
+  /*         of 2 corresponds to no anti-aliasing; a count of 5 uses    */
+  /*         3 intermediate levels between the background and           */
+  /*         foreground, while a count of 17 uses 15 of them..          */
+  /*                                                                    */
+  /* <Return>                                                           */
+  /*     An error code, used as a FT_Error by the FreeType library.     */
+  /*                                                                    */
+  /* <Note>                                                             */
+  /*     By default, a new object uses mode 5, with a palette of        */
+  /*     0,1,2,3 and 4. You don't need to set the palette if you        */
+  /*     don't need to render pixmaps..                                 */
+  /*                                                                    */
+  /**********************************************************************/
+
+  EXPORT_FUNC
+  int   FT_Raster_SetPalette( FT_Raster    raster,
+                              int          count,
+                              const char*  palette )
+  {
+    switch (count)
+    {
+#ifdef FT_RASTER_OPTION_ANTI_ALIAS
+
+      /******************************/
+      /* The case of 17 gray levels */
+      /******************************/
+    
+      case 17:
+#ifdef FT_RASTER_ANTI_ALIAS_17
+      {
+        int  n;
+        
+        raster->grays_count = count;
+        for ( n = 0; n < count; n++ )
+          raster->grays[n] = (unsigned char)palette[n];
+        Reset_Palette_17( RAS_VAR );
+        break;
+      }
+#else
+      return ErrRaster_Unimplemented;
+#endif
+
+      /*****************************/
+      /* The case of 5 gray levels */
+      /*****************************/
+
+      case 5:      
+#ifdef FT_RASTER_ANTI_ALIAS_5
+      {
+        int  n;
+        
+        raster->grays_count = count;
+        for ( n = 0; n < count; n++ )
+          raster->grays[n] = (unsigned char)palette[n];
+        Reset_Palette_5( RAS_VAR );
+        break;
+      }
+#else
+      return ErrRaster_Unimplemented;
+#endif
+
+#endif /* FT_RASTER_OPTION_ANTI_ALIAS */
+      default:
+        return ErrRaster_Bad_Palette_Count;
+    }
+
+    return ErrRaster_Ok;
+  }  
+
+
+  /**** RASTER OBJECT CREATION : in standalone mode, we simply use *****/
+  /****                          a static object ..                *****/
+#ifdef _STANDALONE_
+
+  static
+  int  ft_black2_new( void*  memory, FT_Raster *araster )
+  {
+     static FT_RasterRec_  the_raster;
+     *araster = &the_raster;  
+     memset( &the_raster, sizeof(the_raster), 0 );
+     return 0;
+  }
+
+  static
+  void  ft_black2_done( FT_Raster  raster )
+  {
+    /* nothing */
+    raster->init = 0;
+  }
+
+#else
+
+#include <ftobjs.h>
+
+  static
+  int  ft_black2_new( FT_Memory  memory, FT_Raster  *araster )
+  {
+    FT_Error   error;
+    FT_Raster  raster;
+    
+    *araster = 0;
+    if ( !ALLOC( raster, sizeof(*raster) ))
+    {
+      raster->memory = memory;
+      *araster = raster;
+    }
+      
+    return error;
+  }
+  
+  static
+  void ft_black2_done( FT_Raster  raster )
+  {
+    FT_Memory  memory = (FT_Memory)raster->memory;
+    FREE( raster );
+  }
+  
+#endif
+
+
+  static void ft_black2_reset( FT_Raster         raster,
+                               const char*       pool_base,
+                               long              pool_size )
+  {
+    static const char  default_palette[5] = { 0, 1, 2, 3, 4 };
+  
+    /* check the object address */
+    if ( !raster )
+      return;
+      
+    /* check the render pool - we won't go under 4 Kb */
+    if ( !pool_base || pool_size < 4096 )
+      return;
+    
+    /* save the pool */
+    raster->pool      = (PPos)pool_base;
+    raster->pool_size = (PPos)(pool_base + (pool_size & -8));
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIAS
+    raster->gray_width = ANTI_ALIAS_BUFFER_SIZE/2;
+    /* clear anti-alias intermediate lines */
+    {
+      char*  p    = raster->gray_lines;
+      int    size = ANTI_ALIAS_BUFFER_SIZE;
+      do
+      {
+        *p++ = 0;
+        size--;
+
+      } while (size > 0);
+    }
+#endif
+    
+    /* set the default palette : 5 levels =  0, 1, 2, 3 and 4 */
+    FT_Raster_SetPalette( raster, 5, default_palette );
+  }
+
+
+  static
+  int  ft_black2_render( FT_Raster          raster,
+                         FT_Raster_Params*  params )
+  {
+    FT_Outline*  outline    = (FT_Outline*)params->source;
+    FT_Bitmap*   target_map = params->target;
+    
+    if ( !raster || !raster->pool || !raster->pool_size )
+      return ErrRaster_Uninitialised_Object;
+
+    if ( !outline || !outline->contours || !outline->points )
+      return ErrRaster_Invalid_Outline;
+
+    /* return immediately if the outline is empty */
+    if ( outline->n_points == 0 || outline->n_contours <= 0 )
+      return ErrRaster_Invalid_Outline;
+
+    if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 )
+      return ErrRaster_Invalid_Outline;
+
+    if ( !target_map || !target_map->buffer )
+      return ErrRaster_Invalid_Map;
+
+    /* this version of the raster does not support direct rendering, sorry */
+    if ( params->flags & ft_raster_flag_direct )
+      return ErrRaster_Unimplemented;
+
+    ras.outline  = outline;
+    ras.target   = *target_map;
+
+    ras.dropout_mode = 2;
+    ras.second_pass  = !(outline->flags & ft_outline_single_pass);
+    SET_High_Precision( (outline->flags & ft_outline_high_precision) );
+
+    return ( params->flags & ft_raster_flag_aa
+           ? Raster_Render8(raster)
+           : Raster_Render1(raster) );
+  }
+
+
+  FT_Raster_Funcs      ft_black2_raster =
+  {
+    ft_glyph_format_outline,
+    (FT_Raster_New_Func)       ft_black2_new,
+    (FT_Raster_Reset_Func)     ft_black2_reset,
+    (FT_Raster_Set_Mode_Func)  0,
+    (FT_Raster_Render_Func)    ft_black2_render,
+    (FT_Raster_Done_Func)      ft_black2_done
+  };
+
+
--- /dev/null
+++ b/demos/src/ftrast2.h
@@ -1,0 +1,42 @@
+/*******************************************************************
+ *
+ *  ftraster.h                                                 v 2.0
+ *
+ *  The FreeType glyph scan-line converter (interface)
+ *
+ *  Copyright 1996-2000 by
+ *  David Turner, Robert Wilhelm, and Werner Lemberg
+ *
+ *  This file is part of the FreeType project, and may only be used
+ *  modified and distributed under the terms of the FreeType project
+ *  license, LICENSE.TXT. By continuing to use, modify, or distribute
+ *  this file you indicate that you have read the license and
+ *  understand and accept it fully.
+ *
+ *
+ ******************************************************************/
+
+#ifndef FTRAST2_H
+#define FTRAST2_H
+
+#include <ftimage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef EXPORT_DEF
+#define EXPORT_DEF  /* nothing */
+#endif
+
+  EXPORT_DEF
+  FT_Raster_Funcs   ft_black2_raster;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FTRAST2_H */
+
+
+/* END */
--- a/demos/src/ftview.c
+++ b/demos/src/ftview.c
@@ -28,7 +28,7 @@
 #include "grfont.h"
 
 #include "ftgrays.h"
-#include "ftrast.h"
+#include "ftrast2.h"
 
 #define  DIM_X   500
 #define  DIM_Y   400
@@ -425,7 +425,7 @@
     
     error = 1;
     if ( !antialias)
-      error = FT_Set_Raster( library, &ft_black_raster );
+      error = FT_Set_Raster( library, &ft_black2_raster );
       
     else if ( use_grays && antialias )
       error = FT_Set_Raster( library, &ft_grays_raster );