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