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