shithub: freetype+ttf2subf

Download patch

ref: 5ae1bad3f6f1c842a6f87d8c6e1e5c0237eb236b
parent: 314bf4a1f436586b38df09f4b87cdfbe6e7add37
author: David Turner <[email protected]>
date: Tue Jun 27 19:18:39 EDT 2000

added new renderer module

git/fs: mount .git/fs: mount/attach disallowed
--- /dev/null
+++ b/src/raster1/ftraster.c
@@ -1,0 +1,3270 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftraster.c                                                             */
+/*                                                                         */
+/*    The FreeType glyph rasterizer (body).                                */
+/*                                                                         */
+/*  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.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This is a rewrite of the FreeType 1.x scan-line converter             */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include "ftraster.h"
+#include <freetype/internal/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:   */
+  /*                                                                       */
+  /*   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 whether it 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.  Additionally, 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.                                    */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /**                                                                     **/
+  /**  CONFIGURATION MACROS                                               **/
+  /**                                                                     **/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* define DEBUG_RASTER if you want to compile a debugging version */
+#define xxxDEBUG_RASTER
+
+  /* The default render pool size in bytes */
+#define RASTER_RENDER_POOL  8192
+
+  /* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */
+  /* 5-levels anti-aliasing                                                */
+#ifdef xxxFT_CONFIG_OPTION_5_GRAY_LEVELS
+#define FT_RASTER_OPTION_ANTI_ALIASING
+#endif
+
+  /* The size of the two-lines intermediate bitmap used */
+  /* for anti-aliasing, in bytes.                       */
+#define RASTER_GRAY_LINES  2048
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /**                                                                     **/
+  /**  OTHER MACROS (do not change)                                       **/
+  /**                                                                     **/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_raster
+
+
+#ifdef _STANDALONE_
+
+
+  /* This macro is used to indicate that a function parameter is unused. */
+  /* Its purpose is simply to reduce compiler warnings.  Note also that  */
+  /* simply defining it as `(void)x' doesn't avoid warnings with certain */
+  /* ANSI compilers (e.g. LCC).                                          */
+#define UNUSED( x )  (x) = (x)
+
+  /* Disable the tracing mechanism for simplicity -- developers can      */
+  /* activate it easily by redefining these two macros.                  */
+#ifndef FT_ERROR
+#define FT_ERROR( x )  do ; while ( 0 )     /* nothing */
+#endif
+
+#ifndef FT_TRACE
+#define FT_TRACE( x )  do ; while ( 0 )     /* nothing */
+#endif
+
+
+#else /* _STANDALONE_ */
+
+
+#include <freetype/internal/ftobjs.h>
+#include <freetype/internal/ftdebug.h> /* for FT_TRACE() and FT_ERROR() */
+
+
+#endif /* _STANDALONE_ */
+
+
+#define Raster_Err_None               0
+#define Raster_Err_Not_Ini           -1
+#define Raster_Err_Overflow          -2
+#define Raster_Err_Neg_Height        -3
+#define Raster_Err_Invalid           -4
+#define Raster_Err_Gray_Unsupported  -5
+#define Raster_Err_Unsupported       -6
+
+  /* FMulDiv means `Fast MulDiv', it is used in case where `b' is       */
+  /* typically a small value and the result of a*b is known to fit into */
+  /* 32 bits.                                                           */
+#define FMulDiv( a, b, c )  ( (a) * (b) / (c) )
+
+  /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
+  /* for clipping computations.  It simply uses the FT_MulDiv() function   */
+  /* defined in `ftcalc.h'.                                                */
+#define SMulDiv  FT_MulDiv
+
+  /* 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
+
+#ifndef SUCCESS
+#define SUCCESS  0
+#endif
+
+#ifndef FAILURE
+#define FAILURE  1
+#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 */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /**                                                                     **/
+  /**  SIMPLE TYPE DECLARATIONS                                           **/
+  /**                                                                     **/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  typedef int             Int;
+  typedef unsigned int    UInt;
+  typedef short           Short;
+  typedef unsigned short  UShort, *PUShort;
+  typedef long            Long, *PLong;
+  typedef unsigned long   ULong;
+
+  typedef unsigned char   Byte, *PByte;
+  typedef char            Bool;
+
+  typedef struct  TPoint_
+  {
+    Long  x;
+    Long  y;
+
+  } TPoint;
+
+
+  typedef enum  TFlow_
+  {
+    Flow_None = 0,
+    Flow_Up   = 1,
+    Flow_Down = -1
+
+  } TFlow;
+
+
+  /* States of each line, arc, and profile */
+  typedef enum  TStates_
+  {
+    Unknown,
+    Ascending,
+    Descending,
+    Flat
+
+  } TStates;
+
+
+  typedef struct TProfile_  TProfile;
+  typedef TProfile*         PProfile;
+
+  struct  TProfile_
+  {
+    FT_F26Dot6  X;           /* current coordinate during sweep        */
+    PProfile    link;        /* link to next profile - various purpose */
+    PLong       offset;      /* start of profile's data in render pool */
+    Int         flow;        /* Profile orientation: Asc/Descending    */
+    Long        height;      /* profile's height in scanlines          */
+    Long        start;       /* profile's starting scanline            */
+
+    UShort      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                               */
+  typedef struct  TBand_
+  {
+    Short  y_min;   /* band's minimum */
+    Short  y_max;   /* band's maximum */
+
+  } TBand;
+
+
+#define AlignProfileSize \
+          ( ( sizeof ( TProfile ) + sizeof ( long ) - 1 ) / sizeof ( long ) )
+
+
+#ifdef TT_STATIC_RASTER
+
+#define RAS_ARGS       /* void */
+#define RAS_ARG        /* void */
+
+#define RAS_VARS       /* void */
+#define RAS_VAR        /* void */
+
+#define UNUSED_RASTER  do ; while ( 0 )
+
+#else /* TT_STATIC_RASTER */
+
+#define RAS_ARGS       TRaster_Instance*  raster,
+#define RAS_ARG        TRaster_Instance*  raster
+
+#define RAS_VARS       raster,
+#define RAS_VAR        raster
+
+#define UNUSED_RASTER  UNUSED( raster )
+
+#endif /* TT_STATIC_RASTER */
+
+
+  typedef struct TRaster_Instance_  TRaster_Instance;
+
+
+  /* prototypes used for sweep function dispatch */
+  typedef void  Function_Sweep_Init( RAS_ARGS Short*  min,
+                                              Short*  max );
+
+  typedef void  Function_Sweep_Span( RAS_ARGS Short       y,
+                                              FT_F26Dot6  x1,
+                                              FT_F26Dot6  x2,
+                                              PProfile    left,
+                                              PProfile    right );
+
+  typedef void  Function_Sweep_Step( RAS_ARG );
+
+
+  /* NOTE: These operations are only valid on 2's complement processors */
+
+#define FLOOR( x )    ( (x) & -ras.precision )
+#define CEILING( x )  ( ( (x) + ras.precision - 1 ) & -ras.precision )
+#define TRUNC( x )    ( (signed long)(x) >> ras.precision_bits )
+#define FRAC( x )     ( (x) & ( ras.precision - 1 ) )
+#define SCALED( x )   ( ( (x) << ras.scale_shift ) - ras.precision_half )
+
+  /* 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  TRaster_Instance_
+  {
+    Int       precision_bits;       /* precision related variables         */
+    Int       precision;
+    Int       precision_half;
+    Long      precision_mask;
+    Int       precision_shift;
+    Int       precision_step;
+    Int       precision_jitter;
+
+    Int       scale_shift;          /* == precision_shift   for bitmaps    */
+                                    /* == precision_shift+1 for pixmaps    */
+
+    PLong     buff;                 /* The profiles buffer                 */
+    PLong     sizeBuff;             /* Render pool size                    */
+    PLong     maxBuff;              /* Profiles buffer size                */
+    PLong     top;                  /* Current cursor in buffer            */
+
+    FT_Error  error;
+
+    Int       numTurns;             /* number of Y-turns in outline        */
+
+    TPoint*   arc;                  /* current Bezier arc pointer          */
+
+    UShort    bWidth;               /* target bitmap width                 */
+    PByte     bTarget;              /* target bitmap buffer                */
+    PByte     gTarget;              /* target pixmap buffer                */
+
+    Long      lastX, lastY, minY, maxY;
+
+    UShort    num_Profs;            /* current number of profiles          */
+
+    Bool      fresh;                /* signals a fresh new profile which   */
+                                    /* 'start' field must be completed     */
+    Bool      joint;                /* signals that the last arc ended     */
+                                    /* exactly on a scanline.  Allows      */
+                                    /* removal of doublets                 */
+    PProfile  cProfile;             /* current profile                     */
+    PProfile  fProfile;             /* head of linked list of profiles     */
+    PProfile  gProfile;             /* contour's first profile in case     */
+                                    /* of impact                           */
+    TStates   state;                /* rendering state                     */
+
+    FT_Bitmap   target;             /* description of target bit/pixmap    */
+    FT_Outline  outline;
+
+    Long      traceOfs;             /* current offset in target bitmap     */
+    Long      traceG;               /* current offset in target pixmap     */
+
+    Short     traceIncr;            /* sweep's increment in target bitmap  */
+
+    Short     gray_min_x;           /* current min x during gray rendering */
+    Short     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_Span*  Proc_Sweep_Drop;
+    Function_Sweep_Step*  Proc_Sweep_Step;
+
+    Byte      dropOutControl;       /* current drop_out control method     */
+
+    Bool      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.                          */
+    TPoint    arcs[2 * MaxBezier + 1]; /* The Bezier stack                 */
+
+    TBand     band_stack[16];       /* band stack used for sub-banding     */
+    Int       band_top;             /* band stack top                      */
+
+    Int       count_table[256];     /* Look-up table used to quickly count */
+                                    /* set bits in a gray 2x2 cell         */
+
+    void*     memory;
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+    Byte      grays[5];             /* Palette of gray levels used for     */
+                                    /* render.                             */
+
+    Byte      gray_lines[RASTER_GRAY_LINES];
+                                /* Intermediate table used to render the   */
+                                /* graylevels pixmaps.                     */
+                                /* gray_lines is a buffer holding two      */
+                                /* monochrome scanlines                    */
+    Short     gray_width;       /* width in bytes of one monochrome        */
+                                /* intermediate scanline of gray_lines.    */
+                                /* Each gray pixel takes 2 bits long there */
+
+                       /* The gray_lines must hold 2 lines, thus with size */
+                       /* in bytes of at least `gray_width*2'.             */
+
+#endif /* FT_RASTER_ANTI_ALIASING */
+
+#if 0
+    PByte       flags;              /* current flags table                 */
+    PUShort     outs;               /* current outlines table              */
+    FT_Vector*  coords;
+
+    UShort      nPoints;            /* number of points in current glyph   */
+    Short       nContours;          /* number of contours in current glyph */
+#endif
+
+  };
+
+
+#ifdef FT_CONFIG_OPTION_STATIC_RASTER
+
+  static TRaster_Instance  cur_ras;
+#define ras  cur_ras
+
+#else
+
+#define ras  (*raster)
+
+#endif /* FT_CONFIG_OPTION_STATIC_RASTER */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /**                                                                     **/
+  /**  PROFILES COMPUTATION                                               **/
+  /**                                                                     **/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <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;
+    }
+
+    FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
+
+    ras.precision       = 1L << 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 :: The state/orientation of the new profile.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*   SUCCESS on success.  FAILURE in case of overflow or of incoherent   */
+  /*   profile.                                                            */
+  /*                                                                       */
+  static
+  Bool  New_Profile( RAS_ARGS TStates  aState )
+  {
+    if ( !ras.fProfile )
+    {
+      ras.cProfile  = (PProfile)ras.top;
+      ras.fProfile  = ras.cProfile;
+      ras.top      += AlignProfileSize;
+    }
+
+    if ( ras.top >= ras.maxBuff )
+    {
+      ras.error = Raster_Err_Overflow;
+      return FAILURE;
+    }
+
+    switch ( aState )
+    {
+    case Ascending:
+      ras.cProfile->flow = Flow_Up;
+      FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile ));
+      break;
+
+    case Descending:
+      ras.cProfile->flow = Flow_Down;
+      FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile ));
+      break;
+
+    default:
+      FT_ERROR(( "New_Profile: invalid profile direction!\n" ));
+      ras.error = Raster_Err_Invalid;
+      return FAILURE;
+    }
+
+    ras.cProfile->start  = 0;
+    ras.cProfile->height = 0;
+    ras.cProfile->offset = ras.top;
+    ras.cProfile->link   = (PProfile)0;
+    ras.cProfile->next   = (PProfile)0;
+
+    if ( !ras.gProfile )
+      ras.gProfile = ras.cProfile;
+
+    ras.state = aState;
+    ras.fresh = TRUE;
+    ras.joint = FALSE;
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    End_Profile                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finalizes the current profile.                                     */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success.  FAILURE in case of overflow or incoherency.   */
+  /*                                                                       */
+  static
+  Bool  End_Profile( RAS_ARG )
+  {
+    Long      h;
+    PProfile  oldProfile;
+
+
+    h = ras.top - ras.cProfile->offset;
+
+    if ( h < 0 )
+    {
+      FT_ERROR(( "End_Profile: negative height encountered!\n" ));
+      ras.error = Raster_Err_Neg_Height;
+      return FAILURE;
+    }
+
+    if ( h > 0 )
+    {
+      FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n",
+                  (long)ras.cProfile, ras.cProfile->start, h ));
+
+      oldProfile           = ras.cProfile;
+      ras.cProfile->height = h;
+      ras.cProfile         = (PProfile)ras.top;
+
+      ras.top             += AlignProfileSize;
+
+      ras.cProfile->height = 0;
+      ras.cProfile->offset = ras.top;
+      oldProfile->next     = ras.cProfile;
+      ras.num_Profs++;
+    }
+
+    if ( ras.top >= ras.maxBuff )
+    {
+      FT_TRACE1(( "overflow in End_Profile\n" ));
+      ras.error = Raster_Err_Overflow;
+      return FAILURE;
+    }
+
+    ras.joint = FALSE;
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Insert_Y_Turn                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Inserts a salient into the sorted list placed on top of the render */
+  /*    pool.                                                              */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    New y scanline position.                                           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success.  FAILURE in case of overflow.                  */
+  /*                                                                       */
+  static
+  Bool  Insert_Y_Turn( RAS_ARGS Int  y )
+  {
+    PLong     y_turns;
+    Int       y2, n;
+
+
+    n       = ras.numTurns - 1;
+    y_turns = ras.sizeBuff - ras.numTurns;
+
+    /* 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 )
+    {
+      if ( ras.maxBuff <= ras.top )
+      {
+        ras.error = Raster_Err_Overflow;
+        return FAILURE;
+      }
+      ras.maxBuff--;
+      ras.numTurns++;
+      ras.sizeBuff[-ras.numTurns] = y;
+    }
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Finalize_Profile_Table                                             */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Adjusts all links in the profiles list.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success.  FAILURE in case of overflow.                  */
+  /*                                                                       */
+  static
+  Bool  Finalize_Profile_Table( RAS_ARG )
+  {
+    Int       bottom, top;
+    UShort    n;
+    PProfile  p;
+
+
+    n = ras.num_Profs;
+
+    if ( n > 1 )
+    {
+      p = ras.fProfile;
+      while ( n > 0 )
+      {
+        if ( n > 1 )
+          p->link = (PProfile)( p->offset + p->height );
+        else
+          p->link = NULL;
+
+        switch ( p->flow )
+        {
+        case Flow_Down:
+          bottom     = p->start - p->height+1;
+          top        = p->start;
+          p->start   = bottom;
+          p->offset += p->height - 1;
+          break;
+
+        case 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.fProfile = NULL;
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Split_Conic                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Subdivides one conic Bezier into two joint sub-arcs in the Bezier  */
+  /*    stack.                                                             */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    None (subdivided Bezier is taken from the top of the stack).       */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    This routine is the `beef' of this component.  It is  _the_ inner  */
+  /*    loop that should be optimized to hell to get the best performance. */
+  /*                                                                       */
+  static
+  void  Split_Conic( TPoint*  base )
+  {
+    Long     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;
+
+    /* hand optimized.  gcc doesn't seem too good at common expression */
+    /* substitution and instruction scheduling ;-)                     */
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <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 )
+  {
+    Long  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 + 1 ) >> 1;
+    base[5].x = b = ( base[3].x + d + 1 ) >> 1;
+    c = ( c + d + 1 ) >> 1;
+    base[2].x = a = ( a + c + 1 ) >> 1;
+    base[4].x = b = ( b + c + 1 ) >> 1;
+    base[3].x = ( a + b + 1 ) >> 1;
+
+    base[6].y = base[3].y;
+    c = base[1].y;
+    d = base[2].y;
+    base[1].y = a = ( base[0].y + c + 1 ) >> 1;
+    base[5].y = b = ( base[3].y + d + 1 ) >> 1;
+    c = ( c + d + 1 ) >> 1;
+    base[2].y = a = ( a + c + 1 ) >> 1;
+    base[4].y = b = ( b + c + 1 ) >> 1;
+    base[3].y = ( a + b + 1 ) >> 1;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Line_Up                                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the x-coordinates of an ascending line segment and stores */
+  /*    them in the render pool.                                           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    x1   :: The x-coordinate of the segment's start point.             */
+  /*                                                                       */
+  /*    y1   :: The y-coordinate of the segment's start point.             */
+  /*                                                                       */
+  /*    x2   :: The x-coordinate of the segment's end point.               */
+  /*                                                                       */
+  /*    y2   :: The y-coordinate of the segment's end point.               */
+  /*                                                                       */
+  /*    miny :: A lower vertical clipping bound value.                     */
+  /*                                                                       */
+  /*    maxy :: An upper vertical clipping bound value.                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success, FAILURE on render pool overflow.               */
+  /*                                                                       */
+  static
+  Bool  Line_Up( RAS_ARGS Long  x1, Long  y1,
+                          Long  x2, Long  y2,
+                          Long  miny, Long  maxy )
+  {
+    Long   Dx, Dy;
+    Int    e1, e2, f1, f2, size;     /* XXX: is `Short' sufficient? */
+    Long   Ix, Rx, Ax;
+
+    PLong  top;
+
+
+    Dx = x2 - x1;
+    Dy = y2 - y1;
+
+    if ( Dy <= 0 || y2 < miny || y1 > maxy )
+      return SUCCESS;
+
+    if ( y1 < miny )
+    {
+      /* Take care: miny-y1 can be a very large value; we use     */
+      /*            a slow MulDiv function to avoid clipping bugs */
+      x1 += SMulDiv( 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.top--;
+        ras.joint = FALSE;
+      }
+
+    ras.joint = ( f2 == 0 );
+
+    if ( ras.fresh )
+    {
+      ras.cProfile->start = e1;
+      ras.fresh           = FALSE;
+    }
+
+    size = e2 - e1 + 1;
+    if ( ras.top + size >= ras.maxBuff )
+    {
+      ras.error = Raster_Err_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.top;
+
+    while ( size > 0 )
+    {
+      *top++ = x1;
+
+      x1 += Ix;
+      Ax += Rx;
+      if ( Ax >= 0 )
+      {
+        Ax -= Dy;
+        x1 += Dx;
+      }
+      size--;
+    }
+
+    ras.top = top;
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Line_Down                                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the x-coordinates of an descending line segment and       */
+  /*    stores them in the render pool.                                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    x1   :: The x-coordinate of the segment's start point.             */
+  /*                                                                       */
+  /*    y1   :: The y-coordinate of the segment's start point.             */
+  /*                                                                       */
+  /*    x2   :: The x-coordinate of the segment's end point.               */
+  /*                                                                       */
+  /*    y2   :: The y-coordinate of the segment's end point.               */
+  /*                                                                       */
+  /*    miny :: A lower vertical clipping bound value.                     */
+  /*                                                                       */
+  /*    maxy :: An upper vertical clipping bound value.                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success, FAILURE on render pool overflow.               */
+  /*                                                                       */
+  static
+  Bool  Line_Down( RAS_ARGS Long  x1, Long  y1,
+                            Long  x2, Long  y2,
+                            Long  miny, Long  maxy )
+  {
+    Bool  result, fresh;
+
+
+    fresh  = ras.fresh;
+
+    result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
+
+    if ( fresh && !ras.fresh )
+      ras.cProfile->start = -ras.cProfile->start;
+
+    return result;
+  }
+
+
+  /* A function type describing the functions used to split Bezier arcs */
+  typedef void  (*TSplitter)( TPoint*  base );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Bezier_Up                                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the x-coordinates of an ascending Bezier arc and stores   */
+  /*    them in the render pool.                                           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    degree   :: The degree of the Bezier arc (either 2 or 3).          */
+  /*                                                                       */
+  /*    splitter :: The function to split Bezier arcs.                     */
+  /*                                                                       */
+  /*    miny     :: A lower vertical clipping bound value.                 */
+  /*                                                                       */
+  /*    maxy     :: An upper vertical clipping bound value.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success, FAILURE on render pool overflow.               */
+  /*                                                                       */
+  static
+  Bool  Bezier_Up( RAS_ARGS Int        degree,
+                            TSplitter  splitter,
+                            Long       miny,
+                            Long       maxy )
+  {
+    Long   y1, y2, e, e2, e0;
+    Short  f1;
+
+    TPoint*  arc;
+    TPoint*  start_arc;
+
+    PLong top;
+
+
+    arc = ras.arc;
+    y1  = arc[degree].y;
+    y2  = arc[0].y;
+    top = ras.top;
+
+    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[degree].x;
+
+        e += ras.precision;
+      }
+    }
+
+    if ( ras.fresh )
+    {
+      ras.cProfile->start = TRUNC( e0 );
+      ras.fresh = FALSE;
+    }
+
+    if ( e2 < e )
+      goto Fin;
+
+    if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
+    {
+      ras.top   = top;
+      ras.error = Raster_Err_Overflow;
+      return FAILURE;
+    }
+
+    start_arc = arc;
+
+    while ( arc >= start_arc && e <= e2 )
+    {
+      ras.joint = FALSE;
+
+      y2 = arc[0].y;
+
+      if ( y2 > e )
+      {
+        y1 = arc[degree].y;
+        if ( y2 - y1 >= ras.precision_step )
+        {
+          splitter( arc );
+          arc += degree;
+        }
+        else
+        {
+          *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x,
+                                            e - y1, y2 - y1 );
+          arc -= degree;
+          e   += ras.precision;
+        }
+      }
+      else
+      {
+        if ( y2 == e )
+        {
+          ras.joint  = TRUE;
+          *top++     = arc[0].x;
+
+          e += ras.precision;
+        }
+        arc -= degree;
+      }
+    }
+
+  Fin:
+    ras.top  = top;
+    ras.arc -= degree;
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Bezier_Down                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the x-coordinates of an descending Bezier arc and stores  */
+  /*    them in the render pool.                                           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    degree   :: The degree of the Bezier arc (either 2 or 3).          */
+  /*                                                                       */
+  /*    splitter :: The function to split Bezier arcs.                     */
+  /*                                                                       */
+  /*    miny     :: A lower vertical clipping bound value.                 */
+  /*                                                                       */
+  /*    maxy     :: An upper vertical clipping bound value.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success, FAILURE on render pool overflow.               */
+  /*                                                                       */
+  static
+  Bool  Bezier_Down( RAS_ARGS Int        degree,
+                              TSplitter  splitter,
+                              Long       miny,
+                              Long       maxy )
+  {
+    TPoint*  arc = ras.arc;
+    Bool     result, fresh;
+
+
+    arc[0].y = -arc[0].y;
+    arc[1].y = -arc[1].y;
+    arc[2].y = -arc[2].y;
+    if ( degree > 2 )
+      arc[3].y = -arc[3].y;
+
+    fresh = ras.fresh;
+
+    result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny );
+
+    if ( fresh && !ras.fresh )
+      ras.cProfile->start = -ras.cProfile->start;
+
+    arc[0].y = -arc[0].y;
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Line_To                                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Injects a new line segment and adjusts Profiles list.              */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*   x :: The x-coordinate of the segment's end point (its start point   */
+  /*        is stored in `LastX').                                         */
+  /*                                                                       */
+  /*   y :: The y-coordinate of the segment's end point (its start point   */
+  /*        is stored in `LastY').                                         */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
+  /*   profile.                                                            */
+  /*                                                                       */
+  static
+  Bool  Line_To( RAS_ARGS Long  x,
+                          Long  y )
+  {
+    /* First, detect a change of direction */
+
+    switch ( ras.state )
+    {
+    case Unknown:
+      if ( y > ras.lastY )
+      {
+        if ( New_Profile( RAS_VARS Ascending ) )
+          return FAILURE;
+      }
+      else
+      {
+        if ( y < ras.lastY )
+          if ( New_Profile( RAS_VARS Descending ) )
+            return FAILURE;
+      }
+      break;
+
+    case Ascending:
+      if ( y < ras.lastY )
+      {
+        if ( End_Profile( RAS_VAR )             ||
+             New_Profile( RAS_VARS Descending ) )
+          return FAILURE;
+      }
+      break;
+
+    case Descending:
+      if ( y > ras.lastY )
+      {
+        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.lastX, ras.lastY,
+                     x, y, ras.minY, ras.maxY ) )
+        return FAILURE;
+      break;
+
+    case Descending:
+      if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
+                      x, y, ras.minY, ras.maxY ) )
+        return FAILURE;
+      break;
+
+    default:
+      ;
+    }
+
+    ras.lastX = x;
+    ras.lastY = y;
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Conic_To                                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Injects a new conic arc and adjusts the profile list.              */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*   cx :: The x-coordinate of the arc's new control point.              */
+  /*                                                                       */
+  /*   cy :: The y-coordinate of the arc's new control point.              */
+  /*                                                                       */
+  /*   x  :: The x-coordinate of the arc's end point (its start point is   */
+  /*         stored in `LastX').                                           */
+  /*                                                                       */
+  /*   y  :: The y-coordinate of the arc's end point (its start point is   */
+  /*         stored in `LastY').                                           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
+  /*   profile.                                                            */
+  /*                                                                       */
+  static
+  Bool  Conic_To( RAS_ARGS Long  cx,
+                           Long  cy,
+                           Long  x,
+                           Long  y )
+  {
+    Long     y1, y2, y3, x3, ymin, ymax;
+    TStates  state_bez;
+
+
+    ras.arc      = ras.arcs;
+    ras.arc[2].x = ras.lastX;
+    ras.arc[2].y = ras.lastY;
+    ras.arc[1].x = cx; ras.arc[1].y = cy;
+    ras.arc[0].x = x;  ras.arc[0].y = y;
+
+    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 )
+      {
+        ymin = y1;
+        ymax = y3;
+      }
+      else
+      {
+        ymin = y3;
+        ymax = y1;
+      }
+
+      if ( y2 < ymin || y2 > ymax )
+      {
+        /* this arc has no given direction, split it! */
+        Split_Conic( ras.arc );
+        ras.arc += 2;
+      }
+      else if ( y1 == y3 )
+      {
+        /* this arc is flat, ignore it and pop it from the Bezier stack */
+        ras.arc -= 2;
+      }
+      else
+      {
+        /* the arc is y-monotonous, either ascending or descending */
+        /* detect a change of direction                            */
+        state_bez = y1 < y3 ? Ascending : Descending;
+        if ( ras.state != state_bez )
+        {
+          /* finalize current profile if any */
+          if ( ras.state != Unknown   &&
+               End_Profile( RAS_VAR ) )
+            goto Fail;
+
+          /* create a new profile */
+          if ( New_Profile( RAS_VARS state_bez ) )
+            goto Fail;
+        }
+
+        /* now call the appropriate routine */
+        if ( state_bez == Ascending )
+        {
+          if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
+            goto Fail;
+        }
+        else
+          if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
+            goto Fail;
+      }
+
+    } while ( ras.arc >= ras.arcs );
+
+    ras.lastX = x3;
+    ras.lastY = y3;
+
+    return SUCCESS;
+
+  Fail:
+    return FAILURE;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Cubic_To                                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Injects a new cubic arc and adjusts the profile list.              */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*   cx1 :: The x-coordinate of the arc's first new control point.       */
+  /*                                                                       */
+  /*   cy1 :: The y-coordinate of the arc's first new control point.       */
+  /*                                                                       */
+  /*   cx2 :: The x-coordinate of the arc's second new control point.      */
+  /*                                                                       */
+  /*   cy2 :: The y-coordinate of the arc's second new control point.      */
+  /*                                                                       */
+  /*   x   :: The x-coordinate of the arc's end point (its start point is  */
+  /*          stored in `LastX').                                          */
+  /*                                                                       */
+  /*   y   :: The y-coordinate of the arc's end point (its start point is  */
+  /*          stored in `LastY').                                          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
+  /*   profile.                                                            */
+  /*                                                                       */
+  static
+  Bool  Cubic_To( RAS_ARGS Long  cx1,
+                           Long  cy1,
+                           Long  cx2,
+                           Long  cy2,
+                           Long  x,
+                           Long  y )
+  {
+    Long     y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2;
+    TStates  state_bez;
+
+
+    ras.arc      = ras.arcs;
+    ras.arc[3].x = ras.lastX;
+    ras.arc[3].y = ras.lastY;
+    ras.arc[2].x = cx1; ras.arc[2].y = cy1;
+    ras.arc[1].x = cx2; ras.arc[1].y = cy2;
+    ras.arc[0].x = x;   ras.arc[0].y = y;
+
+    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 )
+      {
+        ymin1 = y1;
+        ymax1 = y4;
+      }
+      else
+      {
+        ymin1 = y4;
+        ymax1 = y1;
+      }
+
+      if ( y2 <= y3 )
+      {
+        ymin2 = y2;
+        ymax2 = y3;
+      }
+      else
+      {
+        ymin2 = y3;
+        ymax2 = y2;
+      }
+
+      if ( ymin2 < ymin1 || ymax2 > ymax1 )
+      {
+        /* this arc has no given direction, split it! */
+        Split_Cubic( ras.arc );
+        ras.arc += 3;
+      }
+      else if ( y1 == y4 )
+      {
+        /* this arc is flat, ignore it and pop it from the Bezier stack */
+        ras.arc -= 3;
+      }
+      else
+      {
+        state_bez = y1 <= y4 ? Ascending : Descending;
+
+        /* detect a change of direction */
+        if ( ras.state != state_bez )
+        {
+          if ( ras.state != Unknown   &&
+               End_Profile( RAS_VAR ) )
+            goto Fail;
+
+          if ( New_Profile( RAS_VARS state_bez ) )
+            goto Fail;
+        }
+
+        /* compute intersections */
+        if ( state_bez == Ascending )
+        {
+          if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
+            goto Fail;
+        }
+        else
+          if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
+            goto Fail;
+      }
+
+    } while ( ras.arc >= ras.arcs );
+
+    ras.lastX = x4;
+    ras.lastY = y4;
+
+    return SUCCESS;
+
+  Fail:
+    return FAILURE;
+  }
+
+
+#undef  SWAP_
+#define SWAP_( x, y )  do                \
+                       {                 \
+                         Long  swap = x; \
+                                         \
+                                         \
+                         x = y;          \
+                         y = swap;       \
+                       } while ( 0 )
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Decompose_Curve                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Scans the outline arays in order to emit individual segments and   */
+  /*    Beziers by calling Line_To() and Bezier_To().  It handles all      */
+  /*    weird cases, like when the first point is off the curve, or when   */
+  /*    there are simply no `on' points in the contour!                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    first   :: The index of the first point in the contour.            */
+  /*                                                                       */
+  /*    last    :: The index of the last point in the contour.             */
+  /*                                                                       */
+  /*    flipped :: If set, flip the direction of the curve.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success, FAILURE on error.                              */
+  /*                                                                       */
+  static
+  Bool  Decompose_Curve( RAS_ARGS UShort  first,
+                                  UShort  last,
+                                  int     flipped )
+  {
+    FT_Vector   v_last;
+    FT_Vector   v_control;
+    FT_Vector   v_start;
+
+    FT_Vector*  points;
+    FT_Vector*  point;
+    FT_Vector*  limit;
+    char*       tags;
+
+    char        tag;       /* current point's state           */
+
+
+    points = ras.outline.points;
+    limit  = points + last;
+
+    v_start.x = SCALED( points[first].x );
+    v_start.y = SCALED( points[first].y );
+    v_last.x  = SCALED( points[last].x );
+    v_last.y  = SCALED( points[last].y );
+
+    if ( flipped )
+    {
+      SWAP_( v_start.x, v_start.y );
+      SWAP_( v_last.x, v_last.y );
+    }
+
+    v_control = v_start;
+
+    point = points + first;
+    tags  = ras.outline.tags  + first;
+    tag   = FT_CURVE_TAG( tags[0] );
+
+    /* A contour cannot start with a cubic control point! */
+    if ( tag == FT_Curve_Tag_Cubic )
+      goto Invalid_Outline;
+
+    /* check first point to determine origin */
+    if ( tag == FT_Curve_Tag_Conic )
+    {
+      /* first point is conic control.  Yes, this happens. */
+      if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_Curve_Tag_On )
+      {
+        /* start at last point if it is on the curve */
+        v_start = v_last;
+        limit--;
+      }
+      else
+      {
+        /* if both first and last points are conic,         */
+        /* start at their middle and record its position    */
+        /* for closure                                      */
+        v_start.x = ( v_start.x + v_last.x ) / 2;
+        v_start.y = ( v_start.y + v_last.y ) / 2;
+
+        v_last = v_start;
+      }
+      point--;
+      tags--;
+    }
+
+    ras.lastX = v_start.x;
+    ras.lastY = v_start.y;
+
+    while ( point < limit )
+    {
+      point++;
+      tags++;
+
+      tag = FT_CURVE_TAG( tags[0] );
+
+      switch ( tag )
+      {
+      case FT_Curve_Tag_On:  /* emit a single line_to */
+        {
+          Long  x, y;
+
+
+          x = SCALED( point->x );
+          y = SCALED( point->y );
+          if ( flipped )
+            SWAP_( x, y );
+
+          if ( Line_To( RAS_VARS x, y ) )
+            goto Fail;
+          continue;
+        }
+
+      case FT_Curve_Tag_Conic:  /* consume conic arcs */
+        {
+          v_control.x = SCALED( point[0].x );
+          v_control.y = SCALED( point[0].y );
+
+          if ( flipped )
+            SWAP_( v_control.x, v_control.y );
+
+        Do_Conic:
+          if ( point < limit )
+          {
+            FT_Vector  v_middle;
+            Long       x, y;
+
+
+            point++;
+            tags++;
+            tag = FT_CURVE_TAG( tags[0] );
+
+            x = SCALED( point[0].x );
+            y = SCALED( point[0].y );
+
+            if ( flipped )
+              SWAP_( x, y );
+
+            if ( tag == FT_Curve_Tag_On )
+            {
+              if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) )
+                goto Fail;
+              continue;
+            }
+
+            if ( tag != FT_Curve_Tag_Conic )
+              goto Invalid_Outline;
+
+            v_middle.x = ( v_control.x + x ) / 2;
+            v_middle.y = ( v_control.y + y ) / 2;
+
+            if ( Conic_To( RAS_VARS v_control.x, v_control.y,
+                                    v_middle.x,  v_middle.y ) )
+              goto Fail;
+
+            v_control.x = x;
+            v_control.y = y;
+
+            goto Do_Conic;
+          }
+
+          if ( Conic_To( RAS_VARS v_control.x, v_control.y,
+                                  v_start.x,   v_start.y ) )
+            goto Fail;
+
+          goto Close;
+        }
+
+      default:  /* FT_Curve_Tag_Cubic */
+        {
+          Long  x1, y1, x2, y2, x3, y3;
+
+
+          if ( point + 1 > limit                             ||
+               FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic )
+            goto Invalid_Outline;
+
+          point += 2;
+          tags  += 2;
+
+          x1 = SCALED( point[-2].x );
+          y1 = SCALED( point[-2].y );
+          x2 = SCALED( point[-1].x );
+          y2 = SCALED( point[-1].y );
+          x3 = SCALED( point[ 0].x );
+          y3 = SCALED( point[ 0].y );
+
+          if ( flipped )
+          {
+            SWAP_( x1, y1 );
+            SWAP_( x2, y2 );
+            SWAP_( x3, y3 );
+          }
+
+          if ( point <= limit )
+          {
+            if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) )
+              goto Fail;
+            continue;
+          }
+
+          if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) )
+            goto Fail;
+          goto Close;
+        }
+      }
+    }
+
+    /* close the contour with a line segment */
+    if ( Line_To( RAS_VARS v_start.x, v_start.y ) )
+      goto Fail;
+
+  Close:
+    return SUCCESS;
+
+  Invalid_Outline:
+    ras.error = Raster_Err_Invalid;
+
+  Fail:
+    return FAILURE;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Convert_Glyph                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Converts a glyph into a series of segments and arcs and makes a    */
+  /*    profiles list with them.                                           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    flipped :: If set, flip the direction of curve.                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success, FAILURE if any error was encountered during    */
+  /*    rendering.                                                         */
+  /*                                                                       */
+  static
+  Bool  Convert_Glyph( RAS_ARGS int  flipped )
+  {
+    Short     i;
+    UShort    start;
+
+    PProfile  lastProfile;
+
+
+    ras.fProfile = NULL;
+    ras.joint    = FALSE;
+    ras.fresh    = FALSE;
+
+    ras.maxBuff  = ras.sizeBuff - AlignProfileSize;
+
+    ras.numTurns = 0;
+
+    ras.cProfile         = (PProfile)ras.top;
+    ras.cProfile->offset = ras.top;
+    ras.num_Profs        = 0;
+
+    start = 0;
+
+    for ( i = 0; i < ras.outline.n_contours; i++ )
+    {
+      ras.state    = Unknown;
+      ras.gProfile = NULL;
+
+      if ( Decompose_Curve( RAS_VARS start, ras.outline.contours[i], flipped ) )
+        return FAILURE;
+
+      start = ras.outline.contours[i] + 1;
+
+      /* We must now see whether the extreme arcs join or not */
+      if ( FRAC( ras.lastY ) == 0 &&
+           ras.lastY >= ras.minY  &&
+           ras.lastY <= ras.maxY  )
+        if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow )
+          ras.top--;
+        /* Note that ras.gProfile can be nil if the contour was too small */
+        /* to be drawn.                                                   */
+
+      lastProfile = ras.cProfile;
+      if ( End_Profile( RAS_VAR ) )
+        return FAILURE;
+
+      /* close the `next profile in contour' linked list */
+      if ( ras.gProfile )
+        lastProfile->next = ras.gProfile;
+    }
+
+    if ( Finalize_Profile_Table( RAS_VAR ) )
+      return FAILURE;
+
+    return ( ras.top < ras.maxBuff ? SUCCESS : FAILURE );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /**                                                                     **/
+  /**  SCAN-LINE SWEEPS AND DRAWING                                       **/
+  /**                                                                     **/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  Init_Linked                                                          */
+  /*                                                                       */
+  /*    Initializes 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;
+    Long       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 Sweep Procedure Set                                         */
+  /*                                                                       */
+  /*  These four routines are used during the vertical black/white         */
+  /*  sweep phase by the generic Draw_Sweep() function.                    */
+  /*                                                                       */
+  /*************************************************************************/
+
+  static
+  void  Vertical_Sweep_Init( RAS_ARGS Short*  min,
+                                      Short*  max )
+  {
+    Long  pitch = ras.target.pitch;
+
+    UNUSED( max );
+
+
+    ras.traceIncr = (Short)-pitch;
+    ras.traceOfs  = -*min * pitch;
+    if ( pitch > 0 )
+      ras.traceOfs += ( ras.target.rows - 1 ) * pitch;
+
+    ras.gray_min_x = 0;
+    ras.gray_max_x = 0;
+  }
+
+
+  static
+  void  Vertical_Sweep_Span( RAS_ARGS Short       y,
+                                      FT_F26Dot6  x1,
+                                      FT_F26Dot6  x2,
+                                      PProfile    left,
+                                      PProfile    right )
+  {
+    Long   e1, e2;
+    Short  c1, c2;
+    Byte   f1, f2;
+    Byte*  target;
+
+    UNUSED( y );
+    UNUSED( left );
+    UNUSED( right );
+
+
+    /* Drop-out control */
+
+    e1 = TRUNC( CEILING( x1 ) );
+
+    if ( x2 - x1 - ras.precision <= ras.precision_jitter )
+      e2 = e1;
+    else
+      e2 = TRUNC( FLOOR( x2 ) );
+
+    if ( e2 >= 0 && e1 < ras.bWidth )
+    {
+      if ( e1 < 0 )           e1 = 0;
+      if ( e2 >= ras.bWidth ) e2 = ras.bWidth - 1;
+
+      c1 = (Short)( e1 >> 3 );
+      c2 = (Short)( e2 >> 3 );
+
+      f1 =   (unsigned char)0xFF >> ( e1 & 7 );
+      f2 = ~((unsigned char)0x7F >> ( e2 & 7 ));
+
+      if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
+      if ( ras.gray_max_x < c2 ) ras.gray_max_x = c2;
+
+      target = ras.bTarget + ras.traceOfs + 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 );
+    }
+  }
+
+
+  static
+  void Vertical_Sweep_Drop( RAS_ARGS Short       y,
+                                     FT_F26Dot6  x1,
+                                     FT_F26Dot6  x2,
+                                     PProfile    left,
+                                     PProfile    right )
+  {
+    Long   e1, e2;
+    Short  c1, f1;
+
+
+    /* Drop-out control */
+
+    e1 = CEILING( x1 );
+    e2 = FLOOR  ( x2 );
+
+    if ( e1 > e2 )
+    {
+      if ( e1 == e2 + ras.precision )
+      {
+        switch ( ras.dropOutControl )
+        {
+        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 if:          */
+          /*                                                        */
+          /*  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                          */
+          /*                                                        */
+
+          /* FIXXXME: uncommenting this line solves the disappearing */
+          /*          bit problem in the `7' of verdana 10pts, but   */
+          /*          makes a new one in the `C' of arial 14pts      */
+
+#if 0
+          if ( x2 - x1 < ras.precision_half )
+#endif
+          {
+            /* upper stub test */
+            if ( left->next == right && left->height <= 0 )
+              return;
+
+            /* lower stub test */
+            if ( right->next == left && left->start == y )
+              return;
+          }
+
+          /* check that the rightmost pixel isn't set */
+
+          e1 = TRUNC( e1 );
+
+          c1 = (Short)( e1 >> 3 );
+          f1 = e1 &  7;
+
+          if ( e1 >= 0 && e1 < ras.bWidth                      &&
+               ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) )
+            return;
+
+          if ( ras.dropOutControl == 2 )
+            e1 = e2;
+          else
+            e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+          break;
+
+        default:
+          return;  /* unsupported mode */
+        }
+      }
+      else
+        return;
+    }
+
+    e1 = TRUNC( e1 );
+
+    if ( e1 >= 0 && e1 < ras.bWidth )
+    {
+      c1 = (Short)( e1 >> 3 );
+      f1 = e1 & 7;
+
+      if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
+      if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1;
+
+      ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 );
+    }
+  }
+
+
+  static
+  void Vertical_Sweep_Step( RAS_ARG )
+  {
+    ras.traceOfs += ras.traceIncr;
+  }
+
+
+  /***********************************************************************/
+  /*                                                                     */
+  /*  Horizontal Sweep Procedure Set                                     */
+  /*                                                                     */
+  /*  These four routines are used during the horizontal black/white     */
+  /*  sweep phase by the generic Draw_Sweep() function.                  */
+  /*                                                                     */
+  /***********************************************************************/
+
+  static
+  void  Horizontal_Sweep_Init( RAS_ARGS Short*  min,
+                                        Short*  max )
+  {
+    /* nothing, really */
+    UNUSED( raster );
+    UNUSED( min );
+    UNUSED( max );
+  }
+
+
+  static
+  void  Horizontal_Sweep_Span( RAS_ARGS Short       y,
+                                        FT_F26Dot6  x1,
+                                        FT_F26Dot6  x2,
+                                        PProfile    left,
+                                        PProfile    right )
+  {
+    Long   e1, e2;
+    PByte  bits;
+    Byte   f1;
+
+    UNUSED( left );
+    UNUSED( right );
+
+
+    if ( x2 - x1 < ras.precision )
+    {
+      e1 = CEILING( x1 );
+      e2 = FLOOR  ( x2 );
+
+      if ( e1 == e2 )
+      {
+        bits = ras.bTarget + ( y >> 3 );
+        f1   = (Byte)( 0x80 >> ( y & 7 ) );
+
+        e1 = TRUNC( e1 );
+
+        if ( e1 >= 0 && e1 < ras.target.rows )
+        {
+          PByte  p;
+
+
+          p = bits - e1*ras.target.pitch;
+          if ( ras.target.pitch > 0 )
+            p += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+          p[0] |= f1;
+        }
+      }
+    }
+  }
+
+
+  static
+  void  Horizontal_Sweep_Drop( RAS_ARGS Short       y,
+                                        FT_F26Dot6  x1,
+                                        FT_F26Dot6  x2,
+                                        PProfile    left,
+                                        PProfile    right )
+  {
+    Long   e1, e2;
+    PByte  bits;
+    Byte   f1;
+
+
+    /* During the horizontal sweep, we only take care of drop-outs */
+
+    e1 = CEILING( x1 );
+    e2 = FLOOR  ( x2 );
+
+    if ( e1 > e2 )
+    {
+      if ( e1 == e2 + ras.precision )
+      {
+        switch ( ras.dropOutControl )
+        {
+        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'.    */
+          /*                                                        */
+
+          /* rightmost stub test */
+          if ( left->next == right && left->height <= 0 )
+            return;
+
+          /* leftmost stub test */
+          if ( right->next == left && left->start == y )
+            return;
+
+          /* check that the rightmost pixel isn't set */
+
+          e1 = TRUNC( e1 );
+
+          bits = ras.bTarget + ( y >> 3 );
+          f1   = (Byte)( 0x80 >> ( y & 7 ) );
+
+          bits -= e1 * ras.target.pitch;
+          if ( ras.target.pitch > 0 )
+            bits += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+          if ( e1 >= 0              &&
+               e1 < ras.target.rows &&
+               *bits & f1 )
+            return;
+
+          if ( ras.dropOutControl == 2 )
+            e1 = e2;
+          else
+            e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+          break;
+
+        default:
+          return;  /* unsupported mode */
+        }
+      }
+      else
+        return;
+    }
+
+    bits = ras.bTarget + ( y >> 3 );
+    f1   = (Byte)( 0x80 >> ( y & 7 ) );
+
+    e1 = TRUNC( e1 );
+
+    if ( e1 >= 0 && e1 < ras.target.rows )
+    {
+      bits -= e1 * ras.target.pitch;
+      if ( ras.target.pitch > 0 )
+        bits += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+      bits[0] |= f1;
+    }
+  }
+
+
+  static
+  void Horizontal_Sweep_Step( RAS_ARG )
+  {
+    /* Nothing, really */
+    UNUSED( raster );
+  }
+
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  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_Gray_Sweep_Init( RAS_ARGS Short*  min,
+                                           Short*  max )
+  {
+    Long  pitch, byte_len;
+
+
+    *min = *min & -2;
+    *max = ( *max + 3 ) & -2;
+
+    ras.traceOfs  = 0;
+    pitch         = ras.target.pitch;
+    byte_len      = -pitch;
+    ras.traceIncr = (Short)byte_len;
+    ras.traceG    = ( *min / 2 ) * byte_len;
+
+    if ( pitch > 0 )
+    {
+      ras.traceG += ( ras.target.rows - 1 ) * pitch;
+      byte_len    = -byte_len;
+    }
+
+    ras.gray_min_x =  (Short)byte_len;
+    ras.gray_max_x = -(Short)byte_len;
+  }
+
+
+  static
+  void  Vertical_Gray_Sweep_Step( RAS_ARG )
+  {
+    Int    c1, c2;
+    PByte  pix, bit, bit2;
+    Int*   count = ras.count_table;
+    Byte*  grays;
+
+
+    ras.traceOfs += ras.gray_width;
+
+    if ( ras.traceOfs > ras.gray_width )
+    {
+      pix   = ras.gTarget + ras.traceG + ras.gray_min_x * 4;
+      grays = ras.grays;
+
+      if ( ras.gray_max_x >= 0 )
+      {
+        Long   last_pixel = ras.target.width - 1;
+        Int    last_cell  = last_pixel >> 2;
+        Int    last_bit   = last_pixel & 3;
+        Bool   over       = 0;
+
+        if ( ras.gray_max_x >= last_cell && last_bit != 3 )
+        {
+          ras.gray_max_x = last_cell - 1;
+          over = 1;
+        }
+
+        if ( ras.gray_min_x < 0 )
+          ras.gray_min_x = 0;
+
+        bit   = ras.bTarget + ras.gray_min_x;
+        bit2  = bit + ras.gray_width;
+
+        c1 = ras.gray_max_x - ras.gray_min_x;
+
+        while ( c1 >= 0 )
+        {
+          c2 = count[*bit] + count[*bit2];
+
+          if ( c2 )
+          {
+            pix[0] = grays[(c2 >> 12) & 0x000F];
+            pix[1] = grays[(c2 >> 8 ) & 0x000F];
+            pix[2] = grays[(c2 >> 4 ) & 0x000F];
+            pix[3] = grays[ c2        & 0x000F];
+
+            *bit  = 0;
+            *bit2 = 0;
+          }
+
+          bit++;
+          bit2++;
+          pix += 4;
+          c1--;
+        }
+
+        if ( over )
+        {
+          c2 = count[*bit] + count[*bit2];
+          if ( c2 )
+          {
+            switch ( last_bit )
+            {
+            case 2:
+              pix[2] = grays[(c2 >> 4 ) & 0x000F];
+            case 1:
+              pix[1] = grays[(c2 >> 8 ) & 0x000F];
+            default:
+              pix[0] = grays[(c2 >> 12) & 0x000F];
+            }
+
+            *bit  = 0;
+            *bit2 = 0;
+          }
+        }
+      }
+
+      ras.traceOfs = 0;
+      ras.traceG  += ras.traceIncr;
+
+      ras.gray_min_x =  32000;
+      ras.gray_max_x = -32000;
+    }
+  }
+
+
+  static
+  void  Horizontal_Gray_Sweep_Span( RAS_ARGS Short       y,
+                                             FT_F26Dot6  x1,
+                                             FT_F26Dot6  x2,
+                                             PProfile    left,
+                                             PProfile    right )
+  {
+    /* nothing, really */
+    UNUSED( raster );
+    UNUSED( y );
+    UNUSED( x1 );
+    UNUSED( x2 );
+    UNUSED( left );
+    UNUSED( right );
+  }
+
+
+  static
+  void  Horizontal_Gray_Sweep_Drop( RAS_ARGS Short       y,
+                                             FT_F26Dot6  x1,
+                                             FT_F26Dot6  x2,
+                                             PProfile    left,
+                                             PProfile    right )
+  {
+    Long   e1, e2;
+    PByte  pixel;
+    Byte   color;
+
+
+    /* During the horizontal sweep, we only take care of drop-outs */
+    e1 = CEILING( x1 );
+    e2 = FLOOR  ( x2 );
+
+    if ( e1 > e2 )
+    {
+      if ( e1 == e2 + ras.precision )
+      {
+        switch ( ras.dropOutControl )
+        {
+        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'.    */
+          /*                                                        */
+
+          /* rightmost stub test */
+          if ( left->next == right && left->height <= 0 )
+            return;
+
+          /* leftmost stub test */
+          if ( right->next == left && left->start == y )
+            return;
+
+          if ( ras.dropOutControl == 2 )
+            e1 = e2;
+          else
+            e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+          break;
+
+        default:
+          return;  /* unsupported mode */
+        }
+      }
+      else
+        return;
+    }
+
+    if ( e1 >= 0 )
+    {
+      if ( x2 - x1 >= ras.precision_half )
+        color = ras.grays[2];
+      else
+        color = ras.grays[1];
+
+      e1 = TRUNC( e1 ) / 2;
+      if ( e1 < ras.target.rows )
+      {
+        pixel = ras.gTarget - e1 * ras.target.pitch + y / 2;
+        if ( ras.target.pitch > 0 )
+          pixel += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+        if ( pixel[0] == ras.grays[0] )
+          pixel[0] = color;
+      }
+    }
+  }
+
+
+#endif /* FT_RASTER_OPTION_ANTI_ALIASING */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  Generic Sweep Drawing routine                                        */
+  /*                                                                       */
+  /*************************************************************************/
+
+  static
+  Bool  Draw_Sweep( RAS_ARG )
+  {
+    Short  y, y_change, y_height;
+
+    PProfile  P, Q, P_Left, P_Right;
+
+    Short  min_Y, max_Y, top, bottom, dropouts;
+
+    Long  x1, x2, xs, e1, e2;
+
+    TProfileList  wait;
+    TProfileList  draw_left, draw_right;
+
+
+    /* Init empty linked lists */
+
+    Init_Linked( &wait );
+
+    Init_Linked( &draw_left  );
+    Init_Linked( &draw_right );
+
+    /* first, compute min and max Y */
+
+    P     = ras.fProfile;
+    max_Y = (short)TRUNC( ras.minY );
+    min_Y = (short)TRUNC( ras.maxY );
+
+    while ( P )
+    {
+      Q = P->link;
+
+      bottom = (Short)P->start;
+      top    = (Short)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.numTurns == 0 )
+    {
+      ras.error = Raster_Err_Invalid;
+      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.numTurns > 0 &&
+         ras.sizeBuff[-ras.numTurns] == min_Y )
+      ras.numTurns--;
+
+    while ( ras.numTurns > 0 )
+    {
+      /* look in the wait list for new activations */
+
+      P = wait;
+
+      while ( P )
+      {
+        Q = P->link;
+        P->countL -= y_height;
+        if ( P->countL == 0 )
+        {
+          DelOld( &wait, P );
+
+          switch ( P->flow )
+          {
+          case Flow_Up:
+            InsNew( &draw_left,  P );
+            break;
+
+          case Flow_Down:
+            InsNew( &draw_right, P );
+            break;
+          }
+        }
+
+        P = Q;
+      }
+
+      /* Sort the drawing lists */
+
+      Sort( &draw_left );
+      Sort( &draw_right );
+
+      y_change = (Short)ras.sizeBuff[-ras.numTurns--];
+      y_height = y_change - y;
+
+      while ( y < y_change )
+      {
+        /* Let's trace */
+
+        dropouts = 0;
+
+        P_Left  = draw_left;
+        P_Right = draw_right;
+
+        while ( P_Left )
+        {
+          x1 = P_Left ->X;
+          x2 = P_Right->X;
+
+          if ( x1 > x2 )
+          {
+            xs = x1;
+            x1 = x2;
+            x2 = xs;
+          }
+
+          if ( x2 - x1 <= ras.precision )
+          {
+            e1 = FLOOR( x1 );
+            e2 = CEILING( x2 );
+
+            if ( ras.dropOutControl != 0                 &&
+                 ( e1 > e2 || e2 == e1 + ras.precision ) )
+            {
+              /* a drop out was detected */
+
+              P_Left ->X = x1;
+              P_Right->X = x2;
+
+              /* mark profile for drop-out processing */
+              P_Left->countL = 1;
+              dropouts++;
+
+              goto Skip_To_Next;
+            }
+          }
+
+          ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right );
+
+        Skip_To_Next:
+
+          P_Left  = P_Left->link;
+          P_Right = P_Right->link;
+        }
+
+        /* 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_left  );
+          Sort( &draw_right );
+        }
+      }
+
+      /* Now finalize the profiles that needs it */
+
+      {
+        PProfile  Q, P;
+
+
+        P = draw_left;
+        while ( P )
+        {
+          Q = P->link;
+          if ( P->height == 0 )
+            DelOld( &draw_left, P );
+          P = Q;
+        }
+      }
+
+      {
+        PProfile  Q, P = draw_right;
+
+
+        while ( P )
+        {
+          Q = P->link;
+          if ( P->height == 0 )
+            DelOld( &draw_right, P );
+          P = Q;
+        }
+      }
+    }
+
+    /* 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_left;
+    P_Right = draw_right;
+
+    while ( P_Left )
+    {
+      if ( P_Left->countL )
+      {
+        P_Left->countL = 0;
+#if 0
+        dropouts--;  /* -- this is useful when debugging only */
+#endif
+        ras.Proc_Sweep_Drop( RAS_VARS y,
+                                      P_Left->X,
+                                      P_Right->X,
+                                      P_Left,
+                                      P_Right );
+      }
+
+      P_Left  = P_Left->link;
+      P_Right = P_Right->link;
+    }
+
+    goto Next_Line;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Render_Single_Pass                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Performs one sweep with sub-banding.                               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    flipped :: If set, flip the direction of the outline.              */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Renderer error code.                                               */
+  /*                                                                       */
+  static
+  int  Render_Single_Pass( RAS_ARGS Bool  flipped )
+  {
+    Short  i, j, k;
+
+
+    while ( ras.band_top >= 0 )
+    {
+      ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision;
+      ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision;
+
+      ras.top = ras.buff;
+
+      ras.error = Raster_Err_None;
+
+      if ( Convert_Glyph( RAS_VARS flipped ) )
+      {
+        if ( ras.error != Raster_Err_Overflow )
+          return FAILURE;
+
+        ras.error = Raster_Err_None;
+
+        /* 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 = ( i + j ) / 2;
+
+        if ( ras.band_top >= 7 || k < i )
+        {
+          ras.band_top = 0;
+          ras.error    = Raster_Err_Invalid;
+
+          return ras.error;
+        }
+
+        ras.band_stack[ras.band_top + 1].y_min = k;
+        ras.band_stack[ras.band_top + 1].y_max = j;
+
+        ras.band_stack[ras.band_top].y_max = k - 1;
+
+        ras.band_top++;
+      }
+      else
+      {
+        if ( ras.fProfile )
+          if ( Draw_Sweep( RAS_VAR ) )
+             return ras.error;
+        ras.band_top--;
+      }
+    }
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Render_Glyph                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Renders a glyph in a bitmap.  Sub-banding if needed.               */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* XXX Fixme: ftraster's error codes don't harmonize with FT2's ones!    */
+  /*                                                                       */
+  LOCAL_FUNC
+  FT_Error  Render_Glyph( RAS_ARG )
+  {
+    FT_Error  error;
+
+
+    Set_High_Precision( RAS_VARS ras.outline.flags &
+                        ft_outline_high_precision );
+    ras.scale_shift    = ras.precision_shift;
+    ras.dropOutControl = 2;
+    ras.second_pass    = !( ras.outline.flags & ft_outline_single_pass );
+
+    /* Vertical Sweep */
+    ras.Proc_Sweep_Init = Vertical_Sweep_Init;
+    ras.Proc_Sweep_Span = Vertical_Sweep_Span;
+    ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
+    ras.Proc_Sweep_Step = Vertical_Sweep_Step;
+
+    ras.band_top            = 0;
+    ras.band_stack[0].y_min = 0;
+    ras.band_stack[0].y_max = ras.target.rows - 1;
+
+    ras.bWidth  = ras.target.width;
+    ras.bTarget = (Byte*)ras.target.buffer;
+
+    if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 )
+      return error;
+
+    /* Horizontal Sweep */
+    if ( ras.second_pass && ras.dropOutControl != 0 )
+    {
+      ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
+      ras.Proc_Sweep_Span = Horizontal_Sweep_Span;
+      ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop;
+      ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
+
+      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 FT_Err_Ok;
+  }
+
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Render_Gray_Glyph                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Renders a glyph with grayscaling.  Sub-banding if needed.          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  LOCAL_FUNC
+  FT_Error  Render_Gray_Glyph( RAS_ARG )
+  {
+    Long      pixel_width;
+    FT_Error  error;
+
+
+    Set_High_Precision( RAS_VARS ras.outline.flags &
+                        ft_outline_high_precision );
+    ras.scale_shift    = ras.precision_shift + 1;
+    ras.dropOutControl = 2;
+    ras.second_pass    = !( ras.outline.flags & ft_outline_single_pass );
+
+
+    /* Vertical Sweep */
+
+    ras.band_top            = 0;
+    ras.band_stack[0].y_min = 0;
+    ras.band_stack[0].y_max = 2 * ras.target.rows - 1;
+
+    ras.bWidth  = ras.gray_width;
+    pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 );
+
+    if ( ras.bWidth > pixel_width )
+      ras.bWidth = pixel_width;
+
+    ras.bWidth  = ras.bWidth * 8;
+    ras.bTarget = (Byte*)ras.gray_lines;
+    ras.gTarget = (Byte*)ras.target.buffer;
+
+    ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init;
+    ras.Proc_Sweep_Span = Vertical_Sweep_Span;
+    ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
+    ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step;
+
+    error = Render_Single_Pass( RAS_VARS 0 );
+    if (error)
+      return error;
+
+    /* Horizontal Sweep */
+    if ( ras.second_pass && ras.dropOutControl != 0 )
+    {
+      ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
+      ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span;
+      ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop;
+      ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
+
+      ras.band_top            = 0;
+      ras.band_stack[0].y_min = 0;
+      ras.band_stack[0].y_max = ras.target.width * 2 - 1;
+
+      error = Render_Single_Pass( RAS_VARS 1 );
+      if (error)
+        return error;
+    }
+
+    return FT_Err_Ok;
+  }
+
+#else /* FT_RASTER_OPTION_ANTI_ALIASING */
+
+  LOCAL_FUNC
+  FT_Error  Render_Gray_Glyph( RAS_ARG )
+  {
+    UNUSED_RASTER;
+    return FT_Err_Cannot_Render_Glyph;
+  }
+
+#endif
+
+
+  static
+  void  ft_black_init( TRaster_Instance*  raster )
+  {
+    FT_UInt  n;
+    FT_ULong c;
+
+    /* setup count table */
+    for ( n = 0; n < 256; n++ )
+    {
+      c = ( n & 0x55 ) + ( ( n & 0xAA ) >> 1 );
+
+      c = ( ( c << 6 ) & 0x3000 ) |
+          ( ( c << 4 ) & 0x0300 ) |
+          ( ( c << 2 ) & 0x0030 ) |
+                   (c  & 0x0003 );
+
+      raster->count_table[n] = c;
+    }
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+    /* set default 5-levels gray palette */
+    for ( n = 0; n < 5; n++ )
+      raster->grays[n] = n * 255 / 4;
+
+    raster->gray_width = RASTER_GRAY_LINES / 2;
+#endif    
+  }
+
+  /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
+  /****                         a static object.                  *****/
+
+#ifdef _STANDALONE_
+
+
+  static
+  int  ft_black_new( void*  memory,
+                     FT_Raster *araster )
+  {
+     static FT_RasterRec_  the_raster;
+
+
+     *araster = &the_raster;
+     memset( &the_raster, sizeof ( the_raster ), 0 );
+     ft_black_init( &the_raster );
+
+     return 0;
+  }
+
+
+  static
+  void  ft_black_done( FT_Raster  raster )
+  {
+    /* nothing */
+    raster->init = 0;
+  }
+
+
+#else /* _STANDALONE_ */
+
+
+  static
+  int  ft_black_new( FT_Memory           memory,
+                     TRaster_Instance**  araster )
+  {
+    FT_Error           error;
+    TRaster_Instance*  raster;
+
+
+    *araster = 0;
+    if ( !ALLOC( raster, sizeof ( *raster ) ) )
+    {
+      raster->memory = memory;
+      ft_black_init( raster );
+
+      *araster = raster;
+    }
+
+    return error;
+  }
+
+
+  static
+  void ft_black_done( TRaster_Instance*  raster )
+  {
+    FT_Memory  memory = (FT_Memory)raster->memory;
+    FREE( raster );
+  }
+
+
+#endif /* _STANDALONE_ */
+
+
+  static
+  void ft_black_reset( TRaster_Instance* raster,
+                       const char*       pool_base,
+                       long              pool_size )
+  {
+    if ( raster && pool_base && pool_size >= 4096 )
+    {
+      /* save the pool */
+      raster->buff     = (PLong)pool_base;
+      raster->sizeBuff = raster->buff + pool_size / sizeof ( Long );
+    }
+  }
+
+
+  static
+  void ft_black_set_mode( TRaster_Instance* raster,
+                          unsigned long     mode,
+                          const char*       palette )
+  {
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING  
+    if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) )
+    {
+      /* set 5-levels gray palette */
+      raster->grays[0] = palette[0];
+      raster->grays[1] = palette[1];
+      raster->grays[2] = palette[2];
+      raster->grays[3] = palette[3];
+      raster->grays[4] = palette[4];
+    }
+#else
+    UNUSED(raster);
+    UNUSED(mode);
+    UNUSED(palette);    
+#endif    
+  }
+
+
+  static
+  int  ft_black_render( TRaster_Instance*  raster,
+                        FT_Raster_Params*  params )
+  {
+    FT_Outline*  outline    = (FT_Outline*)params->source;
+    FT_Bitmap*   target_map = params->target;
+
+
+    if ( !raster || !raster->buff || !raster->sizeBuff )
+      return Raster_Err_Not_Ini;
+
+    if ( !outline || !outline->contours || !outline->points )
+      return Raster_Err_Invalid;
+
+    /* return immediately if the outline is empty */
+    if ( outline->n_points == 0 || outline->n_contours <= 0 )
+      return Raster_Err_None;
+
+    if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 )
+      return Raster_Err_Invalid;
+
+    if ( !target_map || !target_map->buffer )
+      return Raster_Err_Invalid;
+
+    /* this version of the raster does not support direct rendering, sorry */
+    if ( params->flags & ft_raster_flag_direct )
+      return Raster_Err_Unsupported;
+
+    ras.outline  = *outline;
+    ras.target   = *target_map;
+
+    return ( params->flags & ft_raster_flag_aa
+               ? Render_Gray_Glyph( raster )
+               : Render_Glyph( raster ) );
+  }
+
+
+  FT_Raster_Funcs  ft_standard_raster =
+  {
+    ft_glyph_format_outline,
+    (FT_Raster_New_Func)     ft_black_new,
+    (FT_Raster_Reset_Func)   ft_black_reset,
+    (FT_Raster_Set_Mode_Func)ft_black_set_mode,
+    (FT_Raster_Render_Func)  ft_black_render,
+    (FT_Raster_Done_Func)    ft_black_done
+  };
+
+
+/* END */
--- /dev/null
+++ b/src/raster1/ftraster.h
@@ -1,0 +1,48 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftraster.h                                                             */
+/*                                                                         */
+/*    The FreeType glyph rasterizer (specification).                       */
+/*                                                                         */
+/*  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 FTRASTER_H
+#define FTRASTER_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+#include <freetype/ftimage.h>
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Uncomment the following line if you are using ftraster.c as a         */
+  /* standalone module, fully independent of FreeType.                     */
+  /*                                                                       */
+/* #define _STANDALONE_ */
+
+#ifndef FT_EXPORT_VAR
+#define FT_EXPORT_VAR(x)  extern x
+#endif
+
+  FT_EXPORT_VAR(FT_Raster_Funcs)  ft_standard_raster;
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif /* FTRASTER_H */
+
+
+/* END */
--- /dev/null
+++ b/src/raster1/ftrend1.c
@@ -1,0 +1,231 @@
+#include <freetype/internal/ftobjs.h>
+#include <raster1.h>
+#include <ftraster.h>
+
+ /* initialise renderer - init its raster */
+  static FT_Error ft_raster1_init( FT_Renderer  render )
+  {
+    FT_Library  library = FT_MODULE_LIBRARY(render);
+    
+    render->clazz->raster_class->raster_reset( render->raster,
+        library->raster_pool, library->raster_pool_size );
+
+    return 0;
+  }
+  
+
+
+ /* sets render-specific mode */
+  static  FT_Error  ft_raster1_set_mode( FT_Renderer  render,
+                                         FT_ULong     mode_tag,
+                                         FT_Pointer   data )
+  {
+    /* we simply pass it to the raster */
+    return render->clazz->raster_class->raster_set_mode(
+                    render->raster, mode_tag, data );
+  }                                          
+
+ /* transform a given glyph image */
+  static  FT_Error  ft_raster1_transform( FT_Renderer   render,
+                                           FT_GlyphSlot  slot,
+                                           FT_Matrix*    matrix,
+                                           FT_Vector*    delta )
+  {
+    FT_Error error = FT_Err_Ok;
+    
+    if (slot->format != render->glyph_format)
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+    
+    if (matrix)
+      FT_Outline_Transform( &slot->outline, matrix );
+      
+    if (delta)
+      FT_Outline_Translate( &slot->outline, delta->x, delta->y );
+    
+  Exit:
+    return error;
+  }
+
+ /* return the glyph's control box */
+  static  void  ft_raster1_get_cbox( FT_Renderer   render,
+                                      FT_GlyphSlot  slot,
+                                      FT_BBox      *cbox )
+  {
+    MEM_Set( cbox, 0, sizeof(*cbox) );
+
+    if (slot->format == render->glyph_format)
+      FT_Outline_Get_CBox( &slot->outline, cbox );
+  }                                      
+  
+
+ /* convert a slot's glyph image into a bitmap */
+  static  FT_Error  ft_raster1_render( FT_Renderer  render,
+                                       FT_GlyphSlot slot,
+                                       FT_UInt      mode,
+                                       FT_Vector*   origin )
+  {
+    FT_Error     error;
+    FT_Outline*  outline;
+    FT_BBox      cbox;
+    FT_UInt      width, height, pitch;
+    FT_Bitmap*   bitmap;
+    FT_Memory    memory;
+    
+    FT_Raster_Params  params;
+    
+    /* check glyph image format */
+    if (slot->format != render->glyph_format)
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    /* check rendering mode */
+    if ( mode & ft_render_mode_antialias )
+    {
+      /* raster1 is only capable of producing monochrome bitmaps */
+      if (render->clazz == &ft_raster1_renderer_class)
+        return FT_Err_Cannot_Render_Glyph;
+    }
+    else
+    {
+      /* raster5 is only capable of producing 5-gray-levels bitmaps */
+      if (render->clazz == &ft_raster5_renderer_class)
+        return FT_Err_Cannot_Render_Glyph;
+    }
+    
+    outline = &slot->outline;
+    
+    /* translate the outline to the new origin if needed */
+    if (origin)
+      FT_Outline_Translate( outline, origin->x, origin->y );
+    
+    /* compute the control box, and grid fit it */
+    FT_Outline_Get_CBox( outline, &cbox );
+    
+    cbox.xMin &= -64;
+    cbox.yMin &= -64;
+    cbox.xMax  = (cbox.xMax+63) & -64;
+    cbox.yMax  = (cbox.yMax+63) & -64;
+
+    width  = (cbox.xMax - cbox.xMin) >> 6;
+    height = (cbox.yMax - cbox.yMin) >> 6;
+    bitmap = &slot->bitmap;
+    memory = render->root.memory;
+    
+    /* release old bitmap buffer */
+    if ((slot->flags & ft_glyph_own_bitmap))
+    {
+      FREE(bitmap->buffer);
+      slot->flags &= ~ft_glyph_own_bitmap;
+    }
+      
+    /* allocate new one, depends on pixel format */
+    if ( mode & ft_render_mode_antialias )
+    {
+      /* we pad to 32 bits, only for backwards compatibility with FT 1.x */
+      pitch = (width+3) & -4;
+      bitmap->pixel_mode = ft_pixel_mode_grays;
+      bitmap->num_grays  = 256;
+    }
+    else
+    {
+      pitch  = (width+7) >> 3;
+      bitmap->pixel_mode = ft_pixel_mode_mono;
+    }
+
+    bitmap->width = width;
+    bitmap->rows  = height;
+    bitmap->pitch = pitch;
+    
+    if (ALLOC( bitmap->buffer, (FT_ULong)pitch * height ))
+      goto Exit;
+
+    slot->flags |= ft_glyph_own_bitmap;
+    
+    /* translate outline to render it into the bitmap */
+    FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin );
+
+    /* set up parameters */
+    params.target = bitmap;
+    params.source = outline;
+    params.flags  = 0;
+
+    if ( bitmap->pixel_mode == ft_pixel_mode_grays )
+      params.flags |= ft_raster_flag_aa;
+
+    /* render outline into the bitmap */
+    error = render->raster_render( render->raster, &params );
+    if (error) goto Exit;
+    
+    slot->format      = ft_glyph_format_bitmap;
+    slot->bitmap_left = cbox.xMin >> 6;
+    slot->bitmap_top  = cbox.yMax >> 6;
+
+  Exit:
+    return error;
+  }
+
+
+  const FT_Renderer_Class   ft_raster1_renderer_class =
+  {
+    {
+      ft_module_renderer,
+      sizeof( FT_RendererRec ),
+      
+      "raster1",
+      0x10000,
+      0x20000,
+      
+      0,    /* module specific interface */
+      
+      (FT_Module_Constructor)  ft_raster1_init,
+      (FT_Module_Destructor)   0,
+      (FT_Module_Requester)    0
+    },
+    
+    ft_glyph_format_outline,
+    
+    (FTRenderer_render)       ft_raster1_render,
+    (FTRenderer_transform)    ft_raster1_transform,
+    (FTRenderer_getCBox)      ft_raster1_get_cbox,
+    (FTRenderer_setMode)      ft_raster1_set_mode,
+    
+    (FT_Raster_Funcs*)        &ft_standard_raster
+  };
+  
+
+ /* this renderer is _NOT_ part of the default modules, you'll need */
+ /* to register it by hand in your application. It should only be   */
+ /* used for backwards-compatibility with FT 1.x anyway..           */
+  const FT_Renderer_Class  ft_raster5_renderer_class =
+  {
+    {
+      ft_module_renderer,
+      sizeof( FT_RendererRec ),
+      
+      "raster5",
+      0x10000,
+      0x20000,
+      
+      0,    /* module specific interface */
+      
+      (FT_Module_Constructor)  ft_raster1_init,
+      (FT_Module_Destructor)   0,
+      (FT_Module_Requester)    0
+    },
+
+    ft_glyph_format_outline,
+    
+    (FTRenderer_render)       ft_raster1_render,
+    (FTRenderer_transform)    ft_raster1_transform,
+    (FTRenderer_getCBox)      ft_raster1_get_cbox,
+    (FTRenderer_setMode)      ft_raster1_set_mode,
+
+    (FT_Raster_Funcs*)        &ft_standard_raster
+  };
+
+
--- /dev/null
+++ b/src/raster1/ftrend1.h
@@ -1,0 +1,14 @@
+#ifndef FTREND1_H
+#define FTREND1_H
+
+#include <freetype/ftrender.h>
+
+  FT_EXPORT_VAR(const FT_Renderer_Class)   ft_raster1_renderer_class;
+
+ /* this renderer is _NOT_ part of the default modules, you'll need */
+ /* to register it by hand in your application. It should only be   */
+ /* used for backwards-compatibility with FT 1.x anyway..           */
+ /*                                                                 */
+  FT_EXPORT_VAR(const FT_Renderer_Class)   ft_raster5_renderer_class;
+
+#endif /* FTREND1_H */
--- /dev/null
+++ b/src/raster1/module.mk
@@ -1,0 +1,7 @@
+make_module_list: add_raster1_module
+
+add_raster1_module:
+	$(OPEN_DRIVER)ft_raster1_renderer_class$(CLOSE_DRIVER)
+	$(ECHO_DRIVER)raster1   $(ECHO_DRIVER_DESC)monochrome bitmap renderer$(ECHO_DRIVER_DONE)
+
+# EOF
--- /dev/null
+++ b/src/raster1/raster1.c
@@ -1,0 +1,4 @@
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+#include <ftraster.c>
+#include <ftrend1.c>
+
--- /dev/null
+++ b/src/raster1/raster1.h
@@ -1,0 +1,14 @@
+#ifndef RASTER1_H
+#define RASTER1_H
+
+#include <freetype/ftrender.h>
+
+  FT_EXPORT_VAR(const FT_Renderer_Class)   ft_raster1_renderer_class;
+
+ /* this renderer is _NOT_ part of the default modules, you'll need */
+ /* to register it by hand in your application. It should only be   */
+ /* used for backwards-compatibility with FT 1.x anyway..           */
+ /*                                                                 */
+  FT_EXPORT_VAR(const FT_Renderer_Class)   ft_raster5_renderer_class;
+
+#endif /* RASTER1_H */
--- /dev/null
+++ b/src/raster1/rules.mk
@@ -1,0 +1,74 @@
+#
+# FreeType 2 renderer module build rules
+#
+
+
+# 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.
+
+
+# renderer driver directory
+#
+RAS1_DIR  := $(SRC_)raster1
+RAS1_DIR_ := $(RAS1_DIR)$(SEP)
+
+
+# additional include flags used when compiling the driver
+#
+RAS1_INCLUDE := $(RAS1_DIR)
+
+# compilation flags for the driver
+#
+RAS1_CFLAGS  := $(RAS1_INCLUDE:%=$I%)
+RAS1_COMPILE := $(FT_COMPILE) $(RAS1_CFLAGS)
+
+
+# RASTER1 driver sources (i.e., C files)
+#
+RAS1_DRV_SRC := $(RAS1_DIR_)ftraster.c  \
+                $(RAS1_DIR_)ftrend1.c
+
+# RASTER1 driver headers
+#
+RAS1_DRV_H := $(RAS1_DRV_SRC:%c=%h)
+
+
+# RASTER1 driver object(s)
+#
+#   RAS1_DRV_OBJ_M is used during `multi' builds.
+#   RAS1_DRV_OBJ_S is used during `single' builds.
+#
+RAS1_DRV_OBJ_M := $(RAS1_DRV_SRC:$(RAS1_DIR_)%.c=$(OBJ_)%.$O)
+RAS1_DRV_OBJ_S := $(OBJ_)raster1.$O
+
+# RASTER1 driver source file for single build
+#
+RAS1_DRV_SRC_S := $(RAS1_DIR_)raster1.c
+
+
+# RASTER1 driver - single object
+#
+$(RAS1_DRV_OBJ_S): $(RAS1_DRV_SRC_S) $(RAS1_DRV_SRC) \
+                   $(FREETYPE_H) $(RAS1_DRV_H)
+	$(RAS1_COMPILE) $T$@ $(RAS1_DRV_SRC_S)
+
+
+# RASTER1 driver - multiple objects
+#
+$(OBJ_)%.$O: $(RAS1_DIR_)%.c $(FREETYPE_H) $(RAS1_DRV_H)
+	$(RAS1_COMPILE) $T$@ $<
+
+
+# update main driver object lists
+#
+DRV_OBJS_S += $(RAS1_DRV_OBJ_S)
+DRV_OBJS_M += $(RAS1_DRV_OBJ_M)
+
+
+# EOF
--- /dev/null
+++ b/src/smooth/ftgrays.c
@@ -1,0 +1,1954 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftgrays.c                                                              */
+/*                                                                         */
+/*    A new `perfect' anti-aliasing renderer (body).                       */
+/*                                                                         */
+/*  Copyright 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.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  This file can be compiled without the rest of the FreeType engine,   */
+  /*  by defining the _STANDALONE_ macro when compiling it.  You also need */
+  /*  to put the files `ftgrays.h' and `ftimage.h' into the current        */
+  /*  compilation directory.  Typically, you could do something like       */
+  /*                                                                       */
+  /*  - copy `src/base/ftgrays.c' to your current directory                */
+  /*                                                                       */
+  /*  - copy `include/freetype/ftimage.h' and                              */
+  /*    `include/freetype/ftgrays.h' to the same directory                 */
+  /*                                                                       */
+  /*  - compile `ftgrays' with the _STANDALONE_ macro defined, as in       */
+  /*                                                                       */
+  /*      cc -c -D_STANDALONE_ ftgrays.c                                   */
+  /*                                                                       */
+  /*  The renderer can be initialized with a call to                       */
+  /*  `ft_grays_raster.grays_raster_new'; an anti-aliased bitmap can be    */
+  /*  generated with a call to `ft_grays_raster.grays_raster_render'.      */
+  /*                                                                       */
+  /*  See the comments and documentation in the file `ftimage.h' for       */
+  /*  more details on how the raster works.                                */
+  /*                                                                       */
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  This is a new anti-aliasing scan-converter for FreeType 2.  The      */
+  /*  algorithm used here is _very_ different from the one in the standard */
+  /*  `ftraster' module.  Actually, `ftgrays' computes the _exact_         */
+  /*  coverage of the outline on each pixel cell.                          */
+  /*                                                                       */
+  /*  It is based on ideas that I initially found in Raph Levien's         */
+  /*  excellent LibArt graphics library (see http://www.levien.com/libart  */
+  /*  for more information, though the web pages do not tell anything      */
+  /*  about the renderer; you'll have to dive into the source code to      */
+  /*  understand how it works).                                            */
+  /*                                                                       */
+  /*  Note, however, that this is a _very_ different implementation        */
+  /*  compared Raph's.  Coverage information is stored in a very different */
+  /*  way, and I don't use sorted vector paths.  Also, it doesn't use      */
+  /*  floating point values.                                               */
+  /*                                                                       */
+  /*  This renderer has the following advantages:                          */
+  /*                                                                       */
+  /*  - It doesn't need an intermediate bitmap.  Instead, one can supply   */
+  /*    a callback function that will be called by the renderer to draw    */
+  /*    gray spans on any target surface.  You can thus do direct          */
+  /*    composition on any kind of bitmap, provided that you give the      */
+  /*    renderer the right callback.                                       */
+  /*                                                                       */
+  /*  - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on  */
+  /*    each pixel cell                                                    */
+  /*                                                                       */
+  /*  - It performs a single pass on the outline (the `standard' FT2       */
+  /*    renderer makes two passes).                                        */
+  /*                                                                       */
+  /*  - It can easily be modified to render to _any_ number of gray levels */
+  /*    cheaply.                                                           */
+  /*                                                                       */
+  /*  - For small (< 20) pixel sizes, it is faster than the standard       */
+  /*    renderer.                                                          */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <string.h>             /* for memcpy() */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_aaraster
+
+
+#define ErrRaster_Invalid_Outline  -1
+
+#ifdef _STANDALONE_
+
+#define ErrRaster_Invalid_Mode     -2
+
+#include "ftimage.h"
+#include "ftgrays.h"
+
+  /* This macro is used to indicate that a function parameter is unused. */
+  /* Its purpose is simply to reduce compiler warnings.  Note also that  */
+  /* simply defining it as `(void)x' doesn't avoid warnings with certain */
+  /* ANSI compilers (e.g. LCC).                                          */
+#define UNUSED( x )  (x) = (x)
+
+  /* Disable the tracing mechanism for simplicity -- developers can      */
+  /* activate it easily by redefining these two macros.                  */
+#ifndef FT_ERROR
+#define FT_ERROR( x )  do ; while ( 0 )     /* nothing */
+#endif
+
+#ifndef FT_TRACE
+#define FT_TRACE( x )  do ; while ( 0 )     /* nothing */
+#endif
+
+
+#else /* _STANDALONE_ */
+
+
+#include "ftgrays.h"
+#include <freetype/internal/ftobjs.h>  /* for UNUSED()                  */
+#include <freetype/internal/ftdebug.h> /* for FT_TRACE() and FT_ERROR() */
+#include <freetype/freetype.h>         /* for FT_Outline_Decompose()    */
+
+#define ErrRaster_Invalid_Mode     FT_Err_Cannot_Render_Glyph
+
+
+#endif /* _STANDALONE_ */
+
+
+  /* define this to dump debugging information */
+#define xxxDEBUG_GRAYS
+
+  /* as usual, for the speed hungry :-) */
+
+#ifndef FT_STATIC_RASTER
+
+
+#define RAS_ARG   PRaster  raster
+#define RAS_ARG_  PRaster  raster,
+
+#define RAS_VAR   raster
+#define RAS_VAR_  raster,
+
+#define ras       (*raster)
+
+
+#else /* FT_STATIC_RASTER */
+
+
+#define RAS_ARG   /* empty */
+#define RAS_ARG_  /* empty */
+#define RAS_VAR   /* empty */
+#define RAS_VAR_  /* empty */
+
+  static TRaster  ras;
+
+
+#endif /* FT_STATIC_RASTER */
+
+
+  /* must be at least 6 bits! */
+#define PIXEL_BITS  8
+
+#define ONE_PIXEL       ( 1L << PIXEL_BITS )
+#define PIXEL_MASK      ( -1L << PIXEL_BITS )
+#define TRUNC( x )      ( (x) >> PIXEL_BITS )
+#define SUBPIXELS( x )  ( (x) << PIXEL_BITS )
+#define FLOOR( x )      ( (x) & -ONE_PIXEL )
+#define CEILING( x )    ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
+#define ROUND( x )      ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
+
+#if PIXEL_BITS >= 6
+#define UPSCALE( x )    ( (x) << ( PIXEL_BITS - 6 ) )
+#define DOWNSCALE( x )  ( (x) >> ( PIXEL_BITS - 6 ) )
+#else
+#define UPSCALE( x )    ( (x) >> ( 6 - PIXEL_BITS ) )
+#define DOWNSCALE( x )  ( (x) << ( 6 - PIXEL_BITS ) )
+#endif
+
+  /* Define this if you want to use a more compact storage scheme.  This   */
+  /* increases the number of cells available in the render pool but slows  */
+  /* down the rendering a bit.  It is useful if you have a really tiny     */
+  /* render pool.                                                          */
+#define xxxGRAYS_COMPACT
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*   TYPE DEFINITIONS                                                    */
+  /*                                                                       */
+  typedef int   TScan;   /* integer scanline/pixel coordinate */
+  typedef long  TPos;    /* sub-pixel coordinate              */
+
+  /* maximal number of gray spans in a call to the span callback */
+#define FT_MAX_GRAY_SPANS  32
+
+
+#ifdef GRAYS_COMPACT
+
+  typedef struct  TCell_
+  {
+    short  x     : 14;
+    short  y     : 14;
+    int    cover : PIXEL_BITS + 2;
+    int    area  : PIXEL_BITS * 2 + 2;
+
+  } TCell, *PCell;
+
+#else /* GRAYS_COMPACT */
+
+  typedef struct  TCell_
+  {
+    TScan  x;
+    TScan  y;
+    int    cover;
+    int    area;
+
+  } TCell, *PCell;
+
+#endif /* GRAYS_COMPACT */
+
+
+  typedef struct TRaster_
+  {
+    PCell  cells;
+    int    max_cells;
+    int    num_cells;
+
+    TScan  min_ex, max_ex;
+    TScan  min_ey, max_ey;
+
+    int    area;
+    int    cover;
+    int    invalid;
+
+    TScan  ex, ey;
+    TScan  cx, cy;
+    TPos   x,  y;
+
+    TScan  last_ey;
+
+    FT_Vector   bez_stack[32 * 3];
+    int         lev_stack[32];
+
+    FT_Outline  outline;
+    FT_Bitmap   target;
+
+    FT_Span     gray_spans[FT_MAX_GRAY_SPANS];
+    int         num_gray_spans;
+
+    FT_Raster_Span_Func  render_span;
+    void*                render_span_data;
+    int                  span_y;
+
+    int    band_size;
+    int    band_shoot;
+    int    conic_level;
+    int    cubic_level;
+
+    void*  memory;
+
+  } TRaster, *PRaster;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Initialize the cells table.                                           */
+  /*                                                                       */
+  static
+  void  init_cells( RAS_ARG_ void*  buffer,
+                    long            byte_size )
+  {
+    ras.cells     = (PCell)buffer;
+    ras.max_cells = byte_size / sizeof ( TCell );
+    ras.num_cells = 0;
+    ras.area      = 0;
+    ras.cover     = 0;
+    ras.invalid   = 1;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Compute the outline bounding box.                                     */
+  /*                                                                       */
+  static
+  void  compute_cbox( RAS_ARG_ FT_Outline*  outline )
+  {
+    FT_Vector*  vec   = outline->points;
+    FT_Vector*  limit = vec + outline->n_points;
+
+
+    if ( outline->n_points <= 0 )
+    {
+      ras.min_ex = ras.max_ex = 0;
+      ras.min_ey = ras.max_ey = 0;
+      return;
+    }
+
+    ras.min_ex = ras.max_ex = vec->x;
+    ras.min_ey = ras.max_ey = vec->y;
+
+    vec++;
+
+    for ( ; vec < limit; vec++ )
+    {
+      TPos  x = vec->x;
+      TPos  y = vec->y;
+
+
+      if ( x < ras.min_ex ) ras.min_ex = x;
+      if ( x > ras.max_ex ) ras.max_ex = x;
+      if ( y < ras.min_ey ) ras.min_ey = y;
+      if ( y > ras.max_ey ) ras.max_ey = y;
+    }
+
+    /* truncate the bounding box to integer pixels */
+    ras.min_ex = ras.min_ex >> 6;
+    ras.min_ey = ras.min_ey >> 6;
+    ras.max_ex = ( ras.max_ex + 63 ) >> 6;
+    ras.max_ey = ( ras.max_ey + 63 ) >> 6;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Record the current cell in the table.                                 */
+  /*                                                                       */
+  static
+  int  record_cell( RAS_ARG )
+  {
+    PCell  cell;
+
+
+    if ( !ras.invalid && ( ras.area | ras.cover ) )
+    {
+      if ( ras.num_cells >= ras.max_cells )
+        return 1;
+
+      cell        = ras.cells + ras.num_cells++;
+      cell->x     = ras.ex - ras.min_ex;
+      cell->y     = ras.ey - ras.min_ey;
+      cell->area  = ras.area;
+      cell->cover = ras.cover;
+    }
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Set the current cell to a new position.                               */
+  /*                                                                       */
+  static
+  int  set_cell( RAS_ARG_ TScan  ex,
+                          TScan  ey )
+  {
+    int  invalid, record, clean;
+
+
+    /* Move the cell pointer to a new position.  We set the `invalid'      */
+    /* flag to indicate that the cell isn't part of those we're interested */
+    /* in during the render phase.  This means that:                       */
+    /*                                                                     */
+    /* . the new vertical position must be within min_ey..max_ey - 1.      */
+    /* . the new horizontal position must be strictly less than max_ex     */
+    /*                                                                     */
+    /* Note that if a cell is to the left of the clipping region, it is    */
+    /* actually set to the (min_ex-1) horizontal position.                 */
+
+    record  = 0;
+    clean   = 1;
+
+    invalid = ( ey < ras.min_ey || ey >= ras.max_ey || ex >= ras.max_ex );
+    if ( !invalid )
+    {
+      /* All cells that are on the left of the clipping region go to the */
+      /* min_ex - 1 horizontal position.                                 */
+      if ( ex < ras.min_ex )
+        ex = ras.min_ex - 1;
+
+      /* if our position is new, then record the previous cell */
+      if ( ex != ras.ex || ey != ras.ey )
+        record = 1;
+      else
+        clean = ras.invalid;  /* do not clean if we didn't move from */
+                              /* a valid cell                        */
+    }
+
+    /* record the previous cell if needed (i.e., if we changed the cell */
+    /* position, of changed the `invalid' flag)                         */
+    if ( ( ras.invalid != invalid || record ) && record_cell( RAS_VAR ) )
+      return 1;
+
+    if ( clean )
+    {
+      ras.area  = 0;
+      ras.cover = 0;
+    }
+
+    ras.invalid = invalid;
+    ras.ex      = ex;
+    ras.ey      = ey;
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Start a new contour at a given cell.                                  */
+  /*                                                                       */
+  static
+  void  start_cell( RAS_ARG_  TScan  ex,
+                              TScan  ey )
+  {
+    if ( ex < ras.min_ex )
+      ex = ras.min_ex - 1;
+
+    ras.area    = 0;
+    ras.cover   = 0;
+    ras.ex      = ex;
+    ras.ey      = ey;
+    ras.last_ey = SUBPIXELS( ey );
+    ras.invalid = 0;
+
+    (void)set_cell( RAS_VAR_ ex, ey );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Render a scanline as one or more cells.                               */
+  /*                                                                       */
+  static
+  int  render_scanline( RAS_ARG_  TScan  ey,
+                                  TPos   x1,
+                                  TScan  y1,
+                                  TPos   x2,
+                                  TScan  y2 )
+  {
+    TScan  ex1, ex2, fx1, fx2, delta;
+    long   p, first, dx;
+    int    incr, lift, mod, rem;
+
+
+    dx = x2 - x1;
+
+    ex1 = TRUNC( x1 ); /* if (ex1 >= ras.max_ex) ex1 = ras.max_ex-1; */
+    ex2 = TRUNC( x2 ); /* if (ex2 >= ras.max_ex) ex2 = ras.max_ex-1; */
+    fx1 = x1 - SUBPIXELS( ex1 );
+    fx2 = x2 - SUBPIXELS( ex2 );
+
+    /* trivial case.  Happens often */
+    if ( y1 == y2 )
+      return set_cell( RAS_VAR_ ex2, ey );
+
+    /* everything is located in a single cell.  That is easy! */
+    /*                                                        */
+    if ( ex1 == ex2 )
+    {
+      delta      = y2 - y1;
+      ras.area  += ( fx1 + fx2 ) * delta;
+      ras.cover += delta;
+      return 0;
+    }
+
+    /* ok, we'll have to render a run of adjacent cells on the same */
+    /* scanline...                                                  */
+    /*                                                              */
+    p     = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
+    first = ONE_PIXEL;
+    incr  = 1;
+
+    if ( dx < 0 )
+    {
+      p     = fx1 * ( y2 - y1 );
+      first = 0;
+      incr  = -1;
+      dx    = -dx;
+    }
+
+    delta = p / dx;
+    mod   = p % dx;
+    if ( mod < 0 )
+    {
+      delta--;
+      mod += dx;
+    }
+
+    ras.area  += ( fx1 + first ) * delta;
+    ras.cover += delta;
+
+    ex1 += incr;
+    if ( set_cell( RAS_VAR_ ex1, ey ) )
+      goto Error;
+    y1  += delta;
+
+    if ( ex1 != ex2 )
+    {
+      p     = ONE_PIXEL * ( y2 - y1 );
+      lift  = p / dx;
+      rem   = p % dx;
+      if ( rem < 0 )
+      {
+        lift--;
+        rem += dx;
+      }
+
+      mod -= dx;
+
+      while ( ex1 != ex2 )
+      {
+        delta = lift;
+        mod  += rem;
+        if ( mod >= 0 )
+        {
+          mod -= dx;
+          delta++;
+        }
+
+        ras.area  += ONE_PIXEL * delta;
+        ras.cover += delta;
+        y1        += delta;
+        ex1       += incr;
+        if ( set_cell( RAS_VAR_ ex1, ey ) )
+          goto Error;
+      }
+    }
+
+    delta      = y2 - y1;
+    ras.area  += ( fx2 + ONE_PIXEL - first ) * delta;
+    ras.cover += delta;
+
+    return 0;
+
+  Error:
+    return 1;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Render a given line as a series of scanlines.                         */
+  /*                                                                       */
+  static
+  int  render_line( RAS_ARG_ TPos  to_x,
+                             TPos  to_y )
+  {
+    TScan  ey1, ey2, fy1, fy2;
+    TPos   dx, dy, x, x2;
+    int    p, rem, mod, lift, delta, first, incr;
+
+
+    ey1 = TRUNC( ras.last_ey );
+    ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
+    fy1 = ras.y - ras.last_ey;
+    fy2 = to_y - SUBPIXELS( ey2 );
+
+    dx = to_x - ras.x;
+    dy = to_y - ras.y;
+
+    /* we should do something about the trivial case where dx == 0, */
+    /* as it happens very often!       XXXXX                        */
+
+    /* perform vertical clipping */
+    {
+      TScan  min, max;
+
+
+      min = ey1;
+      max = ey2;
+      if ( ey1 > ey2 )
+      {
+        min = ey2;
+        max = ey1;
+      }
+      if ( min >= ras.max_ey || max < ras.min_ey )
+        goto End;
+    }
+
+    /* everything is on a single scanline */
+    if ( ey1 == ey2 )
+    {
+      if ( render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ) )
+        goto Error;
+      goto End;
+    }
+
+    /* ok, we'll have to render several scanlines */
+    p     = ( ONE_PIXEL - fy1 ) * dx;
+    first = ONE_PIXEL;
+    incr  = 1;
+
+    if ( dy < 0 )
+    {
+      p     = fy1 * dx;
+      first = 0;
+      incr  = -1;
+      dy    = -dy;
+    }
+
+    delta = p / dy;
+    mod   = p % dy;
+    if ( mod < 0 )
+    {
+      delta--;
+      mod += dy;
+    }
+
+    x = ras.x + delta;
+    if ( render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first ) )
+      goto Error;
+
+    ey1 += incr;
+    if ( set_cell( RAS_VAR_ TRUNC( x ), ey1 ) )
+      goto Error;
+
+    if ( ey1 != ey2 )
+    {
+      p     = ONE_PIXEL * dx;
+      lift  = p / dy;
+      rem   = p % dy;
+      if ( rem < 0 )
+      {
+        lift--;
+        rem += dy;
+      }
+      mod -= dy;
+
+      while ( ey1 != ey2 )
+      {
+        delta = lift;
+        mod  += rem;
+        if ( mod >= 0 )
+        {
+          mod -= dy;
+          delta++;
+        }
+
+        x2 = x + delta;
+        if ( render_scanline( RAS_VAR_ ey1,
+                              x, ONE_PIXEL - first, x2, first ) )
+          goto Error;
+        x = x2;
+        ey1 += incr;
+        if ( set_cell( RAS_VAR_ TRUNC( x ), ey1 ) )
+          goto Error;
+      }
+    }
+
+    if ( render_scanline( RAS_VAR_ ey1,
+                          x, ONE_PIXEL - first, to_x, fy2 ) )
+      goto Error;
+
+  End:
+    ras.x       = to_x;
+    ras.y       = to_y;
+    ras.last_ey = SUBPIXELS( ey2 );
+
+    return 0;
+
+  Error:
+    return 1;
+  }
+
+
+  static
+  void  split_conic( FT_Vector*  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;
+  }
+
+
+  static
+  int  render_conic( RAS_ARG_ FT_Vector*  control,
+                              FT_Vector*  to )
+  {
+    TPos        dx, dy;
+    int         top, level;
+    int*        levels;
+    FT_Vector*  arc;
+
+
+    dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 );
+    if ( dx < 0 )
+      dx = -dx;
+    dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 );
+    if ( dy < 0 )
+      dy = -dy;
+    if ( dx < dy )
+      dx = dy;
+
+    level = 1;
+    dx = dx / ras.conic_level;
+    while ( dx > 0 )
+    {
+      dx >>= 1;
+      level++;
+    }
+
+    /* a shortcut to speed things up */
+    if ( level <= 1 )
+    {
+      /* we compute the mid-point directly in order to avoid */
+      /* calling split_conic()                               */
+      TPos   to_x, to_y, mid_x, mid_y;
+
+
+      to_x  = UPSCALE( to->x );
+      to_y  = UPSCALE( to->y );
+      mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
+      mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
+
+      return render_line( RAS_VAR_ mid_x, mid_y ) ||
+             render_line( RAS_VAR_ to_x, to_y );
+    }
+
+    arc       = ras.bez_stack;
+    levels    = ras.lev_stack;
+    top       = 0;
+    levels[0] = level;
+
+    arc[0].x = UPSCALE( to->x );
+    arc[0].y = UPSCALE( to->y );
+    arc[1].x = UPSCALE( control->x );
+    arc[1].y = UPSCALE( control->y );
+    arc[2].x = ras.x;
+    arc[2].y = ras.y;
+
+    while ( top >= 0 )
+    {
+      level = levels[top];
+      if ( level > 1 )
+      {
+        /* check that the arc crosses the current band */
+        TPos  min, max, y;
+
+
+        min = max = arc[0].y;
+
+        y = arc[1].y;
+        if ( y < min ) min = y;
+        if ( y > max ) max = y;
+
+        y = arc[2].y;
+        if ( y < min ) min = y;
+        if ( y > max ) max = y;
+
+        if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
+          goto Draw;
+
+        split_conic( arc );
+        arc += 2;
+        top++;
+        levels[top] = levels[top - 1] = level - 1;
+        continue;
+      }
+
+    Draw:
+      {
+        TPos  to_x, to_y, mid_x, mid_y;
+
+
+        to_x  = arc[0].x;
+        to_y  = arc[0].y;
+        mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
+        mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
+
+        if ( render_line( RAS_VAR_ mid_x, mid_y ) ||
+             render_line( RAS_VAR_ to_x, to_y )   )
+          return 1;
+
+        top--;
+        arc -= 2;
+      }
+    }
+    return 0;
+  }
+
+
+  static
+  void  split_cubic( FT_Vector*  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;
+  }
+
+
+  static
+  int  render_cubic( RAS_ARG_ FT_Vector*  control1,
+                              FT_Vector*  control2,
+                              FT_Vector*  to )
+  {
+    TPos        dx, dy, da, db;
+    int         top, level;
+    int*        levels;
+    FT_Vector*  arc;
+
+
+    dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 );
+    if ( dx < 0 )
+      dx = -dx;
+    dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 );
+    if ( dy < 0 )
+      dy = -dy;
+    if ( dx < dy )
+      dx = dy;
+    da = dx;
+
+    dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x );
+    if ( dx < 0 )
+      dx = -dx;
+    dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y );
+    if ( dy < 0 )
+      dy = -dy;
+    if ( dx < dy )
+      dx = dy;
+    db = dx;
+
+    level = 1;
+    da    = da / ras.cubic_level;
+    db    = db / ras.conic_level;
+    while ( da > 0 || db > 0 )
+    {
+      da >>= 1;
+      db >>= 2;
+      level++;
+    }
+
+    if ( level <= 1 )
+    {
+      TPos   to_x, to_y, mid_x, mid_y;
+
+
+      to_x  = UPSCALE( to->x );
+      to_y  = UPSCALE( to->y );
+      mid_x = ( ras.x + to_x +
+                3 * UPSCALE( control1->x + control2->x ) ) / 8;
+      mid_y = ( ras.y + to_y +
+                3 * UPSCALE( control1->y + control2->y ) ) / 8;
+
+      return render_line( RAS_VAR_ mid_x, mid_y ) ||
+             render_line( RAS_VAR_ to_x, to_y );
+    }
+
+    arc      = ras.bez_stack;
+    arc[0].x = UPSCALE( to->x );
+    arc[0].y = UPSCALE( to->y );
+    arc[1].x = UPSCALE( control2->x );
+    arc[1].y = UPSCALE( control2->y );
+    arc[2].x = UPSCALE( control1->x );
+    arc[2].y = UPSCALE( control1->y );
+    arc[3].x = ras.x;
+    arc[3].y = ras.y;
+
+    levels    = ras.lev_stack;
+    top       = 0;
+    levels[0] = level;
+
+    while ( top >= 0 )
+    {
+      level = levels[top];
+      if ( level > 1 )
+      {
+        /* check that the arc crosses the current band */
+        TPos  min, max, y;
+
+
+        min = max = arc[0].y;
+        y = arc[1].y;
+        if ( y < min ) min = y;
+        if ( y > max ) max = y;
+        y = arc[2].y;
+        if ( y < min ) min = y;
+        if ( y > max ) max = y;
+        y = arc[3].y;
+        if ( y < min ) min = y;
+        if ( y > max ) max = y;
+        if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
+          goto Draw;
+        split_cubic( arc );
+        arc += 3;
+        top ++;
+        levels[top] = levels[top - 1] = level - 1;
+        continue;
+      }
+
+    Draw:
+      {
+        TPos   to_x, to_y, mid_x, mid_y;
+
+
+        to_x  = arc[0].x;
+        to_y  = arc[0].y;
+        mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
+        mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
+
+        if ( render_line( RAS_VAR_ mid_x, mid_y ) ||
+             render_line( RAS_VAR_ to_x, to_y )   )
+          return 1;
+        top --;
+        arc -= 3;
+      }
+    }
+    return 0;
+  }
+
+
+  /* a macro comparing two cell pointers.  Returns true if a <= b. */
+#if 1
+#define PACK( a )          ( ( (long)(a)->y << 16 ) + (a)->x )
+#define LESS_THAN( a, b )  ( PACK( a ) < PACK( b ) )
+#else /* 1 */
+#define LESS_THAN( a, b )  ( (a)->y < (b)->y || \
+                             ( (a)->y == (b)->y && (a)->x < (b)->x ) )
+#endif /* 1 */
+
+#define SWAP_CELLS( a, b, temp )  do             \
+                                  {              \
+                                    temp = *(a); \
+                                    *(a) = *(b); \
+                                    *(b) = temp; \
+                                  } while ( 0 )
+#define DEBUG_SORT
+#define QUICK_SORT
+
+#ifdef SHELL_SORT
+
+  /* A simple shell sort algorithm that works directly on our */
+  /* cells table..                                            */
+  static
+  void  shell_sort ( PCell  cells,
+                     int    count )
+  {
+    PCell  i, j, limit = cells + count;
+    TCell  temp;
+    int    gap;
+
+
+    /* compute initial gap */
+    for ( gap = 0; ++gap < count; gap *= 3 )
+      ;
+
+    while ( gap /= 3 )
+    {
+      for ( i = cells + gap; i < limit; i++ )
+      {
+        for ( j = i - gap; ; j -= gap )
+        {
+          PCell  k = j + gap;
+
+
+          if ( LESS_THAN( j, k ) )
+            break;
+
+          SWAP_CELLS( j, k, temp );
+
+          if ( j < cells + gap )
+            break;
+        }
+      }
+    }
+  }
+
+#endif /* SHELL_SORT */
+
+
+#ifdef QUICK_SORT
+
+  /* This is a non-recursive quicksort that directly process our cells     */
+  /* array.  It should be faster than calling the stdlib qsort(), and we   */
+  /* can even tailor our insertion threshold...                            */
+
+#define QSORT_THRESHOLD  9  /* below this size, a sub-array will be sorted */
+                            /* through a normal insertion sort..           */
+
+  static
+  void  quick_sort( PCell  cells,
+                    int    count )
+  {
+    PCell   stack[40];  /* should be enough ;-) */
+    PCell*  top;        /* top of stack */
+    PCell   base, limit;
+    TCell   temp;
+
+
+    limit = cells + count;
+    base  = cells;
+    top   = stack;
+
+    for (;;)
+    {
+      int    len = limit - base;
+      PCell  i, j, pivot;
+
+
+      if ( len > QSORT_THRESHOLD )
+      {
+        /* we use base + len/2 as the pivot */
+        pivot = base + len / 2;
+        SWAP_CELLS( base, pivot, temp );
+
+        i = base + 1;
+        j = limit - 1;
+
+        /* now ensure that *i <= *base <= *j */
+        if ( LESS_THAN( j, i ) )
+          SWAP_CELLS( i, j, temp );
+
+        if ( LESS_THAN( base, i ) )
+          SWAP_CELLS( base, i, temp );
+
+        if ( LESS_THAN( j, base ) )
+          SWAP_CELLS( base, j, temp );
+
+        for (;;)
+        {
+          do i++; while ( LESS_THAN( i, base ) );
+          do j--; while ( LESS_THAN( base, j ) );
+
+          if ( i > j )
+            break;
+
+          SWAP_CELLS( i, j, temp );
+        }
+
+        SWAP_CELLS( base, j, temp );
+
+        /* now, push the largest sub-array */
+        if ( j - base > limit - i )
+        {
+          top[0] = base;
+          top[1] = j;
+          base   = i;
+        }
+        else
+        {
+          top[0] = i;
+          top[1] = limit;
+          limit  = j;
+        }
+        top += 2;
+      }
+      else
+      {
+        /* the sub-array is small, perform insertion sort */
+        j = base;
+        i = j + 1;
+
+        for ( ; i < limit; j = i, i++ )
+        {
+          for ( ; LESS_THAN( j + 1, j ); j-- )
+          {
+            SWAP_CELLS( j + 1, j, temp );
+            if ( j == base )
+              break;
+          }
+        }
+        if ( top > stack )
+        {
+          top  -= 2;
+          base  = top[0];
+          limit = top[1];
+        }
+        else
+          break;
+      }
+    }
+  }
+
+#endif /* QUICK_SORT */
+
+
+#ifdef DEBUG_GRAYS
+#ifdef DEBUG_SORT
+
+  static
+  int  check_sort( PCell  cells,
+                   int    count )
+  {
+    PCell  p, q;
+
+
+    for ( p = cells + count - 2; p >= cells; p-- )
+    {
+      q = p + 1;
+      if ( !LESS_THAN( p, q ) )
+        return 0;
+    }
+    return 1;
+  }
+
+#endif /* DEBUG_SORT */
+#endif /* DEBUG_GRAYS */
+
+
+  static
+  int  Move_To( FT_Vector*  to,
+                FT_Raster   raster )
+  {
+    TPos  x, y;
+
+
+    /* record current cell, if any */
+    record_cell( (PRaster)raster );
+
+    /* start to a new position */
+    x = UPSCALE( to->x );
+    y = UPSCALE( to->y );
+    start_cell( (PRaster)raster, TRUNC( x ), TRUNC( y ) );
+    ((PRaster)raster)->x = x;
+    ((PRaster)raster)->y = y;
+    return 0;
+  }
+
+
+  static
+  int  Line_To( FT_Vector*  to,
+                FT_Raster   raster )
+  {
+    return render_line( (PRaster)raster,
+                        UPSCALE( to->x ), UPSCALE( to->y ) );
+  }
+
+
+  static
+  int  Conic_To( FT_Vector*  control,
+                 FT_Vector*  to,
+                 FT_Raster   raster )
+  {
+    return render_conic( (PRaster)raster, control, to );
+  }
+
+
+  static
+  int  Cubic_To( FT_Vector*  control1,
+                 FT_Vector*  control2,
+                 FT_Vector*  to,
+                 FT_Raster   raster )
+  {
+    return render_cubic( (PRaster)raster, control1, control2, to );
+  }
+
+
+  static
+  void  grays_render_span( int       y,
+                           int       count,
+                           FT_Span*  spans,
+                           PRaster   raster )
+  {
+    unsigned char*  p;
+    FT_Bitmap*      map = &raster->target;
+
+
+    /* first of all, compute the scanline offset */
+    p = (unsigned char*)map->buffer - y * map->pitch;
+    if ( map->pitch >= 0 )
+      p += ( map->rows - 1 ) * map->pitch;
+
+    for ( ; count > 0; count--, spans++ )
+    {
+      if ( spans->coverage )
+#if 1
+        memset( p + spans->x, (unsigned char)spans->coverage, spans->len );
+#else /* 1 */
+      {
+        q     = p + spans->x;
+        limit = q + spans->len;
+        for ( ; q < limit; q++ )
+          q[0] = (unsigned char)spans->coverage;
+      }
+#endif /* 1 */
+    }
+  }
+
+
+#ifdef DEBUG_GRAYS
+
+#include <stdio.h>
+
+  static
+  void  dump_cells( RAS_ARG )
+  {
+    PCell  cell, limit;
+    int    y = -1;
+
+
+    cell  = ras.cells;
+    limit = cell + ras.num_cells;
+
+    for ( ; cell < limit; cell++ )
+    {
+      if ( cell->y != y )
+      {
+        fprintf( stderr, "\n%2d: ", cell->y );
+        y = cell->y;
+      }
+      fprintf( stderr, "[%d %d %d]",
+               cell->x, cell->area, cell->cover );
+    }
+    fprintf(stderr, "\n" );
+  }
+
+#endif /* DEBUG_GRAYS */
+
+
+  static
+  void  grays_hline( RAS_ARG_ TScan  x,
+                              TScan  y,
+                              TPos   area,
+                              int    acount )
+  {
+    FT_Span*   span;
+    int        count;
+    int        coverage;
+
+
+    /* compute the coverage line's coverage, depending on the    */
+    /* outline fill rule                                         */
+    /*                                                           */
+    /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
+    /*                                                           */
+    coverage = area >> ( PIXEL_BITS * 2 + 1 - 8);  /* use range 0..256 */
+
+    if ( ras.outline.flags & ft_outline_even_odd_fill )
+    {
+      if ( coverage < 0 )
+        coverage = -coverage;
+
+      while ( coverage >= 512 )
+        coverage -= 512;
+
+      if ( coverage > 256 )
+        coverage = 512 - coverage;
+      else if ( coverage == 256 )
+        coverage = 255;
+    }
+    else
+    {
+      /* normal non-zero winding rule */
+      if ( coverage < 0 )
+        coverage = -coverage;
+
+      if ( coverage >= 256 )
+        coverage = 255;
+    }
+
+    y += ras.min_ey;
+    x += ras.min_ex;
+
+    if ( coverage )
+    {
+      /* see if we can add this span to the current list */
+      count = ras.num_gray_spans;
+      span  = ras.gray_spans + count - 1;
+      if ( count > 0                          &&
+           ras.span_y == y                    &&
+           (int)span->x + span->len == (int)x &&
+           span->coverage == coverage )
+      {
+        span->len += acount;
+        return;
+      }
+
+      if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS )
+      {
+        if ( ras.render_span )
+          ras.render_span( ras.span_y, count, ras.gray_spans,
+                           ras.render_span_data );
+        /* ras.render_span( span->y, ras.gray_spans, count ); */
+
+#ifdef DEBUG_GRAYS
+
+        if ( ras.span_y >= 0 )
+        {
+          int  n;
+
+
+          fprintf( stderr, "y=%3d ", ras.span_y );
+          span = ras.gray_spans;
+          for ( n = 0; n < count; n++, span++ )
+            fprintf( stderr, "[%d..%d]:%02x ",
+                     span->x, span->x + span->len - 1, span->coverage );
+          fprintf( stderr, "\n" );
+        }
+
+#endif /* DEBUG_GRAYS */
+
+        ras.num_gray_spans = 0;
+        ras.span_y         = y;
+
+        count = 0;
+        span  = ras.gray_spans;
+      }
+      else
+        span++;
+
+      /* add a gray span to the current list */
+      span->x        = (short)x;
+      span->len      = (unsigned short)acount;
+      span->coverage = (unsigned char)coverage;
+      ras.num_gray_spans++;
+    }
+  }
+
+
+  static
+  void  grays_sweep( RAS_ARG_ FT_Bitmap*  target )
+  {
+    TScan  x, y, cover, area;
+    PCell  start, cur, limit;
+
+    UNUSED( target );
+
+
+    cur   = ras.cells;
+    limit = cur + ras.num_cells;
+
+    cover              = 0;
+    ras.span_y         = -1;
+    ras.num_gray_spans = 0;
+
+    for (;;)
+    {
+      start  = cur;
+      y      = start->y;
+      x      = start->x;
+
+      area   = start->area;
+      cover += start->cover;
+
+      /* accumulate all start cells */
+      for (;;)
+      {
+        ++cur;
+        if ( cur >= limit || cur->y != start->y || cur->x != start->x )
+          break;
+
+        area  += cur->area;
+        cover += cur->cover;
+      }
+
+      /* if the start cell has a non-null area, we must draw an */
+      /* individual gray pixel there                            */
+      if ( area && x >= 0 )
+      {
+        grays_hline( RAS_VAR_ x, y, cover * ( ONE_PIXEL * 2 ) - area, 1 );
+        x++;
+      }
+
+      if ( x < 0 )
+        x = 0;
+
+      if ( cur < limit && start->y == cur->y )
+      {
+        /* draw a gray span between the start cell and the current one */
+        if ( cur->x > x )
+          grays_hline( RAS_VAR_ x, y,
+                       cover * ( ONE_PIXEL * 2 ), cur->x - x );
+      }
+      else
+      {
+        /* draw a gray span until the end of the clipping region */
+        if ( cover && x < ras.max_ex - ras.min_ex )
+          grays_hline( RAS_VAR_ x, y,
+                       cover * ( ONE_PIXEL * 2 ),
+                       ras.max_ex - x - ras.min_ex );
+        cover = 0;
+      }
+
+      if ( cur >= limit )
+        break;
+    }
+
+    if ( ras.render_span && ras.num_gray_spans > 0 )
+      ras.render_span( ras.span_y, ras.num_gray_spans,
+                       ras.gray_spans, ras.render_span_data );
+
+#ifdef DEBUG_GRAYS
+
+    {
+      int       n;
+      FT_Span*  span;
+
+
+      fprintf( stderr, "y=%3d ", ras.span_y );
+      span = ras.gray_spans;
+      for ( n = 0; n < ras.num_gray_spans; n++, span++ )
+        fprintf( stderr, "[%d..%d]:%02x ",
+                 span->x, span->x + span->len - 1, span->coverage );
+      fprintf( stderr, "\n" );
+    }
+
+#endif /* DEBUG_GRAYS */
+
+  }
+
+
+#ifdef _STANDALONE_
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  The following function should only compile in stand_alone mode,      */
+  /*  i.e., when building this component without the rest of FreeType.     */
+  /*                                                                       */
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_Outline_Decompose                                               */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Walks over an outline's structure to decompose it into individual  */
+  /*    segments and Bezier arcs.  This function is also able to emit      */
+  /*    `move to' and `close to' operations to indicate the start and end  */
+  /*    of new contours in the outline.                                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    outline   :: A pointer to the source target.                       */
+  /*                                                                       */
+  /*    interface :: A table of `emitters', i.e,. function pointers called */
+  /*                 during decomposition to indicate path operations.     */
+  /*                                                                       */
+  /*    user      :: A typeless pointer which is passed to each emitter    */
+  /*                 during the decomposition.  It can be used to store    */
+  /*                 the state during the decomposition.                   */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Error code.  0 means sucess.                                       */
+  /*                                                                       */
+  static
+  int  FT_Outline_Decompose( FT_Outline*        outline,
+                             FT_Outline_Funcs*  interface,
+                             void*              user )
+  {
+#undef SCALED
+#define SCALED( x )  ( ( (x) << shift ) - delta )
+
+    FT_Vector   v_last;
+    FT_Vector   v_control;
+    FT_Vector   v_start;
+
+    FT_Vector*  point;
+    FT_Vector*  limit;
+    char*       tags;
+
+    int     n;         /* index of contour in outline     */
+    int     first;     /* index of first point in contour */
+    int     error;
+    char    tag;       /* current point's state           */
+
+    int     shift = interface->shift;
+    FT_Pos  delta = interface->delta;
+
+
+    first = 0;
+
+    for ( n = 0; n < outline->n_contours; n++ )
+    {
+      int  last;  /* index of last point in contour */
+
+
+      last  = outline->contours[n];
+      limit = outline->points + last;
+
+      v_start = outline->points[first];
+      v_last  = outline->points[last];
+
+      v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y );
+      v_last.x  = SCALED( v_last.x );  v_last.y  = SCALED( v_last.y );
+
+      v_control = v_start;
+
+      point = outline->points + first;
+      tags  = outline->tags  + first;
+      tag   = FT_CURVE_TAG( tags[0] );
+
+      /* A contour cannot start with a cubic control point! */
+      if ( tag == FT_Curve_Tag_Cubic )
+        goto Invalid_Outline;
+
+      /* check first point to determine origin */
+      if ( tag == FT_Curve_Tag_Conic )
+      {
+        /* first point is conic control.  Yes, this happens. */
+        if ( FT_CURVE_TAG( outline->tags[last] ) == FT_Curve_Tag_On )
+        {
+          /* start at last point if it is on the curve */
+          v_start = v_last;
+          limit--;
+        }
+        else
+        {
+          /* if both first and last points are conic,         */
+          /* start at their middle and record its position    */
+          /* for closure                                      */
+          v_start.x = ( v_start.x + v_last.x ) / 2;
+          v_start.y = ( v_start.y + v_last.y ) / 2;
+
+          v_last = v_start;
+        }
+        point--;
+        tags--;
+      }
+
+      error = interface->move_to( &v_start, user );
+      if ( error )
+        goto Exit;
+
+      while ( point < limit )
+      {
+        point++;
+        tags++;
+
+        tag = FT_CURVE_TAG( tags[0] );
+        switch ( tag )
+        {
+        case FT_Curve_Tag_On:  /* emit a single line_to */
+          {
+            FT_Vector  vec;
+
+
+            vec.x = SCALED( point->x );
+            vec.y = SCALED( point->y );
+
+            error = interface->line_to( &vec, user );
+            if ( error )
+              goto Exit;
+            continue;
+          }
+
+        case FT_Curve_Tag_Conic:  /* consume conic arcs */
+          {
+            v_control.x = SCALED( point->x );
+            v_control.y = SCALED( point->y );
+
+          Do_Conic:
+            if ( point < limit )
+            {
+              FT_Vector  vec;
+              FT_Vector  v_middle;
+
+
+              point++;
+              tags++;
+              tag = FT_CURVE_TAG( tags[0] );
+
+              vec.x = SCALED( point->x );
+              vec.y = SCALED( point->y );
+
+              if ( tag == FT_Curve_Tag_On )
+              {
+                error = interface->conic_to( &v_control, &vec, user );
+                if ( error )
+                  goto Exit;
+                continue;
+              }
+
+              if ( tag != FT_Curve_Tag_Conic )
+                goto Invalid_Outline;
+
+              v_middle.x = ( v_control.x + vec.x ) / 2;
+              v_middle.y = ( v_control.y + vec.y ) / 2;
+
+              error = interface->conic_to( &v_control, &v_middle, user );
+              if ( error )
+                goto Exit;
+
+              v_control = vec;
+              goto Do_Conic;
+            }
+
+            error = interface->conic_to( &v_control, &v_start, user );
+            goto Close;
+          }
+
+        default:  /* FT_Curve_Tag_Cubic */
+          {
+            FT_Vector  vec1, vec2;
+
+
+            if ( point + 1 > limit                             ||
+                 FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic )
+              goto Invalid_Outline;
+
+            point += 2;
+            tags  += 2;
+
+            vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y );
+            vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y );
+
+            if ( point <= limit )
+            {
+              FT_Vector  vec;
+
+
+              vec.x = SCALED( point->x );
+              vec.y = SCALED( point->y );
+
+              error = interface->cubic_to( &vec1, &vec2, &vec, user );
+              if ( error )
+                goto Exit;
+              continue;
+            }
+
+            error = interface->cubic_to( &vec1, &vec2, &v_start, user );
+            goto Close;
+          }
+        }
+      }
+
+      /* close the contour with a line segment */
+      error = interface->line_to( &v_start, user );
+
+   Close:
+      if ( error )
+        goto Exit;
+
+      first = last + 1;
+    }
+
+    return 0;
+
+  Exit:
+    return error;
+
+  Invalid_Outline:
+    return ErrRaster_Invalid_Outline;
+  }
+
+#endif /* _STANDALONE_ */
+
+
+  typedef struct  TBand_
+  {
+    FT_Pos  min, max;
+
+  } TBand;
+
+
+  static
+  int  grays_convert_glyph( RAS_ARG_ 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,
+      0,
+      0
+    };
+
+    TBand    bands[40], *band;
+    int      n, num_bands;
+    TPos     min, max, max_y;
+
+
+    /* Set up state in the raster object */
+    compute_cbox( RAS_VAR_ outline );
+
+    /* clip to target bitmap, exit if nothing to do */
+    if ( ras.max_ex <= 0 || ras.min_ex >= ras.target.width ||
+         ras.max_ey <= 0 || ras.min_ey >= ras.target.rows  )
+      return 0;
+
+    if ( ras.min_ex < 0 ) ras.min_ex = 0;
+    if ( ras.min_ey < 0 ) ras.min_ey = 0;
+
+    if ( ras.max_ex > ras.target.width ) ras.max_ex = ras.target.width;
+    if ( ras.max_ey > ras.target.rows )  ras.max_ey = ras.target.rows;
+
+    /* simple heuristic used to speed-up the bezier decomposition     */
+    /* see the code in render_conic and render_cubic for more details */
+    ras.conic_level = 32;
+    ras.cubic_level = 16;
+
+    {
+      int level = 0;
+
+
+      if ( ras.max_ex > 24 || ras.max_ey > 24 )
+        level++;
+      if ( ras.max_ex > 120 || ras.max_ey > 120 )
+        level += 2;
+
+      ras.conic_level <<= level;
+      ras.cubic_level <<= level;
+    }
+
+    /* setup vertical bands */
+    num_bands = ( ras.max_ey - ras.min_ey ) / ras.band_size;
+    if ( num_bands == 0 )  num_bands = 1;
+    if ( num_bands >= 39 ) num_bands = 39;
+
+    ras.band_shoot = 0;
+
+    min   = ras.min_ey;
+    max_y = ras.max_ey;
+
+    for ( n = 0; n < num_bands; n++, min = max )
+    {
+      max = min + ras.band_size;
+      if ( n == num_bands - 1 || max > max_y )
+        max = max_y;
+
+      bands[0].min = min;
+      bands[0].max = max;
+      band         = bands;
+
+      while ( band >= bands )
+      {
+        FT_Pos  bottom, top, middle;
+        int     error;
+
+
+        ras.num_cells = 0;
+        ras.invalid   = 1;
+        ras.min_ey    = band->min;
+        ras.max_ey    = band->max;
+
+        error = FT_Outline_Decompose( outline, &interface, &ras ) ||
+                record_cell( RAS_VAR );
+
+        if ( !error )
+        {
+#ifdef SHELL_SORT
+          shell_sort( ras.cells, ras.num_cells );
+#else
+          quick_sort( ras.cells, ras.num_cells );
+#endif
+
+#ifdef DEBUG_GRAYS
+          check_sort( ras.cells, ras.num_cells );
+          dump_cells( RAS_VAR );
+#endif
+
+          grays_sweep( RAS_VAR_  &ras.target );
+          band--;
+          continue;
+        }
+
+        /* render pool overflow, we will reduce the render band by half */
+        bottom = band->min;
+        top    = band->max;
+        middle = bottom + ( ( top - bottom ) >> 1 );
+
+        /* waoow! This is too complex for a single scanline, something */
+        /* must be really rotten here!                                 */
+        if ( middle == bottom )
+        {
+#ifdef DEBUG_GRAYS
+          fprintf( stderr, "Rotten glyph!\n" );
+#endif
+          return 1;
+        }
+
+        if ( bottom-top >= ras.band_size )
+          ras.band_shoot++;
+
+        band[1].min = bottom;
+        band[1].max = middle;
+        band[0].min = middle;
+        band[0].max = top;
+        band++;
+      }
+    }
+
+    if ( ras.band_shoot > 8 && ras.band_size > 16 )
+      ras.band_size = ras.band_size / 2;
+
+    return 0;
+  }
+
+
+  extern
+  int  grays_raster_render( PRaster            raster,
+                            FT_Raster_Params*  params )
+  {
+    FT_Outline*  outline = (FT_Outline*)params->source;
+    FT_Bitmap*   target_map = params->target;
+
+
+    if ( !raster || !raster->cells || !raster->max_cells )
+      return -1;
+
+    /* return immediately if the outline is empty */
+    if ( outline->n_points == 0 || outline->n_contours <= 0 )
+      return 0;
+
+    if ( !outline || !outline->contours || !outline->points )
+      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 -1;
+
+    /* XXXX: this version does not support monochrome rendering yet! */
+    if ( !(params->flags & ft_raster_flag_aa) )
+      return ErrRaster_Invalid_Mode;
+
+    ras.outline   = *outline;
+    ras.target    = *target_map;
+    ras.num_cells = 0;
+    ras.invalid   = 1;
+
+    ras.render_span      = (FT_Raster_Span_Func)grays_render_span;
+    ras.render_span_data = &ras;
+
+    if ( params->flags & ft_raster_flag_direct )
+    {
+      ras.render_span      = (FT_Raster_Span_Func)params->gray_spans;
+      ras.render_span_data = params->user;
+    }
+
+    return grays_convert_glyph( (PRaster)raster, outline );
+  }
+
+
+  /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
+  /****                         a static object.                  *****/
+
+#ifdef _STANDALONE_
+
+  static
+  int  grays_raster_new( void*       memory,
+                         FT_Raster*  araster )
+  {
+    static TRaster  the_raster;
+
+    UNUSED( memory );
+
+
+    *araster = (FT_Raster)&the_raster;
+    memset( &the_raster, 0, sizeof ( the_raster ) );
+
+    return 0;
+  }
+
+
+  static
+  void  grays_raster_done( FT_Raster  raster )
+  {
+    /* nothing */
+    UNUSED( raster );
+  }
+
+#else /* _STANDALONE_ */
+
+  static
+  int  grays_raster_new( FT_Memory   memory,
+                         FT_Raster*  araster )
+  {
+    FT_Error  error;
+    PRaster   raster;
+
+
+    *araster = 0;
+    if ( !ALLOC( raster, sizeof ( TRaster ) ) )
+    {
+      raster->memory = memory;
+      *araster = (FT_Raster)raster;
+    }
+
+    return error;
+  }
+
+
+  static
+  void grays_raster_done( FT_Raster  raster )
+  {
+    FT_Memory  memory = (FT_Memory)((PRaster)raster)->memory;
+
+
+    FREE( raster );
+  }
+
+#endif /* _STANDALONE_ */
+
+
+  static
+  void  grays_raster_reset( FT_Raster    raster,
+                            const char*  pool_base,
+                            long         pool_size )
+  {
+    PRaster  rast = (PRaster)raster;
+
+
+    if ( raster && pool_base && pool_size >= 4096 )
+      init_cells( rast, (char*)pool_base, pool_size );
+
+    rast->band_size  = ( pool_size / sizeof ( TCell ) ) / 8;
+  }
+
+
+  FT_Raster_Funcs  ft_grays_raster =
+  {
+    ft_glyph_format_outline,
+
+    (FT_Raster_New_Func)     grays_raster_new,
+    (FT_Raster_Reset_Func)   grays_raster_reset,
+    (FT_Raster_Set_Mode_Func)0,
+    (FT_Raster_Render_Func)  grays_raster_render,
+    (FT_Raster_Done_Func)    grays_raster_done
+  };
+
+
+/* END */
--- /dev/null
+++ b/src/smooth/ftgrays.h
@@ -1,0 +1,49 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftgrays.h                                                              */
+/*                                                                         */
+/*    FreeType smooth renderer declaration                                 */
+/*                                                                         */
+/*  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 FTGRAYS_H
+#define FTGRAYS_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+#ifdef _STANDALONE_
+#include "ftimage.h"
+#else
+#include <freetype/ftimage.h>
+#endif
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* To make ftgrays.h independent from configuration files we check       */
+  /* whether FT_EXPORT_DEF has been defined already.                          */
+  /*                                                                       */
+  /* On some systems and compilers (Win32 mostly), an extra keyword is     */
+  /* necessary to compile the library as a DLL.                            */
+  /*                                                                       */
+#ifndef FT_EXPORT_VAR
+#define FT_EXPORT_VAR(x)  extern  x
+#endif
+
+  FT_EXPORT_VAR(FT_Raster_Funcs)  ft_grays_raster;
+
+  #ifdef __cplusplus
+  }
+  #endif
+
+#endif
--- /dev/null
+++ b/src/smooth/ftsmooth.c
@@ -1,0 +1,176 @@
+#include <freetype/internal/ftobjs.h>
+#include <ftsmooth.h>
+#include <ftgrays.h>
+
+ /* initialise renderer - init its raster */
+  static FT_Error ft_smooth_init( FT_Renderer  render )
+  {
+    FT_Library  library = FT_MODULE_LIBRARY(render);
+    
+    render->clazz->raster_class->raster_reset( render->raster,
+        library->raster_pool, library->raster_pool_size );
+
+    return 0;
+  }
+  
+
+
+ /* sets render-specific mode */
+  static  FT_Error  ft_smooth_set_mode( FT_Renderer  render,
+                                        FT_ULong     mode_tag,
+                                        FT_Pointer   data )
+  {
+    /* we simply pass it to the raster */
+    return render->clazz->raster_class->raster_set_mode(
+                    render->raster, mode_tag, data );
+  }                                          
+
+ /* transform a given glyph image */
+  static  FT_Error  ft_smooth_transform( FT_Renderer   render,
+                                         FT_GlyphSlot  slot,
+                                         FT_Matrix*    matrix,
+                                         FT_Vector*    delta )
+  {
+    FT_Error error = FT_Err_Ok;
+    
+    if (slot->format != render->glyph_format)
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+    
+    if (matrix)
+      FT_Outline_Transform( &slot->outline, matrix );
+      
+    if (delta)
+      FT_Outline_Translate( &slot->outline, delta->x, delta->y );
+    
+  Exit:
+    return error;
+  }
+
+ /* return the glyph's control box */
+  static  void  ft_smooth_get_cbox( FT_Renderer   render,
+                                      FT_GlyphSlot  slot,
+                                      FT_BBox      *cbox )
+  {
+    MEM_Set( cbox, 0, sizeof(*cbox) );
+
+    if (slot->format == render->glyph_format)
+      FT_Outline_Get_CBox( &slot->outline, cbox );
+  }                                      
+  
+
+ /* convert a slot's glyph image into a bitmap */
+  static  FT_Error  ft_smooth_render( FT_Renderer  render,
+                                      FT_GlyphSlot slot,
+                                      FT_UInt      mode,
+                                      FT_Vector*   origin )
+  {
+    FT_Error     error;
+    FT_Outline*  outline;
+    FT_BBox      cbox;
+    FT_UInt      width, height, pitch;
+    FT_Bitmap*   bitmap;
+    FT_Memory    memory;
+    
+    FT_Raster_Params  params;
+    
+    /* check glyph image format */
+    if (slot->format != render->glyph_format)
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+    
+    /* check mode */
+    if ( !(mode & ft_render_mode_antialias) )
+      return FT_Err_Cannot_Render_Glyph;
+      
+    outline = &slot->outline;
+    
+    /* translate the outline to the new origin if needed */
+    if (origin)
+      FT_Outline_Translate( outline, origin->x, origin->y );
+    
+    /* compute the control box, and grid fit it */
+    FT_Outline_Get_CBox( outline, &cbox );
+    
+    cbox.xMin &= -64;
+    cbox.yMin &= -64;
+    cbox.xMax  = (cbox.xMax+63) & -64;
+    cbox.yMax  = (cbox.yMax+63) & -64;
+
+    width  = (cbox.xMax - cbox.xMin) >> 6;
+    height = (cbox.yMax - cbox.yMin) >> 6;
+    bitmap = &slot->bitmap;
+    memory = slot->face->memory;
+    
+    /* release old bitmap buffer */
+    if ((slot->flags & ft_glyph_own_bitmap))
+    {
+      FREE(bitmap->buffer);
+      slot->flags &= ~ft_glyph_own_bitmap;
+    }
+      
+    /* allocate new one, depends on pixel format */
+    pitch = width;
+    bitmap->pixel_mode = ft_pixel_mode_grays;
+    bitmap->num_grays  = 256;
+    bitmap->width      = width;
+    bitmap->rows       = height;
+    bitmap->pitch      = pitch;
+    
+    if (ALLOC( bitmap->buffer, (FT_ULong)pitch * height ))
+      goto Exit;
+
+    slot->flags |= ft_glyph_own_bitmap;
+    
+    /* translate outline to render it into the bitmap */
+    FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin );
+
+    /* set up parameters */
+    params.target = bitmap;
+    params.source = outline;
+    params.flags  = ft_raster_flag_aa;
+
+    /* render outline into the bitmap */
+    error = render->raster_render( render->raster, &params );
+    if (error) goto Exit;
+    
+    slot->format      = ft_glyph_format_bitmap;
+    slot->bitmap_left = cbox.xMin >> 6;
+    slot->bitmap_top  = cbox.yMax >> 6;
+
+  Exit:
+    return error;
+  }
+
+
+  const FT_Renderer_Class  ft_smooth_renderer_class =
+  {
+    {
+      ft_module_renderer,
+      sizeof( FT_RendererRec ),
+      
+      "smooth",
+      0x10000,
+      0x20000,
+      
+      0,    /* module specific interface */
+      
+      (FT_Module_Constructor)  ft_smooth_init,
+      (FT_Module_Destructor)   0,
+      (FT_Module_Requester)    0
+    },
+
+    ft_glyph_format_outline,
+    
+    (FTRenderer_render)       ft_smooth_render,
+    (FTRenderer_transform)    ft_smooth_transform,
+    (FTRenderer_getCBox)      ft_smooth_get_cbox,
+    (FTRenderer_setMode)      ft_smooth_set_mode,
+    
+    (FT_Raster_Funcs*)        &ft_grays_raster
+  };
+
--- /dev/null
+++ b/src/smooth/ftsmooth.h
@@ -1,0 +1,8 @@
+#ifndef FTSMOOTH_H
+#define FTSMOOTH_H
+
+#include <freetype/ftrender.h>
+
+  FT_EXPORT_VAR(const FT_Renderer_Class)   ft_smooth_renderer_class;
+
+#endif /* FTSMOOTH_H */
--- /dev/null
+++ b/src/smooth/module.mk
@@ -1,0 +1,7 @@
+make_module_list: add_smooth_renderer
+
+add_smooth_renderer:
+	$(OPEN_DRIVER)ft_smooth_renderer_class$(CLOSE_DRIVER)
+	$(ECHO_DRIVER)smooth    $(ECHO_DRIVER_DESC)anti-aliased bitmap renderer$(ECHO_DRIVER_DONE)
+
+# EOF
--- /dev/null
+++ b/src/smooth/rules.mk
@@ -1,0 +1,74 @@
+#
+# FreeType 2 renderer module build rules
+#
+
+
+# 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.
+
+
+# renderer driver directory
+#
+SMOOTH_DIR  := $(SRC_)smooth
+SMOOTH_DIR_ := $(SMOOTH_DIR)$(SEP)
+
+
+# additional include flags used when compiling the driver
+#
+SMOOTH_INCLUDE := $(SMOOTH_DIR)
+
+# compilation flags for the driver
+#
+SMOOTH_CFLAGS  := $(SMOOTH_INCLUDE:%=$I%)
+SMOOTH_COMPILE := $(FT_COMPILE) $(SMOOTH_CFLAGS)
+
+
+# SMOOTH driver sources (i.e., C files)
+#
+SMOOTH_DRV_SRC := $(SMOOTH_DIR_)ftgrays.c   \
+                  $(SMOOTH_DIR_)ftsmooth.c
+
+# SMOOTH driver headers
+#
+SMOOTH_DRV_H := $(SMOOTH_DRV_SRC:%c=%h)
+
+
+# SMOOTH driver object(s)
+#
+#   SMOOTH_DRV_OBJ_M is used during `multi' builds.
+#   SMOOTH_DRV_OBJ_S is used during `single' builds.
+#
+SMOOTH_DRV_OBJ_M := $(SMOOTH_DRV_SRC:$(SMOOTH_DIR_)%.c=$(OBJ_)%.$O)
+SMOOTH_DRV_OBJ_S := $(OBJ_)smooth.$O
+
+# SMOOTH driver source file for single build
+#
+SMOOTH_DRV_SRC_S := $(SMOOTH_DIR_)smooth.c
+
+
+# SMOOTH driver - single object
+#
+$(SMOOTH_DRV_OBJ_S): $(SMOOTH_DRV_SRC_S) $(SMOOTH_DRV_SRC) \
+                   $(FREETYPE_H) $(SMOOTH_DRV_H)
+	$(SMOOTH_COMPILE) $T$@ $(SMOOTH_DRV_SRC_S)
+
+
+# SMOOTH driver - multiple objects
+#
+$(OBJ_)%.$O: $(SMOOTH_DIR_)%.c $(FREETYPE_H) $(SMOOTH_DRV_H)
+	$(SMOOTH_COMPILE) $T$@ $<
+
+
+# update main driver object lists
+#
+DRV_OBJS_S += $(SMOOTH_DRV_OBJ_S)
+DRV_OBJS_M += $(SMOOTH_DRV_OBJ_M)
+
+
+# EOF
--- /dev/null
+++ b/src/smooth/smooth.c
@@ -1,0 +1,4 @@
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+#include <ftgrays.c>
+#include <ftsmooth.c>
+
--- /dev/null
+++ b/src/smooth/smooth.h
@@ -1,0 +1,14 @@
+#ifndef RENDERER_H
+#define RENDERER_H
+
+#include <freetype/ftrender.h>
+
+#ifndef FT_CONFIG_OPTION_NO_STD_RASTER
+  FT_EXPORT_VAR(const FT_Renderer_Class)   ft_std_renderer_class;
+#endif
+
+#ifndef FT_CONFIG_OPTION_NO_SMOOTH_RASTER
+  FT_EXPORT_VAR(const FT_Renderer_Class)   ft_smooth_renderer_class;
+#endif
+
+#endif /* RENDERER_H */