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