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