ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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, 2010 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   /*************************************************************************/
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   /*************************************************************************/
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   /*************************************************************************/
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 
00306   typedef unsigned char   Byte, *PByte;
00307   typedef char            Bool;
00308 
00309 
00310   typedef union  Alignment_
00311   {
00312     long    l;
00313     void*   p;
00314     void  (*f)(void);
00315 
00316   } Alignment, *PAlignment;
00317 
00318 
00319   typedef struct  TPoint_
00320   {
00321     Long  x;
00322     Long  y;
00323 
00324   } TPoint;
00325 
00326 
00327   /* values for the `flags' bit field */
00328 #define Flow_Up           0x8
00329 #define Overshoot_Top     0x10
00330 #define Overshoot_Bottom  0x20
00331 
00332 
00333   /* States of each line, arc, and profile */
00334   typedef enum  TStates_
00335   {
00336     Unknown_State,
00337     Ascending_State,
00338     Descending_State,
00339     Flat_State
00340 
00341   } TStates;
00342 
00343 
00344   typedef struct TProfile_  TProfile;
00345   typedef TProfile*         PProfile;
00346 
00347   struct  TProfile_
00348   {
00349     FT_F26Dot6  X;           /* current coordinate during sweep          */
00350     PProfile    link;        /* link to next profile (various purposes)  */
00351     PLong       offset;      /* start of profile's data in render pool   */
00352     unsigned    flags;       /* Bit 0-2: drop-out mode                   */
00353                              /* Bit 3: profile orientation (up/down)     */
00354                              /* Bit 4: is top profile?                   */
00355                              /* Bit 5: is bottom profile?                */
00356     long        height;      /* profile's height in scanlines            */
00357     long        start;       /* profile's starting scanline              */
00358 
00359     unsigned    countL;      /* number of lines to step before this      */
00360                              /* profile becomes drawable                 */
00361 
00362     PProfile    next;        /* next profile in same contour, used       */
00363                              /* during drop-out control                  */
00364   };
00365 
00366   typedef PProfile   TProfileList;
00367   typedef PProfile*  PProfileList;
00368 
00369 
00370   /* Simple record used to implement a stack of bands, required */
00371   /* by the sub-banding mechanism                               */
00372   typedef struct  TBand_
00373   {
00374     Short  y_min;   /* band's minimum */
00375     Short  y_max;   /* band's maximum */
00376 
00377   } TBand;
00378 
00379 
00380 #define AlignProfileSize \
00381   ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( long ) )
00382 
00383 
00384 #ifdef FT_STATIC_RASTER
00385 
00386 
00387 #define RAS_ARGS       /* void */
00388 #define RAS_ARG        /* void */
00389 
00390 #define RAS_VARS       /* void */
00391 #define RAS_VAR        /* void */
00392 
00393 #define FT_UNUSED_RASTER  do { } while ( 0 )
00394 
00395 
00396 #else /* !FT_STATIC_RASTER */
00397 
00398 
00399 #define RAS_ARGS       PWorker    worker,
00400 #define RAS_ARG        PWorker    worker
00401 
00402 #define RAS_VARS       worker,
00403 #define RAS_VAR        worker
00404 
00405 #define FT_UNUSED_RASTER  FT_UNUSED( worker )
00406 
00407 
00408 #endif /* !FT_STATIC_RASTER */
00409 
00410 
00411   typedef struct TWorker_  TWorker, *PWorker;
00412 
00413 
00414   /* prototypes used for sweep function dispatch */
00415   typedef void
00416   Function_Sweep_Init( RAS_ARGS Short*  min,
00417                                 Short*  max );
00418 
00419   typedef void
00420   Function_Sweep_Span( RAS_ARGS Short       y,
00421                                 FT_F26Dot6  x1,
00422                                 FT_F26Dot6  x2,
00423                                 PProfile    left,
00424                                 PProfile    right );
00425 
00426   typedef void
00427   Function_Sweep_Step( RAS_ARG );
00428 
00429 
00430   /* NOTE: These operations are only valid on 2's complement processors */
00431 
00432 #define FLOOR( x )    ( (x) & -ras.precision )
00433 #define CEILING( x )  ( ( (x) + ras.precision - 1 ) & -ras.precision )
00434 #define TRUNC( x )    ( (signed long)(x) >> ras.precision_bits )
00435 #define FRAC( x )     ( (x) & ( ras.precision - 1 ) )
00436 #define SCALED( x )   ( ( (x) << ras.scale_shift ) - ras.precision_half )
00437 
00438 #define IS_BOTTOM_OVERSHOOT( x )  ( CEILING( x ) - x >= ras.precision_half )
00439 #define IS_TOP_OVERSHOOT( x )     ( x - FLOOR( x ) >= ras.precision_half )
00440 
00441   /* The most used variables are positioned at the top of the structure. */
00442   /* Thus, their offset can be coded with less opcodes, resulting in a   */
00443   /* smaller executable.                                                 */
00444 
00445   struct  TWorker_
00446   {
00447     Int         precision_bits;     /* precision related variables         */
00448     Int         precision;
00449     Int         precision_half;
00450     Int         precision_shift;
00451     Int         precision_step;
00452     Int         precision_jitter;
00453 
00454     Int         scale_shift;        /* == precision_shift   for bitmaps    */
00455                                     /* == precision_shift+1 for pixmaps    */
00456 
00457     PLong       buff;               /* The profiles buffer                 */
00458     PLong       sizeBuff;           /* Render pool size                    */
00459     PLong       maxBuff;            /* Profiles buffer size                */
00460     PLong       top;                /* Current cursor in buffer            */
00461 
00462     FT_Error    error;
00463 
00464     Int         numTurns;           /* number of Y-turns in outline        */
00465 
00466     TPoint*     arc;                /* current Bezier arc pointer          */
00467 
00468     UShort      bWidth;             /* target bitmap width                 */
00469     PByte       bTarget;            /* target bitmap buffer                */
00470     PByte       gTarget;            /* target pixmap buffer                */
00471 
00472     Long        lastX, lastY;
00473     Long        minY, maxY;
00474 
00475     UShort      num_Profs;          /* current number of profiles          */
00476 
00477     Bool        fresh;              /* signals a fresh new profile which   */
00478                                     /* `start' field must be completed     */
00479     Bool        joint;              /* signals that the last arc ended     */
00480                                     /* exactly on a scanline.  Allows      */
00481                                     /* removal of doublets                 */
00482     PProfile    cProfile;           /* current profile                     */
00483     PProfile    fProfile;           /* head of linked list of profiles     */
00484     PProfile    gProfile;           /* contour's first profile in case     */
00485                                     /* of impact                           */
00486 
00487     TStates     state;              /* rendering state                     */
00488 
00489     FT_Bitmap   target;             /* description of target bit/pixmap    */
00490     FT_Outline  outline;
00491 
00492     Long        traceOfs;           /* current offset in target bitmap     */
00493     Long        traceG;             /* current offset in target pixmap     */
00494 
00495     Short       traceIncr;          /* sweep's increment in target bitmap  */
00496 
00497     Short       gray_min_x;         /* current min x during gray rendering */
00498     Short       gray_max_x;         /* current max x during gray rendering */
00499 
00500     /* dispatch variables */
00501 
00502     Function_Sweep_Init*  Proc_Sweep_Init;
00503     Function_Sweep_Span*  Proc_Sweep_Span;
00504     Function_Sweep_Span*  Proc_Sweep_Drop;
00505     Function_Sweep_Step*  Proc_Sweep_Step;
00506 
00507     Byte        dropOutControl;     /* current drop_out control method     */
00508 
00509     Bool        second_pass;        /* indicates whether a horizontal pass */
00510                                     /* should be performed to control      */
00511                                     /* drop-out accurately when calling    */
00512                                     /* Render_Glyph.  Note that there is   */
00513                                     /* no horizontal pass during gray      */
00514                                     /* rendering.                          */
00515 
00516     TPoint      arcs[3 * MaxBezier + 1]; /* The Bezier stack               */
00517 
00518     TBand       band_stack[16];     /* band stack used for sub-banding     */
00519     Int         band_top;           /* band stack top                      */
00520 
00521 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
00522 
00523     Byte*       grays;
00524 
00525     Byte        gray_lines[RASTER_GRAY_LINES];
00526                                 /* Intermediate table used to render the   */
00527                                 /* graylevels pixmaps.                     */
00528                                 /* gray_lines is a buffer holding two      */
00529                                 /* monochrome scanlines                    */
00530 
00531     Short       gray_width;     /* width in bytes of one monochrome        */
00532                                 /* intermediate scanline of gray_lines.    */
00533                                 /* Each gray pixel takes 2 bits long there */
00534 
00535                        /* The gray_lines must hold 2 lines, thus with size */
00536                        /* in bytes of at least `gray_width*2'.             */
00537 
00538 #endif /* FT_RASTER_ANTI_ALIASING */
00539 
00540   };
00541 
00542 
00543   typedef struct  TRaster_
00544   {
00545     char*    buffer;
00546     long     buffer_size;
00547     void*    memory;
00548     PWorker  worker;
00549     Byte     grays[5];
00550     Short    gray_width;
00551 
00552   } TRaster, *PRaster;
00553 
00554 #ifdef FT_STATIC_RASTER
00555 
00556   static TWorker  cur_ras;
00557 #define ras  cur_ras
00558 
00559 #else /* !FT_STATIC_RASTER */
00560 
00561 #define ras  (*worker)
00562 
00563 #endif /* !FT_STATIC_RASTER */
00564 
00565 
00566 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
00567 
00568   /* A lookup table used to quickly count set bits in four gray 2x2 */
00569   /* cells.  The values of the table have been produced with the    */
00570   /* following code:                                                */
00571   /*                                                                */
00572   /*   for ( i = 0; i < 256; i++ )                                  */
00573   /*   {                                                            */
00574   /*     l = 0;                                                     */
00575   /*     j = i;                                                     */
00576   /*                                                                */
00577   /*     for ( c = 0; c < 4; c++ )                                  */
00578   /*     {                                                          */
00579   /*       l <<= 4;                                                 */
00580   /*                                                                */
00581   /*       if ( j & 0x80 ) l++;                                     */
00582   /*       if ( j & 0x40 ) l++;                                     */
00583   /*                                                                */
00584   /*       j = ( j << 2 ) & 0xFF;                                   */
00585   /*     }                                                          */
00586   /*     printf( "0x%04X", l );                                     */
00587   /*   }                                                            */
00588   /*                                                                */
00589 
00590   static const short  count_table[256] =
00591   {
00592     0x0000, 0x0001, 0x0001, 0x0002, 0x0010, 0x0011, 0x0011, 0x0012,
00593     0x0010, 0x0011, 0x0011, 0x0012, 0x0020, 0x0021, 0x0021, 0x0022,
00594     0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
00595     0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
00596     0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
00597     0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
00598     0x0200, 0x0201, 0x0201, 0x0202, 0x0210, 0x0211, 0x0211, 0x0212,
00599     0x0210, 0x0211, 0x0211, 0x0212, 0x0220, 0x0221, 0x0221, 0x0222,
00600     0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
00601     0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
00602     0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
00603     0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
00604     0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
00605     0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
00606     0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
00607     0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
00608     0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
00609     0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
00610     0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
00611     0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
00612     0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
00613     0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
00614     0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
00615     0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
00616     0x2000, 0x2001, 0x2001, 0x2002, 0x2010, 0x2011, 0x2011, 0x2012,
00617     0x2010, 0x2011, 0x2011, 0x2012, 0x2020, 0x2021, 0x2021, 0x2022,
00618     0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
00619     0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
00620     0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
00621     0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
00622     0x2200, 0x2201, 0x2201, 0x2202, 0x2210, 0x2211, 0x2211, 0x2212,
00623     0x2210, 0x2211, 0x2211, 0x2212, 0x2220, 0x2221, 0x2221, 0x2222
00624   };
00625 
00626 #endif /* FT_RASTER_OPTION_ANTI_ALIASING */
00627 
00628 
00629 
00630   /*************************************************************************/
00631   /*************************************************************************/
00635   /*************************************************************************/
00636   /*************************************************************************/
00637 
00638 
00639   /*************************************************************************/
00640   /*                                                                       */
00641   /* <Function>                                                            */
00642   /*    Set_High_Precision                                                 */
00643   /*                                                                       */
00644   /* <Description>                                                         */
00645   /*    Set precision variables according to param flag.                   */
00646   /*                                                                       */
00647   /* <Input>                                                               */
00648   /*    High :: Set to True for high precision (typically for ppem < 18),  */
00649   /*            false otherwise.                                           */
00650   /*                                                                       */
00651   static void
00652   Set_High_Precision( RAS_ARGS Int  High )
00653   {
00654     if ( High )
00655     {
00656       ras.precision_bits   = 12;
00657       ras.precision_step   = 256;
00658       ras.precision_jitter = 50;
00659     }
00660     else
00661     {
00662       ras.precision_bits   = 6;
00663       ras.precision_step   = 32;
00664       ras.precision_jitter = 2;
00665     }
00666 
00667     FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
00668 
00669     ras.precision       = 1 << ras.precision_bits;
00670     ras.precision_half  = ras.precision / 2;
00671     ras.precision_shift = ras.precision_bits - Pixel_Bits;
00672   }
00673 
00674 
00675   /*************************************************************************/
00676   /*                                                                       */
00677   /* <Function>                                                            */
00678   /*    New_Profile                                                        */
00679   /*                                                                       */
00680   /* <Description>                                                         */
00681   /*    Create a new profile in the render pool.                           */
00682   /*                                                                       */
00683   /* <Input>                                                               */
00684   /*    aState    :: The state/orientation of the new profile.             */
00685   /*                                                                       */
00686   /*    overshoot :: Whether the profile's unrounded start position        */
00687   /*                 differs by at least a half pixel.                     */
00688   /*                                                                       */
00689   /* <Return>                                                              */
00690   /*   SUCCESS on success.  FAILURE in case of overflow or of incoherent   */
00691   /*   profile.                                                            */
00692   /*                                                                       */
00693   static Bool
00694   New_Profile( RAS_ARGS TStates  aState,
00695                         Bool     overshoot )
00696   {
00697     if ( !ras.fProfile )
00698     {
00699       ras.cProfile  = (PProfile)ras.top;
00700       ras.fProfile  = ras.cProfile;
00701       ras.top      += AlignProfileSize;
00702     }
00703 
00704     if ( ras.top >= ras.maxBuff )
00705     {
00706       ras.error = Raster_Err_Overflow;
00707       return FAILURE;
00708     }
00709 
00710     ras.cProfile->flags  = 0;
00711     ras.cProfile->start  = 0;
00712     ras.cProfile->height = 0;
00713     ras.cProfile->offset = ras.top;
00714     ras.cProfile->link   = (PProfile)0;
00715     ras.cProfile->next   = (PProfile)0;
00716     ras.cProfile->flags  = ras.dropOutControl;
00717 
00718     switch ( aState )
00719     {
00720     case Ascending_State:
00721       ras.cProfile->flags |= Flow_Up;
00722       if ( overshoot )
00723         ras.cProfile->flags |= Overshoot_Bottom;
00724 
00725       FT_TRACE6(( "New ascending profile = %p\n", ras.cProfile ));
00726       break;
00727 
00728     case Descending_State:
00729       if ( overshoot )
00730         ras.cProfile->flags |= Overshoot_Top;
00731       FT_TRACE6(( "New descending profile = %p\n", ras.cProfile ));
00732       break;
00733 
00734     default:
00735       FT_ERROR(( "New_Profile: invalid profile direction\n" ));
00736       ras.error = Raster_Err_Invalid;
00737       return FAILURE;
00738     }
00739 
00740     if ( !ras.gProfile )
00741       ras.gProfile = ras.cProfile;
00742 
00743     ras.state = aState;
00744     ras.fresh = TRUE;
00745     ras.joint = FALSE;
00746 
00747     return SUCCESS;
00748   }
00749 
00750 
00751   /*************************************************************************/
00752   /*                                                                       */
00753   /* <Function>                                                            */
00754   /*    End_Profile                                                        */
00755   /*                                                                       */
00756   /* <Description>                                                         */
00757   /*    Finalize the current profile.                                      */
00758   /*                                                                       */
00759   /* <Input>                                                               */
00760   /*    overshoot :: Whether the profile's unrounded end position differs  */
00761   /*                 by at least a half pixel.                             */
00762   /*                                                                       */
00763   /* <Return>                                                              */
00764   /*    SUCCESS on success.  FAILURE in case of overflow or incoherency.   */
00765   /*                                                                       */
00766   static Bool
00767   End_Profile( RAS_ARGS Bool  overshoot )
00768   {
00769     Long      h;
00770     PProfile  oldProfile;
00771 
00772 
00773     h = (Long)( ras.top - ras.cProfile->offset );
00774 
00775     if ( h < 0 )
00776     {
00777       FT_ERROR(( "End_Profile: negative height encountered\n" ));
00778       ras.error = Raster_Err_Neg_Height;
00779       return FAILURE;
00780     }
00781 
00782     if ( h > 0 )
00783     {
00784       FT_TRACE6(( "Ending profile %p, start = %ld, height = %ld\n",
00785                   ras.cProfile, ras.cProfile->start, h ));
00786 
00787       ras.cProfile->height = h;
00788       if ( overshoot )
00789       {
00790         if ( ras.cProfile->flags & Flow_Up )
00791           ras.cProfile->flags |= Overshoot_Top;
00792         else
00793           ras.cProfile->flags |= Overshoot_Bottom;
00794       }
00795 
00796       oldProfile   = ras.cProfile;
00797       ras.cProfile = (PProfile)ras.top;
00798 
00799       ras.top += AlignProfileSize;
00800 
00801       ras.cProfile->height = 0;
00802       ras.cProfile->offset = ras.top;
00803 
00804       oldProfile->next = ras.cProfile;
00805       ras.num_Profs++;
00806     }
00807 
00808     if ( ras.top >= ras.maxBuff )
00809     {
00810       FT_TRACE1(( "overflow in End_Profile\n" ));
00811       ras.error = Raster_Err_Overflow;
00812       return FAILURE;
00813     }
00814 
00815     ras.joint = FALSE;
00816 
00817     return SUCCESS;
00818   }
00819 
00820 
00821   /*************************************************************************/
00822   /*                                                                       */
00823   /* <Function>                                                            */
00824   /*    Insert_Y_Turn                                                      */
00825   /*                                                                       */
00826   /* <Description>                                                         */
00827   /*    Insert a salient into the sorted list placed on top of the render  */
00828   /*    pool.                                                              */
00829   /*                                                                       */
00830   /* <Input>                                                               */
00831   /*    New y scanline position.                                           */
00832   /*                                                                       */
00833   /* <Return>                                                              */
00834   /*    SUCCESS on success.  FAILURE in case of overflow.                  */
00835   /*                                                                       */
00836   static Bool
00837   Insert_Y_Turn( RAS_ARGS Int  y )
00838   {
00839     PLong  y_turns;
00840     Int    y2, n;
00841 
00842 
00843     n       = ras.numTurns - 1;
00844     y_turns = ras.sizeBuff - ras.numTurns;
00845 
00846     /* look for first y value that is <= */
00847     while ( n >= 0 && y < y_turns[n] )
00848       n--;
00849 
00850     /* if it is <, simply insert it, ignore if == */
00851     if ( n >= 0 && y > y_turns[n] )
00852       while ( n >= 0 )
00853       {
00854         y2 = (Int)y_turns[n];
00855         y_turns[n] = y;
00856         y = y2;
00857         n--;
00858       }
00859 
00860     if ( n < 0 )
00861     {
00862       ras.maxBuff--;
00863       if ( ras.maxBuff <= ras.top )
00864       {
00865         ras.error = Raster_Err_Overflow;
00866         return FAILURE;
00867       }
00868       ras.numTurns++;
00869       ras.sizeBuff[-ras.numTurns] = y;
00870     }
00871 
00872     return SUCCESS;
00873   }
00874 
00875 
00876   /*************************************************************************/
00877   /*                                                                       */
00878   /* <Function>                                                            */
00879   /*    Finalize_Profile_Table                                             */
00880   /*                                                                       */
00881   /* <Description>                                                         */
00882   /*    Adjust all links in the profiles list.                             */
00883   /*                                                                       */
00884   /* <Return>                                                              */
00885   /*    SUCCESS on success.  FAILURE in case of overflow.                  */
00886   /*                                                                       */
00887   static Bool
00888   Finalize_Profile_Table( RAS_ARG )
00889   {
00890     Int       bottom, top;
00891     UShort    n;
00892     PProfile  p;
00893 
00894 
00895     n = ras.num_Profs;
00896     p = ras.fProfile;
00897 
00898     if ( n > 1 && p )
00899     {
00900       while ( n > 0 )
00901       {
00902         if ( n > 1 )
00903           p->link = (PProfile)( p->offset + p->height );
00904         else
00905           p->link = NULL;
00906 
00907         if ( p->flags & Flow_Up )
00908         {
00909           bottom = (Int)p->start;
00910           top    = (Int)( p->start + p->height - 1 );
00911         }
00912         else
00913         {
00914           bottom     = (Int)( p->start - p->height + 1 );
00915           top        = (Int)p->start;
00916           p->start   = bottom;
00917           p->offset += p->height - 1;
00918         }
00919 
00920         if ( Insert_Y_Turn( RAS_VARS bottom )  ||
00921              Insert_Y_Turn( RAS_VARS top + 1 ) )
00922           return FAILURE;
00923 
00924         p = p->link;
00925         n--;
00926       }
00927     }
00928     else
00929       ras.fProfile = NULL;
00930 
00931     return SUCCESS;
00932   }
00933 
00934 
00935   /*************************************************************************/
00936   /*                                                                       */
00937   /* <Function>                                                            */
00938   /*    Split_Conic                                                        */
00939   /*                                                                       */
00940   /* <Description>                                                         */
00941   /*    Subdivide one conic Bezier into two joint sub-arcs in the Bezier   */
00942   /*    stack.                                                             */
00943   /*                                                                       */
00944   /* <Input>                                                               */
00945   /*    None (subdivided Bezier is taken from the top of the stack).       */
00946   /*                                                                       */
00947   /* <Note>                                                                */
00948   /*    This routine is the `beef' of this component.  It is  _the_ inner  */
00949   /*    loop that should be optimized to hell to get the best performance. */
00950   /*                                                                       */
00951   static void
00952   Split_Conic( TPoint*  base )
00953   {
00954     Long  a, b;
00955 
00956 
00957     base[4].x = base[2].x;
00958     b = base[1].x;
00959     a = base[3].x = ( base[2].x + b ) / 2;
00960     b = base[1].x = ( base[0].x + b ) / 2;
00961     base[2].x = ( a + b ) / 2;
00962 
00963     base[4].y = base[2].y;
00964     b = base[1].y;
00965     a = base[3].y = ( base[2].y + b ) / 2;
00966     b = base[1].y = ( base[0].y + b ) / 2;
00967     base[2].y = ( a + b ) / 2;
00968 
00969     /* hand optimized.  gcc doesn't seem to be too good at common      */
00970     /* expression substitution and instruction scheduling ;-)          */
00971   }
00972 
00973 
00974   /*************************************************************************/
00975   /*                                                                       */
00976   /* <Function>                                                            */
00977   /*    Split_Cubic                                                        */
00978   /*                                                                       */
00979   /* <Description>                                                         */
00980   /*    Subdivide a third-order Bezier arc into two joint sub-arcs in the  */
00981   /*    Bezier stack.                                                      */
00982   /*                                                                       */
00983   /* <Note>                                                                */
00984   /*    This routine is the `beef' of the component.  It is one of _the_   */
00985   /*    inner loops that should be optimized like hell to get the best     */
00986   /*    performance.                                                       */
00987   /*                                                                       */
00988   static void
00989   Split_Cubic( TPoint*  base )
00990   {
00991     Long  a, b, c, d;
00992 
00993 
00994     base[6].x = base[3].x;
00995     c = base[1].x;
00996     d = base[2].x;
00997     base[1].x = a = ( base[0].x + c + 1 ) >> 1;
00998     base[5].x = b = ( base[3].x + d + 1 ) >> 1;
00999     c = ( c + d + 1 ) >> 1;
01000     base[2].x = a = ( a + c + 1 ) >> 1;
01001     base[4].x = b = ( b + c + 1 ) >> 1;
01002     base[3].x = ( a + b + 1 ) >> 1;
01003 
01004     base[6].y = base[3].y;
01005     c = base[1].y;
01006     d = base[2].y;
01007     base[1].y = a = ( base[0].y + c + 1 ) >> 1;
01008     base[5].y = b = ( base[3].y + d + 1 ) >> 1;
01009     c = ( c + d + 1 ) >> 1;
01010     base[2].y = a = ( a + c + 1 ) >> 1;
01011     base[4].y = b = ( b + c + 1 ) >> 1;
01012     base[3].y = ( a + b + 1 ) >> 1;
01013   }
01014 
01015 
01016   /*************************************************************************/
01017   /*                                                                       */
01018   /* <Function>                                                            */
01019   /*    Line_Up                                                            */
01020   /*                                                                       */
01021   /* <Description>                                                         */
01022   /*    Compute the x-coordinates of an ascending line segment and store   */
01023   /*    them in the render pool.                                           */
01024   /*                                                                       */
01025   /* <Input>                                                               */
01026   /*    x1   :: The x-coordinate of the segment's start point.             */
01027   /*                                                                       */
01028   /*    y1   :: The y-coordinate of the segment's start point.             */
01029   /*                                                                       */
01030   /*    x2   :: The x-coordinate of the segment's end point.               */
01031   /*                                                                       */
01032   /*    y2   :: The y-coordinate of the segment's end point.               */
01033   /*                                                                       */
01034   /*    miny :: A lower vertical clipping bound value.                     */
01035   /*                                                                       */
01036   /*    maxy :: An upper vertical clipping bound value.                    */
01037   /*                                                                       */
01038   /* <Return>                                                              */
01039   /*    SUCCESS on success, FAILURE on render pool overflow.               */
01040   /*                                                                       */
01041   static Bool
01042   Line_Up( RAS_ARGS Long  x1,
01043                     Long  y1,
01044                     Long  x2,
01045                     Long  y2,
01046                     Long  miny,
01047                     Long  maxy )
01048   {
01049     Long   Dx, Dy;
01050     Int    e1, e2, f1, f2, size;     /* XXX: is `Short' sufficient? */
01051     Long   Ix, Rx, Ax;
01052 
01053     PLong  top;
01054 
01055 
01056     Dx = x2 - x1;
01057     Dy = y2 - y1;
01058 
01059     if ( Dy <= 0 || y2 < miny || y1 > maxy )
01060       return SUCCESS;
01061 
01062     if ( y1 < miny )
01063     {
01064       /* Take care: miny-y1 can be a very large value; we use     */
01065       /*            a slow MulDiv function to avoid clipping bugs */
01066       x1 += SMulDiv( Dx, miny - y1, Dy );
01067       e1  = (Int)TRUNC( miny );
01068       f1  = 0;
01069     }
01070     else
01071     {
01072       e1 = (Int)TRUNC( y1 );
01073       f1 = (Int)FRAC( y1 );
01074     }
01075 
01076     if ( y2 > maxy )
01077     {
01078       /* x2 += FMulDiv( Dx, maxy - y2, Dy );  UNNECESSARY */
01079       e2  = (Int)TRUNC( maxy );
01080       f2  = 0;
01081     }
01082     else
01083     {
01084       e2 = (Int)TRUNC( y2 );
01085       f2 = (Int)FRAC( y2 );
01086     }
01087 
01088     if ( f1 > 0 )
01089     {
01090       if ( e1 == e2 )
01091         return SUCCESS;
01092       else
01093       {
01094         x1 += SMulDiv( Dx, ras.precision - f1, Dy );
01095         e1 += 1;
01096       }
01097     }
01098     else
01099       if ( ras.joint )
01100       {
01101         ras.top--;
01102         ras.joint = FALSE;
01103       }
01104 
01105     ras.joint = (char)( f2 == 0 );
01106 
01107     if ( ras.fresh )
01108     {
01109       ras.cProfile->start = e1;
01110       ras.fresh           = FALSE;
01111     }
01112 
01113     size = e2 - e1 + 1;
01114     if ( ras.top + size >= ras.maxBuff )
01115     {
01116       ras.error = Raster_Err_Overflow;
01117       return FAILURE;
01118     }
01119 
01120     if ( Dx > 0 )
01121     {
01122       Ix = SMulDiv( ras.precision, Dx, Dy);
01123       Rx = ( ras.precision * Dx ) % Dy;
01124       Dx = 1;
01125     }
01126     else
01127     {
01128       Ix = SMulDiv( ras.precision, -Dx, Dy) * -1;
01129       Rx =    ( ras.precision * -Dx ) % Dy;
01130       Dx = -1;
01131     }
01132 
01133     Ax  = -Dy;
01134     top = ras.top;
01135 
01136     while ( size > 0 )
01137     {
01138       *top++ = x1;
01139 
01140       x1 += Ix;
01141       Ax += Rx;
01142       if ( Ax >= 0 )
01143       {
01144         Ax -= Dy;
01145         x1 += Dx;
01146       }
01147       size--;
01148     }
01149 
01150     ras.top = top;
01151     return SUCCESS;
01152   }
01153 
01154 
01155   /*************************************************************************/
01156   /*                                                                       */
01157   /* <Function>                                                            */
01158   /*    Line_Down                                                          */
01159   /*                                                                       */
01160   /* <Description>                                                         */
01161   /*    Compute the x-coordinates of an descending line segment and store  */
01162   /*    them in the render pool.                                           */
01163   /*                                                                       */
01164   /* <Input>                                                               */
01165   /*    x1   :: The x-coordinate of the segment's start point.             */
01166   /*                                                                       */
01167   /*    y1   :: The y-coordinate of the segment's start point.             */
01168   /*                                                                       */
01169   /*    x2   :: The x-coordinate of the segment's end point.               */
01170   /*                                                                       */
01171   /*    y2   :: The y-coordinate of the segment's end point.               */
01172   /*                                                                       */
01173   /*    miny :: A lower vertical clipping bound value.                     */
01174   /*                                                                       */
01175   /*    maxy :: An upper vertical clipping bound value.                    */
01176   /*                                                                       */
01177   /* <Return>                                                              */
01178   /*    SUCCESS on success, FAILURE on render pool overflow.               */
01179   /*                                                                       */
01180   static Bool
01181   Line_Down( RAS_ARGS Long  x1,
01182                       Long  y1,
01183                       Long  x2,
01184                       Long  y2,
01185                       Long  miny,
01186                       Long  maxy )
01187   {
01188     Bool  result, fresh;
01189 
01190 
01191     fresh  = ras.fresh;
01192 
01193     result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
01194 
01195     if ( fresh && !ras.fresh )
01196       ras.cProfile->start = -ras.cProfile->start;
01197 
01198     return result;
01199   }
01200 
01201 
01202   /* A function type describing the functions used to split Bezier arcs */
01203   typedef void  (*TSplitter)( TPoint*  base );
01204 
01205 
01206   /*************************************************************************/
01207   /*                                                                       */
01208   /* <Function>                                                            */
01209   /*    Bezier_Up                                                          */
01210   /*                                                                       */
01211   /* <Description>                                                         */
01212   /*    Compute the x-coordinates of an ascending Bezier arc and store     */
01213   /*    them in the render pool.                                           */
01214   /*                                                                       */
01215   /* <Input>                                                               */
01216   /*    degree   :: The degree of the Bezier arc (either 2 or 3).          */
01217   /*                                                                       */
01218   /*    splitter :: The function to split Bezier arcs.                     */
01219   /*                                                                       */
01220   /*    miny     :: A lower vertical clipping bound value.                 */
01221   /*                                                                       */
01222   /*    maxy     :: An upper vertical clipping bound value.                */
01223   /*                                                                       */
01224   /* <Return>                                                              */
01225   /*    SUCCESS on success, FAILURE on render pool overflow.               */
01226   /*                                                                       */
01227   static Bool
01228   Bezier_Up( RAS_ARGS Int        degree,
01229                       TSplitter  splitter,
01230                       Long       miny,
01231                       Long       maxy )
01232   {
01233     Long   y1, y2, e, e2, e0;
01234     Short  f1;
01235 
01236     TPoint*  arc;
01237     TPoint*  start_arc;
01238 
01239     PLong top;
01240 
01241 
01242     arc = ras.arc;
01243     y1  = arc[degree].y;
01244     y2  = arc[0].y;
01245     top = ras.top;
01246 
01247     if ( y2 < miny || y1 > maxy )
01248       goto Fin;
01249 
01250     e2 = FLOOR( y2 );
01251 
01252     if ( e2 > maxy )
01253       e2 = maxy;
01254 
01255     e0 = miny;
01256 
01257     if ( y1 < miny )
01258       e = miny;
01259     else
01260     {
01261       e  = CEILING( y1 );
01262       f1 = (Short)( FRAC( y1 ) );
01263       e0 = e;
01264 
01265       if ( f1 == 0 )
01266       {
01267         if ( ras.joint )
01268         {
01269           top--;
01270           ras.joint = FALSE;
01271         }
01272 
01273         *top++ = arc[degree].x;
01274 
01275         e += ras.precision;
01276       }
01277     }
01278 
01279     if ( ras.fresh )
01280     {
01281       ras.cProfile->start = TRUNC( e0 );
01282       ras.fresh = FALSE;
01283     }
01284 
01285     if ( e2 < e )
01286       goto Fin;
01287 
01288     if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
01289     {
01290       ras.top   = top;
01291       ras.error = Raster_Err_Overflow;
01292       return FAILURE;
01293     }
01294 
01295     start_arc = arc;
01296 
01297     while ( arc >= start_arc && e <= e2 )
01298     {
01299       ras.joint = FALSE;
01300 
01301       y2 = arc[0].y;
01302 
01303       if ( y2 > e )
01304       {
01305         y1 = arc[degree].y;
01306         if ( y2 - y1 >= ras.precision_step )
01307         {
01308           splitter( arc );
01309           arc += degree;
01310         }
01311         else
01312         {
01313           *top++ = arc[degree].x + FMulDiv( arc[0].x - arc[degree].x,
01314                                             e - y1, y2 - y1 );
01315           arc -= degree;
01316           e   += ras.precision;
01317         }
01318       }
01319       else
01320       {
01321         if ( y2 == e )
01322         {
01323           ras.joint  = TRUE;
01324           *top++     = arc[0].x;
01325 
01326           e += ras.precision;
01327         }
01328         arc -= degree;
01329       }
01330     }
01331 
01332   Fin:
01333     ras.top  = top;
01334     ras.arc -= degree;
01335     return SUCCESS;
01336   }
01337 
01338 
01339   /*************************************************************************/
01340   /*                                                                       */
01341   /* <Function>                                                            */
01342   /*    Bezier_Down                                                        */
01343   /*                                                                       */
01344   /* <Description>                                                         */
01345   /*    Compute the x-coordinates of an descending Bezier arc and store    */
01346   /*    them in the render pool.                                           */
01347   /*                                                                       */
01348   /* <Input>                                                               */
01349   /*    degree   :: The degree of the Bezier arc (either 2 or 3).          */
01350   /*                                                                       */
01351   /*    splitter :: The function to split Bezier arcs.                     */
01352   /*                                                                       */
01353   /*    miny     :: A lower vertical clipping bound value.                 */
01354   /*                                                                       */
01355   /*    maxy     :: An upper vertical clipping bound value.                */
01356   /*                                                                       */
01357   /* <Return>                                                              */
01358   /*    SUCCESS on success, FAILURE on render pool overflow.               */
01359   /*                                                                       */
01360   static Bool
01361   Bezier_Down( RAS_ARGS Int        degree,
01362                         TSplitter  splitter,
01363                         Long       miny,
01364                         Long       maxy )
01365   {
01366     TPoint*  arc = ras.arc;
01367     Bool     result, fresh;
01368 
01369 
01370     arc[0].y = -arc[0].y;
01371     arc[1].y = -arc[1].y;
01372     arc[2].y = -arc[2].y;
01373     if ( degree > 2 )
01374       arc[3].y = -arc[3].y;
01375 
01376     fresh = ras.fresh;
01377 
01378     result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny );
01379 
01380     if ( fresh && !ras.fresh )
01381       ras.cProfile->start = -ras.cProfile->start;
01382 
01383     arc[0].y = -arc[0].y;
01384     return result;
01385   }
01386 
01387 
01388   /*************************************************************************/
01389   /*                                                                       */
01390   /* <Function>                                                            */
01391   /*    Line_To                                                            */
01392   /*                                                                       */
01393   /* <Description>                                                         */
01394   /*    Inject a new line segment and adjust the Profiles list.            */
01395   /*                                                                       */
01396   /* <Input>                                                               */
01397   /*   x :: The x-coordinate of the segment's end point (its start point   */
01398   /*        is stored in `lastX').                                         */
01399   /*                                                                       */
01400   /*   y :: The y-coordinate of the segment's end point (its start point   */
01401   /*        is stored in `lastY').                                         */
01402   /*                                                                       */
01403   /* <Return>                                                              */
01404   /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
01405   /*   profile.                                                            */
01406   /*                                                                       */
01407   static Bool
01408   Line_To( RAS_ARGS Long  x,
01409                     Long  y )
01410   {
01411     /* First, detect a change of direction */
01412 
01413     switch ( ras.state )
01414     {
01415     case Unknown_State:
01416       if ( y > ras.lastY )
01417       {
01418         if ( New_Profile( RAS_VARS Ascending_State,
01419                                    IS_BOTTOM_OVERSHOOT( ras.lastY ) ) )
01420           return FAILURE;
01421       }
01422       else
01423       {
01424         if ( y < ras.lastY )
01425           if ( New_Profile( RAS_VARS Descending_State,
01426                                      IS_TOP_OVERSHOOT( ras.lastY ) ) )
01427             return FAILURE;
01428       }
01429       break;
01430 
01431     case Ascending_State:
01432       if ( y < ras.lastY )
01433       {
01434         if ( End_Profile( RAS_VARS IS_TOP_OVERSHOOT( ras.lastY ) ) ||
01435              New_Profile( RAS_VARS Descending_State,
01436                                    IS_TOP_OVERSHOOT( ras.lastY ) ) )
01437           return FAILURE;
01438       }
01439       break;
01440 
01441     case Descending_State:
01442       if ( y > ras.lastY )
01443       {
01444         if ( End_Profile( RAS_VARS IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ||
01445              New_Profile( RAS_VARS Ascending_State,
01446                                    IS_BOTTOM_OVERSHOOT( ras.lastY ) ) )
01447           return FAILURE;
01448       }
01449       break;
01450 
01451     default:
01452       ;
01453     }
01454 
01455     /* Then compute the lines */
01456 
01457     switch ( ras.state )
01458     {
01459     case Ascending_State:
01460       if ( Line_Up( RAS_VARS ras.lastX, ras.lastY,
01461                              x, y, ras.minY, ras.maxY ) )
01462         return FAILURE;
01463       break;
01464 
01465     case Descending_State:
01466       if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
01467                                x, y, ras.minY, ras.maxY ) )
01468         return FAILURE;
01469       break;
01470 
01471     default:
01472       ;
01473     }
01474 
01475     ras.lastX = x;
01476     ras.lastY = y;
01477 
01478     return SUCCESS;
01479   }
01480 
01481 
01482   /*************************************************************************/
01483   /*                                                                       */
01484   /* <Function>                                                            */
01485   /*    Conic_To                                                           */
01486   /*                                                                       */
01487   /* <Description>                                                         */
01488   /*    Inject a new conic arc and adjust the profile list.                */
01489   /*                                                                       */
01490   /* <Input>                                                               */
01491   /*   cx :: The x-coordinate of the arc's new control point.              */
01492   /*                                                                       */
01493   /*   cy :: The y-coordinate of the arc's new control point.              */
01494   /*                                                                       */
01495   /*   x  :: The x-coordinate of the arc's end point (its start point is   */
01496   /*         stored in `lastX').                                           */
01497   /*                                                                       */
01498   /*   y  :: The y-coordinate of the arc's end point (its start point is   */
01499   /*         stored in `lastY').                                           */
01500   /*                                                                       */
01501   /* <Return>                                                              */
01502   /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
01503   /*   profile.                                                            */
01504   /*                                                                       */
01505   static Bool
01506   Conic_To( RAS_ARGS Long  cx,
01507                      Long  cy,
01508                      Long  x,
01509                      Long  y )
01510   {
01511     Long     y1, y2, y3, x3, ymin, ymax;
01512     TStates  state_bez;
01513 
01514 
01515     ras.arc      = ras.arcs;
01516     ras.arc[2].x = ras.lastX;
01517     ras.arc[2].y = ras.lastY;
01518     ras.arc[1].x = cx;
01519     ras.arc[1].y = cy;
01520     ras.arc[0].x = x;
01521     ras.arc[0].y = y;
01522 
01523     do
01524     {
01525       y1 = ras.arc[2].y;
01526       y2 = ras.arc[1].y;
01527       y3 = ras.arc[0].y;
01528       x3 = ras.arc[0].x;
01529 
01530       /* first, categorize the Bezier arc */
01531 
01532       if ( y1 <= y3 )
01533       {
01534         ymin = y1;
01535         ymax = y3;
01536       }
01537       else
01538       {
01539         ymin = y3;
01540         ymax = y1;
01541       }
01542 
01543       if ( y2 < ymin || y2 > ymax )
01544       {
01545         /* this arc has no given direction, split it! */
01546         Split_Conic( ras.arc );
01547         ras.arc += 2;
01548       }
01549       else if ( y1 == y3 )
01550       {
01551         /* this arc is flat, ignore it and pop it from the Bezier stack */
01552         ras.arc -= 2;
01553       }
01554       else
01555       {
01556         /* the arc is y-monotonous, either ascending or descending */
01557         /* detect a change of direction                            */
01558         state_bez = y1 < y3 ? Ascending_State : Descending_State;
01559         if ( ras.state != state_bez )
01560         {
01561           Bool  o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 )
01562                                                  : IS_TOP_OVERSHOOT( y1 );
01563 
01564 
01565           /* finalize current profile if any */
01566           if ( ras.state != Unknown_State &&
01567                End_Profile( RAS_VARS o )  )
01568             goto Fail;
01569 
01570           /* create a new profile */
01571           if ( New_Profile( RAS_VARS state_bez, o ) )
01572             goto Fail;
01573         }
01574 
01575         /* now call the appropriate routine */
01576         if ( state_bez == Ascending_State )
01577         {
01578           if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
01579             goto Fail;
01580         }
01581         else
01582           if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
01583             goto Fail;
01584       }
01585 
01586     } while ( ras.arc >= ras.arcs );
01587 
01588     ras.lastX = x3;
01589     ras.lastY = y3;
01590 
01591     return SUCCESS;
01592 
01593   Fail:
01594     return FAILURE;
01595   }
01596 
01597 
01598   /*************************************************************************/
01599   /*                                                                       */
01600   /* <Function>                                                            */
01601   /*    Cubic_To                                                           */
01602   /*                                                                       */
01603   /* <Description>                                                         */
01604   /*    Inject a new cubic arc and adjust the profile list.                */
01605   /*                                                                       */
01606   /* <Input>                                                               */
01607   /*   cx1 :: The x-coordinate of the arc's first new control point.       */
01608   /*                                                                       */
01609   /*   cy1 :: The y-coordinate of the arc's first new control point.       */
01610   /*                                                                       */
01611   /*   cx2 :: The x-coordinate of the arc's second new control point.      */
01612   /*                                                                       */
01613   /*   cy2 :: The y-coordinate of the arc's second new control point.      */
01614   /*                                                                       */
01615   /*   x   :: The x-coordinate of the arc's end point (its start point is  */
01616   /*          stored in `lastX').                                          */
01617   /*                                                                       */
01618   /*   y   :: The y-coordinate of the arc's end point (its start point is  */
01619   /*          stored in `lastY').                                          */
01620   /*                                                                       */
01621   /* <Return>                                                              */
01622   /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
01623   /*   profile.                                                            */
01624   /*                                                                       */
01625   static Bool
01626   Cubic_To( RAS_ARGS Long  cx1,
01627                      Long  cy1,
01628                      Long  cx2,
01629                      Long  cy2,
01630                      Long  x,
01631                      Long  y )
01632   {
01633     Long     y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2;
01634     TStates  state_bez;
01635 
01636 
01637     ras.arc      = ras.arcs;
01638     ras.arc[3].x = ras.lastX;
01639     ras.arc[3].y = ras.lastY;
01640     ras.arc[2].x = cx1;
01641     ras.arc[2].y = cy1;
01642     ras.arc[1].x = cx2;
01643     ras.arc[1].y = cy2;
01644     ras.arc[0].x = x;
01645     ras.arc[0].y = y;
01646 
01647     do
01648     {
01649       y1 = ras.arc[3].y;
01650       y2 = ras.arc[2].y;
01651       y3 = ras.arc[1].y;
01652       y4 = ras.arc[0].y;
01653       x4 = ras.arc[0].x;
01654 
01655       /* first, categorize the Bezier arc */
01656 
01657       if ( y1 <= y4 )
01658       {
01659         ymin1 = y1;
01660         ymax1 = y4;
01661       }
01662       else
01663       {
01664         ymin1 = y4;
01665         ymax1 = y1;
01666       }
01667 
01668       if ( y2 <= y3 )
01669       {
01670         ymin2 = y2;
01671         ymax2 = y3;
01672       }
01673       else
01674       {
01675         ymin2 = y3;
01676         ymax2 = y2;
01677       }
01678 
01679       if ( ymin2 < ymin1 || ymax2 > ymax1 )
01680       {
01681         /* this arc has no given direction, split it! */
01682         Split_Cubic( ras.arc );
01683         ras.arc += 3;
01684       }
01685       else if ( y1 == y4 )
01686       {
01687         /* this arc is flat, ignore it and pop it from the Bezier stack */
01688         ras.arc -= 3;
01689       }
01690       else
01691       {
01692         state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State;
01693 
01694         /* detect a change of direction */
01695         if ( ras.state != state_bez )
01696         {
01697           Bool  o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 )
01698                                                  : IS_TOP_OVERSHOOT( y1 );
01699 
01700 
01701           /* finalize current profile if any */
01702           if ( ras.state != Unknown_State &&
01703                End_Profile( RAS_VARS o )  )
01704             goto Fail;
01705 
01706           if ( New_Profile( RAS_VARS state_bez, o ) )
01707             goto Fail;
01708         }
01709 
01710         /* compute intersections */
01711         if ( state_bez == Ascending_State )
01712         {
01713           if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
01714             goto Fail;
01715         }
01716         else
01717           if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
01718             goto Fail;
01719       }
01720 
01721     } while ( ras.arc >= ras.arcs );
01722 
01723     ras.lastX = x4;
01724     ras.lastY = y4;
01725 
01726     return SUCCESS;
01727 
01728   Fail:
01729     return FAILURE;
01730   }
01731 
01732 
01733 #undef  SWAP_
01734 #define SWAP_( x, y )  do                \
01735                        {                 \
01736                          Long  swap = x; \
01737                                          \
01738                                          \
01739                          x = y;          \
01740                          y = swap;       \
01741                        } while ( 0 )
01742 
01743 
01744   /*************************************************************************/
01745   /*                                                                       */
01746   /* <Function>                                                            */
01747   /*    Decompose_Curve                                                    */
01748   /*                                                                       */
01749   /* <Description>                                                         */
01750   /*    Scan the outline arrays in order to emit individual segments and   */
01751   /*    Beziers by calling Line_To() and Bezier_To().  It handles all      */
01752   /*    weird cases, like when the first point is off the curve, or when   */
01753   /*    there are simply no `on' points in the contour!                    */
01754   /*                                                                       */
01755   /* <Input>                                                               */
01756   /*    first   :: The index of the first point in the contour.            */
01757   /*                                                                       */
01758   /*    last    :: The index of the last point in the contour.             */
01759   /*                                                                       */
01760   /*    flipped :: If set, flip the direction of the curve.                */
01761   /*                                                                       */
01762   /* <Return>                                                              */
01763   /*    SUCCESS on success, FAILURE on error.                              */
01764   /*                                                                       */
01765   static Bool
01766   Decompose_Curve( RAS_ARGS UShort  first,
01767                             UShort  last,
01768                             int     flipped )
01769   {
01770     FT_Vector   v_last;
01771     FT_Vector   v_control;
01772     FT_Vector   v_start;
01773 
01774     FT_Vector*  points;
01775     FT_Vector*  point;
01776     FT_Vector*  limit;
01777     char*       tags;
01778 
01779     unsigned    tag;       /* current point's state           */
01780 
01781 
01782     points = ras.outline.points;
01783     limit  = points + last;
01784 
01785     v_start.x = SCALED( points[first].x );
01786     v_start.y = SCALED( points[first].y );
01787     v_last.x  = SCALED( points[last].x );
01788     v_last.y  = SCALED( points[last].y );
01789 
01790     if ( flipped )
01791     {
01792       SWAP_( v_start.x, v_start.y );
01793       SWAP_( v_last.x, v_last.y );
01794     }
01795 
01796     v_control = v_start;
01797 
01798     point = points + first;
01799     tags  = ras.outline.tags + first;
01800 
01801     /* set scan mode if necessary */
01802     if ( tags[0] & FT_CURVE_TAG_HAS_SCANMODE )
01803       ras.dropOutControl = (Byte)tags[0] >> 5;
01804 
01805     tag = FT_CURVE_TAG( tags[0] );
01806 
01807     /* A contour cannot start with a cubic control point! */
01808     if ( tag == FT_CURVE_TAG_CUBIC )
01809       goto Invalid_Outline;
01810 
01811     /* check first point to determine origin */
01812     if ( tag == FT_CURVE_TAG_CONIC )
01813     {
01814       /* first point is conic control.  Yes, this happens. */
01815       if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON )
01816       {
01817         /* start at last point if it is on the curve */
01818         v_start = v_last;
01819         limit--;
01820       }
01821       else
01822       {
01823         /* if both first and last points are conic,         */
01824         /* start at their middle and record its position    */
01825         /* for closure                                      */
01826         v_start.x = ( v_start.x + v_last.x ) / 2;
01827         v_start.y = ( v_start.y + v_last.y ) / 2;
01828 
01829         v_last = v_start;
01830       }
01831       point--;
01832       tags--;
01833     }
01834 
01835     ras.lastX = v_start.x;
01836     ras.lastY = v_start.y;
01837 
01838     while ( point < limit )
01839     {
01840       point++;
01841       tags++;
01842 
01843       tag = FT_CURVE_TAG( tags[0] );
01844 
01845       switch ( tag )
01846       {
01847       case FT_CURVE_TAG_ON:  /* emit a single line_to */
01848         {
01849           Long  x, y;
01850 
01851 
01852           x = SCALED( point->x );
01853           y = SCALED( point->y );
01854           if ( flipped )
01855             SWAP_( x, y );
01856 
01857           if ( Line_To( RAS_VARS x, y ) )
01858             goto Fail;
01859           continue;
01860         }
01861 
01862       case FT_CURVE_TAG_CONIC:  /* consume conic arcs */
01863         v_control.x = SCALED( point[0].x );
01864         v_control.y = SCALED( point[0].y );
01865 
01866         if ( flipped )
01867           SWAP_( v_control.x, v_control.y );
01868 
01869       Do_Conic:
01870         if ( point < limit )
01871         {
01872           FT_Vector  v_middle;
01873           Long       x, y;
01874 
01875 
01876           point++;
01877           tags++;
01878           tag = FT_CURVE_TAG( tags[0] );
01879 
01880           x = SCALED( point[0].x );
01881           y = SCALED( point[0].y );
01882 
01883           if ( flipped )
01884             SWAP_( x, y );
01885 
01886           if ( tag == FT_CURVE_TAG_ON )
01887           {
01888             if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) )
01889               goto Fail;
01890             continue;
01891           }
01892 
01893           if ( tag != FT_CURVE_TAG_CONIC )
01894             goto Invalid_Outline;
01895 
01896           v_middle.x = ( v_control.x + x ) / 2;
01897           v_middle.y = ( v_control.y + y ) / 2;
01898 
01899           if ( Conic_To( RAS_VARS v_control.x, v_control.y,
01900                                   v_middle.x,  v_middle.y ) )
01901             goto Fail;
01902 
01903           v_control.x = x;
01904           v_control.y = y;
01905 
01906           goto Do_Conic;
01907         }
01908 
01909         if ( Conic_To( RAS_VARS v_control.x, v_control.y,
01910                                 v_start.x,   v_start.y ) )
01911           goto Fail;
01912 
01913         goto Close;
01914 
01915       default:  /* FT_CURVE_TAG_CUBIC */
01916         {
01917           Long  x1, y1, x2, y2, x3, y3;
01918 
01919 
01920           if ( point + 1 > limit                             ||
01921                FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
01922             goto Invalid_Outline;
01923 
01924           point += 2;
01925           tags  += 2;
01926 
01927           x1 = SCALED( point[-2].x );
01928           y1 = SCALED( point[-2].y );
01929           x2 = SCALED( point[-1].x );
01930           y2 = SCALED( point[-1].y );
01931 
01932           if ( flipped )
01933           {
01934             SWAP_( x1, y1 );
01935             SWAP_( x2, y2 );
01936           }
01937 
01938           if ( point <= limit )
01939           {
01940             x3 = SCALED( point[0].x );
01941             y3 = SCALED( point[0].y );
01942 
01943             if ( flipped )
01944               SWAP_( x3, y3 );
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   /*************************************************************************/
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      FT_UNUSED( memory );
03386 
03387 
03388      *araster = (FT_Raster)&the_raster;
03389      FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
03390      ft_black_init( &the_raster );
03391 
03392      return 0;
03393   }
03394 
03395 
03396   static void
03397   ft_black_done( FT_Raster  raster )
03398   {
03399     /* nothing */
03400     FT_UNUSED( raster );
03401   }
03402 
03403 
03404 #else /* !_STANDALONE_ */
03405 
03406 
03407   static int
03408   ft_black_new( FT_Memory   memory,
03409                 PRaster    *araster )
03410   {
03411     FT_Error  error;
03412     PRaster   raster = NULL;
03413 
03414 
03415     *araster = 0;
03416     if ( !FT_NEW( raster ) )
03417     {
03418       raster->memory = memory;
03419       ft_black_init( raster );
03420 
03421       *araster = raster;
03422     }
03423 
03424     return error;
03425   }
03426 
03427 
03428   static void
03429   ft_black_done( PRaster  raster )
03430   {
03431     FT_Memory  memory = (FT_Memory)raster->memory;
03432     FT_FREE( raster );
03433   }
03434 
03435 
03436 #endif /* !_STANDALONE_ */
03437 
03438 
03439   static void
03440   ft_black_reset( PRaster  raster,
03441                   char*    pool_base,
03442                   long     pool_size )
03443   {
03444     if ( raster )
03445     {
03446       if ( pool_base && pool_size >= (long)sizeof(TWorker) + 2048 )
03447       {
03448         PWorker  worker = (PWorker)pool_base;
03449 
03450 
03451         raster->buffer      = pool_base + ( ( sizeof ( *worker ) + 7 ) & ~7 );
03452         raster->buffer_size = pool_base + pool_size - (char*)raster->buffer;
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 Sat May 26 2012 04:32:55 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.