Home | History | Annotate | Download | only in raster
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  ftraster.c                                                             */
      4 /*                                                                         */
      5 /*    The FreeType glyph rasterizer (body).                                */
      6 /*                                                                         */
      7 /*  Copyright 1996-2001, 2002, 2003, 2005, 2007, 2008, 2009 by             */
      8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
      9 /*                                                                         */
     10 /*  This file is part of the FreeType project, and may only be used,       */
     11 /*  modified, and distributed under the terms of the FreeType project      */
     12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
     13 /*  this file you indicate that you have read the license and              */
     14 /*  understand and accept it fully.                                        */
     15 /*                                                                         */
     16 /***************************************************************************/
     17 
     18   /*************************************************************************/
     19   /*                                                                       */
     20   /* This file can be compiled without the rest of the FreeType engine, by */
     21   /* defining the _STANDALONE_ macro when compiling it.  You also need to  */
     22   /* put the files `ftimage.h' and `ftmisc.h' into the $(incdir)           */
     23   /* directory.  Typically, you should do something like                   */
     24   /*                                                                       */
     25   /* - copy `src/raster/ftraster.c' (this file) to your current directory  */
     26   /*                                                                       */
     27   /* - copy `include/freetype/ftimage.h' and `src/raster/ftmisc.h'         */
     28   /*   to your current directory                                           */
     29   /*                                                                       */
     30   /* - compile `ftraster' with the _STANDALONE_ macro defined, as in       */
     31   /*                                                                       */
     32   /*     cc -c -D_STANDALONE_ ftraster.c                                   */
     33   /*                                                                       */
     34   /* The renderer can be initialized with a call to                        */
     35   /* `ft_standard_raster.raster_new'; a bitmap can be generated            */
     36   /* with a call to `ft_standard_raster.raster_render'.                    */
     37   /*                                                                       */
     38   /* See the comments and documentation in the file `ftimage.h' for more   */
     39   /* details on how the raster works.                                      */
     40   /*                                                                       */
     41   /*************************************************************************/
     42 
     43 
     44   /*************************************************************************/
     45   /*                                                                       */
     46   /* This is a rewrite of the FreeType 1.x scan-line converter             */
     47   /*                                                                       */
     48   /*************************************************************************/
     49 
     50 #ifdef _STANDALONE_
     51 
     52 #define FT_CONFIG_STANDARD_LIBRARY_H  <stdlib.h>
     53 
     54 #include <string.h>           /* for memset */
     55 
     56 #include "ftmisc.h"
     57 #include "ftimage.h"
     58 
     59 #else /* !_STANDALONE_ */
     60 
     61 #include <ft2build.h>
     62 #include "ftraster.h"
     63 #include FT_INTERNAL_CALC_H   /* for FT_MulDiv only */
     64 
     65 #include "rastpic.h"
     66 
     67 #endif /* !_STANDALONE_ */
     68 
     69 
     70   /*************************************************************************/
     71   /*                                                                       */
     72   /* A simple technical note on how the raster works                       */
     73   /* -----------------------------------------------                       */
     74   /*                                                                       */
     75   /*   Converting an outline into a bitmap is achieved in several steps:   */
     76   /*                                                                       */
     77   /*   1 - Decomposing the outline into successive `profiles'.  Each       */
     78   /*       profile is simply an array of scanline intersections on a given */
     79   /*       dimension.  A profile's main attributes are                     */
     80   /*                                                                       */
     81   /*       o its scanline position boundaries, i.e. `Ymin' and `Ymax'      */
     82   /*                                                                       */
     83   /*       o an array of intersection coordinates for each scanline        */
     84   /*         between `Ymin' and `Ymax'                                     */
     85   /*                                                                       */
     86   /*       o a direction, indicating whether it was built going `up' or    */
     87   /*         `down', as this is very important for filling rules           */
     88   /*                                                                       */
     89   /*       o its drop-out mode                                             */
     90   /*                                                                       */
     91   /*   2 - Sweeping the target map's scanlines in order to compute segment */
     92   /*       `spans' which are then filled.  Additionally, this pass         */
     93   /*       performs drop-out control.                                      */
     94   /*                                                                       */
     95   /*   The outline data is parsed during step 1 only.  The profiles are    */
     96   /*   built from the bottom of the render pool, used as a stack.  The     */
     97   /*   following graphics shows the profile list under construction:       */
     98   /*                                                                       */
     99   /*     __________________________________________________________ _ _    */
    100   /*    |         |                 |         |                 |          */
    101   /*    | profile | coordinates for | profile | coordinates for |-->       */
    102   /*    |    1    |  profile 1      |    2    |  profile 2      |-->       */
    103   /*    |_________|_________________|_________|_________________|__ _ _    */
    104   /*                                                                       */
    105   /*    ^                                                       ^          */
    106   /*    |                                                       |          */
    107   /* start of render pool                                      top         */
    108   /*                                                                       */
    109   /*   The top of the profile stack is kept in the `top' variable.         */
    110   /*                                                                       */
    111   /*   As you can see, a profile record is pushed on top of the render     */
    112   /*   pool, which is then followed by its coordinates/intersections.  If  */
    113   /*   a change of direction is detected in the outline, a new profile is  */
    114   /*   generated until the end of the outline.                             */
    115   /*                                                                       */
    116   /*   Note that when all profiles have been generated, the function       */
    117   /*   Finalize_Profile_Table() is used to record, for each profile, its   */
    118   /*   bottom-most scanline as well as the scanline above its upmost       */
    119   /*   boundary.  These positions are called `y-turns' because they (sort  */
    120   /*   of) correspond to local extrema.  They are stored in a sorted list  */
    121   /*   built from the top of the render pool as a downwards stack:         */
    122   /*                                                                       */
    123   /*      _ _ _______________________________________                      */
    124   /*                            |                    |                     */
    125   /*                         <--| sorted list of     |                     */
    126   /*                         <--|  extrema scanlines |                     */
    127   /*      _ _ __________________|____________________|                     */
    128   /*                                                                       */
    129   /*                            ^                    ^                     */
    130   /*                            |                    |                     */
    131   /*                         maxBuff           sizeBuff = end of pool      */
    132   /*                                                                       */
    133   /*   This list is later used during the sweep phase in order to          */
    134   /*   optimize performance (see technical note on the sweep below).       */
    135   /*                                                                       */
    136   /*   Of course, the raster detects whether the two stacks collide and    */
    137   /*   handles the situation properly.                                     */
    138   /*                                                                       */
    139   /*************************************************************************/
    140 
    141 
    142   /*************************************************************************/
    143   /*************************************************************************/
    144   /**                                                                     **/
    145   /**  CONFIGURATION MACROS                                               **/
    146   /**                                                                     **/
    147   /*************************************************************************/
    148   /*************************************************************************/
    149 
    150   /* define DEBUG_RASTER if you want to compile a debugging version */
    151 /* #define DEBUG_RASTER */
    152 
    153   /* define FT_RASTER_OPTION_ANTI_ALIASING if you want to support */
    154   /* 5-levels anti-aliasing                                       */
    155 /* #define FT_RASTER_OPTION_ANTI_ALIASING */
    156 
    157   /* The size of the two-lines intermediate bitmap used */
    158   /* for anti-aliasing, in bytes.                       */
    159 #define RASTER_GRAY_LINES  2048
    160 
    161 
    162   /*************************************************************************/
    163   /*************************************************************************/
    164   /**                                                                     **/
    165   /**  OTHER MACROS (do not change)                                       **/
    166   /**                                                                     **/
    167   /*************************************************************************/
    168   /*************************************************************************/
    169 
    170   /*************************************************************************/
    171   /*                                                                       */
    172   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
    173   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
    174   /* messages during execution.                                            */
    175   /*                                                                       */
    176 #undef  FT_COMPONENT
    177 #define FT_COMPONENT  trace_raster
    178 
    179 
    180 #ifdef _STANDALONE_
    181 
    182 
    183   /* This macro is used to indicate that a function parameter is unused. */
    184   /* Its purpose is simply to reduce compiler warnings.  Note also that  */
    185   /* simply defining it as `(void)x' doesn't avoid warnings with certain */
    186   /* ANSI compilers (e.g. LCC).                                          */
    187 #define FT_UNUSED( x )  (x) = (x)
    188 
    189   /* Disable the tracing mechanism for simplicity -- developers can      */
    190   /* activate it easily by redefining these two macros.                  */
    191 #ifndef FT_ERROR
    192 #define FT_ERROR( x )  do { } while ( 0 )     /* nothing */
    193 #endif
    194 
    195 #ifndef FT_TRACE
    196 #define FT_TRACE( x )   do { } while ( 0 )    /* nothing */
    197 #define FT_TRACE1( x )  do { } while ( 0 )    /* nothing */
    198 #define FT_TRACE6( x )  do { } while ( 0 )    /* nothing */
    199 #endif
    200 
    201 #define Raster_Err_None          0
    202 #define Raster_Err_Not_Ini      -1
    203 #define Raster_Err_Overflow     -2
    204 #define Raster_Err_Neg_Height   -3
    205 #define Raster_Err_Invalid      -4
    206 #define Raster_Err_Unsupported  -5
    207 
    208 #define ft_memset  memset
    209 
    210 #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, raster_new_, \
    211                                 raster_reset_, raster_set_mode_,    \
    212                                 raster_render_, raster_done_ )      \
    213           const FT_Raster_Funcs class_ =                            \
    214           {                                                         \
    215             glyph_format_,                                          \
    216             raster_new_,                                            \
    217             raster_reset_,                                          \
    218             raster_set_mode_,                                       \
    219             raster_render_,                                         \
    220             raster_done_                                            \
    221          };
    222 
    223 #else /* !_STANDALONE_ */
    224 
    225 
    226 #include FT_INTERNAL_OBJECTS_H
    227 #include FT_INTERNAL_DEBUG_H        /* for FT_TRACE() and FT_ERROR() */
    228 
    229 #include "rasterrs.h"
    230 
    231 #define Raster_Err_None         Raster_Err_Ok
    232 #define Raster_Err_Not_Ini      Raster_Err_Raster_Uninitialized
    233 #define Raster_Err_Overflow     Raster_Err_Raster_Overflow
    234 #define Raster_Err_Neg_Height   Raster_Err_Raster_Negative_Height
    235 #define Raster_Err_Invalid      Raster_Err_Invalid_Outline
    236 #define Raster_Err_Unsupported  Raster_Err_Cannot_Render_Glyph
    237 
    238 
    239 #endif /* !_STANDALONE_ */
    240 
    241 
    242 #ifndef FT_MEM_SET
    243 #define FT_MEM_SET( d, s, c )  ft_memset( d, s, c )
    244 #endif
    245 
    246 #ifndef FT_MEM_ZERO
    247 #define FT_MEM_ZERO( dest, count )  FT_MEM_SET( dest, 0, count )
    248 #endif
    249 
    250   /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is       */
    251   /* typically a small value and the result of a*b is known to fit into */
    252   /* 32 bits.                                                           */
    253 #define FMulDiv( a, b, c )  ( (a) * (b) / (c) )
    254 
    255   /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
    256   /* for clipping computations.  It simply uses the FT_MulDiv() function   */
    257   /* defined in `ftcalc.h'.                                                */
    258 #define SMulDiv  FT_MulDiv
    259 
    260   /* The rasterizer is a very general purpose component; please leave */
    261   /* the following redefinitions there (you never know your target    */
    262   /* environment).                                                    */
    263 
    264 #ifndef TRUE
    265 #define TRUE   1
    266 #endif
    267 
    268 #ifndef FALSE
    269 #define FALSE  0
    270 #endif
    271 
    272 #ifndef NULL
    273 #define NULL  (void*)0
    274 #endif
    275 
    276 #ifndef SUCCESS
    277 #define SUCCESS  0
    278 #endif
    279 
    280 #ifndef FAILURE
    281 #define FAILURE  1
    282 #endif
    283 
    284 
    285 #define MaxBezier  32   /* The maximum number of stacked Bezier curves. */
    286                         /* Setting this constant to more than 32 is a   */
    287                         /* pure waste of space.                         */
    288 
    289 #define Pixel_Bits  6   /* fractional bits of *input* coordinates */
    290 
    291 
    292   /*************************************************************************/
    293   /*************************************************************************/
    294   /**                                                                     **/
    295   /**  SIMPLE TYPE DECLARATIONS                                           **/
    296   /**                                                                     **/
    297   /*************************************************************************/
    298   /*************************************************************************/
    299 
    300   typedef int             Int;
    301   typedef unsigned int    UInt;
    302   typedef short           Short;
    303   typedef unsigned short  UShort, *PUShort;
    304   typedef long            Long, *PLong;
    305   typedef unsigned long   ULong;
    306 
    307   typedef unsigned char   Byte, *PByte;
    308   typedef char            Bool;
    309 
    310 
    311   typedef union  Alignment_
    312   {
    313     long    l;
    314     void*   p;
    315     void  (*f)(void);
    316 
    317   } Alignment, *PAlignment;
    318 
    319 
    320   typedef struct  TPoint_
    321   {
    322     Long  x;
    323     Long  y;
    324 
    325   } TPoint;
    326 
    327 
    328   /* values for the `flags' bit field */
    329 #define Flow_Up           0x8
    330 #define Overshoot_Top     0x10
    331 #define Overshoot_Bottom  0x20
    332 
    333 
    334   /* States of each line, arc, and profile */
    335   typedef enum  TStates_
    336   {
    337     Unknown_State,
    338     Ascending_State,
    339     Descending_State,
    340     Flat_State
    341 
    342   } TStates;
    343 
    344 
    345   typedef struct TProfile_  TProfile;
    346   typedef TProfile*         PProfile;
    347 
    348   struct  TProfile_
    349   {
    350     FT_F26Dot6  X;           /* current coordinate during sweep          */
    351     PProfile    link;        /* link to next profile (various purposes)  */
    352     PLong       offset;      /* start of profile's data in render pool   */
    353     unsigned    flags;       /* Bit 0-2: drop-out mode                   */
    354                              /* Bit 3: profile orientation (up/down)     */
    355                              /* Bit 4: is top profile?                   */
    356                              /* Bit 5: is bottom profile?                */
    357     long        height;      /* profile's height in scanlines            */
    358     long        start;       /* profile's starting scanline              */
    359 
    360     unsigned    countL;      /* number of lines to step before this      */
    361                              /* profile becomes drawable                 */
    362 
    363     PProfile    next;        /* next profile in same contour, used       */
    364                              /* during drop-out control                  */
    365   };
    366 
    367   typedef PProfile   TProfileList;
    368   typedef PProfile*  PProfileList;
    369 
    370 
    371   /* Simple record used to implement a stack of bands, required */
    372   /* by the sub-banding mechanism                               */
    373   typedef struct  TBand_
    374   {
    375     Short  y_min;   /* band's minimum */
    376     Short  y_max;   /* band's maximum */
    377 
    378   } TBand;
    379 
    380 
    381 #define AlignProfileSize \
    382   ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( long ) )
    383 
    384 
    385 #ifdef FT_STATIC_RASTER
    386 
    387 
    388 #define RAS_ARGS       /* void */
    389 #define RAS_ARG        /* void */
    390 
    391 #define RAS_VARS       /* void */
    392 #define RAS_VAR        /* void */
    393 
    394 #define FT_UNUSED_RASTER  do { } while ( 0 )
    395 
    396 
    397 #else /* !FT_STATIC_RASTER */
    398 
    399 
    400 #define RAS_ARGS       PWorker    worker,
    401 #define RAS_ARG        PWorker    worker
    402 
    403 #define RAS_VARS       worker,
    404 #define RAS_VAR        worker
    405 
    406 #define FT_UNUSED_RASTER  FT_UNUSED( worker )
    407 
    408 
    409 #endif /* !FT_STATIC_RASTER */
    410 
    411 
    412   typedef struct TWorker_  TWorker, *PWorker;
    413 
    414 
    415   /* prototypes used for sweep function dispatch */
    416   typedef void
    417   Function_Sweep_Init( RAS_ARGS Short*  min,
    418                                 Short*  max );
    419 
    420   typedef void
    421   Function_Sweep_Span( RAS_ARGS Short       y,
    422                                 FT_F26Dot6  x1,
    423                                 FT_F26Dot6  x2,
    424                                 PProfile    left,
    425                                 PProfile    right );
    426 
    427   typedef void
    428   Function_Sweep_Step( RAS_ARG );
    429 
    430 
    431   /* NOTE: These operations are only valid on 2's complement processors */
    432 
    433 #define FLOOR( x )    ( (x) & -ras.precision )
    434 #define CEILING( x )  ( ( (x) + ras.precision - 1 ) & -ras.precision )
    435 #define TRUNC( x )    ( (signed long)(x) >> ras.precision_bits )
    436 #define FRAC( x )     ( (x) & ( ras.precision - 1 ) )
    437 #define SCALED( x )   ( ( (x) << ras.scale_shift ) - ras.precision_half )
    438 
    439 #define IS_BOTTOM_OVERSHOOT( x )  ( CEILING( x ) - x >= ras.precision_half )
    440 #define IS_TOP_OVERSHOOT( x )     ( x - FLOOR( x ) >= ras.precision_half )
    441 
    442   /* The most used variables are positioned at the top of the structure. */
    443   /* Thus, their offset can be coded with less opcodes, resulting in a   */
    444   /* smaller executable.                                                 */
    445 
    446   struct  TWorker_
    447   {
    448     Int         precision_bits;     /* precision related variables         */
    449     Int         precision;
    450     Int         precision_half;
    451     Long        precision_mask;
    452     Int         precision_shift;
    453     Int         precision_step;
    454     Int         precision_jitter;
    455 
    456     Int         scale_shift;        /* == precision_shift   for bitmaps    */
    457                                     /* == precision_shift+1 for pixmaps    */
    458 
    459     PLong       buff;               /* The profiles buffer                 */
    460     PLong       sizeBuff;           /* Render pool size                    */
    461     PLong       maxBuff;            /* Profiles buffer size                */
    462     PLong       top;                /* Current cursor in buffer            */
    463 
    464     FT_Error    error;
    465 
    466     Int         numTurns;           /* number of Y-turns in outline        */
    467 
    468     TPoint*     arc;                /* current Bezier arc pointer          */
    469 
    470     UShort      bWidth;             /* target bitmap width                 */
    471     PByte       bTarget;            /* target bitmap buffer                */
    472     PByte       gTarget;            /* target pixmap buffer                */
    473 
    474     Long        lastX, lastY;
    475     Long        minY, maxY;
    476 
    477     UShort      num_Profs;          /* current number of profiles          */
    478 
    479     Bool        fresh;              /* signals a fresh new profile which   */
    480                                     /* `start' field must be completed     */
    481     Bool        joint;              /* signals that the last arc ended     */
    482                                     /* exactly on a scanline.  Allows      */
    483                                     /* removal of doublets                 */
    484     PProfile    cProfile;           /* current profile                     */
    485     PProfile    fProfile;           /* head of linked list of profiles     */
    486     PProfile    gProfile;           /* contour's first profile in case     */
    487                                     /* of impact                           */
    488 
    489     TStates     state;              /* rendering state                     */
    490 
    491     FT_Bitmap   target;             /* description of target bit/pixmap    */
    492     FT_Outline  outline;
    493 
    494     Long        traceOfs;           /* current offset in target bitmap     */
    495     Long        traceG;             /* current offset in target pixmap     */
    496 
    497     Short       traceIncr;          /* sweep's increment in target bitmap  */
    498 
    499     Short       gray_min_x;         /* current min x during gray rendering */
    500     Short       gray_max_x;         /* current max x during gray rendering */
    501 
    502     /* dispatch variables */
    503 
    504     Function_Sweep_Init*  Proc_Sweep_Init;
    505     Function_Sweep_Span*  Proc_Sweep_Span;
    506     Function_Sweep_Span*  Proc_Sweep_Drop;
    507     Function_Sweep_Step*  Proc_Sweep_Step;
    508 
    509     Byte        dropOutControl;     /* current drop_out control method     */
    510 
    511     Bool        second_pass;        /* indicates whether a horizontal pass */
    512                                     /* should be performed to control      */
    513                                     /* drop-out accurately when calling    */
    514                                     /* Render_Glyph.  Note that there is   */
    515                                     /* no horizontal pass during gray      */
    516                                     /* rendering.                          */
    517 
    518     TPoint      arcs[3 * MaxBezier + 1]; /* The Bezier stack               */
    519 
    520     TBand       band_stack[16];     /* band stack used for sub-banding     */
    521     Int         band_top;           /* band stack top                      */
    522 
    523 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
    524 
    525     Byte*       grays;
    526 
    527     Byte        gray_lines[RASTER_GRAY_LINES];
    528                                 /* Intermediate table used to render the   */
    529                                 /* graylevels pixmaps.                     */
    530                                 /* gray_lines is a buffer holding two      */
    531                                 /* monochrome scanlines                    */
    532 
    533     Short       gray_width;     /* width in bytes of one monochrome        */
    534                                 /* intermediate scanline of gray_lines.    */
    535                                 /* Each gray pixel takes 2 bits long there */
    536 
    537                        /* The gray_lines must hold 2 lines, thus with size */
    538                        /* in bytes of at least `gray_width*2'.             */
    539 
    540 #endif /* FT_RASTER_ANTI_ALIASING */
    541 
    542   };
    543 
    544 
    545   typedef struct  TRaster_
    546   {
    547     char*    buffer;
    548     long     buffer_size;
    549     void*    memory;
    550     PWorker  worker;
    551     Byte     grays[5];
    552     Short    gray_width;
    553 
    554   } TRaster, *PRaster;
    555 
    556 #ifdef FT_STATIC_RASTER
    557 
    558   static TWorker  cur_ras;
    559 #define ras  cur_ras
    560 
    561 #else /* !FT_STATIC_RASTER */
    562 
    563 #define ras  (*worker)
    564 
    565 #endif /* !FT_STATIC_RASTER */
    566 
    567 
    568 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
    569 
    570   /* A lookup table used to quickly count set bits in four gray 2x2 */
    571   /* cells.  The values of the table have been produced with the    */
    572   /* following code:                                                */
    573   /*                                                                */
    574   /*   for ( i = 0; i < 256; i++ )                                  */
    575   /*   {                                                            */
    576   /*     l = 0;                                                     */
    577   /*     j = i;                                                     */
    578   /*                                                                */
    579   /*     for ( c = 0; c < 4; c++ )                                  */
    580   /*     {                                                          */
    581   /*       l <<= 4;                                                 */
    582   /*                                                                */
    583   /*       if ( j & 0x80 ) l++;                                     */
    584   /*       if ( j & 0x40 ) l++;                                     */
    585   /*                                                                */
    586   /*       j = ( j << 2 ) & 0xFF;                                   */
    587   /*     }                                                          */
    588   /*     printf( "0x%04X", l );                                     */
    589   /*   }                                                            */
    590   /*                                                                */
    591 
    592   static const short  count_table[256] =
    593   {
    594     0x0000, 0x0001, 0x0001, 0x0002, 0x0010, 0x0011, 0x0011, 0x0012,
    595     0x0010, 0x0011, 0x0011, 0x0012, 0x0020, 0x0021, 0x0021, 0x0022,
    596     0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
    597     0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
    598     0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
    599     0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
    600     0x0200, 0x0201, 0x0201, 0x0202, 0x0210, 0x0211, 0x0211, 0x0212,
    601     0x0210, 0x0211, 0x0211, 0x0212, 0x0220, 0x0221, 0x0221, 0x0222,
    602     0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
    603     0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
    604     0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
    605     0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
    606     0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
    607     0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
    608     0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
    609     0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
    610     0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
    611     0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
    612     0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
    613     0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
    614     0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
    615     0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
    616     0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
    617     0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
    618     0x2000, 0x2001, 0x2001, 0x2002, 0x2010, 0x2011, 0x2011, 0x2012,
    619     0x2010, 0x2011, 0x2011, 0x2012, 0x2020, 0x2021, 0x2021, 0x2022,
    620     0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
    621     0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
    622     0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
    623     0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
    624     0x2200, 0x2201, 0x2201, 0x2202, 0x2210, 0x2211, 0x2211, 0x2212,
    625     0x2210, 0x2211, 0x2211, 0x2212, 0x2220, 0x2221, 0x2221, 0x2222
    626   };
    627 
    628 #endif /* FT_RASTER_OPTION_ANTI_ALIASING */
    629 
    630 
    631 
    632   /*************************************************************************/
    633   /*************************************************************************/
    634   /**                                                                     **/
    635   /**  PROFILES COMPUTATION                                               **/
    636   /**                                                                     **/
    637   /*************************************************************************/
    638   /*************************************************************************/
    639 
    640 
    641   /*************************************************************************/
    642   /*                                                                       */
    643   /* <Function>                                                            */
    644   /*    Set_High_Precision                                                 */
    645   /*                                                                       */
    646   /* <Description>                                                         */
    647   /*    Set precision variables according to param flag.                   */
    648   /*                                                                       */
    649   /* <Input>                                                               */
    650   /*    High :: Set to True for high precision (typically for ppem < 18),  */
    651   /*            false otherwise.                                           */
    652   /*                                                                       */
    653   static void
    654   Set_High_Precision( RAS_ARGS Int  High )
    655   {
    656     if ( High )
    657     {
    658       ras.precision_bits   = 12;
    659       ras.precision_step   = 256;
    660       ras.precision_jitter = 50;
    661     }
    662     else
    663     {
    664       ras.precision_bits   = 6;
    665       ras.precision_step   = 32;
    666       ras.precision_jitter = 2;
    667     }
    668 
    669     FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
    670 
    671     ras.precision       = 1 << ras.precision_bits;
    672     ras.precision_half  = ras.precision / 2;
    673     ras.precision_shift = ras.precision_bits - Pixel_Bits;
    674     ras.precision_mask  = -ras.precision;
    675   }
    676 
    677 
    678   /*************************************************************************/
    679   /*                                                                       */
    680   /* <Function>                                                            */
    681   /*    New_Profile                                                        */
    682   /*                                                                       */
    683   /* <Description>                                                         */
    684   /*    Create a new profile in the render pool.                           */
    685   /*                                                                       */
    686   /* <Input>                                                               */
    687   /*    aState    :: The state/orientation of the new profile.             */
    688   /*                                                                       */
    689   /*    overshoot :: Whether the profile's unrounded start position        */
    690   /*                 differs by at least a half pixel.                     */
    691   /*                                                                       */
    692   /* <Return>                                                              */
    693   /*   SUCCESS on success.  FAILURE in case of overflow or of incoherent   */
    694   /*   profile.                                                            */
    695   /*                                                                       */
    696   static Bool
    697   New_Profile( RAS_ARGS TStates  aState,
    698                         Bool     overshoot )
    699   {
    700     if ( !ras.fProfile )
    701     {
    702       ras.cProfile  = (PProfile)ras.top;
    703       ras.fProfile  = ras.cProfile;
    704       ras.top      += AlignProfileSize;
    705     }
    706 
    707     if ( ras.top >= ras.maxBuff )
    708     {
    709       ras.error = Raster_Err_Overflow;
    710       return FAILURE;
    711     }
    712 
    713     ras.cProfile->flags  = 0;
    714     ras.cProfile->start  = 0;
    715     ras.cProfile->height = 0;
    716     ras.cProfile->offset = ras.top;
    717     ras.cProfile->link   = (PProfile)0;
    718     ras.cProfile->next   = (PProfile)0;
    719     ras.cProfile->flags  = ras.dropOutControl;
    720 
    721     switch ( aState )
    722     {
    723     case Ascending_State:
    724       ras.cProfile->flags |= Flow_Up;
    725       if ( overshoot )
    726         ras.cProfile->flags |= Overshoot_Bottom;
    727 
    728       FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile ));
    729       break;
    730 
    731     case Descending_State:
    732       if ( overshoot )
    733         ras.cProfile->flags |= Overshoot_Top;
    734       FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile ));
    735       break;
    736 
    737     default:
    738       FT_ERROR(( "New_Profile: invalid profile direction\n" ));
    739       ras.error = Raster_Err_Invalid;
    740       return FAILURE;
    741     }
    742 
    743     if ( !ras.gProfile )
    744       ras.gProfile = ras.cProfile;
    745 
    746     ras.state = aState;
    747     ras.fresh = TRUE;
    748     ras.joint = FALSE;
    749 
    750     return SUCCESS;
    751   }
    752 
    753 
    754   /*************************************************************************/
    755   /*                                                                       */
    756   /* <Function>                                                            */
    757   /*    End_Profile                                                        */
    758   /*                                                                       */
    759   /* <Description>                                                         */
    760   /*    Finalize the current profile.                                      */
    761   /*                                                                       */
    762   /* <Input>                                                               */
    763   /*    overshoot :: Whether the profile's unrounded end position differs  */
    764   /*                 by at least a half pixel.                             */
    765   /*                                                                       */
    766   /* <Return>                                                              */
    767   /*    SUCCESS on success.  FAILURE in case of overflow or incoherency.   */
    768   /*                                                                       */
    769   static Bool
    770   End_Profile( RAS_ARGS Bool  overshoot )
    771   {
    772     Long      h;
    773     PProfile  oldProfile;
    774 
    775 
    776     h = (Long)( ras.top - ras.cProfile->offset );
    777 
    778     if ( h < 0 )
    779     {
    780       FT_ERROR(( "End_Profile: negative height encountered\n" ));
    781       ras.error = Raster_Err_Neg_Height;
    782       return FAILURE;
    783     }
    784 
    785     if ( h > 0 )
    786     {
    787       FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n",
    788                   (long)ras.cProfile, ras.cProfile->start, h ));
    789 
    790       ras.cProfile->height = h;
    791       if ( overshoot )
    792       {
    793         if ( ras.cProfile->flags & Flow_Up )
    794           ras.cProfile->flags |= Overshoot_Top;
    795         else
    796           ras.cProfile->flags |= Overshoot_Bottom;
    797       }
    798 
    799       oldProfile   = ras.cProfile;
    800       ras.cProfile = (PProfile)ras.top;
    801 
    802       ras.top += AlignProfileSize;
    803 
    804       ras.cProfile->height = 0;
    805       ras.cProfile->offset = ras.top;
    806 
    807       oldProfile->next = ras.cProfile;
    808       ras.num_Profs++;
    809     }
    810 
    811     if ( ras.top >= ras.maxBuff )
    812     {
    813       FT_TRACE1(( "overflow in End_Profile\n" ));
    814       ras.error = Raster_Err_Overflow;
    815       return FAILURE;
    816     }
    817 
    818     ras.joint = FALSE;
    819 
    820     return SUCCESS;
    821   }
    822 
    823 
    824   /*************************************************************************/
    825   /*                                                                       */
    826   /* <Function>                                                            */
    827   /*    Insert_Y_Turn                                                      */
    828   /*                                                                       */
    829   /* <Description>                                                         */
    830   /*    Insert a salient into the sorted list placed on top of the render  */
    831   /*    pool.                                                              */
    832   /*                                                                       */
    833   /* <Input>                                                               */
    834   /*    New y scanline position.                                           */
    835   /*                                                                       */
    836   /* <Return>                                                              */
    837   /*    SUCCESS on success.  FAILURE in case of overflow.                  */
    838   /*                                                                       */
    839   static Bool
    840   Insert_Y_Turn( RAS_ARGS Int  y )
    841   {
    842     PLong  y_turns;
    843     Int    y2, n;
    844 
    845 
    846     n       = ras.numTurns - 1;
    847     y_turns = ras.sizeBuff - ras.numTurns;
    848 
    849     /* look for first y value that is <= */
    850     while ( n >= 0 && y < y_turns[n] )
    851       n--;
    852 
    853     /* if it is <, simply insert it, ignore if == */
    854     if ( n >= 0 && y > y_turns[n] )
    855       while ( n >= 0 )
    856       {
    857         y2 = (Int)y_turns[n];
    858         y_turns[n] = y;
    859         y = y2;
    860         n--;
    861       }
    862 
    863     if ( n < 0 )
    864     {
    865       ras.maxBuff--;
    866       if ( ras.maxBuff <= ras.top )
    867       {
    868         ras.error = Raster_Err_Overflow;
    869         return FAILURE;
    870       }
    871       ras.numTurns++;
    872       ras.sizeBuff[-ras.numTurns] = y;
    873     }
    874 
    875     return SUCCESS;
    876   }
    877 
    878 
    879   /*************************************************************************/
    880   /*                                                                       */
    881   /* <Function>                                                            */
    882   /*    Finalize_Profile_Table                                             */
    883   /*                                                                       */
    884   /* <Description>                                                         */
    885   /*    Adjust all links in the profiles list.                             */
    886   /*                                                                       */
    887   /* <Return>                                                              */
    888   /*    SUCCESS on success.  FAILURE in case of overflow.                  */
    889   /*                                                                       */
    890   static Bool
    891   Finalize_Profile_Table( RAS_ARG )
    892   {
    893     Int       bottom, top;
    894     UShort    n;
    895     PProfile  p;
    896 
    897 
    898     n = ras.num_Profs;
    899     p = ras.fProfile;
    900 
    901     if ( n > 1 && p )
    902     {
    903       while ( n > 0 )
    904       {
    905         if ( n > 1 )
    906           p->link = (PProfile)( p->offset + p->height );
    907         else
    908           p->link = NULL;
    909 
    910         if ( p->flags & Flow_Up )
    911         {
    912           bottom = (Int)p->start;
    913           top    = (Int)( p->start + p->height - 1 );
    914         }
    915         else
    916         {
    917           bottom     = (Int)( p->start - p->height + 1 );
    918           top        = (Int)p->start;
    919           p->start   = bottom;
    920           p->offset += p->height - 1;
    921         }
    922 
    923         if ( Insert_Y_Turn( RAS_VARS bottom )  ||
    924              Insert_Y_Turn( RAS_VARS top + 1 ) )
    925           return FAILURE;
    926 
    927         p = p->link;
    928         n--;
    929       }
    930     }
    931     else
    932       ras.fProfile = NULL;
    933 
    934     return SUCCESS;
    935   }
    936 
    937 
    938   /*************************************************************************/
    939   /*                                                                       */
    940   /* <Function>                                                            */
    941   /*    Split_Conic                                                        */
    942   /*                                                                       */
    943   /* <Description>                                                         */
    944   /*    Subdivide one conic Bezier into two joint sub-arcs in the Bezier   */
    945   /*    stack.                                                             */
    946   /*                                                                       */
    947   /* <Input>                                                               */
    948   /*    None (subdivided Bezier is taken from the top of the stack).       */
    949   /*                                                                       */
    950   /* <Note>                                                                */
    951   /*    This routine is the `beef' of this component.  It is  _the_ inner  */
    952   /*    loop that should be optimized to hell to get the best performance. */
    953   /*                                                                       */
    954   static void
    955   Split_Conic( TPoint*  base )
    956   {
    957     Long  a, b;
    958 
    959 
    960     base[4].x = base[2].x;
    961     b = base[1].x;
    962     a = base[3].x = ( base[2].x + b ) / 2;
    963     b = base[1].x = ( base[0].x + b ) / 2;
    964     base[2].x = ( a + b ) / 2;
    965 
    966     base[4].y = base[2].y;
    967     b = base[1].y;
    968     a = base[3].y = ( base[2].y + b ) / 2;
    969     b = base[1].y = ( base[0].y + b ) / 2;
    970     base[2].y = ( a + b ) / 2;
    971 
    972     /* hand optimized.  gcc doesn't seem to be too good at common      */
    973     /* expression substitution and instruction scheduling ;-)          */
    974   }
    975 
    976 
    977   /*************************************************************************/
    978   /*                                                                       */
    979   /* <Function>                                                            */
    980   /*    Split_Cubic                                                        */
    981   /*                                                                       */
    982   /* <Description>                                                         */
    983   /*    Subdivide a third-order Bezier arc into two joint sub-arcs in the  */
    984   /*    Bezier stack.                                                      */
    985   /*                                                                       */
    986   /* <Note>                                                                */
    987   /*    This routine is the `beef' of the component.  It is one of _the_   */
    988   /*    inner loops that should be optimized like hell to get the best     */
    989   /*    performance.                                                       */
    990   /*                                                                       */
    991   static void
    992   Split_Cubic( TPoint*  base )
    993   {
    994     Long  a, b, c, d;
    995 
    996 
    997     base[6].x = base[3].x;
    998     c = base[1].x;
    999     d = base[2].x;
   1000     base[1].x = a = ( base[0].x + c + 1 ) >> 1;
   1001     base[5].x = b = ( base[3].x + d + 1 ) >> 1;
   1002     c = ( c + d + 1 ) >> 1;
   1003     base[2].x = a = ( a + c + 1 ) >> 1;
   1004     base[4].x = b = ( b + c + 1 ) >> 1;
   1005     base[3].x = ( a + b + 1 ) >> 1;
   1006 
   1007     base[6].y = base[3].y;
   1008     c = base[1].y;
   1009     d = base[2].y;
   1010     base[1].y = a = ( base[0].y + c + 1 ) >> 1;
   1011     base[5].y = b = ( base[3].y + d + 1 ) >> 1;
   1012     c = ( c + d + 1 ) >> 1;
   1013     base[2].y = a = ( a + c + 1 ) >> 1;
   1014     base[4].y = b = ( b + c + 1 ) >> 1;
   1015     base[3].y = ( a + b + 1 ) >> 1;
   1016   }
   1017 
   1018 
   1019   /*************************************************************************/
   1020   /*                                                                       */
   1021   /* <Function>                                                            */
   1022   /*    Line_Up                                                            */
   1023   /*                                                                       */
   1024   /* <Description>                                                         */
   1025   /*    Compute the x-coordinates of an ascending line segment and store   */
   1026   /*    them in the render pool.                                           */
   1027   /*                                                                       */
   1028   /* <Input>                                                               */
   1029   /*    x1   :: The x-coordinate of the segment's start point.             */
   1030   /*                                                                       */
   1031   /*    y1   :: The y-coordinate of the segment's start point.             */
   1032   /*                                                                       */
   1033   /*    x2   :: The x-coordinate of the segment's end point.               */
   1034   /*                                                                       */
   1035   /*    y2   :: The y-coordinate of the segment's end point.               */
   1036   /*                                                                       */
   1037   /*    miny :: A lower vertical clipping bound value.                     */
   1038   /*                                                                       */
   1039   /*    maxy :: An upper vertical clipping bound value.                    */
   1040   /*                                                                       */
   1041   /* <Return>                                                              */
   1042   /*    SUCCESS on success, FAILURE on render pool overflow.               */
   1043   /*                                                                       */
   1044   static Bool
   1045   Line_Up( RAS_ARGS Long  x1,
   1046                     Long  y1,
   1047                     Long  x2,
   1048                     Long  y2,
   1049                     Long  miny,
   1050                     Long  maxy )
   1051   {
   1052     Long   Dx, Dy;
   1053     Int    e1, e2, f1, f2, size;     /* XXX: is `Short' sufficient? */
   1054     Long   Ix, Rx, Ax;
   1055 
   1056     PLong  top;
   1057 
   1058 
   1059     Dx = x2 - x1;
   1060     Dy = y2 - y1;
   1061 
   1062     if ( Dy <= 0 || y2 < miny || y1 > maxy )
   1063       return SUCCESS;
   1064 
   1065     if ( y1 < miny )
   1066     {
   1067       /* Take care: miny-y1 can be a very large value; we use     */
   1068       /*            a slow MulDiv function to avoid clipping bugs */
   1069       x1 += SMulDiv( Dx, miny - y1, Dy );
   1070       e1  = (Int)TRUNC( miny );
   1071       f1  = 0;
   1072     }
   1073     else
   1074     {
   1075       e1 = (Int)TRUNC( y1 );
   1076       f1 = (Int)FRAC( y1 );
   1077     }
   1078 
   1079     if ( y2 > maxy )
   1080     {
   1081       /* x2 += FMulDiv( Dx, maxy - y2, Dy );  UNNECESSARY */
   1082       e2  = (Int)TRUNC( maxy );
   1083       f2  = 0;
   1084     }
   1085     else
   1086     {
   1087       e2 = (Int)TRUNC( y2 );
   1088       f2 = (Int)FRAC( y2 );
   1089     }
   1090 
   1091     if ( f1 > 0 )
   1092     {
   1093       if ( e1 == e2 )
   1094         return SUCCESS;
   1095       else
   1096       {
   1097         x1 += FMulDiv( Dx, ras.precision - f1, Dy );
   1098         e1 += 1;
   1099       }
   1100     }
   1101     else
   1102       if ( ras.joint )
   1103       {
   1104         ras.top--;
   1105         ras.joint = FALSE;
   1106       }
   1107 
   1108     ras.joint = (char)( f2 == 0 );
   1109 
   1110     if ( ras.fresh )
   1111     {
   1112       ras.cProfile->start = e1;
   1113       ras.fresh           = FALSE;
   1114     }
   1115 
   1116     size = e2 - e1 + 1;
   1117     if ( ras.top + size >= ras.maxBuff )
   1118     {
   1119       ras.error = Raster_Err_Overflow;
   1120       return FAILURE;
   1121     }
   1122 
   1123     if ( Dx > 0 )
   1124     {
   1125       Ix = ( ras.precision * Dx ) / Dy;
   1126       Rx = ( ras.precision * Dx ) % Dy;
   1127       Dx = 1;
   1128     }
   1129     else
   1130     {
   1131       Ix = -( ( ras.precision * -Dx ) / Dy );
   1132       Rx =    ( ras.precision * -Dx ) % Dy;
   1133       Dx = -1;
   1134     }
   1135 
   1136     Ax  = -Dy;
   1137     top = ras.top;
   1138 
   1139     while ( size > 0 )
   1140     {
   1141       *top++ = x1;
   1142 
   1143       x1 += Ix;
   1144       Ax += Rx;
   1145       if ( Ax >= 0 )
   1146       {
   1147         Ax -= Dy;
   1148         x1 += Dx;
   1149       }
   1150       size--;
   1151     }
   1152 
   1153     ras.top = top;
   1154     return SUCCESS;
   1155   }
   1156 
   1157 
   1158   /*************************************************************************/
   1159   /*                                                                       */
   1160   /* <Function>                                                            */
   1161   /*    Line_Down                                                          */
   1162   /*                                                                       */
   1163   /* <Description>                                                         */
   1164   /*    Compute the x-coordinates of an descending line segment and store  */
   1165   /*    them in the render pool.                                           */
   1166   /*                                                                       */
   1167   /* <Input>                                                               */
   1168   /*    x1   :: The x-coordinate of the segment's start point.             */
   1169   /*                                                                       */
   1170   /*    y1   :: The y-coordinate of the segment's start point.             */
   1171   /*                                                                       */
   1172   /*    x2   :: The x-coordinate of the segment's end point.               */
   1173   /*                                                                       */
   1174   /*    y2   :: The y-coordinate of the segment's end point.               */
   1175   /*                                                                       */
   1176   /*    miny :: A lower vertical clipping bound value.                     */
   1177   /*                                                                       */
   1178   /*    maxy :: An upper vertical clipping bound value.                    */
   1179   /*                                                                       */
   1180   /* <Return>                                                              */
   1181   /*    SUCCESS on success, FAILURE on render pool overflow.               */
   1182   /*                                                                       */
   1183   static Bool
   1184   Line_Down( RAS_ARGS Long  x1,
   1185                       Long  y1,
   1186                       Long  x2,
   1187                       Long  y2,
   1188                       Long  miny,
   1189                       Long  maxy )
   1190   {
   1191     Bool  result, fresh;
   1192 
   1193 
   1194     fresh  = ras.fresh;
   1195 
   1196     result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
   1197 
   1198     if ( fresh && !ras.fresh )
   1199       ras.cProfile->start = -ras.cProfile->start;
   1200 
   1201     return result;
   1202   }
   1203 
   1204 
   1205   /* A function type describing the functions used to split Bezier arcs */
   1206   typedef void  (*TSplitter)( TPoint*  base );
   1207 
   1208 
   1209   /*************************************************************************/
   1210   /*                                                                       */
   1211   /* <Function>                                                            */
   1212   /*    Bezier_Up                                                          */
   1213   /*                                                                       */
   1214   /* <Description>                                                         */
   1215   /*    Compute the x-coordinates of an ascending Bezier arc and store     */
   1216   /*    them in the render pool.                                           */
   1217   /*                                                                       */
   1218   /* <Input>                                                               */
   1219   /*    degree   :: The degree of the Bezier arc (either 2 or 3).          */
   1220   /*                                                                       */
   1221   /*    splitter :: The function to split Bezier arcs.                     */
   1222   /*                                                                       */
   1223   /*    miny     :: A lower vertical clipping bound value.                 */
   1224   /*                                                                       */
   1225   /*    maxy     :: An upper vertical clipping bound value.                */
   1226   /*                                                                       */
   1227   /* <Return>                                                              */
   1228   /*    SUCCESS on success, FAILURE on render pool overflow.               */
   1229   /*                                                                       */
   1230   static Bool
   1231   Bezier_Up( RAS_ARGS Int        degree,
   1232                       TSplitter  splitter,
   1233                       Long       miny,
   1234                       Long       maxy )
   1235   {
   1236     Long   y1, y2, e, e2, e0;
   1237     Short  f1;
   1238 
   1239     TPoint*  arc;
   1240     TPoint*  start_arc;
   1241 
   1242     PLong top;
   1243 
   1244 
   1245     arc = ras.arc;
   1246     y1  = arc[degree].y;
   1247     y2  = arc[0].y;
   1248     top = ras.top;
   1249 
   1250     if ( y2 < miny || y1 > maxy )
   1251       goto Fin;
   1252 
   1253     e2 = FLOOR( y2 );
   1254 
   1255     if ( e2 > maxy )
   1256       e2 = maxy;
   1257 
   1258     e0 = miny;
   1259 
   1260     if ( y1 < miny )
   1261       e = miny;
   1262     else
   1263     {
   1264       e  = CEILING( y1 );
   1265       f1 = (Short)( FRAC( y1 ) );
   1266       e0 = e;
   1267 
   1268       if ( f1 == 0 )
   1269       {
   1270         if ( ras.joint )
   1271         {
   1272           top--;
   1273           ras.joint = FALSE;
   1274         }
   1275 
   1276         *top++ = arc[degree].x;
   1277 
   1278         e += ras.precision;
   1279       }
   1280     }
   1281 
   1282     if ( ras.fresh )
   1283     {
   1284       ras.cProfile->start = TRUNC( e0 );
   1285       ras.fresh = FALSE;
   1286     }
   1287 
   1288     if ( e2 < e )
   1289       goto Fin;
   1290 
   1291     if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
   1292     {
   1293       ras.top   = top;
   1294       ras.error = Raster_Err_Overflow;
   1295       return FAILURE;
   1296     }
   1297 
   1298     start_arc = arc;
   1299 
   1300     while ( arc >= start_arc && e <= e2 )
   1301     {
   1302       ras.joint = FALSE;
   1303 
   1304       y2 = arc[0].y;
   1305 
   1306       if ( y2 > e )
   1307       {
   1308         y1 = arc[degree].y;
   1309         if ( y2 - y1 >= ras.precision_step )
   1310         {
   1311           splitter( arc );
   1312           arc += degree;
   1313         }
   1314         else
   1315         {
   1316           *top++ = arc[degree].x + FMulDiv( arc[0].x - arc[degree].x,
   1317                                             e - y1, y2 - y1 );
   1318           arc -= degree;
   1319           e   += ras.precision;
   1320         }
   1321       }
   1322       else
   1323       {
   1324         if ( y2 == e )
   1325         {
   1326           ras.joint  = TRUE;
   1327           *top++     = arc[0].x;
   1328 
   1329           e += ras.precision;
   1330         }
   1331         arc -= degree;
   1332       }
   1333     }
   1334 
   1335   Fin:
   1336     ras.top  = top;
   1337     ras.arc -= degree;
   1338     return SUCCESS;
   1339   }
   1340 
   1341 
   1342   /*************************************************************************/
   1343   /*                                                                       */
   1344   /* <Function>                                                            */
   1345   /*    Bezier_Down                                                        */
   1346   /*                                                                       */
   1347   /* <Description>                                                         */
   1348   /*    Compute the x-coordinates of an descending Bezier arc and store    */
   1349   /*    them in the render pool.                                           */
   1350   /*                                                                       */
   1351   /* <Input>                                                               */
   1352   /*    degree   :: The degree of the Bezier arc (either 2 or 3).          */
   1353   /*                                                                       */
   1354   /*    splitter :: The function to split Bezier arcs.                     */
   1355   /*                                                                       */
   1356   /*    miny     :: A lower vertical clipping bound value.                 */
   1357   /*                                                                       */
   1358   /*    maxy     :: An upper vertical clipping bound value.                */
   1359   /*                                                                       */
   1360   /* <Return>                                                              */
   1361   /*    SUCCESS on success, FAILURE on render pool overflow.               */
   1362   /*                                                                       */
   1363   static Bool
   1364   Bezier_Down( RAS_ARGS Int        degree,
   1365                         TSplitter  splitter,
   1366                         Long       miny,
   1367                         Long       maxy )
   1368   {
   1369     TPoint*  arc = ras.arc;
   1370     Bool     result, fresh;
   1371 
   1372 
   1373     arc[0].y = -arc[0].y;
   1374     arc[1].y = -arc[1].y;
   1375     arc[2].y = -arc[2].y;
   1376     if ( degree > 2 )
   1377       arc[3].y = -arc[3].y;
   1378 
   1379     fresh = ras.fresh;
   1380 
   1381     result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny );
   1382 
   1383     if ( fresh && !ras.fresh )
   1384       ras.cProfile->start = -ras.cProfile->start;
   1385 
   1386     arc[0].y = -arc[0].y;
   1387     return result;
   1388   }
   1389 
   1390 
   1391   /*************************************************************************/
   1392   /*                                                                       */
   1393   /* <Function>                                                            */
   1394   /*    Line_To                                                            */
   1395   /*                                                                       */
   1396   /* <Description>                                                         */
   1397   /*    Inject a new line segment and adjust the Profiles list.            */
   1398   /*                                                                       */
   1399   /* <Input>                                                               */
   1400   /*   x :: The x-coordinate of the segment's end point (its start point   */
   1401   /*        is stored in `lastX').                                         */
   1402   /*                                                                       */
   1403   /*   y :: The y-coordinate of the segment's end point (its start point   */
   1404   /*        is stored in `lastY').                                         */
   1405   /*                                                                       */
   1406   /* <Return>                                                              */
   1407   /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
   1408   /*   profile.                                                            */
   1409   /*                                                                       */
   1410   static Bool
   1411   Line_To( RAS_ARGS Long  x,
   1412                     Long  y )
   1413   {
   1414     /* First, detect a change of direction */
   1415 
   1416     switch ( ras.state )
   1417     {
   1418     case Unknown_State:
   1419       if ( y > ras.lastY )
   1420       {
   1421         if ( New_Profile( RAS_VARS Ascending_State,
   1422                                    IS_BOTTOM_OVERSHOOT( ras.lastY ) ) )
   1423           return FAILURE;
   1424       }
   1425       else
   1426       {
   1427         if ( y < ras.lastY )
   1428           if ( New_Profile( RAS_VARS Descending_State,
   1429                                      IS_TOP_OVERSHOOT( ras.lastY ) ) )
   1430             return FAILURE;
   1431       }
   1432       break;
   1433 
   1434     case Ascending_State:
   1435       if ( y < ras.lastY )
   1436       {
   1437         if ( End_Profile( RAS_VARS IS_TOP_OVERSHOOT( ras.lastY ) ) ||
   1438              New_Profile( RAS_VARS Descending_State,
   1439                                    IS_TOP_OVERSHOOT( ras.lastY ) ) )
   1440           return FAILURE;
   1441       }
   1442       break;
   1443 
   1444     case Descending_State:
   1445       if ( y > ras.lastY )
   1446       {
   1447         if ( End_Profile( RAS_VARS IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ||
   1448              New_Profile( RAS_VARS Ascending_State,
   1449                                    IS_BOTTOM_OVERSHOOT( ras.lastY ) ) )
   1450           return FAILURE;
   1451       }
   1452       break;
   1453 
   1454     default:
   1455       ;
   1456     }
   1457 
   1458     /* Then compute the lines */
   1459 
   1460     switch ( ras.state )
   1461     {
   1462     case Ascending_State:
   1463       if ( Line_Up( RAS_VARS ras.lastX, ras.lastY,
   1464                              x, y, ras.minY, ras.maxY ) )
   1465         return FAILURE;
   1466       break;
   1467 
   1468     case Descending_State:
   1469       if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
   1470                                x, y, ras.minY, ras.maxY ) )
   1471         return FAILURE;
   1472       break;
   1473 
   1474     default:
   1475       ;
   1476     }
   1477 
   1478     ras.lastX = x;
   1479     ras.lastY = y;
   1480 
   1481     return SUCCESS;
   1482   }
   1483 
   1484 
   1485   /*************************************************************************/
   1486   /*                                                                       */
   1487   /* <Function>                                                            */
   1488   /*    Conic_To                                                           */
   1489   /*                                                                       */
   1490   /* <Description>                                                         */
   1491   /*    Inject a new conic arc and adjust the profile list.                */
   1492   /*                                                                       */
   1493   /* <Input>                                                               */
   1494   /*   cx :: The x-coordinate of the arc's new control point.              */
   1495   /*                                                                       */
   1496   /*   cy :: The y-coordinate of the arc's new control point.              */
   1497   /*                                                                       */
   1498   /*   x  :: The x-coordinate of the arc's end point (its start point is   */
   1499   /*         stored in `lastX').                                           */
   1500   /*                                                                       */
   1501   /*   y  :: The y-coordinate of the arc's end point (its start point is   */
   1502   /*         stored in `lastY').                                           */
   1503   /*                                                                       */
   1504   /* <Return>                                                              */
   1505   /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
   1506   /*   profile.                                                            */
   1507   /*                                                                       */
   1508   static Bool
   1509   Conic_To( RAS_ARGS Long  cx,
   1510                      Long  cy,
   1511                      Long  x,
   1512                      Long  y )
   1513   {
   1514     Long     y1, y2, y3, x3, ymin, ymax;
   1515     TStates  state_bez;
   1516 
   1517 
   1518     ras.arc      = ras.arcs;
   1519     ras.arc[2].x = ras.lastX;
   1520     ras.arc[2].y = ras.lastY;
   1521     ras.arc[1].x = cx;
   1522     ras.arc[1].y = cy;
   1523     ras.arc[0].x = x;
   1524     ras.arc[0].y = y;
   1525 
   1526     do
   1527     {
   1528       y1 = ras.arc[2].y;
   1529       y2 = ras.arc[1].y;
   1530       y3 = ras.arc[0].y;
   1531       x3 = ras.arc[0].x;
   1532 
   1533       /* first, categorize the Bezier arc */
   1534 
   1535       if ( y1 <= y3 )
   1536       {
   1537         ymin = y1;
   1538         ymax = y3;
   1539       }
   1540       else
   1541       {
   1542         ymin = y3;
   1543         ymax = y1;
   1544       }
   1545 
   1546       if ( y2 < ymin || y2 > ymax )
   1547       {
   1548         /* this arc has no given direction, split it! */
   1549         Split_Conic( ras.arc );
   1550         ras.arc += 2;
   1551       }
   1552       else if ( y1 == y3 )
   1553       {
   1554         /* this arc is flat, ignore it and pop it from the Bezier stack */
   1555         ras.arc -= 2;
   1556       }
   1557       else
   1558       {
   1559         /* the arc is y-monotonous, either ascending or descending */
   1560         /* detect a change of direction                            */
   1561         state_bez = y1 < y3 ? Ascending_State : Descending_State;
   1562         if ( ras.state != state_bez )
   1563         {
   1564           Bool  o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 )
   1565                                                  : IS_TOP_OVERSHOOT( y1 );
   1566 
   1567 
   1568           /* finalize current profile if any */
   1569           if ( ras.state != Unknown_State &&
   1570                End_Profile( RAS_VARS o )  )
   1571             goto Fail;
   1572 
   1573           /* create a new profile */
   1574           if ( New_Profile( RAS_VARS state_bez, o ) )
   1575             goto Fail;
   1576         }
   1577 
   1578         /* now call the appropriate routine */
   1579         if ( state_bez == Ascending_State )
   1580         {
   1581           if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
   1582             goto Fail;
   1583         }
   1584         else
   1585           if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
   1586             goto Fail;
   1587       }
   1588 
   1589     } while ( ras.arc >= ras.arcs );
   1590 
   1591     ras.lastX = x3;
   1592     ras.lastY = y3;
   1593 
   1594     return SUCCESS;
   1595 
   1596   Fail:
   1597     return FAILURE;
   1598   }
   1599 
   1600 
   1601   /*************************************************************************/
   1602   /*                                                                       */
   1603   /* <Function>                                                            */
   1604   /*    Cubic_To                                                           */
   1605   /*                                                                       */
   1606   /* <Description>                                                         */
   1607   /*    Inject a new cubic arc and adjust the profile list.                */
   1608   /*                                                                       */
   1609   /* <Input>                                                               */
   1610   /*   cx1 :: The x-coordinate of the arc's first new control point.       */
   1611   /*                                                                       */
   1612   /*   cy1 :: The y-coordinate of the arc's first new control point.       */
   1613   /*                                                                       */
   1614   /*   cx2 :: The x-coordinate of the arc's second new control point.      */
   1615   /*                                                                       */
   1616   /*   cy2 :: The y-coordinate of the arc's second new control point.      */
   1617   /*                                                                       */
   1618   /*   x   :: The x-coordinate of the arc's end point (its start point is  */
   1619   /*          stored in `lastX').                                          */
   1620   /*                                                                       */
   1621   /*   y   :: The y-coordinate of the arc's end point (its start point is  */
   1622   /*          stored in `lastY').                                          */
   1623   /*                                                                       */
   1624   /* <Return>                                                              */
   1625   /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
   1626   /*   profile.                                                            */
   1627   /*                                                                       */
   1628   static Bool
   1629   Cubic_To( RAS_ARGS Long  cx1,
   1630                      Long  cy1,
   1631                      Long  cx2,
   1632                      Long  cy2,
   1633                      Long  x,
   1634                      Long  y )
   1635   {
   1636     Long     y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2;
   1637     TStates  state_bez;
   1638 
   1639 
   1640     ras.arc      = ras.arcs;
   1641     ras.arc[3].x = ras.lastX;
   1642     ras.arc[3].y = ras.lastY;
   1643     ras.arc[2].x = cx1;
   1644     ras.arc[2].y = cy1;
   1645     ras.arc[1].x = cx2;
   1646     ras.arc[1].y = cy2;
   1647     ras.arc[0].x = x;
   1648     ras.arc[0].y = y;
   1649 
   1650     do
   1651     {
   1652       y1 = ras.arc[3].y;
   1653       y2 = ras.arc[2].y;
   1654       y3 = ras.arc[1].y;
   1655       y4 = ras.arc[0].y;
   1656       x4 = ras.arc[0].x;
   1657 
   1658       /* first, categorize the Bezier arc */
   1659 
   1660       if ( y1 <= y4 )
   1661       {
   1662         ymin1 = y1;
   1663         ymax1 = y4;
   1664       }
   1665       else
   1666       {
   1667         ymin1 = y4;
   1668         ymax1 = y1;
   1669       }
   1670 
   1671       if ( y2 <= y3 )
   1672       {
   1673         ymin2 = y2;
   1674         ymax2 = y3;
   1675       }
   1676       else
   1677       {
   1678         ymin2 = y3;
   1679         ymax2 = y2;
   1680       }
   1681 
   1682       if ( ymin2 < ymin1 || ymax2 > ymax1 )
   1683       {
   1684         /* this arc has no given direction, split it! */
   1685         Split_Cubic( ras.arc );
   1686         ras.arc += 3;
   1687       }
   1688       else if ( y1 == y4 )
   1689       {
   1690         /* this arc is flat, ignore it and pop it from the Bezier stack */
   1691         ras.arc -= 3;
   1692       }
   1693       else
   1694       {
   1695         state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State;
   1696 
   1697         /* detect a change of direction */
   1698         if ( ras.state != state_bez )
   1699         {
   1700           Bool  o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 )
   1701                                                  : IS_TOP_OVERSHOOT( y1 );
   1702 
   1703 
   1704           /* finalize current profile if any */
   1705           if ( ras.state != Unknown_State &&
   1706                End_Profile( RAS_VARS o )  )
   1707             goto Fail;
   1708 
   1709           if ( New_Profile( RAS_VARS state_bez, o ) )
   1710             goto Fail;
   1711         }
   1712 
   1713         /* compute intersections */
   1714         if ( state_bez == Ascending_State )
   1715         {
   1716           if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
   1717             goto Fail;
   1718         }
   1719         else
   1720           if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
   1721             goto Fail;
   1722       }
   1723 
   1724     } while ( ras.arc >= ras.arcs );
   1725 
   1726     ras.lastX = x4;
   1727     ras.lastY = y4;
   1728 
   1729     return SUCCESS;
   1730 
   1731   Fail:
   1732     return FAILURE;
   1733   }
   1734 
   1735 
   1736 #undef  SWAP_
   1737 #define SWAP_( x, y )  do                \
   1738                        {                 \
   1739                          Long  swap = x; \
   1740                                          \
   1741                                          \
   1742                          x = y;          \
   1743                          y = swap;       \
   1744                        } while ( 0 )
   1745 
   1746 
   1747   /*************************************************************************/
   1748   /*                                                                       */
   1749   /* <Function>                                                            */
   1750   /*    Decompose_Curve                                                    */
   1751   /*                                                                       */
   1752   /* <Description>                                                         */
   1753   /*    Scan the outline arrays in order to emit individual segments and   */
   1754   /*    Beziers by calling Line_To() and Bezier_To().  It handles all      */
   1755   /*    weird cases, like when the first point is off the curve, or when   */
   1756   /*    there are simply no `on' points in the contour!                    */
   1757   /*                                                                       */
   1758   /* <Input>                                                               */
   1759   /*    first   :: The index of the first point in the contour.            */
   1760   /*                                                                       */
   1761   /*    last    :: The index of the last point in the contour.             */
   1762   /*                                                                       */
   1763   /*    flipped :: If set, flip the direction of the curve.                */
   1764   /*                                                                       */
   1765   /* <Return>                                                              */
   1766   /*    SUCCESS on success, FAILURE on error.                              */
   1767   /*                                                                       */
   1768   static Bool
   1769   Decompose_Curve( RAS_ARGS UShort  first,
   1770                             UShort  last,
   1771                             int     flipped )
   1772   {
   1773     FT_Vector   v_last;
   1774     FT_Vector   v_control;
   1775     FT_Vector   v_start;
   1776 
   1777     FT_Vector*  points;
   1778     FT_Vector*  point;
   1779     FT_Vector*  limit;
   1780     char*       tags;
   1781 
   1782     unsigned    tag;       /* current point's state           */
   1783 
   1784 
   1785     points = ras.outline.points;
   1786     limit  = points + last;
   1787 
   1788     v_start.x = SCALED( points[first].x );
   1789     v_start.y = SCALED( points[first].y );
   1790     v_last.x  = SCALED( points[last].x );
   1791     v_last.y  = SCALED( points[last].y );
   1792 
   1793     if ( flipped )
   1794     {
   1795       SWAP_( v_start.x, v_start.y );
   1796       SWAP_( v_last.x, v_last.y );
   1797     }
   1798 
   1799     v_control = v_start;
   1800 
   1801     point = points + first;
   1802     tags  = ras.outline.tags + first;
   1803 
   1804     /* set scan mode if necessary */
   1805     if ( tags[0] & FT_CURVE_TAG_HAS_SCANMODE )
   1806       ras.dropOutControl = (Byte)tags[0] >> 5;
   1807 
   1808     tag = FT_CURVE_TAG( tags[0] );
   1809 
   1810     /* A contour cannot start with a cubic control point! */
   1811     if ( tag == FT_CURVE_TAG_CUBIC )
   1812       goto Invalid_Outline;
   1813 
   1814     /* check first point to determine origin */
   1815     if ( tag == FT_CURVE_TAG_CONIC )
   1816     {
   1817       /* first point is conic control.  Yes, this happens. */
   1818       if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON )
   1819       {
   1820         /* start at last point if it is on the curve */
   1821         v_start = v_last;
   1822         limit--;
   1823       }
   1824       else
   1825       {
   1826         /* if both first and last points are conic,         */
   1827         /* start at their middle and record its position    */
   1828         /* for closure                                      */
   1829         v_start.x = ( v_start.x + v_last.x ) / 2;
   1830         v_start.y = ( v_start.y + v_last.y ) / 2;
   1831 
   1832         v_last = v_start;
   1833       }
   1834       point--;
   1835       tags--;
   1836     }
   1837 
   1838     ras.lastX = v_start.x;
   1839     ras.lastY = v_start.y;
   1840 
   1841     while ( point < limit )
   1842     {
   1843       point++;
   1844       tags++;
   1845 
   1846       tag = FT_CURVE_TAG( tags[0] );
   1847 
   1848       switch ( tag )
   1849       {
   1850       case FT_CURVE_TAG_ON:  /* emit a single line_to */
   1851         {
   1852           Long  x, y;
   1853 
   1854 
   1855           x = SCALED( point->x );
   1856           y = SCALED( point->y );
   1857           if ( flipped )
   1858             SWAP_( x, y );
   1859 
   1860           if ( Line_To( RAS_VARS x, y ) )
   1861             goto Fail;
   1862           continue;
   1863         }
   1864 
   1865       case FT_CURVE_TAG_CONIC:  /* consume conic arcs */
   1866         v_control.x = SCALED( point[0].x );
   1867         v_control.y = SCALED( point[0].y );
   1868 
   1869         if ( flipped )
   1870           SWAP_( v_control.x, v_control.y );
   1871 
   1872       Do_Conic:
   1873         if ( point < limit )
   1874         {
   1875           FT_Vector  v_middle;
   1876           Long       x, y;
   1877 
   1878 
   1879           point++;
   1880           tags++;
   1881           tag = FT_CURVE_TAG( tags[0] );
   1882 
   1883           x = SCALED( point[0].x );
   1884           y = SCALED( point[0].y );
   1885 
   1886           if ( flipped )
   1887             SWAP_( x, y );
   1888 
   1889           if ( tag == FT_CURVE_TAG_ON )
   1890           {
   1891             if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) )
   1892               goto Fail;
   1893             continue;
   1894           }
   1895 
   1896           if ( tag != FT_CURVE_TAG_CONIC )
   1897             goto Invalid_Outline;
   1898 
   1899           v_middle.x = ( v_control.x + x ) / 2;
   1900           v_middle.y = ( v_control.y + y ) / 2;
   1901 
   1902           if ( Conic_To( RAS_VARS v_control.x, v_control.y,
   1903                                   v_middle.x,  v_middle.y ) )
   1904             goto Fail;
   1905 
   1906           v_control.x = x;
   1907           v_control.y = y;
   1908 
   1909           goto Do_Conic;
   1910         }
   1911 
   1912         if ( Conic_To( RAS_VARS v_control.x, v_control.y,
   1913                                 v_start.x,   v_start.y ) )
   1914           goto Fail;
   1915 
   1916         goto Close;
   1917 
   1918       default:  /* FT_CURVE_TAG_CUBIC */
   1919         {
   1920           Long  x1, y1, x2, y2, x3, y3;
   1921 
   1922 
   1923           if ( point + 1 > limit                             ||
   1924                FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
   1925             goto Invalid_Outline;
   1926 
   1927           point += 2;
   1928           tags  += 2;
   1929 
   1930           x1 = SCALED( point[-2].x );
   1931           y1 = SCALED( point[-2].y );
   1932           x2 = SCALED( point[-1].x );
   1933           y2 = SCALED( point[-1].y );
   1934           x3 = SCALED( point[ 0].x );
   1935           y3 = SCALED( point[ 0].y );
   1936 
   1937           if ( flipped )
   1938           {
   1939             SWAP_( x1, y1 );
   1940             SWAP_( x2, y2 );
   1941             SWAP_( x3, y3 );
   1942           }
   1943 
   1944           if ( point <= limit )
   1945           {
   1946             if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) )
   1947               goto Fail;
   1948             continue;
   1949           }
   1950 
   1951           if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) )
   1952             goto Fail;
   1953           goto Close;
   1954         }
   1955       }
   1956     }
   1957 
   1958     /* close the contour with a line segment */
   1959     if ( Line_To( RAS_VARS v_start.x, v_start.y ) )
   1960       goto Fail;
   1961 
   1962   Close:
   1963     return SUCCESS;
   1964 
   1965   Invalid_Outline:
   1966     ras.error = Raster_Err_Invalid;
   1967 
   1968   Fail:
   1969     return FAILURE;
   1970   }
   1971 
   1972 
   1973   /*************************************************************************/
   1974   /*                                                                       */
   1975   /* <Function>                                                            */
   1976   /*    Convert_Glyph                                                      */
   1977   /*                                                                       */
   1978   /* <Description>                                                         */
   1979   /*    Convert a glyph into a series of segments and arcs and make a      */
   1980   /*    profiles list with them.                                           */
   1981   /*                                                                       */
   1982   /* <Input>                                                               */
   1983   /*    flipped :: If set, flip the direction of curve.                    */
   1984   /*                                                                       */
   1985   /* <Return>                                                              */
   1986   /*    SUCCESS on success, FAILURE if any error was encountered during    */
   1987   /*    rendering.                                                         */
   1988   /*                                                                       */
   1989   static Bool
   1990   Convert_Glyph( RAS_ARGS int  flipped )
   1991   {
   1992     int       i;
   1993     unsigned  start;
   1994 
   1995     PProfile  lastProfile;
   1996 
   1997 
   1998     ras.fProfile = NULL;
   1999     ras.joint    = FALSE;
   2000     ras.fresh    = FALSE;
   2001 
   2002     ras.maxBuff  = ras.sizeBuff - AlignProfileSize;
   2003 
   2004     ras.numTurns = 0;
   2005 
   2006     ras.cProfile         = (PProfile)ras.top;
   2007     ras.cProfile->offset = ras.top;
   2008     ras.num_Profs        = 0;
   2009 
   2010     start = 0;
   2011 
   2012     for ( i = 0; i < ras.outline.n_contours; i++ )
   2013     {
   2014       Bool  o;
   2015 
   2016 
   2017       ras.state    = Unknown_State;
   2018       ras.gProfile = NULL;
   2019 
   2020       if ( Decompose_Curve( RAS_VARS (unsigned short)start,
   2021                                      ras.outline.contours[i],
   2022                                      flipped ) )
   2023         return FAILURE;
   2024 
   2025       start = ras.outline.contours[i] + 1;
   2026 
   2027       /* we must now check whether the extreme arcs join or not */
   2028       if ( FRAC( ras.lastY ) == 0 &&
   2029            ras.lastY >= ras.minY  &&
   2030            ras.lastY <= ras.maxY  )
   2031         if ( ras.gProfile                        &&
   2032              ( ras.gProfile->flags & Flow_Up ) ==
   2033                ( ras.cProfile->flags & Flow_Up ) )
   2034           ras.top--;
   2035         /* Note that ras.gProfile can be nil if the contour was too small */
   2036         /* to be drawn.                                                   */
   2037 
   2038       lastProfile = ras.cProfile;
   2039       if ( ras.cProfile->flags & Flow_Up )
   2040         o = IS_TOP_OVERSHOOT( ras.lastY );
   2041       else
   2042         o = IS_BOTTOM_OVERSHOOT( ras.lastY );
   2043       if ( End_Profile( RAS_VARS o ) )
   2044         return FAILURE;
   2045 
   2046       /* close the `next profile in contour' linked list */
   2047       if ( ras.gProfile )
   2048         lastProfile->next = ras.gProfile;
   2049     }
   2050 
   2051     if ( Finalize_Profile_Table( RAS_VAR ) )
   2052       return FAILURE;
   2053 
   2054     return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE );
   2055   }
   2056 
   2057 
   2058   /*************************************************************************/
   2059   /*************************************************************************/
   2060   /**                                                                     **/
   2061   /**  SCAN-LINE SWEEPS AND DRAWING                                       **/
   2062   /**                                                                     **/
   2063   /*************************************************************************/
   2064   /*************************************************************************/
   2065 
   2066 
   2067   /*************************************************************************/
   2068   /*                                                                       */
   2069   /*  Init_Linked                                                          */
   2070   /*                                                                       */
   2071   /*    Initializes an empty linked list.                                  */
   2072   /*                                                                       */
   2073   static void
   2074   Init_Linked( TProfileList*  l )
   2075   {
   2076     *l = NULL;
   2077   }
   2078 
   2079 
   2080   /*************************************************************************/
   2081   /*                                                                       */
   2082   /*  InsNew                                                               */
   2083   /*                                                                       */
   2084   /*    Inserts a new profile in a linked list.                            */
   2085   /*                                                                       */
   2086   static void
   2087   InsNew( PProfileList  list,
   2088           PProfile      profile )
   2089   {
   2090     PProfile  *old, current;
   2091     Long       x;
   2092 
   2093 
   2094     old     = list;
   2095     current = *old;
   2096     x       = profile->X;
   2097 
   2098     while ( current )
   2099     {
   2100       if ( x < current->X )
   2101         break;
   2102       old     = &current->link;
   2103       current = *old;
   2104     }
   2105 
   2106     profile->link = current;
   2107     *old          = profile;
   2108   }
   2109 
   2110 
   2111   /*************************************************************************/
   2112   /*                                                                       */
   2113   /*  DelOld                                                               */
   2114   /*                                                                       */
   2115   /*    Removes an old profile from a linked list.                         */
   2116   /*                                                                       */
   2117   static void
   2118   DelOld( PProfileList  list,
   2119           PProfile      profile )
   2120   {
   2121     PProfile  *old, current;
   2122 
   2123 
   2124     old     = list;
   2125     current = *old;
   2126 
   2127     while ( current )
   2128     {
   2129       if ( current == profile )
   2130       {
   2131         *old = current->link;
   2132         return;
   2133       }
   2134 
   2135       old     = &current->link;
   2136       current = *old;
   2137     }
   2138 
   2139     /* we should never get there, unless the profile was not part of */
   2140     /* the list.                                                     */
   2141   }
   2142 
   2143 
   2144   /*************************************************************************/
   2145   /*                                                                       */
   2146   /*  Sort                                                                 */
   2147   /*                                                                       */
   2148   /*    Sorts a trace list.  In 95%, the list is already sorted.  We need  */
   2149   /*    an algorithm which is fast in this case.  Bubble sort is enough    */
   2150   /*    and simple.                                                        */
   2151   /*                                                                       */
   2152   static void
   2153   Sort( PProfileList  list )
   2154   {
   2155     PProfile  *old, current, next;
   2156 
   2157 
   2158     /* First, set the new X coordinate of each profile */
   2159     current = *list;
   2160     while ( current )
   2161     {
   2162       current->X       = *current->offset;
   2163       current->offset += current->flags & Flow_Up ? 1 : -1;
   2164       current->height--;
   2165       current = current->link;
   2166     }
   2167 
   2168     /* Then sort them */
   2169     old     = list;
   2170     current = *old;
   2171 
   2172     if ( !current )
   2173       return;
   2174 
   2175     next = current->link;
   2176 
   2177     while ( next )
   2178     {
   2179       if ( current->X <= next->X )
   2180       {
   2181         old     = &current->link;
   2182         current = *old;
   2183 
   2184         if ( !current )
   2185           return;
   2186       }
   2187       else
   2188       {
   2189         *old          = next;
   2190         current->link = next->link;
   2191         next->link    = current;
   2192 
   2193         old     = list;
   2194         current = *old;
   2195       }
   2196 
   2197       next = current->link;
   2198     }
   2199   }
   2200 
   2201 
   2202   /*************************************************************************/
   2203   /*                                                                       */
   2204   /*  Vertical Sweep Procedure Set                                         */
   2205   /*                                                                       */
   2206   /*  These four routines are used during the vertical black/white sweep   */
   2207   /*  phase by the generic Draw_Sweep() function.                          */
   2208   /*                                                                       */
   2209   /*************************************************************************/
   2210 
   2211   static void
   2212   Vertical_Sweep_Init( RAS_ARGS Short*  min,
   2213                                 Short*  max )
   2214   {
   2215     Long  pitch = ras.target.pitch;
   2216 
   2217     FT_UNUSED( max );
   2218 
   2219 
   2220     ras.traceIncr = (Short)-pitch;
   2221     ras.traceOfs  = -*min * pitch;
   2222     if ( pitch > 0 )
   2223       ras.traceOfs += ( ras.target.rows - 1 ) * pitch;
   2224 
   2225     ras.gray_min_x = 0;
   2226     ras.gray_max_x = 0;
   2227   }
   2228 
   2229 
   2230   static void
   2231   Vertical_Sweep_Span( RAS_ARGS Short       y,
   2232                                 FT_F26Dot6  x1,
   2233                                 FT_F26Dot6  x2,
   2234                                 PProfile    left,
   2235                                 PProfile    right )
   2236   {
   2237     Long   e1, e2;
   2238     int    c1, c2;
   2239     Byte   f1, f2;
   2240     Byte*  target;
   2241 
   2242     FT_UNUSED( y );
   2243     FT_UNUSED( left );
   2244     FT_UNUSED( right );
   2245 
   2246 
   2247     /* Drop-out control */
   2248 
   2249     e1 = TRUNC( CEILING( x1 ) );
   2250 
   2251     if ( x2 - x1 - ras.precision <= ras.precision_jitter )
   2252       e2 = e1;
   2253     else
   2254       e2 = TRUNC( FLOOR( x2 ) );
   2255 
   2256     if ( e2 >= 0 && e1 < ras.bWidth )
   2257     {
   2258       if ( e1 < 0 )
   2259         e1 = 0;
   2260       if ( e2 >= ras.bWidth )
   2261         e2 = ras.bWidth - 1;
   2262 
   2263       c1 = (Short)( e1 >> 3 );
   2264       c2 = (Short)( e2 >> 3 );
   2265 
   2266       f1 = (Byte)  ( 0xFF >> ( e1 & 7 ) );
   2267       f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) );
   2268 
   2269       if ( ras.gray_min_x > c1 )
   2270         ras.gray_min_x = (short)c1;
   2271       if ( ras.gray_max_x < c2 )
   2272         ras.gray_max_x = (short)c2;
   2273 
   2274       target = ras.bTarget + ras.traceOfs + c1;
   2275       c2 -= c1;
   2276 
   2277       if ( c2 > 0 )
   2278       {
   2279         target[0] |= f1;
   2280 
   2281         /* memset() is slower than the following code on many platforms. */
   2282         /* This is due to the fact that, in the vast majority of cases,  */
   2283         /* the span length in bytes is relatively small.                 */
   2284         c2--;
   2285         while ( c2 > 0 )
   2286         {
   2287           *(++target) = 0xFF;
   2288           c2--;
   2289         }
   2290         target[1] |= f2;
   2291       }
   2292       else
   2293         *target |= ( f1 & f2 );
   2294     }
   2295   }
   2296 
   2297 
   2298   static void
   2299   Vertical_Sweep_Drop( RAS_ARGS Short       y,
   2300                                 FT_F26Dot6  x1,
   2301                                 FT_F26Dot6  x2,
   2302                                 PProfile    left,
   2303                                 PProfile    right )
   2304   {
   2305     Long   e1, e2, pxl;
   2306     Short  c1, f1;
   2307 
   2308 
   2309     /* Drop-out control */
   2310 
   2311     /*   e2            x2                    x1           e1   */
   2312     /*                                                         */
   2313     /*                 ^                     |                 */
   2314     /*                 |                     |                 */
   2315     /*   +-------------+---------------------+------------+    */
   2316     /*                 |                     |                 */
   2317     /*                 |                     v                 */
   2318     /*                                                         */
   2319     /* pixel         contour              contour       pixel  */
   2320     /* center                                           center */
   2321 
   2322     /* drop-out mode    scan conversion rules (as defined in OpenType) */
   2323     /* --------------------------------------------------------------- */
   2324     /*  0                1, 2, 3                                       */
   2325     /*  1                1, 2, 4                                       */
   2326     /*  2                1, 2                                          */
   2327     /*  3                same as mode 2                                */
   2328     /*  4                1, 2, 5                                       */
   2329     /*  5                1, 2, 6                                       */
   2330     /*  6, 7             same as mode 2                                */
   2331 
   2332     e1  = CEILING( x1 );
   2333     e2  = FLOOR  ( x2 );
   2334     pxl = e1;
   2335 
   2336     if ( e1 > e2 )
   2337     {
   2338       Int  dropOutControl = left->flags & 7;
   2339 
   2340 
   2341       if ( e1 == e2 + ras.precision )
   2342       {
   2343         switch ( dropOutControl )
   2344         {
   2345         case 0: /* simple drop-outs including stubs */
   2346           pxl = e2;
   2347           break;
   2348 
   2349         case 4: /* smart drop-outs including stubs */
   2350           pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
   2351           break;
   2352 
   2353         case 1: /* simple drop-outs excluding stubs */
   2354         case 5: /* smart drop-outs excluding stubs  */
   2355 
   2356           /* Drop-out Control Rules #4 and #6 */
   2357 
   2358           /* The specification neither provides an exact definition */
   2359           /* of a `stub' nor gives exact rules to exclude them.     */
   2360           /*                                                        */
   2361           /* Here the constraints we use to recognize a stub.       */
   2362           /*                                                        */
   2363           /*  upper stub:                                           */
   2364           /*                                                        */
   2365           /*   - P_Left and P_Right are in the same contour         */
   2366           /*   - P_Right is the successor of P_Left in that contour */
   2367           /*   - y is the top of P_Left and P_Right                 */
   2368           /*                                                        */
   2369           /*  lower stub:                                           */
   2370           /*                                                        */
   2371           /*   - P_Left and P_Right are in the same contour         */
   2372           /*   - P_Left is the successor of P_Right in that contour */
   2373           /*   - y is the bottom of P_Left                          */
   2374           /*                                                        */
   2375           /* We draw a stub if the following constraints are met.   */
   2376           /*                                                        */
   2377           /*   - for an upper or lower stub, there is top or bottom */
   2378           /*     overshoot, respectively                            */
   2379           /*   - the covered interval is greater or equal to a half */
   2380           /*     pixel                                              */
   2381 
   2382           /* upper stub test */
   2383           if ( left->next == right                &&
   2384                left->height <= 0                  &&
   2385                !( left->flags & Overshoot_Top   &&
   2386                   x2 - x1 >= ras.precision_half ) )
   2387             return;
   2388 
   2389           /* lower stub test */
   2390           if ( right->next == left                 &&
   2391                left->start == y                    &&
   2392                !( left->flags & Overshoot_Bottom &&
   2393                   x2 - x1 >= ras.precision_half  ) )
   2394             return;
   2395 
   2396           if ( dropOutControl == 1 )
   2397             pxl = e2;
   2398           else
   2399             pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
   2400           break;
   2401 
   2402         default: /* modes 2, 3, 6, 7 */
   2403           return;  /* no drop-out control */
   2404         }
   2405 
   2406         /* check that the other pixel isn't set */
   2407         e1 = pxl == e1 ? e2 : e1;
   2408 
   2409         e1 = TRUNC( e1 );
   2410 
   2411         c1 = (Short)( e1 >> 3 );
   2412         f1 = (Short)( e1 &  7 );
   2413 
   2414         if ( e1 >= 0 && e1 < ras.bWidth                      &&
   2415              ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) )
   2416           return;
   2417       }
   2418       else
   2419         return;
   2420     }
   2421 
   2422     e1 = TRUNC( pxl );
   2423 
   2424     if ( e1 >= 0 && e1 < ras.bWidth )
   2425     {
   2426       c1 = (Short)( e1 >> 3 );
   2427       f1 = (Short)( e1 & 7 );
   2428 
   2429       if ( ras.gray_min_x > c1 )
   2430         ras.gray_min_x = c1;
   2431       if ( ras.gray_max_x < c1 )
   2432         ras.gray_max_x = c1;
   2433 
   2434       ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 );
   2435     }
   2436   }
   2437 
   2438 
   2439   static void
   2440   Vertical_Sweep_Step( RAS_ARG )
   2441   {
   2442     ras.traceOfs += ras.traceIncr;
   2443   }
   2444 
   2445 
   2446   /***********************************************************************/
   2447   /*                                                                     */
   2448   /*  Horizontal Sweep Procedure Set                                     */
   2449   /*                                                                     */
   2450   /*  These four routines are used during the horizontal black/white     */
   2451   /*  sweep phase by the generic Draw_Sweep() function.                  */
   2452   /*                                                                     */
   2453   /***********************************************************************/
   2454 
   2455   static void
   2456   Horizontal_Sweep_Init( RAS_ARGS Short*  min,
   2457                                   Short*  max )
   2458   {
   2459     /* nothing, really */
   2460     FT_UNUSED_RASTER;
   2461     FT_UNUSED( min );
   2462     FT_UNUSED( max );
   2463   }
   2464 
   2465 
   2466   static void
   2467   Horizontal_Sweep_Span( RAS_ARGS Short       y,
   2468                                   FT_F26Dot6  x1,
   2469                                   FT_F26Dot6  x2,
   2470                                   PProfile    left,
   2471                                   PProfile    right )
   2472   {
   2473     Long   e1, e2;
   2474     PByte  bits;
   2475     Byte   f1;
   2476 
   2477     FT_UNUSED( left );
   2478     FT_UNUSED( right );
   2479 
   2480 
   2481     if ( x2 - x1 < ras.precision )
   2482     {
   2483       e1 = CEILING( x1 );
   2484       e2 = FLOOR  ( x2 );
   2485 
   2486       if ( e1 == e2 )
   2487       {
   2488         bits = ras.bTarget + ( y >> 3 );
   2489         f1   = (Byte)( 0x80 >> ( y & 7 ) );
   2490 
   2491         e1 = TRUNC( e1 );
   2492 
   2493         if ( e1 >= 0 && e1 < ras.target.rows )
   2494         {
   2495           PByte  p;
   2496 
   2497 
   2498           p = bits - e1*ras.target.pitch;
   2499           if ( ras.target.pitch > 0 )
   2500             p += ( ras.target.rows - 1 ) * ras.target.pitch;
   2501 
   2502           p[0] |= f1;
   2503         }
   2504       }
   2505     }
   2506   }
   2507 
   2508 
   2509   static void
   2510   Horizontal_Sweep_Drop( RAS_ARGS Short       y,
   2511                                   FT_F26Dot6  x1,
   2512                                   FT_F26Dot6  x2,
   2513                                   PProfile    left,
   2514                                   PProfile    right )
   2515   {
   2516     Long   e1, e2, pxl;
   2517     PByte  bits;
   2518     Byte   f1;
   2519 
   2520 
   2521     /* During the horizontal sweep, we only take care of drop-outs */
   2522 
   2523     /* e1     +       <-- pixel center */
   2524     /*        |                        */
   2525     /* x1  ---+-->    <-- contour      */
   2526     /*        |                        */
   2527     /*        |                        */
   2528     /* x2  <--+---    <-- contour      */
   2529     /*        |                        */
   2530     /*        |                        */
   2531     /* e2     +       <-- pixel center */
   2532 
   2533     e1  = CEILING( x1 );
   2534     e2  = FLOOR  ( x2 );
   2535     pxl = e1;
   2536 
   2537     if ( e1 > e2 )
   2538     {
   2539       Int  dropOutControl = left->flags & 7;
   2540 
   2541 
   2542       if ( e1 == e2 + ras.precision )
   2543       {
   2544         switch ( dropOutControl )
   2545         {
   2546         case 0: /* simple drop-outs including stubs */
   2547           pxl = e2;
   2548           break;
   2549 
   2550         case 4: /* smart drop-outs including stubs */
   2551           pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
   2552           break;
   2553 
   2554         case 1: /* simple drop-outs excluding stubs */
   2555         case 5: /* smart drop-outs excluding stubs  */
   2556           /* see Vertical_Sweep_Drop for details */
   2557 
   2558           /* rightmost stub test */
   2559           if ( left->next == right                &&
   2560                left->height <= 0                  &&
   2561                !( left->flags & Overshoot_Top   &&
   2562                   x2 - x1 >= ras.precision_half ) )
   2563             return;
   2564 
   2565           /* leftmost stub test */
   2566           if ( right->next == left                 &&
   2567                left->start == y                    &&
   2568                !( left->flags & Overshoot_Bottom &&
   2569                   x2 - x1 >= ras.precision_half  ) )
   2570             return;
   2571 
   2572           if ( dropOutControl == 1 )
   2573             pxl = e2;
   2574           else
   2575             pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
   2576           break;
   2577 
   2578         default: /* modes 2, 3, 6, 7 */
   2579           return;  /* no drop-out control */
   2580         }
   2581 
   2582         /* check that the other pixel isn't set */
   2583         e1 = pxl == e1 ? e2 : e1;
   2584 
   2585         e1 = TRUNC( e1 );
   2586 
   2587         bits = ras.bTarget + ( y >> 3 );
   2588         f1   = (Byte)( 0x80 >> ( y & 7 ) );
   2589 
   2590         bits -= e1 * ras.target.pitch;
   2591         if ( ras.target.pitch > 0 )
   2592           bits += ( ras.target.rows - 1 ) * ras.target.pitch;
   2593 
   2594         if ( e1 >= 0              &&
   2595              e1 < ras.target.rows &&
   2596              *bits & f1           )
   2597           return;
   2598       }
   2599       else
   2600         return;
   2601     }
   2602 
   2603     bits = ras.bTarget + ( y >> 3 );
   2604     f1   = (Byte)( 0x80 >> ( y & 7 ) );
   2605 
   2606     e1 = TRUNC( pxl );
   2607 
   2608     if ( e1 >= 0 && e1 < ras.target.rows )
   2609     {
   2610       bits -= e1 * ras.target.pitch;
   2611       if ( ras.target.pitch > 0 )
   2612         bits += ( ras.target.rows - 1 ) * ras.target.pitch;
   2613 
   2614       bits[0] |= f1;
   2615     }
   2616   }
   2617 
   2618 
   2619   static void
   2620   Horizontal_Sweep_Step( RAS_ARG )
   2621   {
   2622     /* Nothing, really */
   2623     FT_UNUSED_RASTER;
   2624   }
   2625 
   2626 
   2627 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
   2628 
   2629 
   2630   /*************************************************************************/
   2631   /*                                                                       */
   2632   /*  Vertical Gray Sweep Procedure Set                                    */
   2633   /*                                                                       */
   2634   /*  These two routines are used during the vertical gray-levels sweep    */
   2635   /*  phase by the generic Draw_Sweep() function.                          */
   2636   /*                                                                       */
   2637   /*  NOTES                                                                */
   2638   /*                                                                       */
   2639   /*  - The target pixmap's width *must* be a multiple of 4.               */
   2640   /*                                                                       */
   2641   /*  - You have to use the function Vertical_Sweep_Span() for the gray    */
   2642   /*    span call.                                                         */
   2643   /*                                                                       */
   2644   /*************************************************************************/
   2645 
   2646   static void
   2647   Vertical_Gray_Sweep_Init( RAS_ARGS Short*  min,
   2648                                      Short*  max )
   2649   {
   2650     Long  pitch, byte_len;
   2651 
   2652 
   2653     *min = *min & -2;
   2654     *max = ( *max + 3 ) & -2;
   2655 
   2656     ras.traceOfs  = 0;
   2657     pitch         = ras.target.pitch;
   2658     byte_len      = -pitch;
   2659     ras.traceIncr = (Short)byte_len;
   2660     ras.traceG    = ( *min / 2 ) * byte_len;
   2661 
   2662     if ( pitch > 0 )
   2663     {
   2664       ras.traceG += ( ras.target.rows - 1 ) * pitch;
   2665       byte_len    = -byte_len;
   2666     }
   2667 
   2668     ras.gray_min_x =  (Short)byte_len;
   2669     ras.gray_max_x = -(Short)byte_len;
   2670   }
   2671 
   2672 
   2673   static void
   2674   Vertical_Gray_Sweep_Step( RAS_ARG )
   2675   {
   2676     Int     c1, c2;
   2677     PByte   pix, bit, bit2;
   2678     short*  count = (short*)count_table;
   2679     Byte*   grays;
   2680 
   2681 
   2682     ras.traceOfs += ras.gray_width;
   2683 
   2684     if ( ras.traceOfs > ras.gray_width )
   2685     {
   2686       pix   = ras.gTarget + ras.traceG + ras.gray_min_x * 4;
   2687       grays = ras.grays;
   2688 
   2689       if ( ras.gray_max_x >= 0 )
   2690       {
   2691         Long  last_pixel = ras.target.width - 1;
   2692         Int   last_cell  = last_pixel >> 2;
   2693         Int   last_bit   = last_pixel & 3;
   2694         Bool  over       = 0;
   2695 
   2696 
   2697         if ( ras.gray_max_x >= last_cell && last_bit != 3 )
   2698         {
   2699           ras.gray_max_x = last_cell - 1;
   2700           over = 1;
   2701         }
   2702 
   2703         if ( ras.gray_min_x < 0 )
   2704           ras.gray_min_x = 0;
   2705 
   2706         bit  = ras.bTarget + ras.gray_min_x;
   2707         bit2 = bit + ras.gray_width;
   2708 
   2709         c1 = ras.gray_max_x - ras.gray_min_x;
   2710 
   2711         while ( c1 >= 0 )
   2712         {
   2713           c2 = count[*bit] + count[*bit2];
   2714 
   2715           if ( c2 )
   2716           {
   2717             pix[0] = grays[(c2 >> 12) & 0x000F];
   2718             pix[1] = grays[(c2 >> 8 ) & 0x000F];
   2719             pix[2] = grays[(c2 >> 4 ) & 0x000F];
   2720             pix[3] = grays[ c2        & 0x000F];
   2721 
   2722             *bit  = 0;
   2723             *bit2 = 0;
   2724           }
   2725 
   2726           bit++;
   2727           bit2++;
   2728           pix += 4;
   2729           c1--;
   2730         }
   2731 
   2732         if ( over )
   2733         {
   2734           c2 = count[*bit] + count[*bit2];
   2735           if ( c2 )
   2736           {
   2737             switch ( last_bit )
   2738             {
   2739             case 2:
   2740               pix[2] = grays[(c2 >> 4 ) & 0x000F];
   2741             case 1:
   2742               pix[1] = grays[(c2 >> 8 ) & 0x000F];
   2743             default:
   2744               pix[0] = grays[(c2 >> 12) & 0x000F];
   2745             }
   2746 
   2747             *bit  = 0;
   2748             *bit2 = 0;
   2749           }
   2750         }
   2751       }
   2752 
   2753       ras.traceOfs = 0;
   2754       ras.traceG  += ras.traceIncr;
   2755 
   2756       ras.gray_min_x =  32000;
   2757       ras.gray_max_x = -32000;
   2758     }
   2759   }
   2760 
   2761 
   2762   static void
   2763   Horizontal_Gray_Sweep_Span( RAS_ARGS Short       y,
   2764                                        FT_F26Dot6  x1,
   2765                                        FT_F26Dot6  x2,
   2766                                        PProfile    left,
   2767                                        PProfile    right )
   2768   {
   2769     /* nothing, really */
   2770     FT_UNUSED_RASTER;
   2771     FT_UNUSED( y );
   2772     FT_UNUSED( x1 );
   2773     FT_UNUSED( x2 );
   2774     FT_UNUSED( left );
   2775     FT_UNUSED( right );
   2776   }
   2777 
   2778 
   2779   static void
   2780   Horizontal_Gray_Sweep_Drop( RAS_ARGS Short       y,
   2781                                        FT_F26Dot6  x1,
   2782                                        FT_F26Dot6  x2,
   2783                                        PProfile    left,
   2784                                        PProfile    right )
   2785   {
   2786     Long   e1, e2;
   2787     PByte  pixel;
   2788     Byte   color;
   2789 
   2790 
   2791     /* During the horizontal sweep, we only take care of drop-outs */
   2792 
   2793     e1 = CEILING( x1 );
   2794     e2 = FLOOR  ( x2 );
   2795 
   2796     if ( e1 > e2 )
   2797     {
   2798       Int  dropOutControl = left->flags & 7;
   2799 
   2800 
   2801       if ( e1 == e2 + ras.precision )
   2802       {
   2803         switch ( dropOutControl )
   2804         {
   2805         case 0: /* simple drop-outs including stubs */
   2806           e1 = e2;
   2807           break;
   2808 
   2809         case 4: /* smart drop-outs including stubs */
   2810           e1 = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
   2811           break;
   2812 
   2813         case 1: /* simple drop-outs excluding stubs */
   2814         case 5: /* smart drop-outs excluding stubs  */
   2815           /* see Vertical_Sweep_Drop for details */
   2816 
   2817           /* rightmost stub test */
   2818           if ( left->next == right && left->height <= 0 )
   2819             return;
   2820 
   2821           /* leftmost stub test */
   2822           if ( right->next == left && left->start == y )
   2823             return;
   2824 
   2825           if ( dropOutControl == 1 )
   2826             e1 = e2;
   2827           else
   2828             e1 = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
   2829 
   2830           break;
   2831 
   2832         default: /* modes 2, 3, 6, 7 */
   2833           return;  /* no drop-out control */
   2834         }
   2835       }
   2836       else
   2837         return;
   2838     }
   2839 
   2840     if ( e1 >= 0 )
   2841     {
   2842       if ( x2 - x1 >= ras.precision_half )
   2843         color = ras.grays[2];
   2844       else
   2845         color = ras.grays[1];
   2846 
   2847       e1 = TRUNC( e1 ) / 2;
   2848       if ( e1 < ras.target.rows )
   2849       {
   2850         pixel = ras.gTarget - e1 * ras.target.pitch + y / 2;
   2851         if ( ras.target.pitch > 0 )
   2852           pixel += ( ras.target.rows - 1 ) * ras.target.pitch;
   2853 
   2854         if ( pixel[0] == ras.grays[0] )
   2855           pixel[0] = color;
   2856       }
   2857     }
   2858   }
   2859 
   2860 
   2861 #endif /* FT_RASTER_OPTION_ANTI_ALIASING */
   2862 
   2863 
   2864   /*************************************************************************/
   2865   /*                                                                       */
   2866   /*  Generic Sweep Drawing routine                                        */
   2867   /*                                                                       */
   2868   /*************************************************************************/
   2869 
   2870   static Bool
   2871   Draw_Sweep( RAS_ARG )
   2872   {
   2873     Short         y, y_change, y_height;
   2874 
   2875     PProfile      P, Q, P_Left, P_Right;
   2876 
   2877     Short         min_Y, max_Y, top, bottom, dropouts;
   2878 
   2879     Long          x1, x2, xs, e1, e2;
   2880 
   2881     TProfileList  waiting;
   2882     TProfileList  draw_left, draw_right;
   2883 
   2884 
   2885     /* initialize empty linked lists */
   2886 
   2887     Init_Linked( &waiting );
   2888 
   2889     Init_Linked( &draw_left  );
   2890     Init_Linked( &draw_right );
   2891 
   2892     /* first, compute min and max Y */
   2893 
   2894     P     = ras.fProfile;
   2895     max_Y = (Short)TRUNC( ras.minY );
   2896     min_Y = (Short)TRUNC( ras.maxY );
   2897 
   2898     while ( P )
   2899     {
   2900       Q = P->link;
   2901 
   2902       bottom = (Short)P->start;
   2903       top    = (Short)( P->start + P->height - 1 );
   2904 
   2905       if ( min_Y > bottom )
   2906         min_Y = bottom;
   2907       if ( max_Y < top )
   2908         max_Y = top;
   2909 
   2910       P->X = 0;
   2911       InsNew( &waiting, P );
   2912 
   2913       P = Q;
   2914     }
   2915 
   2916     /* check the Y-turns */
   2917     if ( ras.numTurns == 0 )
   2918     {
   2919       ras.error = Raster_Err_Invalid;
   2920       return FAILURE;
   2921     }
   2922 
   2923     /* now initialize the sweep */
   2924 
   2925     ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y );
   2926 
   2927     /* then compute the distance of each profile from min_Y */
   2928 
   2929     P = waiting;
   2930 
   2931     while ( P )
   2932     {
   2933       P->countL = (UShort)( P->start - min_Y );
   2934       P = P->link;
   2935     }
   2936 
   2937     /* let's go */
   2938 
   2939     y        = min_Y;
   2940     y_height = 0;
   2941 
   2942     if ( ras.numTurns > 0                     &&
   2943          ras.sizeBuff[-ras.numTurns] == min_Y )
   2944       ras.numTurns--;
   2945 
   2946     while ( ras.numTurns > 0 )
   2947     {
   2948       /* check waiting list for new activations */
   2949 
   2950       P = waiting;
   2951 
   2952       while ( P )
   2953       {
   2954         Q = P->link;
   2955         P->countL -= y_height;
   2956         if ( P->countL == 0 )
   2957         {
   2958           DelOld( &waiting, P );
   2959 
   2960           if ( P->flags & Flow_Up )
   2961             InsNew( &draw_left,  P );
   2962           else
   2963             InsNew( &draw_right, P );
   2964         }
   2965 
   2966         P = Q;
   2967       }
   2968 
   2969       /* sort the drawing lists */
   2970 
   2971       Sort( &draw_left );
   2972       Sort( &draw_right );
   2973 
   2974       y_change = (Short)ras.sizeBuff[-ras.numTurns--];
   2975       y_height = (Short)( y_change - y );
   2976 
   2977       while ( y < y_change )
   2978       {
   2979         /* let's trace */
   2980 
   2981         dropouts = 0;
   2982 
   2983         P_Left  = draw_left;
   2984         P_Right = draw_right;
   2985 
   2986         while ( P_Left )
   2987         {
   2988           x1 = P_Left ->X;
   2989           x2 = P_Right->X;
   2990 
   2991           if ( x1 > x2 )
   2992           {
   2993             xs = x1;
   2994             x1 = x2;
   2995             x2 = xs;
   2996           }
   2997 
   2998           e1 = FLOOR( x1 );
   2999           e2 = CEILING( x2 );
   3000 
   3001           if ( x2 - x1 <= ras.precision &&
   3002                e1 != x1 && e2 != x2     )
   3003           {
   3004             if ( e1 > e2 || e2 == e1 + ras.precision )
   3005             {
   3006               Int  dropOutControl = P_Left->flags & 7;
   3007 
   3008 
   3009               if ( dropOutControl != 2 )
   3010               {
   3011                 /* a drop-out was detected */
   3012 
   3013                 P_Left ->X = x1;
   3014                 P_Right->X = x2;
   3015 
   3016                 /* mark profile for drop-out processing */
   3017                 P_Left->countL = 1;
   3018                 dropouts++;
   3019               }
   3020 
   3021               goto Skip_To_Next;
   3022             }
   3023           }
   3024 
   3025           ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right );
   3026 
   3027         Skip_To_Next:
   3028 
   3029           P_Left  = P_Left->link;
   3030           P_Right = P_Right->link;
   3031         }
   3032 
   3033         /* handle drop-outs _after_ the span drawing --       */
   3034         /* drop-out processing has been moved out of the loop */
   3035         /* for performance tuning                             */
   3036         if ( dropouts > 0 )
   3037           goto Scan_DropOuts;
   3038 
   3039       Next_Line:
   3040 
   3041         ras.Proc_Sweep_Step( RAS_VAR );
   3042 
   3043         y++;
   3044 
   3045         if ( y < y_change )
   3046         {
   3047           Sort( &draw_left  );
   3048           Sort( &draw_right );
   3049         }
   3050       }
   3051 
   3052       /* now finalize the profiles that need it */
   3053 
   3054       P = draw_left;
   3055       while ( P )
   3056       {
   3057         Q = P->link;
   3058         if ( P->height == 0 )
   3059           DelOld( &draw_left, P );
   3060         P = Q;
   3061       }
   3062 
   3063       P = draw_right;
   3064       while ( P )
   3065       {
   3066         Q = P->link;
   3067         if ( P->height == 0 )
   3068           DelOld( &draw_right, P );
   3069         P = Q;
   3070       }
   3071     }
   3072 
   3073     /* for gray-scaling, flush the bitmap scanline cache */
   3074     while ( y <= max_Y )
   3075     {
   3076       ras.Proc_Sweep_Step( RAS_VAR );
   3077       y++;
   3078     }
   3079 
   3080     return SUCCESS;
   3081 
   3082   Scan_DropOuts:
   3083 
   3084     P_Left  = draw_left;
   3085     P_Right = draw_right;
   3086 
   3087     while ( P_Left )
   3088     {
   3089       if ( P_Left->countL )
   3090       {
   3091         P_Left->countL = 0;
   3092 #if 0
   3093         dropouts--;  /* -- this is useful when debugging only */
   3094 #endif
   3095         ras.Proc_Sweep_Drop( RAS_VARS y,
   3096                                       P_Left->X,
   3097                                       P_Right->X,
   3098                                       P_Left,
   3099                                       P_Right );
   3100       }
   3101 
   3102       P_Left  = P_Left->link;
   3103       P_Right = P_Right->link;
   3104     }
   3105 
   3106     goto Next_Line;
   3107   }
   3108 
   3109 
   3110   /*************************************************************************/
   3111   /*                                                                       */
   3112   /* <Function>                                                            */
   3113   /*    Render_Single_Pass                                                 */
   3114   /*                                                                       */
   3115   /* <Description>                                                         */
   3116   /*    Perform one sweep with sub-banding.                                */
   3117   /*                                                                       */
   3118   /* <Input>                                                               */
   3119   /*    flipped :: If set, flip the direction of the outline.              */
   3120   /*                                                                       */
   3121   /* <Return>                                                              */
   3122   /*    Renderer error code.                                               */
   3123   /*                                                                       */
   3124   static int
   3125   Render_Single_Pass( RAS_ARGS Bool  flipped )
   3126   {
   3127     Short  i, j, k;
   3128 
   3129 
   3130     while ( ras.band_top >= 0 )
   3131     {
   3132       ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision;
   3133       ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision;
   3134 
   3135       ras.top = ras.buff;
   3136 
   3137       ras.error = Raster_Err_None;
   3138 
   3139       if ( Convert_Glyph( RAS_VARS flipped ) )
   3140       {
   3141         if ( ras.error != Raster_Err_Overflow )
   3142           return FAILURE;
   3143 
   3144         ras.error = Raster_Err_None;
   3145 
   3146         /* sub-banding */
   3147 
   3148 #ifdef DEBUG_RASTER
   3149         ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) );
   3150 #endif
   3151 
   3152         i = ras.band_stack[ras.band_top].y_min;
   3153         j = ras.band_stack[ras.band_top].y_max;
   3154 
   3155         k = (Short)( ( i + j ) / 2 );
   3156 
   3157         if ( ras.band_top >= 7 || k < i )
   3158         {
   3159           ras.band_top = 0;
   3160           ras.error    = Raster_Err_Invalid;
   3161 
   3162           return ras.error;
   3163         }
   3164 
   3165         ras.band_stack[ras.band_top + 1].y_min = k;
   3166         ras.band_stack[ras.band_top + 1].y_max = j;
   3167 
   3168         ras.band_stack[ras.band_top].y_max = (Short)( k - 1 );
   3169 
   3170         ras.band_top++;
   3171       }
   3172       else
   3173       {
   3174         if ( ras.fProfile )
   3175           if ( Draw_Sweep( RAS_VAR ) )
   3176              return ras.error;
   3177         ras.band_top--;
   3178       }
   3179     }
   3180 
   3181     return SUCCESS;
   3182   }
   3183 
   3184 
   3185   /*************************************************************************/
   3186   /*                                                                       */
   3187   /* <Function>                                                            */
   3188   /*    Render_Glyph                                                       */
   3189   /*                                                                       */
   3190   /* <Description>                                                         */
   3191   /*    Render a glyph in a bitmap.  Sub-banding if needed.                */
   3192   /*                                                                       */
   3193   /* <Return>                                                              */
   3194   /*    FreeType error code.  0 means success.                             */
   3195   /*                                                                       */
   3196   FT_LOCAL_DEF( FT_Error )
   3197   Render_Glyph( RAS_ARG )
   3198   {
   3199     FT_Error  error;
   3200 
   3201 
   3202     Set_High_Precision( RAS_VARS ras.outline.flags &
   3203                                  FT_OUTLINE_HIGH_PRECISION );
   3204     ras.scale_shift = ras.precision_shift;
   3205 
   3206     if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS )
   3207       ras.dropOutControl = 2;
   3208     else
   3209     {
   3210       if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS )
   3211         ras.dropOutControl = 4;
   3212       else
   3213         ras.dropOutControl = 0;
   3214 
   3215       if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) )
   3216         ras.dropOutControl += 1;
   3217     }
   3218 
   3219     ras.second_pass = (FT_Byte)( !( ras.outline.flags &
   3220                                     FT_OUTLINE_SINGLE_PASS ) );
   3221 
   3222     /* Vertical Sweep */
   3223     ras.Proc_Sweep_Init = Vertical_Sweep_Init;
   3224     ras.Proc_Sweep_Span = Vertical_Sweep_Span;
   3225     ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
   3226     ras.Proc_Sweep_Step = Vertical_Sweep_Step;
   3227 
   3228     ras.band_top            = 0;
   3229     ras.band_stack[0].y_min = 0;
   3230     ras.band_stack[0].y_max = (short)( ras.target.rows - 1 );
   3231 
   3232     ras.bWidth  = (unsigned short)ras.target.width;
   3233     ras.bTarget = (Byte*)ras.target.buffer;
   3234 
   3235     if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 )
   3236       return error;
   3237 
   3238     /* Horizontal Sweep */
   3239     if ( ras.second_pass && ras.dropOutControl != 2 )
   3240     {
   3241       ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
   3242       ras.Proc_Sweep_Span = Horizontal_Sweep_Span;
   3243       ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop;
   3244       ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
   3245 
   3246       ras.band_top            = 0;
   3247       ras.band_stack[0].y_min = 0;
   3248       ras.band_stack[0].y_max = (short)( ras.target.width - 1 );
   3249 
   3250       if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 )
   3251         return error;
   3252     }
   3253 
   3254     return Raster_Err_None;
   3255   }
   3256 
   3257 
   3258 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
   3259 
   3260   /*************************************************************************/
   3261   /*                                                                       */
   3262   /* <Function>                                                            */
   3263   /*    Render_Gray_Glyph                                                  */
   3264   /*                                                                       */
   3265   /* <Description>                                                         */
   3266   /*    Render a glyph with grayscaling.  Sub-banding if needed.           */
   3267   /*                                                                       */
   3268   /* <Return>                                                              */
   3269   /*    FreeType error code.  0 means success.                             */
   3270   /*                                                                       */
   3271   FT_LOCAL_DEF( FT_Error )
   3272   Render_Gray_Glyph( RAS_ARG )
   3273   {
   3274     Long      pixel_width;
   3275     FT_Error  error;
   3276 
   3277 
   3278     Set_High_Precision( RAS_VARS ras.outline.flags &
   3279                                  FT_OUTLINE_HIGH_PRECISION );
   3280     ras.scale_shift = ras.precision_shift + 1;
   3281 
   3282     if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS )
   3283       ras.dropOutControl = 2;
   3284     else
   3285     {
   3286       if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS )
   3287         ras.dropOutControl = 4;
   3288       else
   3289         ras.dropOutControl = 0;
   3290 
   3291       if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) )
   3292         ras.dropOutControl += 1;
   3293     }
   3294 
   3295     ras.second_pass = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS );
   3296 
   3297     /* Vertical Sweep */
   3298 
   3299     ras.band_top            = 0;
   3300     ras.band_stack[0].y_min = 0;
   3301     ras.band_stack[0].y_max = 2 * ras.target.rows - 1;
   3302 
   3303     ras.bWidth  = ras.gray_width;
   3304     pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 );
   3305 
   3306     if ( ras.bWidth > pixel_width )
   3307       ras.bWidth = pixel_width;
   3308 
   3309     ras.bWidth  = ras.bWidth * 8;
   3310     ras.bTarget = (Byte*)ras.gray_lines;
   3311     ras.gTarget = (Byte*)ras.target.buffer;
   3312 
   3313     ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init;
   3314     ras.Proc_Sweep_Span = Vertical_Sweep_Span;
   3315     ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
   3316     ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step;
   3317 
   3318     error = Render_Single_Pass( RAS_VARS 0 );
   3319     if ( error )
   3320       return error;
   3321 
   3322     /* Horizontal Sweep */
   3323     if ( ras.second_pass && ras.dropOutControl != 2 )
   3324     {
   3325       ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
   3326       ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span;
   3327       ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop;
   3328       ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
   3329 
   3330       ras.band_top            = 0;
   3331       ras.band_stack[0].y_min = 0;
   3332       ras.band_stack[0].y_max = ras.target.width * 2 - 1;
   3333 
   3334       error = Render_Single_Pass( RAS_VARS 1 );
   3335       if ( error )
   3336         return error;
   3337     }
   3338 
   3339     return Raster_Err_None;
   3340   }
   3341 
   3342 #else /* !FT_RASTER_OPTION_ANTI_ALIASING */
   3343 
   3344   FT_LOCAL_DEF( FT_Error )
   3345   Render_Gray_Glyph( RAS_ARG )
   3346   {
   3347     FT_UNUSED_RASTER;
   3348 
   3349     return Raster_Err_Unsupported;
   3350   }
   3351 
   3352 #endif /* !FT_RASTER_OPTION_ANTI_ALIASING */
   3353 
   3354 
   3355   static void
   3356   ft_black_init( PRaster  raster )
   3357   {
   3358 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
   3359     FT_UInt  n;
   3360 
   3361 
   3362     /* set default 5-levels gray palette */
   3363     for ( n = 0; n < 5; n++ )
   3364       raster->grays[n] = n * 255 / 4;
   3365 
   3366     raster->gray_width = RASTER_GRAY_LINES / 2;
   3367 #else
   3368     FT_UNUSED( raster );
   3369 #endif
   3370   }
   3371 
   3372 
   3373   /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
   3374   /****                         a static object.                  *****/
   3375 
   3376 
   3377 #ifdef _STANDALONE_
   3378 
   3379 
   3380   static int
   3381   ft_black_new( void*       memory,
   3382                 FT_Raster  *araster )
   3383   {
   3384      static TRaster  the_raster;
   3385 
   3386 
   3387      *araster = (FT_Raster)&the_raster;
   3388      FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
   3389      ft_black_init( &the_raster );
   3390 
   3391      return 0;
   3392   }
   3393 
   3394 
   3395   static void
   3396   ft_black_done( FT_Raster  raster )
   3397   {
   3398     /* nothing */
   3399     FT_UNUSED( raster );
   3400   }
   3401 
   3402 
   3403 #else /* _STANDALONE_ */
   3404 
   3405 
   3406   static int
   3407   ft_black_new( FT_Memory   memory,
   3408                 PRaster    *araster )
   3409   {
   3410     FT_Error  error;
   3411     PRaster   raster;
   3412 
   3413 
   3414     *araster = 0;
   3415     if ( !FT_NEW( raster ) )
   3416     {
   3417       raster->memory = memory;
   3418       ft_black_init( raster );
   3419 
   3420       *araster = raster;
   3421     }
   3422 
   3423     return error;
   3424   }
   3425 
   3426 
   3427   static void
   3428   ft_black_done( PRaster  raster )
   3429   {
   3430     FT_Memory  memory = (FT_Memory)raster->memory;
   3431     FT_FREE( raster );
   3432   }
   3433 
   3434 
   3435 #endif /* _STANDALONE_ */
   3436 
   3437 
   3438   static void
   3439   ft_black_reset( PRaster  raster,
   3440                   char*    pool_base,
   3441                   long     pool_size )
   3442   {
   3443     if ( raster )
   3444     {
   3445       if ( pool_base && pool_size >= (long)sizeof(TWorker) + 2048 )
   3446       {
   3447         PWorker  worker = (PWorker)pool_base;
   3448 
   3449 
   3450         raster->buffer      = pool_base + ( (sizeof ( *worker ) + 7 ) & ~7 );
   3451         raster->buffer_size = ( ( pool_base + pool_size ) -
   3452                                 (char*)raster->buffer ) / sizeof ( Long );
   3453         raster->worker      = worker;
   3454       }
   3455       else
   3456       {
   3457         raster->buffer      = NULL;
   3458         raster->buffer_size = 0;
   3459         raster->worker      = NULL;
   3460       }
   3461     }
   3462   }
   3463 
   3464 
   3465   static void
   3466   ft_black_set_mode( PRaster        raster,
   3467                      unsigned long  mode,
   3468                      const char*    palette )
   3469   {
   3470 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
   3471 
   3472     if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) )
   3473     {
   3474       /* set 5-levels gray palette */
   3475       raster->grays[0] = palette[0];
   3476       raster->grays[1] = palette[1];
   3477       raster->grays[2] = palette[2];
   3478       raster->grays[3] = palette[3];
   3479       raster->grays[4] = palette[4];
   3480     }
   3481 
   3482 #else
   3483 
   3484     FT_UNUSED( raster );
   3485     FT_UNUSED( mode );
   3486     FT_UNUSED( palette );
   3487 
   3488 #endif
   3489   }
   3490 
   3491 
   3492   static int
   3493   ft_black_render( PRaster                  raster,
   3494                    const FT_Raster_Params*  params )
   3495   {
   3496     const FT_Outline*  outline    = (const FT_Outline*)params->source;
   3497     const FT_Bitmap*   target_map = params->target;
   3498     PWorker            worker;
   3499 
   3500 
   3501     if ( !raster || !raster->buffer || !raster->buffer_size )
   3502       return Raster_Err_Not_Ini;
   3503 
   3504     if ( !outline )
   3505       return Raster_Err_Invalid;
   3506 
   3507     /* return immediately if the outline is empty */
   3508     if ( outline->n_points == 0 || outline->n_contours <= 0 )
   3509       return Raster_Err_None;
   3510 
   3511     if ( !outline->contours || !outline->points )
   3512       return Raster_Err_Invalid;
   3513 
   3514     if ( outline->n_points !=
   3515            outline->contours[outline->n_contours - 1] + 1 )
   3516       return Raster_Err_Invalid;
   3517 
   3518     worker = raster->worker;
   3519 
   3520     /* this version of the raster does not support direct rendering, sorry */
   3521     if ( params->flags & FT_RASTER_FLAG_DIRECT )
   3522       return Raster_Err_Unsupported;
   3523 
   3524     if ( !target_map )
   3525       return Raster_Err_Invalid;
   3526 
   3527     /* nothing to do */
   3528     if ( !target_map->width || !target_map->rows )
   3529       return Raster_Err_None;
   3530 
   3531     if ( !target_map->buffer )
   3532       return Raster_Err_Invalid;
   3533 
   3534     ras.outline = *outline;
   3535     ras.target  = *target_map;
   3536 
   3537     worker->buff       = (PLong) raster->buffer;
   3538     worker->sizeBuff   = worker->buff +
   3539                            raster->buffer_size / sizeof ( Long );
   3540 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
   3541     worker->grays      = raster->grays;
   3542     worker->gray_width = raster->gray_width;
   3543 
   3544     FT_MEM_ZERO( worker->gray_lines, worker->gray_width * 2 );
   3545 #endif
   3546 
   3547     return ( params->flags & FT_RASTER_FLAG_AA )
   3548            ? Render_Gray_Glyph( RAS_VAR )
   3549            : Render_Glyph( RAS_VAR );
   3550   }
   3551 
   3552 
   3553   FT_DEFINE_RASTER_FUNCS( ft_standard_raster,
   3554     FT_GLYPH_FORMAT_OUTLINE,
   3555     (FT_Raster_New_Func)     ft_black_new,
   3556     (FT_Raster_Reset_Func)   ft_black_reset,
   3557     (FT_Raster_Set_Mode_Func)ft_black_set_mode,
   3558     (FT_Raster_Render_Func)  ft_black_render,
   3559     (FT_Raster_Done_Func)    ft_black_done
   3560   )
   3561 
   3562 
   3563 /* END */
   3564