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