tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ftraster.c (72009B)


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