ftraster.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  ftraster.c                                                             */
00004 /*                                                                         */
00005 /*    The FreeType glyph rasterizer (body).                                */
00006 /*                                                                         */
00007 /*  Copyright 1996-2001, 2002, 2003, 2005, 2007, 2008, 2009 by             */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018   /*************************************************************************/
00019   /*                                                                       */
00020   /* This file can be compiled without the rest of the FreeType engine, by */
00021   /* defining the _STANDALONE_ macro when compiling it.  You also need to  */
00022   /* put the files `ftimage.h' and `ftmisc.h' into the $(incdir)           */
00023   /* directory.  Typically, you should do something like                   */
00024   /*                                                                       */
00025   /* - copy `src/raster/ftraster.c' (this file) to your current directory  */
00026   /*                                                                       */
00027   /* - copy `include/freetype/ftimage.h' and `src/raster/ftmisc.h'         */
00028   /*   to your current directory                                           */
00029   /*                                                                       */
00030   /* - compile `ftraster' with the _STANDALONE_ macro defined, as in       */
00031   /*                                                                       */
00032   /*     cc -c -D_STANDALONE_ ftraster.c                                   */
00033   /*                                                                       */
00034   /* The renderer can be initialized with a call to                        */
00035   /* `ft_standard_raster.raster_new'; a bitmap can be generated            */
00036   /* with a call to `ft_standard_raster.raster_render'.                    */
00037   /*                                                                       */
00038   /* See the comments and documentation in the file `ftimage.h' for more   */
00039   /* details on how the raster works.                                      */
00040   /*                                                                       */
00041   /*************************************************************************/
00042 
00043 
00044   /*************************************************************************/
00045   /*                                                                       */
00046   /* This is a rewrite of the FreeType 1.x scan-line converter             */
00047   /*                                                                       */
00048   /*************************************************************************/
00049 
00050 #ifdef _STANDALONE_
00051 
00052 #define FT_CONFIG_STANDARD_LIBRARY_H  <stdlib.h>
00053 
00054 #include <string.h>           /* for memset */
00055 
00056 #include "ftmisc.h"
00057 #include "ftimage.h"
00058 
00059 #else /* !_STANDALONE_ */
00060 
00061 #include <ft2build.h>
00062 #include "ftraster.h"
00063 #include FT_INTERNAL_CALC_H   /* for FT_MulDiv only */
00064 
00065 #include "rastpic.h"
00066 
00067 #endif /* !_STANDALONE_ */
00068 
00069 
00070   /*************************************************************************/
00071   /*                                                                       */
00072   /* A simple technical note on how the raster works                       */
00073   /* -----------------------------------------------                       */
00074   /*                                                                       */
00075   /*   Converting an outline into a bitmap is achieved in several steps:   */
00076   /*                                                                       */
00077   /*   1 - Decomposing the outline into successive `profiles'.  Each       */
00078   /*       profile is simply an array of scanline intersections on a given */
00079   /*       dimension.  A profile's main attributes are                     */
00080   /*                                                                       */
00081   /*       o its scanline position boundaries, i.e. `Ymin' and `Ymax'      */
00082   /*                                                                       */
00083   /*       o an array of intersection coordinates for each scanline        */
00084   /*         between `Ymin' and `Ymax'                                     */
00085   /*                                                                       */
00086   /*       o a direction, indicating whether it was built going `up' or    */
00087   /*         `down', as this is very important for filling rules           */
00088   /*                                                                       */
00089   /*       o its drop-out mode                                             */
00090   /*                                                                       */
00091   /*   2 - Sweeping the target map's scanlines in order to compute segment */
00092   /*       `spans' which are then filled.  Additionally, this pass         */
00093   /*       performs drop-out control.                                      */
00094   /*                                                                       */
00095   /*   The outline data is parsed during step 1 only.  The profiles are    */
00096   /*   built from the bottom of the render pool, used as a stack.  The     */
00097   /*   following graphics shows the profile list under construction:       */
00098   /*                                                                       */
00099   /*     __________________________________________________________ _ _    */
00100   /*    |         |                 |         |                 |          */
00101   /*    | profile | coordinates for | profile | coordinates for |-->       */
00102   /*    |    1    |  profile 1      |    2    |  profile 2      |-->       */
00103   /*    |_________|_________________|_________|_________________|__ _ _    */
00104   /*                                                                       */
00105   /*    ^                                                       ^          */
00106   /*    |                                                       |          */
00107   /* start of render pool                                      top         */
00108   /*                                                                       */
00109   /*   The top of the profile stack is kept in the `top' variable.         */
00110   /*                                                                       */
00111   /*   As you can see, a profile record is pushed on top of the render     */
00112   /*   pool, which is then followed by its coordinates/intersections.  If  */
00113   /*   a change of direction is detected in the outline, a new profile is  */
00114   /*   generated until the end of the outline.                             */
00115   /*                                                                       */
00116   /*   Note that when all profiles have been generated, the function       */
00117   /*   Finalize_Profile_Table() is used to record, for each profile, its   */
00118   /*   bottom-most scanline as well as the scanline above its upmost       */
00119   /*   boundary.  These positions are called `y-turns' because they (sort  */
00120   /*   of) correspond to local extrema.  They are stored in a sorted list  */
00121   /*   built from the top of the render pool as a downwards stack:         */
00122   /*                                                                       */
00123   /*      _ _ _______________________________________                      */
00124   /*                            |                    |                     */
00125   /*                         <--| sorted list of     |                     */
00126   /*                         <--|  extrema scanlines |                     */
00127   /*      _ _ __________________|____________________|                     */
00128   /*                                                                       */
00129   /*                            ^                    ^                     */
00130   /*                            |                    |                     */
00131   /*                         maxBuff           sizeBuff = end of pool      */
00132   /*                                                                       */
00133   /*   This list is later used during the sweep phase in order to          */
00134   /*   optimize performance (see technical note on the sweep below).       */
00135   /*                                                                       */
00136   /*   Of course, the raster detects whether the two stacks collide and    */
00137   /*   handles the situation properly.                                     */
00138   /*                                                                       */
00139   /*************************************************************************/
00140 
00141 
00142   /*************************************************************************/
00143   /*************************************************************************/
00144   /**                                                                     **/
00145   /**  CONFIGURATION MACROS                                               **/
00146   /**                                                                     **/
00147   /*************************************************************************/
00148   /*************************************************************************/
00149 
00150   /* define DEBUG_RASTER if you want to compile a debugging version */
00151 /* #define DEBUG_RASTER */
00152 
00153   /* define FT_RASTER_OPTION_ANTI_ALIASING if you want to support */
00154   /* 5-levels anti-aliasing                                       */
00155 /* #define FT_RASTER_OPTION_ANTI_ALIASING */
00156 
00157   /* The size of the two-lines intermediate bitmap used */
00158   /* for anti-aliasing, in bytes.                       */
00159 #define RASTER_GRAY_LINES  2048
00160 
00161 
00162   /*************************************************************************/
00163   /*************************************************************************/
00164   /**                                                                     **/
00165   /**  OTHER MACROS (do not change)                                       **/
00166   /**                                                                     **/
00167   /*************************************************************************/
00168   /*************************************************************************/
00169 
00170   /*************************************************************************/
00171   /*                                                                       */
00172   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
00173   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
00174   /* messages during execution.                                            */
00175   /*                                                                       */
00176 #undef  FT_COMPONENT
00177 #define FT_COMPONENT  trace_raster
00178 
00179 
00180 #ifdef _STANDALONE_
00181 
00182 
00183   /* This macro is used to indicate that a function parameter is unused. */
00184   /* Its purpose is simply to reduce compiler warnings.  Note also that  */
00185   /* simply defining it as `(void)x' doesn't avoid warnings with certain */
00186   /* ANSI compilers (e.g. LCC).                                          */
00187 #define FT_UNUSED( x )  (x) = (x)
00188 
00189   /* Disable the tracing mechanism for simplicity -- developers can      */
00190   /* activate it easily by redefining these two macros.                  */
00191 #ifndef FT_ERROR
00192 #define FT_ERROR( x )  do { } while ( 0 )     /* nothing */
00193 #endif
00194 
00195 #ifndef FT_TRACE
00196 #define FT_TRACE( x )   do { } while ( 0 )    /* nothing */
00197 #define FT_TRACE1( x )  do { } while ( 0 )    /* nothing */
00198 #define FT_TRACE6( x )  do { } while ( 0 )    /* nothing */
00199 #endif
00200 
00201 #define Raster_Err_None          0
00202 #define Raster_Err_Not_Ini      -1
00203 #define Raster_Err_Overflow     -2
00204 #define Raster_Err_Neg_Height   -3
00205 #define Raster_Err_Invalid      -4
00206 #define Raster_Err_Unsupported  -5
00207 
00208 #define ft_memset  memset
00209 
00210 #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, raster_new_, \
00211                                 raster_reset_, raster_set_mode_,    \
00212                                 raster_render_, raster_done_ )      \
00213           const FT_Raster_Funcs class_ =                            \
00214           {                                                         \
00215             glyph_format_,                                          \
00216             raster_new_,                                            \
00217             raster_reset_,                                          \
00218             raster_set_mode_,                                       \
00219             raster_render_,                                         \
00220             raster_done_                                            \
00221          };
00222 
00223 #else /* !_STANDALONE_ */
00224 
00225 
00226 #include FT_INTERNAL_OBJECTS_H
00227 #include FT_INTERNAL_DEBUG_H        /* for FT_TRACE() and FT_ERROR() */
00228 
00229 #include "rasterrs.h"
00230 
00231 #define Raster_Err_None         Raster_Err_Ok
00232 #define Raster_Err_Not_Ini      Raster_Err_Raster_Uninitialized
00233 #define Raster_Err_Overflow     Raster_Err_Raster_Overflow
00234 #define Raster_Err_Neg_Height   Raster_Err_Raster_Negative_Height
00235 #define Raster_Err_Invalid      Raster_Err_Invalid_Outline
00236 #define Raster_Err_Unsupported  Raster_Err_Cannot_Render_Glyph
00237 
00238 
00239 #endif /* !_STANDALONE_ */
00240 
00241 
00242 #ifndef FT_MEM_SET
00243 #define FT_MEM_SET( d, s, c )  ft_memset( d, s, c )
00244 #endif
00245 
00246 #ifndef FT_MEM_ZERO
00247 #define FT_MEM_ZERO( dest, count )  FT_MEM_SET( dest, 0, count )
00248 #endif
00249 
00250   /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is       */
00251   /* typically a small value and the result of a*b is known to fit into */
00252   /* 32 bits.                                                           */
00253 #define FMulDiv( a, b, c )  ( (a) * (b) / (c) )
00254 
00255   /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
00256   /* for clipping computations.  It simply uses the FT_MulDiv() function   */
00257   /* defined in `ftcalc.h'.                                                */
00258 #define SMulDiv  FT_MulDiv
00259 
00260   /* The rasterizer is a very general purpose component; please leave */
00261   /* the following redefinitions there (you never know your target    */
00262   /* environment).                                                    */
00263 
00264 #ifndef TRUE
00265 #define TRUE   1
00266 #endif
00267 
00268 #ifndef FALSE
00269 #define FALSE  0
00270 #endif
00271 
00272 #ifndef NULL
00273 #define NULL  (void*)0
00274 #endif
00275 
00276 #ifndef SUCCESS
00277 #define SUCCESS  0
00278 #endif
00279 
00280 #ifndef FAILURE
00281 #define FAILURE  1
00282 #endif
00283 
00284 
00285 #define MaxBezier  32   /* The maximum number of stacked Bezier curves. */
00286                         /* Setting this constant to more than 32 is a   */
00287                         /* pure waste of space.                         */
00288 
00289 #define Pixel_Bits  6   /* fractional bits of *input* coordinates */
00290 
00291 
00292   /*************************************************************************/
00293   /*************************************************************************/
00294   /**                                                                     **/
00295   /**  SIMPLE TYPE DECLARATIONS                                           **/
00296   /**                                                                     **/
00297   /*************************************************************************/
00298   /*************************************************************************/
00299 
00300   typedef int             Int;
00301   typedef unsigned int    UInt;
00302   typedef short           Short;
00303   typedef unsigned short  UShort, *PUShort;
00304   typedef long            Long, *PLong;
00305   typedef unsigned long   ULong;
00306 
00307   typedef unsigned char   Byte, *PByte;
00308   typedef char            Bool;
00309 
00310 
00311   typedef union  Alignment_
00312   {
00313     long    l;
00314     void*   p;
00315     void  (*f)(void);
00316 
00317   } Alignment, *PAlignment;
00318 
00319 
00320   typedef struct  TPoint_
00321   {
00322     Long  x;
00323     Long  y;
00324 
00325   } TPoint;
00326 
00327 
00328   /* values for the `flags' bit field */
00329 #define Flow_Up           0x8
00330 #define Overshoot_Top     0x10
00331 #define Overshoot_Bottom  0x20
00332 
00333 
00334   /* States of each line, arc, and profile */
00335   typedef enum  TStates_
00336   {
00337     Unknown_State,
00338     Ascending_State,
00339     Descending_State,
00340     Flat_State
00341 
00342   } TStates;
00343 
00344 
00345   typedef struct TProfile_  TProfile;
00346   typedef TProfile*         PProfile;
00347 
00348   struct  TProfile_
00349   {
00350     FT_F26Dot6  X;           /* current coordinate during sweep          */
00351     PProfile    link;        /* link to next profile (various purposes)  */
00352     PLong       offset;      /* start of profile's data in render pool   */
00353     unsigned    flags;       /* Bit 0-2: drop-out mode                   */
00354                              /* Bit 3: profile orientation (up/down)     */
00355                              /* Bit 4: is top profile?                   */
00356                              /* Bit 5: is bottom profile?                */
00357     long        height;      /* profile's height in scanlines            */
00358     long        start;       /* profile's starting scanline              */
00359 
00360     unsigned    countL;      /* number of lines to step before this      */
00361                              /* profile becomes drawable                 */
00362 
00363     PProfile    next;        /* next profile in same contour, used       */
00364                              /* during drop-out control                  */
00365   };
00366 
00367   typedef PProfile   TProfileList;
00368   typedef PProfile*  PProfileList;
00369 
00370 
00371   /* Simple record used to implement a stack of bands, required */
00372   /* by the sub-banding mechanism                               */
00373   typedef struct  TBand_
00374   {
00375     Short  y_min;   /* band's minimum */
00376     Short  y_max;   /* band's maximum */
00377 
00378   } TBand;
00379 
00380 
00381 #define AlignProfileSize \
00382   ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( long ) )
00383 
00384 
00385 #ifdef FT_STATIC_RASTER
00386 
00387 
00388 #define RAS_ARGS       /* void */
00389 #define RAS_ARG        /* void */
00390 
00391 #define RAS_VARS       /* void */
00392 #define RAS_VAR        /* void */
00393 
00394 #define FT_UNUSED_RASTER  do { } while ( 0 )
00395 
00396 
00397 #else /* !FT_STATIC_RASTER */
00398 
00399 
00400 #define RAS_ARGS       PWorker    worker,
00401 #define RAS_ARG        PWorker    worker
00402 
00403 #define RAS_VARS       worker,
00404 #define RAS_VAR        worker
00405 
00406 #define FT_UNUSED_RASTER  FT_UNUSED( worker )
00407 
00408 
00409 #endif /* !FT_STATIC_RASTER */
00410 
00411 
00412   typedef struct TWorker_  TWorker, *PWorker;
00413 
00414 
00415   /* prototypes used for sweep function dispatch */
00416   typedef void
00417   Function_Sweep_Init( RAS_ARGS Short*  min,
00418                                 Short*  max );
00419 
00420   typedef void
00421   Function_Sweep_Span( RAS_ARGS Short       y,
00422                                 FT_F26Dot6  x1,
00423                                 FT_F26Dot6  x2,
00424                                 PProfile    left,
00425                                 PProfile    right );
00426 
00427   typedef void
00428   Function_Sweep_Step( RAS_ARG );
00429 
00430 
00431   /* NOTE: These operations are only valid on 2's complement processors */
00432 
00433 #define FLOOR( x )    ( (x) & -ras.precision )
00434 #define CEILING( x )  ( ( (x) + ras.precision - 1 ) & -ras.precision )
00435 #define TRUNC( x )    ( (signed long)(x) >> ras.precision_bits )
00436 #define FRAC( x )     ( (x) & ( ras.precision - 1 ) )
00437 #define SCALED( x )   ( ( (x) << ras.scale_shift ) - ras.precision_half )
00438 
00439 #define IS_BOTTOM_OVERSHOOT( x )  ( CEILING( x ) - x >= ras.precision_half )
00440 #define IS_TOP_OVERSHOOT( x )     ( x - FLOOR( x ) >= ras.precision_half )
00441 
00442   /* The most used variables are positioned at the top of the structure. */
00443   /* Thus, their offset can be coded with less opcodes, resulting in a   */
00444   /* smaller executable.                                                 */
00445 
00446   struct  TWorker_
00447   {
00448     Int         precision_bits;     /* precision related variables         */
00449     Int         precision;
00450     Int         precision_half;
00451     Long        precision_mask;
00452     Int         precision_shift;
00453     Int         precision_step;
00454     Int         precision_jitter;
00455 
00456     Int         scale_shift;        /* == precision_shift   for bitmaps    */
00457                                     /* == precision_shift+1 for pixmaps    */
00458 
00459     PLong       buff;               /* The profiles buffer                 */
00460     PLong       sizeBuff;           /* Render pool size                    */
00461     PLong       maxBuff;            /* Profiles buffer size                */
00462     PLong       top;                /* Current cursor in buffer            */
00463 
00464     FT_Error    error;
00465 
00466     Int         numTurns;           /* number of Y-turns in outline        */
00467 
00468     TPoint*     arc;                /* current Bezier arc pointer          */
00469 
00470     UShort      bWidth;             /* target bitmap width                 */
00471     PByte       bTarget;            /* target bitmap buffer                */
00472     PByte       gTarget;            /* target pixmap buffer                */
00473 
00474     Long        lastX, lastY;
00475     Long        minY, maxY;
00476 
00477     UShort      num_Profs;          /* current number of profiles          */
00478 
00479     Bool        fresh;              /* signals a fresh new profile which   */
00480                                     /* `start' field must be completed     */
00481     Bool        joint;              /* signals that the last arc ended     */
00482                                     /* exactly on a scanline.  Allows      */
00483                                     /* removal of doublets                 */
00484     PProfile    cProfile;           /* current profile                     */
00485     PProfile    fProfile;           /* head of linked list of profiles     */
00486     PProfile    gProfile;           /* contour's first profile in case     */
00487                                     /* of impact                           */
00488 
00489     TStates     state;              /* rendering state                     */
00490 
00491     FT_Bitmap   target;             /* description of target bit/pixmap    */
00492     FT_Outline  outline;
00493 
00494     Long        traceOfs;           /* current offset in target bitmap     */
00495     Long        traceG;             /* current offset in target pixmap     */
00496 
00497     Short       traceIncr;          /* sweep's increment in target bitmap  */
00498 
00499     Short       gray_min_x;         /* current min x during gray rendering */
00500     Short       gray_max_x;         /* current max x during gray rendering */
00501 
00502     /* dispatch variables */
00503 
00504     Function_Sweep_Init*  Proc_Sweep_Init;
00505     Function_Sweep_Span*  Proc_Sweep_Span;
00506     Function_Sweep_Span*  Proc_Sweep_Drop;
00507     Function_Sweep_Step*  Proc_Sweep_Step;
00508 
00509     Byte        dropOutControl;     /* current drop_out control method     */
00510 
00511     Bool        second_pass;        /* indicates whether a horizontal pass */
00512                                     /* should be performed to control      */
00513                                     /* drop-out accurately when calling    */
00514                                     /* Render_Glyph.  Note that there is   */
00515                                     /* no horizontal pass during gray      */
00516                                     /* rendering.                          */
00517 
00518     TPoint      arcs[3 * MaxBezier + 1]; /* The Bezier stack               */
00519 
00520     TBand       band_stack[16];     /* band stack used for sub-banding     */
00521     Int         band_top;           /* band stack top                      */
00522 
00523 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
00524 
00525     Byte*       grays;
00526 
00527     Byte        gray_lines[RASTER_GRAY_LINES];
00528                                 /* Intermediate table used to render the   */
00529                                 /* graylevels pixmaps.                     */
00530                                 /* gray_lines is a buffer holding two      */
00531                                 /* monochrome scanlines                    */
00532 
00533     Short       gray_width;     /* width in bytes of one monochrome        */
00534                                 /* intermediate scanline of gray_lines.    */
00535                                 /* Each gray pixel takes 2 bits long there */
00536 
00537                        /* The gray_lines must hold 2 lines, thus with size */
00538                        /* in bytes of at least `gray_width*2'.             */
00539 
00540 #endif /* FT_RASTER_ANTI_ALIASING */
00541 
00542   };
00543 
00544 
00545   typedef struct  TRaster_
00546   {
00547     char*    buffer;
00548     long     buffer_size;
00549     void*    memory;
00550     PWorker  worker;
00551     Byte     grays[5];
00552     Short    gray_width;
00553 
00554   } TRaster, *PRaster;
00555 
00556 #ifdef FT_STATIC_RASTER
00557 
00558   static TWorker  cur_ras;
00559 #define ras  cur_ras
00560 
00561 #else /* !FT_STATIC_RASTER */
00562 
00563 #define ras  (*worker)
00564 
00565 #endif /* !FT_STATIC_RASTER */
00566 
00567 
00568 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
00569 
00570   /* A lookup table used to quickly count set bits in four gray 2x2 */
00571   /* cells.  The values of the table have been produced with the    */
00572   /* following code:                                                */
00573   /*                                                                */
00574   /*   for ( i = 0; i < 256; i++ )                                  */
00575   /*   {                                                            */
00576   /*     l = 0;                                                     */
00577   /*     j = i;                                                     */
00578   /*                                                                */
00579   /*     for ( c = 0; c < 4; c++ )                                  */
00580   /*     {                                                          */
00581   /*       l <<= 4;                                                 */
00582   /*                                                                */
00583   /*       if ( j & 0x80 ) l++;                                     */
00584   /*       if ( j & 0x40 ) l++;                                     */
00585   /*                                                                */
00586   /*       j = ( j << 2 ) & 0xFF;                                   */
00587   /*     }                                                          */
00588   /*     printf( "0x%04X", l );                                     */
00589   /*   }                                                            */
00590   /*                                                                */
00591 
00592   static const short  count_table[256] =
00593   {
00594     0x0000, 0x0001, 0x0001, 0x0002, 0x0010, 0x0011, 0x0011, 0x0012,
00595     0x0010, 0x0011, 0x0011, 0x0012, 0x0020, 0x0021, 0x0021, 0x0022,
00596     0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
00597     0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
00598     0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
00599     0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
00600     0x0200, 0x0201, 0x0201, 0x0202, 0x0210, 0x0211, 0x0211, 0x0212,
00601     0x0210, 0x0211, 0x0211, 0x0212, 0x0220, 0x0221, 0x0221, 0x0222,
00602     0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
00603     0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
00604     0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
00605     0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
00606     0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
00607     0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
00608     0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
00609     0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
00610     0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
00611     0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
00612     0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
00613     0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
00614     0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
00615     0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
00616     0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
00617     0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
00618     0x2000, 0x2001, 0x2001, 0x2002, 0x2010, 0x2011, 0x2011, 0x2012,
00619     0x2010, 0x2011, 0x2011, 0x2012, 0x2020, 0x2021, 0x2021, 0x2022,
00620     0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
00621     0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
00622     0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
00623     0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
00624     0x2200, 0x2201, 0x2201, 0x2202, 0x2210, 0x2211, 0x2211, 0x2212,
00625     0x2210, 0x2211, 0x2211, 0x2212, 0x2220, 0x2221, 0x2221, 0x2222
00626   };
00627 
00628 #endif /* FT_RASTER_OPTION_ANTI_ALIASING */
00629 
00630 
00631 
00632   /*************************************************************************/
00633   /*************************************************************************/
00634   /**                                                                     **/
00635   /**  PROFILES COMPUTATION                                               **/
00636   /**                                                                     **/
00637   /*************************************************************************/
00638   /*************************************************************************/
00639 
00640 
00641   /*************************************************************************/
00642   /*                                                                       */
00643   /* <Function>                                                            */
00644   /*    Set_High_Precision                                                 */
00645   /*                                                                       */
00646   /* <Description>                                                         */
00647   /*    Set precision variables according to param flag.                   */
00648   /*                                                                       */
00649   /* <Input>                                                               */
00650   /*    High :: Set to True for high precision (typically for ppem < 18),  */
00651   /*            false otherwise.                                           */
00652   /*                                                                       */
00653   static void
00654   Set_High_Precision( RAS_ARGS Int  High )
00655   {
00656     if ( High )
00657     {
00658       ras.precision_bits   = 12;
00659       ras.precision_step   = 256;
00660       ras.precision_jitter = 50;
00661     }
00662     else
00663     {
00664       ras.precision_bits   = 6;
00665       ras.precision_step   = 32;
00666       ras.precision_jitter = 2;
00667     }
00668 
00669     FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
00670 
00671     ras.precision       = 1 << ras.precision_bits;
00672     ras.precision_half  = ras.precision / 2;
00673     ras.precision_shift = ras.precision_bits - Pixel_Bits;
00674     ras.precision_mask  = -ras.precision;
00675   }
00676 
00677 
00678   /*************************************************************************/
00679   /*                                                                       */
00680   /* <Function>                                                            */
00681   /*    New_Profile                                                        */
00682   /*                                                                       */
00683   /* <Description>                                                         */
00684   /*    Create a new profile in the render pool.                           */
00685   /*                                                                       */
00686   /* <Input>                                                               */
00687   /*    aState    :: The state/orientation of the new profile.             */
00688   /*                                                                       */
00689   /*    overshoot :: Whether the profile's unrounded start position        */
00690   /*                 differs by at least a half pixel.                     */
00691   /*                                                                       */
00692   /* <Return>                                                              */
00693   /*   SUCCESS on success.  FAILURE in case of overflow or of incoherent   */
00694   /*   profile.                                                            */
00695   /*                                                                       */
00696   static Bool
00697   New_Profile( RAS_ARGS TStates  aState,
00698                         Bool     overshoot )
00699   {
00700     if ( !ras.fProfile )
00701     {
00702       ras.cProfile  = (PProfile)ras.top;
00703       ras.fProfile  = ras.cProfile;
00704       ras.top      += AlignProfileSize;
00705     }
00706 
00707     if ( ras.top >= ras.maxBuff )
00708     {
00709       ras.error = Raster_Err_Overflow;
00710       return FAILURE;
00711     }
00712 
00713     ras.cProfile->flags  = 0;
00714     ras.cProfile->start  = 0;
00715     ras.cProfile->height = 0;
00716     ras.cProfile->offset = ras.top;
00717     ras.cProfile->link   = (PProfile)0;
00718     ras.cProfile->next   = (PProfile)0;
00719     ras.cProfile->flags  = ras.dropOutControl;
00720 
00721     switch ( aState )
00722     {
00723     case Ascending_State:
00724       ras.cProfile->flags |= Flow_Up;
00725       if ( overshoot )
00726         ras.cProfile->flags |= Overshoot_Bottom;
00727 
00728       FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile ));
00729       break;
00730 
00731     case Descending_State:
00732       if ( overshoot )
00733         ras.cProfile->flags |= Overshoot_Top;
00734       FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile ));
00735       break;
00736 
00737     default:
00738       FT_ERROR(( "New_Profile: invalid profile direction\n" ));
00739       ras.error = Raster_Err_Invalid;
00740       return FAILURE;
00741     }
00742 
00743     if ( !ras.gProfile )
00744       ras.gProfile = ras.cProfile;
00745 
00746     ras.state = aState;
00747     ras.fresh = TRUE;
00748     ras.joint = FALSE;
00749 
00750     return SUCCESS;
00751   }
00752 
00753 
00754   /*************************************************************************/
00755   /*                                                                       */
00756   /* <Function>                                                            */
00757   /*    End_Profile                                                        */
00758   /*                                                                       */
00759   /* <Description>                                                         */
00760   /*    Finalize the current profile.                                      */
00761   /*                                                                       */
00762   /* <Input>                                                               */
00763   /*    overshoot :: Whether the profile's unrounded end position differs  */
00764   /*                 by at least a half pixel.                             */
00765   /*                                                                       */
00766   /* <Return>                                                              */
00767   /*    SUCCESS on success.  FAILURE in case of overflow or incoherency.   */
00768   /*                                                                       */
00769   static Bool
00770   End_Profile( RAS_ARGS Bool  overshoot )
00771   {
00772     Long      h;
00773     PProfile  oldProfile;
00774 
00775 
00776     h = (Long)( ras.top - ras.cProfile->offset );
00777 
00778     if ( h < 0 )
00779     {
00780       FT_ERROR(( "End_Profile: negative height encountered\n" ));
00781       ras.error = Raster_Err_Neg_Height;
00782       return FAILURE;
00783     }
00784 
00785     if ( h > 0 )
00786     {
00787       FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n",
00788                   (long)ras.cProfile, ras.cProfile->start, h ));
00789 
00790       ras.cProfile->height = h;
00791       if ( overshoot )
00792       {
00793         if ( ras.cProfile->flags & Flow_Up )
00794           ras.cProfile->flags |= Overshoot_Top;
00795         else
00796           ras.cProfile->flags |= Overshoot_Bottom;
00797       }
00798 
00799       oldProfile   = ras.cProfile;
00800       ras.cProfile = (PProfile)ras.top;
00801 
00802       ras.top += AlignProfileSize;
00803 
00804       ras.cProfile->height = 0;
00805       ras.cProfile->offset = ras.top;
00806 
00807       oldProfile->next = ras.cProfile;
00808       ras.num_Profs++;
00809     }
00810 
00811     if ( ras.top >= ras.maxBuff )
00812     {
00813       FT_TRACE1(( "overflow in End_Profile\n" ));
00814       ras.error = Raster_Err_Overflow;
00815       return FAILURE;
00816     }
00817 
00818     ras.joint = FALSE;
00819 
00820     return SUCCESS;
00821   }
00822 
00823 
00824   /*************************************************************************/
00825   /*                                                                       */
00826   /* <Function>                                                            */
00827   /*    Insert_Y_Turn                                                      */
00828   /*                                                                       */
00829   /* <Description>                                                         */
00830   /*    Insert a salient into the sorted list placed on top of the render  */
00831   /*    pool.                                                              */
00832   /*                                                                       */
00833   /* <Input>                                                               */
00834   /*    New y scanline position.                                           */
00835   /*                                                                       */
00836   /* <Return>                                                              */
00837   /*    SUCCESS on success.  FAILURE in case of overflow.                  */
00838   /*                                                                       */
00839   static Bool
00840   Insert_Y_Turn( RAS_ARGS Int  y )
00841   {
00842     PLong  y_turns;
00843     Int    y2, n;
00844 
00845 
00846     n       = ras.numTurns - 1;
00847     y_turns = ras.sizeBuff - ras.numTurns;
00848 
00849     /* look for first y value that is <= */
00850     while ( n >= 0 && y < y_turns[n] )
00851       n--;
00852 
00853     /* if it is <, simply insert it, ignore if == */
00854     if ( n >= 0 && y > y_turns[n] )
00855       while ( n >= 0 )
00856       {
00857         y2 = (Int)y_turns[n];
00858         y_turns[n] = y;
00859         y = y2;
00860         n--;
00861       }
00862 
00863     if ( n < 0 )
00864     {
00865       ras.maxBuff--;
00866       if ( ras.maxBuff <= ras.top )
00867       {
00868         ras.error = Raster_Err_Overflow;
00869         return FAILURE;
00870       }
00871       ras.numTurns++;
00872       ras.sizeBuff[-ras.numTurns] = y;
00873     }
00874 
00875     return SUCCESS;
00876   }
00877 
00878 
00879   /*************************************************************************/
00880   /*                                                                       */
00881   /* <Function>                                                            */
00882   /*    Finalize_Profile_Table                                             */
00883   /*                                                                       */
00884   /* <Description>                                                         */
00885   /*    Adjust all links in the profiles list.                             */
00886   /*                                                                       */
00887   /* <Return>                                                              */
00888   /*    SUCCESS on success.  FAILURE in case of overflow.                  */
00889   /*                                                                       */
00890   static Bool
00891   Finalize_Profile_Table( RAS_ARG )
00892   {
00893     Int       bottom, top;
00894     UShort    n;
00895     PProfile  p;
00896 
00897 
00898     n = ras.num_Profs;
00899     p = ras.fProfile;
00900 
00901     if ( n > 1 && p )
00902     {
00903       while ( n > 0 )
00904       {
00905         if ( n > 1 )
00906           p->link = (PProfile)( p->offset + p->height );
00907         else
00908           p->link = NULL;
00909 
00910         if ( p->flags & Flow_Up )
00911         {
00912           bottom = (Int)p->start;
00913           top    = (Int)( p->start + p->height - 1 );
00914         }
00915         else
00916         {
00917           bottom     = (Int)( p->start - p->height + 1 );
00918           top        = (Int)p->start;
00919           p->start   = bottom;
00920           p->offset += p->height - 1;
00921         }
00922 
00923         if ( Insert_Y_Turn( RAS_VARS bottom )  ||
00924              Insert_Y_Turn( RAS_VARS top + 1 ) )
00925           return FAILURE;
00926 
00927         p = p->link;
00928         n--;
00929       }
00930     }
00931     else
00932       ras.fProfile = NULL;
00933 
00934     return SUCCESS;
00935   }
00936 
00937 
00938   /*************************************************************************/
00939   /*                                                                       */
00940   /* <Function>                                                            */
00941   /*    Split_Conic                                                        */
00942   /*                                                                       */
00943   /* <Description>                                                         */
00944   /*    Subdivide one conic Bezier into two joint sub-arcs in the Bezier   */
00945   /*    stack.                                                             */
00946   /*                                                                       */
00947   /* <Input>                                                               */
00948   /*    None (subdivided Bezier is taken from the top of the stack).       */
00949   /*                                                                       */
00950   /* <Note>                                                                */
00951   /*    This routine is the `beef' of this component.  It is  _the_ inner  */
00952   /*    loop that should be optimized to hell to get the best performance. */
00953   /*                                                                       */
00954   static void
00955   Split_Conic( TPoint*  base )
00956   {
00957     Long  a, b;
00958 
00959 
00960     base[4].x = base[2].x;
00961     b = base[1].x;
00962     a = base[3].x = ( base[2].x + b ) / 2;
00963     b = base[1].x = ( base[0].x + b ) / 2;
00964     base[2].x = ( a + b ) / 2;
00965 
00966     base[4].y = base[2].y;
00967     b = base[1].y;
00968     a = base[3].y = ( base[2].y + b ) / 2;
00969     b = base[1].y = ( base[0].y + b ) / 2;
00970     base[2].y = ( a + b ) / 2;
00971 
00972     /* hand optimized.  gcc doesn't seem to be too good at common      */
00973     /* expression substitution and instruction scheduling ;-)          */
00974   }
00975 
00976 
00977   /*************************************************************************/
00978   /*                                                                       */
00979   /* <Function>                                                            */
00980   /*    Split_Cubic                                                        */
00981   /*                                                                       */
00982   /* <Description>                                                         */
00983   /*    Subdivide a third-order Bezier arc into two joint sub-arcs in the  */
00984   /*    Bezier stack.                                                      */
00985   /*                                                                       */
00986   /* <Note>                                                                */
00987   /*    This routine is the `beef' of the component.  It is one of _the_   */
00988   /*    inner loops that should be optimized like hell to get the best     */
00989   /*    performance.                                                       */
00990   /*                                                                       */
00991   static void
00992   Split_Cubic( TPoint*  base )
00993   {
00994     Long  a, b, c, d;
00995 
00996 
00997     base[6].x = base[3].x;
00998     c = base[1].x;
00999     d = base[2].x;
01000     base[1].x = a = ( base[0].x + c + 1 ) >> 1;
01001     base[5].x = b = ( base[3].x + d + 1 ) >> 1;
01002     c = ( c + d + 1 ) >> 1;
01003     base[2].x = a = ( a + c + 1 ) >> 1;
01004     base[4].x = b = ( b + c + 1 ) >> 1;
01005     base[3].x = ( a + b + 1 ) >> 1;
01006 
01007     base[6].y = base[3].y;
01008     c = base[1].y;
01009     d = base[2].y;
01010     base[1].y = a = ( base[0].y + c + 1 ) >> 1;
01011     base[5].y = b = ( base[3].y + d + 1 ) >> 1;
01012     c = ( c + d + 1 ) >> 1;
01013     base[2].y = a = ( a + c + 1 ) >> 1;
01014     base[4].y = b = ( b + c + 1 ) >> 1;
01015     base[3].y = ( a + b + 1 ) >> 1;
01016   }
01017 
01018 
01019   /*************************************************************************/
01020   /*                                                                       */
01021   /* <Function>                                                            */
01022   /*    Line_Up                                                            */
01023   /*                                                                       */
01024   /* <Description>                                                         */
01025   /*    Compute the x-coordinates of an ascending line segment and store   */
01026   /*    them in the render pool.                                           */
01027   /*                                                                       */
01028   /* <Input>                                                               */
01029   /*    x1   :: The x-coordinate of the segment's start point.             */
01030   /*                                                                       */
01031   /*    y1   :: The y-coordinate of the segment's start point.             */
01032   /*                                                                       */
01033   /*    x2   :: The x-coordinate of the segment's end point.               */
01034   /*                                                                       */
01035   /*    y2   :: The y-coordinate of the segment's end point.               */
01036   /*                                                                       */
01037   /*    miny :: A lower vertical clipping bound value.                     */
01038   /*                                                                       */
01039   /*    maxy :: An upper vertical clipping bound value.                    */
01040   /*                                                                       */
01041   /* <Return>                                                              */
01042   /*    SUCCESS on success, FAILURE on render pool overflow.               */
01043   /*                                                                       */
01044   static Bool
01045   Line_Up( RAS_ARGS Long  x1,
01046                     Long  y1,
01047                     Long  x2,
01048                     Long  y2,
01049                     Long  miny,
01050                     Long  maxy )
01051   {
01052     Long   Dx, Dy;
01053     Int    e1, e2, f1, f2, size;     /* XXX: is `Short' sufficient? */
01054     Long   Ix, Rx, Ax;
01055 
01056     PLong  top;
01057 
01058 
01059     Dx = x2 - x1;
01060     Dy = y2 - y1;
01061 
01062     if ( Dy <= 0 || y2 < miny || y1 > maxy )
01063       return SUCCESS;
01064 
01065     if ( y1 < miny )
01066     {
01067       /* Take care: miny-y1 can be a very large value; we use     */
01068       /*            a slow MulDiv function to avoid clipping bugs */
01069       x1 += SMulDiv( Dx, miny - y1, Dy );
01070       e1  = (Int)TRUNC( miny );
01071       f1  = 0;
01072     }
01073     else
01074     {
01075       e1 = (Int)TRUNC( y1 );
01076       f1 = (Int)FRAC( y1 );
01077     }
01078 
01079     if ( y2 > maxy )
01080     {
01081       /* x2 += FMulDiv( Dx, maxy - y2, Dy );  UNNECESSARY */
01082       e2  = (Int)TRUNC( maxy );
01083       f2  = 0;
01084     }
01085     else
01086     {
01087       e2 = (Int)TRUNC( y2 );
01088       f2 = (Int)FRAC( y2 );
01089     }
01090 
01091     if ( f1 > 0 )
01092     {
01093       if ( e1 == e2 )
01094         return SUCCESS;
01095       else
01096       {
01097         x1 += FMulDiv( Dx, ras.precision - f1, Dy );
01098         e1 += 1;
01099       }
01100     }
01101     else
01102       if ( ras.joint )
01103       {
01104         ras.top--;
01105         ras.joint = FALSE;
01106       }
01107 
01108     ras.joint = (char)( f2 == 0 );
01109 
01110     if ( ras.fresh )
01111     {
01112       ras.cProfile->start = e1;
01113       ras.fresh           = FALSE;
01114     }
01115 
01116     size = e2 - e1 + 1;
01117     if ( ras.top + size >= ras.maxBuff )
01118     {
01119       ras.error = Raster_Err_Overflow;
01120       return FAILURE;
01121     }
01122 
01123     if ( Dx > 0 )
01124     {
01125       Ix = ( ras.precision * Dx ) / Dy;
01126       Rx = ( ras.precision * Dx ) % Dy;
01127       Dx = 1;
01128     }
01129     else
01130     {
01131       Ix = -( ( ras.precision * -Dx ) / Dy );
01132       Rx =    ( ras.precision * -Dx ) % Dy;
01133       Dx = -1;
01134     }
01135 
01136     Ax  = -Dy;
01137     top = ras.top;
01138 
01139     while ( size > 0 )
01140     {
01141       *top++ = x1;
01142 
01143       x1 += Ix;
01144       Ax += Rx;
01145       if ( Ax >= 0 )
01146       {
01147         Ax -= Dy;
01148         x1 += Dx;
01149       }
01150       size--;
01151     }
01152 
01153     ras.top = top;
01154     return SUCCESS;
01155   }
01156 
01157 
01158   /*************************************************************************/
01159   /*                                                                       */
01160   /* <Function>                                                            */
01161   /*    Line_Down                                                          */
01162   /*                                                                       */
01163   /* <Description>                                                         */
01164   /*    Compute the x-coordinates of an descending line segment and store  */
01165   /*    them in the render pool.                                           */
01166   /*                                                                       */
01167   /* <Input>                                                               */
01168   /*    x1   :: The x-coordinate of the segment's start point.             */
01169   /*                                                                       */
01170   /*    y1   :: The y-coordinate of the segment's start point.             */
01171   /*                                                                       */
01172   /*    x2   :: The x-coordinate of the segment's end point.               */
01173   /*                                                                       */
01174   /*    y2   :: The y-coordinate of the segment's end point.               */
01175   /*                                                                       */
01176   /*    miny :: A lower vertical clipping bound value.                     */
01177   /*                                                                       */
01178   /*    maxy :: An upper vertical clipping bound value.                    */
01179   /*                                                                       */
01180   /* <Return>                                                              */
01181   /*    SUCCESS on success, FAILURE on render pool overflow.               */
01182   /*                                                                       */
01183   static Bool
01184   Line_Down( RAS_ARGS Long  x1,
01185                       Long  y1,
01186                       Long  x2,
01187                       Long  y2,
01188                       Long  miny,
01189                       Long  maxy )
01190   {
01191     Bool  result, fresh;
01192 
01193 
01194     fresh  = ras.fresh;
01195 
01196     result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
01197 
01198     if ( fresh && !ras.fresh )
01199       ras.cProfile->start = -ras.cProfile->start;
01200 
01201     return result;
01202   }
01203 
01204 
01205   /* A function type describing the functions used to split Bezier arcs */
01206   typedef void  (*TSplitter)( TPoint*  base );
01207 
01208 
01209   /*************************************************************************/
01210   /*                                                                       */
01211   /* <Function>                                                            */
01212   /*    Bezier_Up                                                          */
01213   /*                                                                       */
01214   /* <Description>                                                         */
01215   /*    Compute the x-coordinates of an ascending Bezier arc and store     */
01216   /*    them in the render pool.                                           */
01217   /*                                                                       */
01218   /* <Input>                                                               */
01219   /*    degree   :: The degree of the Bezier arc (either 2 or 3).          */
01220   /*                                                                       */
01221   /*    splitter :: The function to split Bezier arcs.                     */
01222   /*                                                                       */
01223   /*    miny     :: A lower vertical clipping bound value.                 */
01224   /*                                                                       */
01225   /*    maxy     :: An upper vertical clipping bound value.                */
01226   /*                                                                       */
01227   /* <Return>                                                              */
01228   /*    SUCCESS on success, FAILURE on render pool overflow.               */
01229   /*                                                                       */
01230   static Bool
01231   Bezier_Up( RAS_ARGS Int        degree,
01232                       TSplitter  splitter,
01233                       Long       miny,
01234                       Long       maxy )
01235   {
01236     Long   y1, y2, e, e2, e0;
01237     Short  f1;
01238 
01239     TPoint*  arc;
01240     TPoint*  start_arc;
01241 
01242     PLong top;
01243 
01244 
01245     arc = ras.arc;
01246     y1  = arc[degree].y;
01247     y2  = arc[0].y;
01248     top = ras.top;
01249 
01250     if ( y2 < miny || y1 > maxy )
01251       goto Fin;
01252 
01253     e2 = FLOOR( y2 );
01254 
01255     if ( e2 > maxy )
01256       e2 = maxy;
01257 
01258     e0 = miny;
01259 
01260     if ( y1 < miny )
01261       e = miny;
01262     else
01263     {
01264       e  = CEILING( y1 );
01265       f1 = (Short)( FRAC( y1 ) );
01266       e0 = e;
01267 
01268       if ( f1 == 0 )
01269       {
01270         if ( ras.joint )
01271         {
01272           top--;
01273           ras.joint = FALSE;
01274         }
01275 
01276         *top++ = arc[degree].x;
01277 
01278         e += ras.precision;
01279       }
01280     }
01281 
01282     if ( ras.fresh )
01283     {
01284       ras.cProfile->start = TRUNC( e0 );
01285       ras.fresh = FALSE;
01286     }
01287 
01288     if ( e2 < e )
01289       goto Fin;
01290 
01291     if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
01292     {
01293       ras.top   = top;
01294       ras.error = Raster_Err_Overflow;
01295       return FAILURE;
01296     }
01297 
01298     start_arc = arc;
01299 
01300     while ( arc >= start_arc && e <= e2 )
01301     {
01302       ras.joint = FALSE;
01303 
01304       y2 = arc[0].y;
01305 
01306       if ( y2 > e )
01307       {
01308         y1 = arc[degree].y;
01309         if ( y2 - y1 >= ras.precision_step )
01310         {
01311           splitter( arc );
01312           arc += degree;
01313         }
01314         else
01315         {
01316           *top++ = arc[degree].x + FMulDiv( arc[0].x - arc[degree].x,
01317                                             e - y1, y2 - y1 );
01318           arc -= degree;
01319           e   += ras.precision;
01320         }
01321       }
01322       else
01323       {
01324         if ( y2 == e )
01325         {
01326           ras.joint  = TRUE;
01327           *top++     = arc[0].x;
01328 
01329           e += ras.precision;
01330         }
01331         arc -= degree;
01332       }
01333     }
01334 
01335   Fin:
01336     ras.top  = top;
01337     ras.arc -= degree;
01338     return SUCCESS;
01339   }
01340 
01341 
01342   /*************************************************************************/
01343   /*                                                                       */
01344   /* <Function>                                                            */
01345   /*    Bezier_Down                                                        */
01346   /*                                                                       */
01347   /* <Description>                                                         */
01348   /*    Compute the x-coordinates of an descending Bezier arc and store    */
01349   /*    them in the render pool.                                           */
01350   /*                                                                       */
01351   /* <Input>                                                               */
01352   /*    degree   :: The degree of the Bezier arc (either 2 or 3).          */
01353   /*                                                                       */
01354   /*    splitter :: The function to split Bezier arcs.                     */
01355   /*                                                                       */
01356   /*    miny     :: A lower vertical clipping bound value.                 */
01357   /*                                                                       */
01358   /*    maxy     :: An upper vertical clipping bound value.                */
01359   /*                                                                       */
01360   /* <Return>                                                              */
01361   /*    SUCCESS on success, FAILURE on render pool overflow.               */
01362   /*                                                                       */
01363   static Bool
01364   Bezier_Down( RAS_ARGS Int        degree,
01365                         TSplitter  splitter,
01366                         Long       miny,
01367                         Long       maxy )
01368   {
01369     TPoint*  arc = ras.arc;
01370     Bool     result, fresh;
01371 
01372 
01373     arc[0].y = -arc[0].y;
01374     arc[1].y = -arc[1].y;
01375     arc[2].y = -arc[2].y;
01376     if ( degree > 2 )
01377       arc[3].y = -arc[3].y;
01378 
01379     fresh = ras.fresh;
01380 
01381     result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny );
01382 
01383     if ( fresh && !ras.fresh )
01384       ras.cProfile->start = -ras.cProfile->start;
01385 
01386     arc[0].y = -arc[0].y;
01387     return result;
01388   }
01389 
01390 
01391   /*************************************************************************/
01392   /*                                                                       */
01393   /* <Function>                                                            */
01394   /*    Line_To                                                            */
01395   /*                                                                       */
01396   /* <Description>                                                         */
01397   /*    Inject a new line segment and adjust the Profiles list.            */
01398   /*                                                                       */
01399   /* <Input>                                                               */
01400   /*   x :: The x-coordinate of the segment's end point (its start point   */
01401   /*        is stored in `lastX').                                         */
01402   /*                                                                       */
01403   /*   y :: The y-coordinate of the segment's end point (its start point   */
01404   /*        is stored in `lastY').                                         */
01405   /*                                                                       */
01406   /* <Return>                                                              */
01407   /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
01408   /*   profile.                                                            */
01409   /*                                                                       */
01410   static Bool
01411   Line_To( RAS_ARGS Long  x,
01412                     Long  y )
01413   {
01414     /* First, detect a change of direction */
01415 
01416     switch ( ras.state )
01417     {
01418     case Unknown_State:
01419       if ( y > ras.lastY )
01420       {
01421         if ( New_Profile( RAS_VARS Ascending_State,
01422                                    IS_BOTTOM_OVERSHOOT( ras.lastY ) ) )
01423           return FAILURE;
01424       }
01425       else
01426       {
01427         if ( y < ras.lastY )
01428           if ( New_Profile( RAS_VARS Descending_State,
01429                                      IS_TOP_OVERSHOOT( ras.lastY ) ) )
01430             return FAILURE;
01431       }
01432       break;
01433 
01434     case Ascending_State:
01435       if ( y < ras.lastY )
01436       {
01437         if ( End_Profile( RAS_VARS IS_TOP_OVERSHOOT( ras.lastY ) ) ||
01438              New_Profile( RAS_VARS Descending_State,
01439                                    IS_TOP_OVERSHOOT( ras.lastY ) ) )
01440           return FAILURE;
01441       }
01442       break;
01443 
01444     case Descending_State:
01445       if ( y > ras.lastY )
01446       {
01447         if ( End_Profile( RAS_VARS IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ||
01448              New_Profile( RAS_VARS Ascending_State,
01449                                    IS_BOTTOM_OVERSHOOT( ras.lastY ) ) )
01450           return FAILURE;
01451       }
01452       break;
01453 
01454     default:
01455       ;
01456     }
01457 
01458     /* Then compute the lines */
01459 
01460     switch ( ras.state )
01461     {
01462     case Ascending_State:
01463       if ( Line_Up( RAS_VARS ras.lastX, ras.lastY,
01464                              x, y, ras.minY, ras.maxY ) )
01465         return FAILURE;
01466       break;
01467 
01468     case Descending_State:
01469       if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
01470                                x, y, ras.minY, ras.maxY ) )
01471         return FAILURE;
01472       break;
01473 
01474     default:
01475       ;
01476     }
01477 
01478     ras.lastX = x;
01479     ras.lastY = y;
01480 
01481     return SUCCESS;
01482   }
01483 
01484 
01485   /*************************************************************************/
01486   /*                                                                       */
01487   /* <Function>                                                            */
01488   /*    Conic_To                                                           */
01489   /*                                                                       */
01490   /* <Description>                                                         */
01491   /*    Inject a new conic arc and adjust the profile list.                */
01492   /*                                                                       */
01493   /* <Input>                                                               */
01494   /*   cx :: The x-coordinate of the arc's new control point.              */
01495   /*                                                                       */
01496   /*   cy :: The y-coordinate of the arc's new control point.              */
01497   /*                                                                       */
01498   /*   x  :: The x-coordinate of the arc's end point (its start point is   */
01499   /*         stored in `lastX').                                           */
01500   /*                                                                       */
01501   /*   y  :: The y-coordinate of the arc's end point (its start point is   */
01502   /*         stored in `lastY').                                           */
01503   /*                                                                       */
01504   /* <Return>                                                              */
01505   /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
01506   /*   profile.                                                            */
01507   /*                                                                       */
01508   static Bool
01509   Conic_To( RAS_ARGS Long  cx,
01510                      Long  cy,
01511                      Long  x,
01512                      Long  y )
01513   {
01514     Long     y1, y2, y3, x3, ymin, ymax;
01515     TStates  state_bez;
01516 
01517 
01518     ras.arc      = ras.arcs;
01519     ras.arc[2].x = ras.lastX;
01520     ras.arc[2].y = ras.lastY;
01521     ras.arc[1].x = cx;
01522     ras.arc[1].y = cy;
01523     ras.arc[0].x = x;
01524     ras.arc[0].y = y;
01525 
01526     do
01527     {
01528       y1 = ras.arc[2].y;
01529       y2 = ras.arc[1].y;
01530       y3 = ras.arc[0].y;
01531       x3 = ras.arc[0].x;
01532 
01533       /* first, categorize the Bezier arc */
01534 
01535       if ( y1 <= y3 )
01536       {
01537         ymin = y1;
01538         ymax = y3;
01539       }
01540       else
01541       {
01542         ymin = y3;
01543         ymax = y1;
01544       }
01545 
01546       if ( y2 < ymin || y2 > ymax )
01547       {
01548         /* this arc has no given direction, split it! */
01549         Split_Conic( ras.arc );
01550         ras.arc += 2;
01551       }
01552       else if ( y1 == y3 )
01553       {
01554         /* this arc is flat, ignore it and pop it from the Bezier stack */
01555         ras.arc -= 2;
01556       }
01557       else
01558       {
01559         /* the arc is y-monotonous, either ascending or descending */
01560         /* detect a change of direction                            */
01561         state_bez = y1 < y3 ? Ascending_State : Descending_State;
01562         if ( ras.state != state_bez )
01563         {
01564           Bool  o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 )
01565                                                  : IS_TOP_OVERSHOOT( y1 );
01566 
01567 
01568           /* finalize current profile if any */
01569           if ( ras.state != Unknown_State &&
01570                End_Profile( RAS_VARS o )  )
01571             goto Fail;
01572 
01573           /* create a new profile */
01574           if ( New_Profile( RAS_VARS state_bez, o ) )
01575             goto Fail;
01576         }
01577 
01578         /* now call the appropriate routine */
01579         if ( state_bez == Ascending_State )
01580         {
01581           if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
01582             goto Fail;
01583         }
01584         else
01585           if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
01586             goto Fail;
01587       }
01588 
01589     } while ( ras.arc >= ras.arcs );
01590 
01591     ras.lastX = x3;
01592     ras.lastY = y3;
01593 
01594     return SUCCESS;
01595 
01596   Fail:
01597     return FAILURE;
01598   }
01599 
01600 
01601   /*************************************************************************/
01602   /*                                                                       */
01603   /* <Function>                                                            */
01604   /*    Cubic_To                                                           */
01605   /*                                                                       */
01606   /* <Description>                                                         */
01607   /*    Inject a new cubic arc and adjust the profile list.                */
01608   /*                                                                       */
01609   /* <Input>                                                               */
01610   /*   cx1 :: The x-coordinate of the arc's first new control point.       */
01611   /*                                                                       */
01612   /*   cy1 :: The y-coordinate of the arc's first new control point.       */
01613   /*                                                                       */
01614   /*   cx2 :: The x-coordinate of the arc's second new control point.      */
01615   /*                                                                       */
01616   /*   cy2 :: The y-coordinate of the arc's second new control point.      */
01617   /*                                                                       */
01618   /*   x   :: The x-coordinate of the arc's end point (its start point is  */
01619   /*          stored in `lastX').                                          */
01620   /*                                                                       */
01621   /*   y   :: The y-coordinate of the arc's end point (its start point is  */
01622   /*          stored in `lastY').                                          */
01623   /*                                                                       */
01624   /* <Return>                                                              */
01625   /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
01626   /*   profile.                                                            */
01627   /*                                                                       */
01628   static Bool
01629   Cubic_To( RAS_ARGS Long  cx1,
01630                      Long  cy1,
01631                      Long  cx2,
01632                      Long  cy2,
01633                      Long  x,
01634                      Long  y )
01635   {
01636     Long     y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2;
01637     TStates  state_bez;
01638 
01639 
01640     ras.arc      = ras.arcs;
01641     ras.arc[3].x = ras.lastX;
01642     ras.arc[3].y = ras.lastY;
01643     ras.arc[2].x = cx1;
01644     ras.arc[2].y = cy1;
01645     ras.arc[1].x = cx2;
01646     ras.arc[1].y = cy2;
01647     ras.arc[0].x = x;
01648     ras.arc[0].y = y;
01649 
01650     do
01651     {
01652       y1 = ras.arc[3].y;
01653       y2 = ras.arc[2].y;
01654       y3 = ras.arc[1].y;
01655       y4 = ras.arc[0].y;
01656       x4 = ras.arc[0].x;
01657 
01658       /* first, categorize the Bezier arc */
01659 
01660       if ( y1 <= y4 )
01661       {
01662         ymin1 = y1;
01663         ymax1 = y4;
01664       }
01665       else
01666       {
01667         ymin1 = y4;
01668         ymax1 = y1;
01669       }
01670 
01671       if ( y2 <= y3 )
01672       {
01673         ymin2 = y2;
01674         ymax2 = y3;
01675       }
01676       else
01677       {
01678         ymin2 = y3;
01679         ymax2 = y2;
01680       }
01681 
01682       if ( ymin2 < ymin1 || ymax2 > ymax1 )
01683       {
01684         /* this arc has no given direction, split it! */
01685         Split_Cubic( ras.arc );
01686         ras.arc += 3;
01687       }
01688       else if ( y1 == y4 )
01689       {
01690         /* this arc is flat, ignore it and pop it from the Bezier stack */
01691         ras.arc -= 3;
01692       }
01693       else
01694       {
01695         state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State;
01696 
01697         /* detect a change of direction */
01698         if ( ras.state != state_bez )
01699         {
01700           Bool  o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 )
01701                                                  : IS_TOP_OVERSHOOT( y1 );
01702 
01703 
01704           /* finalize current profile if any */
01705           if ( ras.state != Unknown_State &&
01706                End_Profile( RAS_VARS o )  )
01707             goto Fail;
01708 
01709           if ( New_Profile( RAS_VARS state_bez, o ) )
01710             goto Fail;
01711         }
01712 
01713         /* compute intersections */
01714         if ( state_bez == Ascending_State )
01715         {
01716           if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
01717             goto Fail;
01718         }
01719         else
01720           if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
01721             goto Fail;
01722       }
01723 
01724     } while ( ras.arc >= ras.arcs );
01725 
01726     ras.lastX = x4;
01727     ras.lastY = y4;
01728 
01729     return SUCCESS;
01730 
01731   Fail:
01732     return FAILURE;
01733   }
01734 
01735 
01736 #undef  SWAP_
01737 #define SWAP_( x, y )  do                \
01738                        {                 \
01739                          Long  swap = x; \
01740                                          \
01741                                          \
01742                          x = y;          \
01743                          y = swap;       \
01744                        } while ( 0 )
01745 
01746 
01747   /*************************************************************************/
01748   /*                                                                       */
01749   /* <Function>                                                            */
01750   /*    Decompose_Curve                                                    */
01751   /*                                                                       */
01752   /* <Description>                                                         */
01753   /*    Scan the outline arrays in order to emit individual segments and   */
01754   /*    Beziers by calling Line_To() and Bezier_To().  It handles all      */
01755   /*    weird cases, like when the first point is off the curve, or when   */
01756   /*    there are simply no `on' points in the contour!                    */
01757   /*                                                                       */
01758   /* <Input>                                                               */
01759   /*    first   :: The index of the first point in the contour.            */
01760   /*                                                                       */
01761   /*    last    :: The index of the last point in the contour.             */
01762   /*                                                                       */
01763   /*    flipped :: If set, flip the direction of the curve.                */
01764   /*                                                                       */
01765   /* <Return>                                                              */
01766   /*    SUCCESS on success, FAILURE on error.                              */
01767   /*                                                                       */
01768   static Bool
01769   Decompose_Curve( RAS_ARGS UShort  first,
01770                             UShort  last,
01771                             int     flipped )
01772   {
01773     FT_Vector   v_last;
01774     FT_Vector   v_control;
01775     FT_Vector   v_start;
01776 
01777     FT_Vector*  points;
01778     FT_Vector*  point;
01779     FT_Vector*  limit;
01780     char*       tags;
01781 
01782     unsigned    tag;       /* current point's state           */
01783 
01784 
01785     points = ras.outline.points;
01786     limit  = points + last;
01787 
01788     v_start.x = SCALED( points[first].x );
01789     v_start.y = SCALED( points[first].y );
01790     v_last.x  = SCALED( points[last].x );
01791     v_last.y  = SCALED( points[last].y );
01792 
01793     if ( flipped )
01794     {
01795       SWAP_( v_start.x, v_start.y );
01796       SWAP_( v_last.x, v_last.y );
01797     }
01798 
01799     v_control = v_start;
01800 
01801     point = points + first;
01802     tags  = ras.outline.tags + first;
01803 
01804     /* set scan mode if necessary */
01805     if ( tags[0] & FT_CURVE_TAG_HAS_SCANMODE )
01806       ras.dropOutControl = (Byte)tags[0] >> 5;
01807 
01808     tag = FT_CURVE_TAG( tags[0] );
01809 
01810     /* A contour cannot start with a cubic control point! */
01811     if ( tag == FT_CURVE_TAG_CUBIC )
01812       goto Invalid_Outline;
01813 
01814     /* check first point to determine origin */
01815     if ( tag == FT_CURVE_TAG_CONIC )
01816     {
01817       /* first point is conic control.  Yes, this happens. */
01818       if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON )
01819       {
01820         /* start at last point if it is on the curve */
01821         v_start = v_last;
01822         limit--;
01823       }
01824       else
01825       {
01826         /* if both first and last points are conic,         */
01827         /* start at their middle and record its position    */
01828         /* for closure                                      */
01829         v_start.x = ( v_start.x + v_last.x ) / 2;
01830         v_start.y = ( v_start.y + v_last.y ) / 2;
01831 
01832         v_last = v_start;
01833       }
01834       point--;
01835       tags--;
01836     }
01837 
01838     ras.lastX = v_start.x;
01839     ras.lastY = v_start.y;
01840 
01841     while ( point < limit )
01842     {
01843       point++;
01844       tags++;
01845 
01846       tag = FT_CURVE_TAG( tags[0] );
01847 
01848       switch ( tag )
01849       {
01850       case FT_CURVE_TAG_ON:  /* emit a single line_to */
01851         {
01852           Long  x, y;
01853 
01854 
01855           x = SCALED( point->x );
01856           y = SCALED( point->y );
01857           if ( flipped )
01858             SWAP_( x, y );
01859 
01860           if ( Line_To( RAS_VARS x, y ) )
01861             goto Fail;
01862           continue;
01863         }
01864 
01865       case FT_CURVE_TAG_CONIC:  /* consume conic arcs */
01866         v_control.x = SCALED( point[0].x );
01867         v_control.y = SCALED( point[0].y );
01868 
01869         if ( flipped )
01870           SWAP_( v_control.x, v_control.y );
01871 
01872       Do_Conic:
01873         if ( point < limit )
01874         {
01875           FT_Vector  v_middle;
01876           Long       x, y;
01877 
01878 
01879           point++;
01880           tags++;
01881           tag = FT_CURVE_TAG( tags[0] );
01882 
01883           x = SCALED( point[0].x );
01884           y = SCALED( point[0].y );
01885 
01886           if ( flipped )
01887             SWAP_( x, y );
01888 
01889           if ( tag == FT_CURVE_TAG_ON )
01890           {
01891             if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) )
01892               goto Fail;
01893             continue;
01894           }
01895 
01896           if ( tag != FT_CURVE_TAG_CONIC )
01897             goto Invalid_Outline;
01898 
01899           v_middle.x = ( v_control.x + x ) / 2;
01900           v_middle.y = ( v_control.y + y ) / 2;
01901 
01902           if ( Conic_To( RAS_VARS v_control.x, v_control.y,
01903                                   v_middle.x,  v_middle.y ) )
01904             goto Fail;
01905 
01906           v_control.x = x;
01907           v_control.y = y;
01908 
01909           goto Do_Conic;
01910         }
01911 
01912         if ( Conic_To( RAS_VARS v_control.x, v_control.y,
01913                                 v_start.x,   v_start.y ) )
01914           goto Fail;
01915 
01916         goto Close;
01917 
01918       default:  /* FT_CURVE_TAG_CUBIC */
01919         {
01920           Long  x1, y1, x2, y2, x3, y3;
01921 
01922 
01923           if ( point + 1 > limit                             ||
01924                FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
01925             goto Invalid_Outline;
01926 
01927           point += 2;
01928           tags  += 2;
01929 
01930           x1 = SCALED( point[-2].x );
01931           y1 = SCALED( point[-2].y );
01932           x2 = SCALED( point[-1].x );
01933           y2 = SCALED( point[-1].y );
01934           x3 = SCALED( point[ 0].x );
01935           y3 = SCALED( point[ 0].y );
01936 
01937           if ( flipped )
01938           {
01939             SWAP_( x1, y1 );
01940             SWAP_( x2, y2 );
01941             SWAP_( x3, y3 );
01942           }
01943 
01944           if ( point <= limit )
01945           {
01946             if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) )
01947               goto Fail;
01948             continue;
01949           }
01950 
01951           if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) )
01952             goto Fail;
01953           goto Close;
01954         }
01955       }
01956     }
01957 
01958     /* close the contour with a line segment */
01959     if ( Line_To( RAS_VARS v_start.x, v_start.y ) )
01960       goto Fail;
01961 
01962   Close:
01963     return SUCCESS;
01964 
01965   Invalid_Outline:
01966     ras.error = Raster_Err_Invalid;
01967 
01968   Fail:
01969     return FAILURE;
01970   }
01971 
01972 
01973   /*************************************************************************/
01974   /*                                                                       */
01975   /* <Function>                                                            */
01976   /*    Convert_Glyph                                                      */
01977   /*                                                                       */
01978   /* <Description>                                                         */
01979   /*    Convert a glyph into a series of segments and arcs and make a      */
01980   /*    profiles list with them.                                           */
01981   /*                                                                       */
01982   /* <Input>                                                               */
01983   /*    flipped :: If set, flip the direction of curve.                    */
01984   /*                                                                       */
01985   /* <Return>                                                              */
01986   /*    SUCCESS on success, FAILURE if any error was encountered during    */
01987   /*    rendering.                                                         */
01988   /*                                                                       */
01989   static Bool
01990   Convert_Glyph( RAS_ARGS int  flipped )
01991   {
01992     int       i;
01993     unsigned  start;
01994 
01995     PProfile  lastProfile;
01996 
01997 
01998     ras.fProfile = NULL;
01999     ras.joint    = FALSE;
02000     ras.fresh    = FALSE;
02001 
02002     ras.maxBuff  = ras.sizeBuff - AlignProfileSize;
02003 
02004     ras.numTurns = 0;
02005 
02006     ras.cProfile         = (PProfile)ras.top;
02007     ras.cProfile->offset = ras.top;
02008     ras.num_Profs        = 0;
02009 
02010     start = 0;
02011 
02012     for ( i = 0; i < ras.outline.n_contours; i++ )
02013     {
02014       Bool  o;
02015 
02016 
02017       ras.state    = Unknown_State;
02018       ras.gProfile = NULL;
02019 
02020       if ( Decompose_Curve( RAS_VARS (unsigned short)start,
02021                                      ras.outline.contours[i],
02022                                      flipped ) )
02023         return FAILURE;
02024 
02025       start = ras.outline.contours[i] + 1;
02026 
02027       /* we must now check whether the extreme arcs join or not */
02028       if ( FRAC( ras.lastY ) == 0 &&
02029            ras.lastY >= ras.minY  &&
02030            ras.lastY <= ras.maxY  )
02031         if ( ras.gProfile                        &&
02032              ( ras.gProfile->flags & Flow_Up ) ==
02033                ( ras.cProfile->flags & Flow_Up ) )
02034           ras.top--;
02035         /* Note that ras.gProfile can be nil if the contour was too small */
02036         /* to be drawn.                                                   */
02037 
02038       lastProfile = ras.cProfile;
02039       if ( ras.cProfile->flags & Flow_Up )
02040         o = IS_TOP_OVERSHOOT( ras.lastY );
02041       else
02042         o = IS_BOTTOM_OVERSHOOT( ras.lastY );
02043       if ( End_Profile( RAS_VARS o ) )
02044         return FAILURE;
02045 
02046       /* close the `next profile in contour' linked list */
02047       if ( ras.gProfile )
02048         lastProfile->next = ras.gProfile;
02049     }
02050 
02051     if ( Finalize_Profile_Table( RAS_VAR ) )
02052       return FAILURE;
02053 
02054     return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE );
02055   }
02056 
02057 
02058   /*************************************************************************/
02059   /*************************************************************************/
02060   /**                                                                     **/
02061   /**  SCAN-LINE SWEEPS AND DRAWING                                       **/
02062   /**                                                                     **/
02063   /*************************************************************************/
02064   /*************************************************************************/
02065 
02066 
02067   /*************************************************************************/
02068   /*                                                                       */
02069   /*  Init_Linked                                                          */
02070   /*                                                                       */
02071   /*    Initializes an empty linked list.                                  */
02072   /*                                                                       */
02073   static void
02074   Init_Linked( TProfileList*  l )
02075   {
02076     *l = NULL;
02077   }
02078 
02079 
02080   /*************************************************************************/
02081   /*                                                                       */
02082   /*  InsNew                                                               */
02083   /*                                                                       */
02084   /*    Inserts a new profile in a linked list.                            */
02085   /*                                                                       */
02086   static void
02087   InsNew( PProfileList  list,
02088           PProfile      profile )
02089   {
02090     PProfile  *old, current;
02091     Long       x;
02092 
02093 
02094     old     = list;
02095     current = *old;
02096     x       = profile->X;
02097 
02098     while ( current )
02099     {
02100       if ( x < current->X )
02101         break;
02102       old     = &current->link;
02103       current = *old;
02104     }
02105 
02106     profile->link = current;
02107     *old          = profile;
02108   }
02109 
02110 
02111   /*************************************************************************/
02112   /*                                                                       */
02113   /*  DelOld                                                               */
02114   /*                                                                       */
02115   /*    Removes an old profile from a linked list.                         */
02116   /*                                                                       */
02117   static void
02118   DelOld( PProfileList  list,
02119           PProfile      profile )
02120   {
02121     PProfile  *old, current;
02122 
02123 
02124     old     = list;
02125     current = *old;
02126 
02127     while ( current )
02128     {
02129       if ( current == profile )
02130       {
02131         *old = current->link;
02132         return;
02133       }
02134 
02135       old     = &current->link;
02136       current = *old;
02137     }
02138 
02139     /* we should never get there, unless the profile was not part of */
02140     /* the list.                                                     */
02141   }
02142 
02143 
02144   /*************************************************************************/
02145   /*                                                                       */
02146   /*  Sort                                                                 */
02147   /*                                                                       */
02148   /*    Sorts a trace list.  In 95%, the list is already sorted.  We need  */
02149   /*    an algorithm which is fast in this case.  Bubble sort is enough    */
02150   /*    and simple.                                                        */
02151   /*                                                                       */
02152   static void
02153   Sort( PProfileList  list )
02154   {
02155     PProfile  *old, current, next;
02156 
02157 
02158     /* First, set the new X coordinate of each profile */
02159     current = *list;
02160     while ( current )
02161     {
02162       current->X       = *current->offset;
02163       current->offset += current->flags & Flow_Up ? 1 : -1;
02164       current->height--;
02165       current = current->link;
02166     }
02167 
02168     /* Then sort them */
02169     old     = list;
02170     current = *old;
02171 
02172     if ( !current )
02173       return;
02174 
02175     next = current->link;
02176 
02177     while ( next )
02178     {
02179       if ( current->X <= next->X )
02180       {
02181         old     = &current->link;
02182         current = *old;
02183 
02184         if ( !current )
02185           return;
02186       }
02187       else
02188       {
02189         *old          = next;
02190         current->link = next->link;
02191         next->link    = current;
02192 
02193         old     = list;
02194         current = *old;
02195       }
02196 
02197       next = current->link;
02198     }
02199   }
02200 
02201 
02202   /*************************************************************************/
02203   /*                                                                       */
02204   /*  Vertical Sweep Procedure Set                                         */
02205   /*                                                                       */
02206   /*  These four routines are used during the vertical black/white sweep   */
02207   /*  phase by the generic Draw_Sweep() function.                          */
02208   /*                                                                       */
02209   /*************************************************************************/
02210 
02211   static void
02212   Vertical_Sweep_Init( RAS_ARGS Short*  min,
02213                                 Short*  max )
02214   {
02215     Long  pitch = ras.target.pitch;
02216 
02217     FT_UNUSED( max );
02218 
02219 
02220     ras.traceIncr = (Short)-pitch;
02221     ras.traceOfs  = -*min * pitch;
02222     if ( pitch > 0 )
02223       ras.traceOfs += ( ras.target.rows - 1 ) * pitch;
02224 
02225     ras.gray_min_x = 0;
02226     ras.gray_max_x = 0;
02227   }
02228 
02229 
02230   static void
02231   Vertical_Sweep_Span( RAS_ARGS Short       y,
02232                                 FT_F26Dot6  x1,
02233                                 FT_F26Dot6  x2,
02234                                 PProfile    left,
02235                                 PProfile    right )
02236   {
02237     Long   e1, e2;
02238     int    c1, c2;
02239     Byte   f1, f2;
02240     Byte*  target;
02241 
02242     FT_UNUSED( y );
02243     FT_UNUSED( left );
02244     FT_UNUSED( right );
02245 
02246 
02247     /* Drop-out control */
02248 
02249     e1 = TRUNC( CEILING( x1 ) );
02250 
02251     if ( x2 - x1 - ras.precision <= ras.precision_jitter )
02252       e2 = e1;
02253     else
02254       e2 = TRUNC( FLOOR( x2 ) );
02255 
02256     if ( e2 >= 0 && e1 < ras.bWidth )
02257     {
02258       if ( e1 < 0 )
02259         e1 = 0;
02260       if ( e2 >= ras.bWidth )
02261         e2 = ras.bWidth - 1;
02262 
02263       c1 = (Short)( e1 >> 3 );
02264       c2 = (Short)( e2 >> 3 );
02265 
02266       f1 = (Byte)  ( 0xFF >> ( e1 & 7 ) );
02267       f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) );
02268 
02269       if ( ras.gray_min_x > c1 )
02270         ras.gray_min_x = (short)c1;
02271       if ( ras.gray_max_x < c2 )
02272         ras.gray_max_x = (short)c2;
02273 
02274       target = ras.bTarget + ras.traceOfs + c1;
02275       c2 -= c1;
02276 
02277       if ( c2 > 0 )
02278       {
02279         target[0] |= f1;
02280 
02281         /* memset() is slower than the following code on many platforms. */
02282         /* This is due to the fact that, in the vast majority of cases,  */
02283         /* the span length in bytes is relatively small.                 */
02284         c2--;
02285         while ( c2 > 0 )
02286         {
02287           *(++target) = 0xFF;
02288           c2--;
02289         }
02290         target[1] |= f2;
02291       }
02292       else
02293         *target |= ( f1 & f2 );
02294     }
02295   }
02296 
02297 
02298   static void
02299   Vertical_Sweep_Drop( RAS_ARGS Short       y,
02300                                 FT_F26Dot6  x1,
02301                                 FT_F26Dot6  x2,
02302                                 PProfile    left,
02303                                 PProfile    right )
02304   {
02305     Long   e1, e2, pxl;
02306     Short  c1, f1;
02307 
02308 
02309     /* Drop-out control */
02310 
02311     /*   e2            x2                    x1           e1   */
02312     /*                                                         */
02313     /*                 ^                     |                 */
02314     /*                 |                     |                 */
02315     /*   +-------------+---------------------+------------+    */
02316     /*                 |                     |                 */
02317     /*                 |                     v                 */
02318     /*                                                         */
02319     /* pixel         contour              contour       pixel  */
02320     /* center                                           center */
02321 
02322     /* drop-out mode    scan conversion rules (as defined in OpenType) */
02323     /* --------------------------------------------------------------- */
02324     /*  0                1, 2, 3                                       */
02325     /*  1                1, 2, 4                                       */
02326     /*  2                1, 2                                          */
02327     /*  3                same as mode 2                                */
02328     /*  4                1, 2, 5                                       */
02329     /*  5                1, 2, 6                                       */
02330     /*  6, 7             same as mode 2                                */
02331 
02332     e1  = CEILING( x1 );
02333     e2  = FLOOR  ( x2 );
02334     pxl = e1;
02335 
02336     if ( e1 > e2 )
02337     {
02338       Int  dropOutControl = left->flags & 7;
02339 
02340 
02341       if ( e1 == e2 + ras.precision )
02342       {
02343         switch ( dropOutControl )
02344         {
02345         case 0: /* simple drop-outs including stubs */
02346           pxl = e2;
02347           break;
02348 
02349         case 4: /* smart drop-outs including stubs */
02350           pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
02351           break;
02352 
02353         case 1: /* simple drop-outs excluding stubs */
02354         case 5: /* smart drop-outs excluding stubs  */
02355 
02356           /* Drop-out Control Rules #4 and #6 */
02357 
02358           /* The specification neither provides an exact definition */
02359           /* of a `stub' nor gives exact rules to exclude them.     */
02360           /*                                                        */
02361           /* Here the constraints we use to recognize a stub.       */
02362           /*                                                        */
02363           /*  upper stub:                                           */
02364           /*                                                        */
02365           /*   - P_Left and P_Right are in the same contour         */
02366           /*   - P_Right is the successor of P_Left in that contour */
02367           /*   - y is the top of P_Left and P_Right                 */
02368           /*                                                        */
02369           /*  lower stub:                                           */
02370           /*                                                        */
02371           /*   - P_Left and P_Right are in the same contour         */
02372           /*   - P_Left is the successor of P_Right in that contour */
02373           /*   - y is the bottom of P_Left                          */
02374           /*                                                        */
02375           /* We draw a stub if the following constraints are met.   */
02376           /*                                                        */
02377           /*   - for an upper or lower stub, there is top or bottom */
02378           /*     overshoot, respectively                            */
02379           /*   - the covered interval is greater or equal to a half */
02380           /*     pixel                                              */
02381 
02382           /* upper stub test */
02383           if ( left->next == right                &&
02384                left->height <= 0                  &&
02385                !( left->flags & Overshoot_Top   &&
02386                   x2 - x1 >= ras.precision_half ) )
02387             return;
02388 
02389           /* lower stub test */
02390           if ( right->next == left                 &&
02391                left->start == y                    &&
02392                !( left->flags & Overshoot_Bottom &&
02393                   x2 - x1 >= ras.precision_half  ) )
02394             return;
02395 
02396           if ( dropOutControl == 1 )
02397             pxl = e2;
02398           else
02399             pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
02400           break;
02401 
02402         default: /* modes 2, 3, 6, 7 */
02403           return;  /* no drop-out control */
02404         }
02405 
02406         /* check that the other pixel isn't set */
02407         e1 = pxl == e1 ? e2 : e1;
02408 
02409         e1 = TRUNC( e1 );
02410 
02411         c1 = (Short)( e1 >> 3 );
02412         f1 = (Short)( e1 &  7 );
02413 
02414         if ( e1 >= 0 && e1 < ras.bWidth                      &&
02415              ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) )
02416           return;
02417       }
02418       else
02419         return;
02420     }
02421 
02422     e1 = TRUNC( pxl );
02423 
02424     if ( e1 >= 0 && e1 < ras.bWidth )
02425     {
02426       c1 = (Short)( e1 >> 3 );
02427       f1 = (Short)( e1 & 7 );
02428 
02429       if ( ras.gray_min_x > c1 )
02430         ras.gray_min_x = c1;
02431       if ( ras.gray_max_x < c1 )
02432         ras.gray_max_x = c1;
02433 
02434       ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 );
02435     }
02436   }
02437 
02438 
02439   static void
02440   Vertical_Sweep_Step( RAS_ARG )
02441   {
02442     ras.traceOfs += ras.traceIncr;
02443   }
02444 
02445 
02446   /***********************************************************************/
02447   /*                                                                     */
02448   /*  Horizontal Sweep Procedure Set                                     */
02449   /*                                                                     */
02450   /*  These four routines are used during the horizontal black/white     */
02451   /*  sweep phase by the generic Draw_Sweep() function.                  */
02452   /*                                                                     */
02453   /***********************************************************************/
02454 
02455   static void
02456   Horizontal_Sweep_Init( RAS_ARGS Short*  min,
02457                                   Short*  max )
02458   {
02459     /* nothing, really */
02460     FT_UNUSED_RASTER;
02461     FT_UNUSED( min );
02462     FT_UNUSED( max );
02463   }
02464 
02465 
02466   static void
02467   Horizontal_Sweep_Span( RAS_ARGS Short       y,
02468                                   FT_F26Dot6  x1,
02469                                   FT_F26Dot6  x2,
02470                                   PProfile    left,
02471                                   PProfile    right )
02472   {
02473     Long   e1, e2;
02474     PByte  bits;
02475     Byte   f1;
02476 
02477     FT_UNUSED( left );
02478     FT_UNUSED( right );
02479 
02480 
02481     if ( x2 - x1 < ras.precision )
02482     {
02483       e1 = CEILING( x1 );
02484       e2 = FLOOR  ( x2 );
02485 
02486       if ( e1 == e2 )
02487       {
02488         bits = ras.bTarget + ( y >> 3 );
02489         f1   = (Byte)( 0x80 >> ( y & 7 ) );
02490 
02491         e1 = TRUNC( e1 );
02492 
02493         if ( e1 >= 0 && e1 < ras.target.rows )
02494         {
02495           PByte  p;
02496 
02497 
02498           p = bits - e1*ras.target.pitch;
02499           if ( ras.target.pitch > 0 )
02500             p += ( ras.target.rows - 1 ) * ras.target.pitch;
02501 
02502           p[0] |= f1;
02503         }
02504       }
02505     }
02506   }
02507 
02508 
02509   static void
02510   Horizontal_Sweep_Drop( RAS_ARGS Short       y,
02511                                   FT_F26Dot6  x1,
02512                                   FT_F26Dot6  x2,
02513                                   PProfile    left,
02514                                   PProfile    right )
02515   {
02516     Long   e1, e2, pxl;
02517     PByte  bits;
02518     Byte   f1;
02519 
02520 
02521     /* During the horizontal sweep, we only take care of drop-outs */
02522 
02523     /* e1     +       <-- pixel center */
02524     /*        |                        */
02525     /* x1  ---+-->    <-- contour      */
02526     /*        |                        */
02527     /*        |                        */
02528     /* x2  <--+---    <-- contour      */
02529     /*        |                        */
02530     /*        |                        */
02531     /* e2     +       <-- pixel center */
02532 
02533     e1  = CEILING( x1 );
02534     e2  = FLOOR  ( x2 );
02535     pxl = e1;
02536 
02537     if ( e1 > e2 )
02538     {
02539       Int  dropOutControl = left->flags & 7;
02540 
02541 
02542       if ( e1 == e2 + ras.precision )
02543       {
02544         switch ( dropOutControl )
02545         {
02546         case 0: /* simple drop-outs including stubs */
02547           pxl = e2;
02548           break;
02549 
02550         case 4: /* smart drop-outs including stubs */
02551           pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
02552           break;
02553 
02554         case 1: /* simple drop-outs excluding stubs */
02555         case 5: /* smart drop-outs excluding stubs  */
02556           /* see Vertical_Sweep_Drop for details */
02557 
02558           /* rightmost stub test */
02559           if ( left->next == right                &&
02560                left->height <= 0                  &&
02561                !( left->flags & Overshoot_Top   &&
02562                   x2 - x1 >= ras.precision_half ) )
02563             return;
02564 
02565           /* leftmost stub test */
02566           if ( right->next == left                 &&
02567                left->start == y                    &&
02568                !( left->flags & Overshoot_Bottom &&
02569                   x2 - x1 >= ras.precision_half  ) )
02570             return;
02571 
02572           if ( dropOutControl == 1 )
02573             pxl = e2;
02574           else
02575             pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
02576           break;
02577 
02578         default: /* modes 2, 3, 6, 7 */
02579           return;  /* no drop-out control */
02580         }
02581 
02582         /* check that the other pixel isn't set */
02583         e1 = pxl == e1 ? e2 : e1;
02584 
02585         e1 = TRUNC( e1 );
02586 
02587         bits = ras.bTarget + ( y >> 3 );
02588         f1   = (Byte)( 0x80 >> ( y & 7 ) );
02589 
02590         bits -= e1 * ras.target.pitch;
02591         if ( ras.target.pitch > 0 )
02592           bits += ( ras.target.rows - 1 ) * ras.target.pitch;
02593 
02594         if ( e1 >= 0              &&
02595              e1 < ras.target.rows &&
02596              *bits & f1           )
02597           return;
02598       }
02599       else
02600         return;
02601     }
02602 
02603     bits = ras.bTarget + ( y >> 3 );
02604     f1   = (Byte)( 0x80 >> ( y & 7 ) );
02605 
02606     e1 = TRUNC( pxl );
02607 
02608     if ( e1 >= 0 && e1 < ras.target.rows )
02609     {
02610       bits -= e1 * ras.target.pitch;
02611       if ( ras.target.pitch > 0 )
02612         bits += ( ras.target.rows - 1 ) * ras.target.pitch;
02613 
02614       bits[0] |= f1;
02615     }
02616   }
02617 
02618 
02619   static void
02620   Horizontal_Sweep_Step( RAS_ARG )
02621   {
02622     /* Nothing, really */
02623     FT_UNUSED_RASTER;
02624   }
02625 
02626 
02627 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
02628 
02629 
02630   /*************************************************************************/
02631   /*                                                                       */
02632   /*  Vertical Gray Sweep Procedure Set                                    */
02633   /*                                                                       */
02634   /*  These two routines are used during the vertical gray-levels sweep    */
02635   /*  phase by the generic Draw_Sweep() function.                          */
02636   /*                                                                       */
02637   /*  NOTES                                                                */
02638   /*                                                                       */
02639   /*  - The target pixmap's width *must* be a multiple of 4.               */
02640   /*                                                                       */
02641   /*  - You have to use the function Vertical_Sweep_Span() for the gray    */
02642   /*    span call.                                                         */
02643   /*                                                                       */
02644   /*************************************************************************/
02645 
02646   static void
02647   Vertical_Gray_Sweep_Init( RAS_ARGS Short*  min,
02648                                      Short*  max )
02649   {
02650     Long  pitch, byte_len;
02651 
02652 
02653     *min = *min & -2;
02654     *max = ( *max + 3 ) & -2;
02655 
02656     ras.traceOfs  = 0;
02657     pitch         = ras.target.pitch;
02658     byte_len      = -pitch;
02659     ras.traceIncr = (Short)byte_len;
02660     ras.traceG    = ( *min / 2 ) * byte_len;
02661 
02662     if ( pitch > 0 )
02663     {
02664       ras.traceG += ( ras.target.rows - 1 ) * pitch;
02665       byte_len    = -byte_len;
02666     }
02667 
02668     ras.gray_min_x =  (Short)byte_len;
02669     ras.gray_max_x = -(Short)byte_len;
02670   }
02671 
02672 
02673   static void
02674   Vertical_Gray_Sweep_Step( RAS_ARG )
02675   {
02676     Int     c1, c2;
02677     PByte   pix, bit, bit2;
02678     short*  count = (short*)count_table;
02679     Byte*   grays;
02680 
02681 
02682     ras.traceOfs += ras.gray_width;
02683 
02684     if ( ras.traceOfs > ras.gray_width )
02685     {
02686       pix   = ras.gTarget + ras.traceG + ras.gray_min_x * 4;
02687       grays = ras.grays;
02688 
02689       if ( ras.gray_max_x >= 0 )
02690       {
02691         Long  last_pixel = ras.target.width - 1;
02692         Int   last_cell  = last_pixel >> 2;
02693         Int   last_bit   = last_pixel & 3;
02694         Bool  over       = 0;
02695 
02696 
02697         if ( ras.gray_max_x >= last_cell && last_bit != 3 )
02698         {
02699           ras.gray_max_x = last_cell - 1;
02700           over = 1;
02701         }
02702 
02703         if ( ras.gray_min_x < 0 )
02704           ras.gray_min_x = 0;
02705 
02706         bit  = ras.bTarget + ras.gray_min_x;
02707         bit2 = bit + ras.gray_width;
02708 
02709         c1 = ras.gray_max_x - ras.gray_min_x;
02710 
02711         while ( c1 >= 0 )
02712         {
02713           c2 = count[*bit] + count[*bit2];
02714 
02715           if ( c2 )
02716           {
02717             pix[0] = grays[(c2 >> 12) & 0x000F];
02718             pix[1] = grays[(c2 >> 8 ) & 0x000F];
02719             pix[2] = grays[(c2 >> 4 ) & 0x000F];
02720             pix[3] = grays[ c2        & 0x000F];
02721 
02722             *bit  = 0;
02723             *bit2 = 0;
02724           }
02725 
02726           bit++;
02727           bit2++;
02728           pix += 4;
02729           c1--;
02730         }
02731 
02732         if ( over )
02733         {
02734           c2 = count[*bit] + count[*bit2];
02735           if ( c2 )
02736           {
02737             switch ( last_bit )
02738             {
02739             case 2:
02740               pix[2] = grays[(c2 >> 4 ) & 0x000F];
02741             case 1:
02742               pix[1] = grays[(c2 >> 8 ) & 0x000F];
02743             default:
02744               pix[0] = grays[(c2 >> 12) & 0x000F];
02745             }
02746 
02747             *bit  = 0;
02748             *bit2 = 0;
02749           }
02750         }
02751       }
02752 
02753       ras.traceOfs = 0;
02754       ras.traceG  += ras.traceIncr;
02755 
02756       ras.gray_min_x =  32000;
02757       ras.gray_max_x = -32000;
02758     }
02759   }
02760 
02761 
02762   static void
02763   Horizontal_Gray_Sweep_Span( RAS_ARGS Short       y,
02764                                        FT_F26Dot6  x1,
02765                                        FT_F26Dot6  x2,
02766                                        PProfile    left,
02767                                        PProfile    right )
02768   {
02769     /* nothing, really */
02770     FT_UNUSED_RASTER;
02771     FT_UNUSED( y );
02772     FT_UNUSED( x1 );
02773     FT_UNUSED( x2 );
02774     FT_UNUSED( left );
02775     FT_UNUSED( right );
02776   }
02777 
02778 
02779   static void
02780   Horizontal_Gray_Sweep_Drop( RAS_ARGS Short       y,
02781                                        FT_F26Dot6  x1,
02782                                        FT_F26Dot6  x2,
02783                                        PProfile    left,
02784                                        PProfile    right )
02785   {
02786     Long   e1, e2;
02787     PByte  pixel;
02788     Byte   color;
02789 
02790 
02791     /* During the horizontal sweep, we only take care of drop-outs */
02792 
02793     e1 = CEILING( x1 );
02794     e2 = FLOOR  ( x2 );
02795 
02796     if ( e1 > e2 )
02797     {
02798       Int  dropOutControl = left->flags & 7;
02799 
02800 
02801       if ( e1 == e2 + ras.precision )
02802       {
02803         switch ( dropOutControl )
02804         {
02805         case 0: /* simple drop-outs including stubs */
02806           e1 = e2;
02807           break;
02808 
02809         case 4: /* smart drop-outs including stubs */
02810           e1 = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
02811           break;
02812 
02813         case 1: /* simple drop-outs excluding stubs */
02814         case 5: /* smart drop-outs excluding stubs  */
02815           /* see Vertical_Sweep_Drop for details */
02816 
02817           /* rightmost stub test */
02818           if ( left->next == right && left->height <= 0 )
02819             return;
02820 
02821           /* leftmost stub test */
02822           if ( right->next == left && left->start == y )
02823             return;
02824 
02825           if ( dropOutControl == 1 )
02826             e1 = e2;
02827           else
02828             e1 = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
02829 
02830           break;
02831 
02832         default: /* modes 2, 3, 6, 7 */
02833           return;  /* no drop-out control */
02834         }
02835       }
02836       else
02837         return;
02838     }
02839 
02840     if ( e1 >= 0 )
02841     {
02842       if ( x2 - x1 >= ras.precision_half )
02843         color = ras.grays[2];
02844       else
02845         color = ras.grays[1];
02846 
02847       e1 = TRUNC( e1 ) / 2;
02848       if ( e1 < ras.target.rows )
02849       {
02850         pixel = ras.gTarget - e1 * ras.target.pitch + y / 2;
02851         if ( ras.target.pitch > 0 )
02852           pixel += ( ras.target.rows - 1 ) * ras.target.pitch;
02853 
02854         if ( pixel[0] == ras.grays[0] )
02855           pixel[0] = color;
02856       }
02857     }
02858   }
02859 
02860 
02861 #endif /* FT_RASTER_OPTION_ANTI_ALIASING */
02862 
02863 
02864   /*************************************************************************/
02865   /*                                                                       */
02866   /*  Generic Sweep Drawing routine                                        */
02867   /*                                                                       */
02868   /*************************************************************************/
02869 
02870   static Bool
02871   Draw_Sweep( RAS_ARG )
02872   {
02873     Short         y, y_change, y_height;
02874 
02875     PProfile      P, Q, P_Left, P_Right;
02876 
02877     Short         min_Y, max_Y, top, bottom, dropouts;
02878 
02879     Long          x1, x2, xs, e1, e2;
02880 
02881     TProfileList  waiting;
02882     TProfileList  draw_left, draw_right;
02883 
02884 
02885     /* initialize empty linked lists */
02886 
02887     Init_Linked( &waiting );
02888 
02889     Init_Linked( &draw_left  );
02890     Init_Linked( &draw_right );
02891 
02892     /* first, compute min and max Y */
02893 
02894     P     = ras.fProfile;
02895     max_Y = (Short)TRUNC( ras.minY );
02896     min_Y = (Short)TRUNC( ras.maxY );
02897 
02898     while ( P )
02899     {
02900       Q = P->link;
02901 
02902       bottom = (Short)P->start;
02903       top    = (Short)( P->start + P->height - 1 );
02904 
02905       if ( min_Y > bottom )
02906         min_Y = bottom;
02907       if ( max_Y < top )
02908         max_Y = top;
02909 
02910       P->X = 0;
02911       InsNew( &waiting, P );
02912 
02913       P = Q;
02914     }
02915 
02916     /* check the Y-turns */
02917     if ( ras.numTurns == 0 )
02918     {
02919       ras.error = Raster_Err_Invalid;
02920       return FAILURE;
02921     }
02922 
02923     /* now initialize the sweep */
02924 
02925     ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y );
02926 
02927     /* then compute the distance of each profile from min_Y */
02928 
02929     P = waiting;
02930 
02931     while ( P )
02932     {
02933       P->countL = (UShort)( P->start - min_Y );
02934       P = P->link;
02935     }
02936 
02937     /* let's go */
02938 
02939     y        = min_Y;
02940     y_height = 0;
02941 
02942     if ( ras.numTurns > 0                     &&
02943          ras.sizeBuff[-ras.numTurns] == min_Y )
02944       ras.numTurns--;
02945 
02946     while ( ras.numTurns > 0 )
02947     {
02948       /* check waiting list for new activations */
02949 
02950       P = waiting;
02951 
02952       while ( P )
02953       {
02954         Q = P->link;
02955         P->countL -= y_height;
02956         if ( P->countL == 0 )
02957         {
02958           DelOld( &waiting, P );
02959 
02960           if ( P->flags & Flow_Up )
02961             InsNew( &draw_left,  P );
02962           else
02963             InsNew( &draw_right, P );
02964         }
02965 
02966         P = Q;
02967       }
02968 
02969       /* sort the drawing lists */
02970 
02971       Sort( &draw_left );
02972       Sort( &draw_right );
02973 
02974       y_change = (Short)ras.sizeBuff[-ras.numTurns--];
02975       y_height = (Short)( y_change - y );
02976 
02977       while ( y < y_change )
02978       {
02979         /* let's trace */
02980 
02981         dropouts = 0;
02982 
02983         P_Left  = draw_left;
02984         P_Right = draw_right;
02985 
02986         while ( P_Left )
02987         {
02988           x1 = P_Left ->X;
02989           x2 = P_Right->X;
02990 
02991           if ( x1 > x2 )
02992           {
02993             xs = x1;
02994             x1 = x2;
02995             x2 = xs;
02996           }
02997 
02998           e1 = FLOOR( x1 );
02999           e2 = CEILING( x2 );
03000 
03001           if ( x2 - x1 <= ras.precision &&
03002                e1 != x1 && e2 != x2     )
03003           {
03004             if ( e1 > e2 || e2 == e1 + ras.precision )
03005             {
03006               Int  dropOutControl = P_Left->flags & 7;
03007 
03008 
03009               if ( dropOutControl != 2 )
03010               {
03011                 /* a drop-out was detected */
03012 
03013                 P_Left ->X = x1;
03014                 P_Right->X = x2;
03015 
03016                 /* mark profile for drop-out processing */
03017                 P_Left->countL = 1;
03018                 dropouts++;
03019               }
03020 
03021               goto Skip_To_Next;
03022             }
03023           }
03024 
03025           ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right );
03026 
03027         Skip_To_Next:
03028 
03029           P_Left  = P_Left->link;
03030           P_Right = P_Right->link;
03031         }
03032 
03033         /* handle drop-outs _after_ the span drawing --       */
03034         /* drop-out processing has been moved out of the loop */
03035         /* for performance tuning                             */
03036         if ( dropouts > 0 )
03037           goto Scan_DropOuts;
03038 
03039       Next_Line:
03040 
03041         ras.Proc_Sweep_Step( RAS_VAR );
03042 
03043         y++;
03044 
03045         if ( y < y_change )
03046         {
03047           Sort( &draw_left  );
03048           Sort( &draw_right );
03049         }
03050       }
03051 
03052       /* now finalize the profiles that need it */
03053 
03054       P = draw_left;
03055       while ( P )
03056       {
03057         Q = P->link;
03058         if ( P->height == 0 )
03059           DelOld( &draw_left, P );
03060         P = Q;
03061       }
03062 
03063       P = draw_right;
03064       while ( P )
03065       {
03066         Q = P->link;
03067         if ( P->height == 0 )
03068           DelOld( &draw_right, P );
03069         P = Q;
03070       }
03071     }
03072 
03073     /* for gray-scaling, flush the bitmap scanline cache */
03074     while ( y <= max_Y )
03075     {
03076       ras.Proc_Sweep_Step( RAS_VAR );
03077       y++;
03078     }
03079 
03080     return SUCCESS;
03081 
03082   Scan_DropOuts:
03083 
03084     P_Left  = draw_left;
03085     P_Right = draw_right;
03086 
03087     while ( P_Left )
03088     {
03089       if ( P_Left->countL )
03090       {
03091         P_Left->countL = 0;
03092 #if 0
03093         dropouts--;  /* -- this is useful when debugging only */
03094 #endif
03095         ras.Proc_Sweep_Drop( RAS_VARS y,
03096                                       P_Left->X,
03097                                       P_Right->X,
03098                                       P_Left,
03099                                       P_Right );
03100       }
03101 
03102       P_Left  = P_Left->link;
03103       P_Right = P_Right->link;
03104     }
03105 
03106     goto Next_Line;
03107   }
03108 
03109 
03110   /*************************************************************************/
03111   /*                                                                       */
03112   /* <Function>                                                            */
03113   /*    Render_Single_Pass                                                 */
03114   /*                                                                       */
03115   /* <Description>                                                         */
03116   /*    Perform one sweep with sub-banding.                                */
03117   /*                                                                       */
03118   /* <Input>                                                               */
03119   /*    flipped :: If set, flip the direction of the outline.              */
03120   /*                                                                       */
03121   /* <Return>                                                              */
03122   /*    Renderer error code.                                               */
03123   /*                                                                       */
03124   static int
03125   Render_Single_Pass( RAS_ARGS Bool  flipped )
03126   {
03127     Short  i, j, k;
03128 
03129 
03130     while ( ras.band_top >= 0 )
03131     {
03132       ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision;
03133       ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision;
03134 
03135       ras.top = ras.buff;
03136 
03137       ras.error = Raster_Err_None;
03138 
03139       if ( Convert_Glyph( RAS_VARS flipped ) )
03140       {
03141         if ( ras.error != Raster_Err_Overflow )
03142           return FAILURE;
03143 
03144         ras.error = Raster_Err_None;
03145 
03146         /* sub-banding */
03147 
03148 #ifdef DEBUG_RASTER
03149         ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) );
03150 #endif
03151 
03152         i = ras.band_stack[ras.band_top].y_min;
03153         j = ras.band_stack[ras.band_top].y_max;
03154 
03155         k = (Short)( ( i + j ) / 2 );
03156 
03157         if ( ras.band_top >= 7 || k < i )
03158         {
03159           ras.band_top = 0;
03160           ras.error    = Raster_Err_Invalid;
03161 
03162           return ras.error;
03163         }
03164 
03165         ras.band_stack[ras.band_top + 1].y_min = k;
03166         ras.band_stack[ras.band_top + 1].y_max = j;
03167 
03168         ras.band_stack[ras.band_top].y_max = (Short)( k - 1 );
03169 
03170         ras.band_top++;
03171       }
03172       else
03173       {
03174         if ( ras.fProfile )
03175           if ( Draw_Sweep( RAS_VAR ) )
03176              return ras.error;
03177         ras.band_top--;
03178       }
03179     }
03180 
03181     return SUCCESS;
03182   }
03183 
03184 
03185   /*************************************************************************/
03186   /*                                                                       */
03187   /* <Function>                                                            */
03188   /*    Render_Glyph                                                       */
03189   /*                                                                       */
03190   /* <Description>                                                         */
03191   /*    Render a glyph in a bitmap.  Sub-banding if needed.                */
03192   /*                                                                       */
03193   /* <Return>                                                              */
03194   /*    FreeType error code.  0 means success.                             */
03195   /*                                                                       */
03196   FT_LOCAL_DEF( FT_Error )
03197   Render_Glyph( RAS_ARG )
03198   {
03199     FT_Error  error;
03200 
03201 
03202     Set_High_Precision( RAS_VARS ras.outline.flags &
03203                                  FT_OUTLINE_HIGH_PRECISION );
03204     ras.scale_shift = ras.precision_shift;
03205 
03206     if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS )
03207       ras.dropOutControl = 2;
03208     else
03209     {
03210       if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS )
03211         ras.dropOutControl = 4;
03212       else
03213         ras.dropOutControl = 0;
03214 
03215       if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) )
03216         ras.dropOutControl += 1;
03217     }
03218 
03219     ras.second_pass = (FT_Byte)( !( ras.outline.flags &
03220                                     FT_OUTLINE_SINGLE_PASS ) );
03221 
03222     /* Vertical Sweep */
03223     ras.Proc_Sweep_Init = Vertical_Sweep_Init;
03224     ras.Proc_Sweep_Span = Vertical_Sweep_Span;
03225     ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
03226     ras.Proc_Sweep_Step = Vertical_Sweep_Step;
03227 
03228     ras.band_top            = 0;
03229     ras.band_stack[0].y_min = 0;
03230     ras.band_stack[0].y_max = (short)( ras.target.rows - 1 );
03231 
03232     ras.bWidth  = (unsigned short)ras.target.width;
03233     ras.bTarget = (Byte*)ras.target.buffer;
03234 
03235     if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 )
03236       return error;
03237 
03238     /* Horizontal Sweep */
03239     if ( ras.second_pass && ras.dropOutControl != 2 )
03240     {
03241       ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
03242       ras.Proc_Sweep_Span = Horizontal_Sweep_Span;
03243       ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop;
03244       ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
03245 
03246       ras.band_top            = 0;
03247       ras.band_stack[0].y_min = 0;
03248       ras.band_stack[0].y_max = (short)( ras.target.width - 1 );
03249 
03250       if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 )
03251         return error;
03252     }
03253 
03254     return Raster_Err_None;
03255   }
03256 
03257 
03258 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
03259 
03260   /*************************************************************************/
03261   /*                                                                       */
03262   /* <Function>                                                            */
03263   /*    Render_Gray_Glyph                                                  */
03264   /*                                                                       */
03265   /* <Description>                                                         */
03266   /*    Render a glyph with grayscaling.  Sub-banding if needed.           */
03267   /*                                                                       */
03268   /* <Return>                                                              */
03269   /*    FreeType error code.  0 means success.                             */
03270   /*                                                                       */
03271   FT_LOCAL_DEF( FT_Error )
03272   Render_Gray_Glyph( RAS_ARG )
03273   {
03274     Long      pixel_width;
03275     FT_Error  error;
03276 
03277 
03278     Set_High_Precision( RAS_VARS ras.outline.flags &
03279                                  FT_OUTLINE_HIGH_PRECISION );
03280     ras.scale_shift = ras.precision_shift + 1;
03281 
03282     if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS )
03283       ras.dropOutControl = 2;
03284     else
03285     {
03286       if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS )
03287         ras.dropOutControl = 4;
03288       else
03289         ras.dropOutControl = 0;
03290 
03291       if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) )
03292         ras.dropOutControl += 1;
03293     }
03294 
03295     ras.second_pass = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS );
03296 
03297     /* Vertical Sweep */
03298 
03299     ras.band_top            = 0;
03300     ras.band_stack[0].y_min = 0;
03301     ras.band_stack[0].y_max = 2 * ras.target.rows - 1;
03302 
03303     ras.bWidth  = ras.gray_width;
03304     pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 );
03305 
03306     if ( ras.bWidth > pixel_width )
03307       ras.bWidth = pixel_width;
03308 
03309     ras.bWidth  = ras.bWidth * 8;
03310     ras.bTarget = (Byte*)ras.gray_lines;
03311     ras.gTarget = (Byte*)ras.target.buffer;
03312 
03313     ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init;
03314     ras.Proc_Sweep_Span = Vertical_Sweep_Span;
03315     ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
03316     ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step;
03317 
03318     error = Render_Single_Pass( RAS_VARS 0 );
03319     if ( error )
03320       return error;
03321 
03322     /* Horizontal Sweep */
03323     if ( ras.second_pass && ras.dropOutControl != 2 )
03324     {
03325       ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
03326       ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span;
03327       ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop;
03328       ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
03329 
03330       ras.band_top            = 0;
03331       ras.band_stack[0].y_min = 0;
03332       ras.band_stack[0].y_max = ras.target.width * 2 - 1;
03333 
03334       error = Render_Single_Pass( RAS_VARS 1 );
03335       if ( error )
03336         return error;
03337     }
03338 
03339     return Raster_Err_None;
03340   }
03341 
03342 #else /* !FT_RASTER_OPTION_ANTI_ALIASING */
03343 
03344   FT_LOCAL_DEF( FT_Error )
03345   Render_Gray_Glyph( RAS_ARG )
03346   {
03347     FT_UNUSED_RASTER;
03348 
03349     return Raster_Err_Unsupported;
03350   }
03351 
03352 #endif /* !FT_RASTER_OPTION_ANTI_ALIASING */
03353 
03354 
03355   static void
03356   ft_black_init( PRaster  raster )
03357   {
03358 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
03359     FT_UInt  n;
03360 
03361 
03362     /* set default 5-levels gray palette */
03363     for ( n = 0; n < 5; n++ )
03364       raster->grays[n] = n * 255 / 4;
03365 
03366     raster->gray_width = RASTER_GRAY_LINES / 2;
03367 #else
03368     FT_UNUSED( raster );
03369 #endif
03370   }
03371 
03372 
03373   /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
03374   /****                         a static object.                  *****/
03375 
03376 
03377 #ifdef _STANDALONE_
03378 
03379 
03380   static int
03381   ft_black_new( void*       memory,
03382                 FT_Raster  *araster )
03383   {
03384      static TRaster  the_raster;
03385 
03386 
03387      *araster = (FT_Raster)&the_raster;
03388      FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
03389      ft_black_init( &the_raster );
03390 
03391      return 0;
03392   }
03393 
03394 
03395   static void
03396   ft_black_done( FT_Raster  raster )
03397   {
03398     /* nothing */
03399     FT_UNUSED( raster );
03400   }
03401 
03402 
03403 #else /* _STANDALONE_ */
03404 
03405 
03406   static int
03407   ft_black_new( FT_Memory   memory,
03408                 PRaster    *araster )
03409   {
03410     FT_Error  error;
03411     PRaster   raster;
03412 
03413 
03414     *araster = 0;
03415     if ( !FT_NEW( raster ) )
03416     {
03417       raster->memory = memory;
03418       ft_black_init( raster );
03419 
03420       *araster = raster;
03421     }
03422 
03423     return error;
03424   }
03425 
03426 
03427   static void
03428   ft_black_done( PRaster  raster )
03429   {
03430     FT_Memory  memory = (FT_Memory)raster->memory;
03431     FT_FREE( raster );
03432   }
03433 
03434 
03435 #endif /* _STANDALONE_ */
03436 
03437 
03438   static void
03439   ft_black_reset( PRaster  raster,
03440                   char*    pool_base,
03441                   long     pool_size )
03442   {
03443     if ( raster )
03444     {
03445       if ( pool_base && pool_size >= (long)sizeof(TWorker) + 2048 )
03446       {
03447         PWorker  worker = (PWorker)pool_base;
03448 
03449 
03450         raster->buffer      = pool_base + ( (sizeof ( *worker ) + 7 ) & ~7 );
03451         raster->buffer_size = ( ( pool_base + pool_size ) -
03452                                 (char*)raster->buffer ) / sizeof ( Long );
03453         raster->worker      = worker;
03454       }
03455       else
03456       {
03457         raster->buffer      = NULL;
03458         raster->buffer_size = 0;
03459         raster->worker      = NULL;
03460       }
03461     }
03462   }
03463 
03464 
03465   static void
03466   ft_black_set_mode( PRaster        raster,
03467                      unsigned long  mode,
03468                      const char*    palette )
03469   {
03470 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
03471 
03472     if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) )
03473     {
03474       /* set 5-levels gray palette */
03475       raster->grays[0] = palette[0];
03476       raster->grays[1] = palette[1];
03477       raster->grays[2] = palette[2];
03478       raster->grays[3] = palette[3];
03479       raster->grays[4] = palette[4];
03480     }
03481 
03482 #else
03483 
03484     FT_UNUSED( raster );
03485     FT_UNUSED( mode );
03486     FT_UNUSED( palette );
03487 
03488 #endif
03489   }
03490 
03491 
03492   static int
03493   ft_black_render( PRaster                  raster,
03494                    const FT_Raster_Params*  params )
03495   {
03496     const FT_Outline*  outline    = (const FT_Outline*)params->source;
03497     const FT_Bitmap*   target_map = params->target;
03498     PWorker            worker;
03499 
03500 
03501     if ( !raster || !raster->buffer || !raster->buffer_size )
03502       return Raster_Err_Not_Ini;
03503 
03504     if ( !outline )
03505       return Raster_Err_Invalid;
03506 
03507     /* return immediately if the outline is empty */
03508     if ( outline->n_points == 0 || outline->n_contours <= 0 )
03509       return Raster_Err_None;
03510 
03511     if ( !outline->contours || !outline->points )
03512       return Raster_Err_Invalid;
03513 
03514     if ( outline->n_points !=
03515            outline->contours[outline->n_contours - 1] + 1 )
03516       return Raster_Err_Invalid;
03517 
03518     worker = raster->worker;
03519 
03520     /* this version of the raster does not support direct rendering, sorry */
03521     if ( params->flags & FT_RASTER_FLAG_DIRECT )
03522       return Raster_Err_Unsupported;
03523 
03524     if ( !target_map )
03525       return Raster_Err_Invalid;
03526 
03527     /* nothing to do */
03528     if ( !target_map->width || !target_map->rows )
03529       return Raster_Err_None;
03530 
03531     if ( !target_map->buffer )
03532       return Raster_Err_Invalid;
03533 
03534     ras.outline = *outline;
03535     ras.target  = *target_map;
03536 
03537     worker->buff       = (PLong) raster->buffer;
03538     worker->sizeBuff   = worker->buff +
03539                            raster->buffer_size / sizeof ( Long );
03540 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
03541     worker->grays      = raster->grays;
03542     worker->gray_width = raster->gray_width;
03543 
03544     FT_MEM_ZERO( worker->gray_lines, worker->gray_width * 2 );
03545 #endif
03546 
03547     return ( params->flags & FT_RASTER_FLAG_AA )
03548            ? Render_Gray_Glyph( RAS_VAR )
03549            : Render_Glyph( RAS_VAR );
03550   }
03551 
03552 
03553   FT_DEFINE_RASTER_FUNCS( ft_standard_raster,
03554     FT_GLYPH_FORMAT_OUTLINE,
03555     (FT_Raster_New_Func)     ft_black_new,
03556     (FT_Raster_Reset_Func)   ft_black_reset,
03557     (FT_Raster_Set_Mode_Func)ft_black_set_mode,
03558     (FT_Raster_Render_Func)  ft_black_render,
03559     (FT_Raster_Done_Func)    ft_black_done
03560   )
03561 
03562 
03563 /* END */

Generated on Tue Jul 5 14:13:50 2011 for ROOT_528-00b_version by  doxygen 1.5.1