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