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