/src/freetype/src/raster/ftraster.c
https://bitbucket.org/cabalistic/ogredeps/ · C · 3612 lines · 2079 code · 732 blank · 801 comment · 336 complexity · 7039c09154560704ab85e1459afc4098 MD5 · raw file
Large files are truncated click here to view the full file
- /***************************************************************************/
- /* */
- /* ftraster.c */
- /* */
- /* The FreeType glyph rasterizer (body). */
- /* */
- /* Copyright 1996-2003, 2005, 2007-2012 by */
- /* David Turner, Robert Wilhelm, and Werner Lemberg. */
- /* */
- /* This file is part of the FreeType project, and may only be used, */
- /* modified, and distributed under the terms of the FreeType project */
- /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
- /* this file you indicate that you have read the license and */
- /* understand and accept it fully. */
- /* */
- /***************************************************************************/
- /*************************************************************************/
- /* */
- /* This file can be compiled without the rest of the FreeType engine, by */
- /* defining the _STANDALONE_ macro when compiling it. You also need to */
- /* put the files `ftimage.h' and `ftmisc.h' into the $(incdir) */
- /* directory. Typically, you should do something like */
- /* */
- /* - copy `src/raster/ftraster.c' (this file) to your current directory */
- /* */
- /* - copy `include/freetype/ftimage.h' and `src/raster/ftmisc.h' */
- /* to your current directory */
- /* */
- /* - compile `ftraster' with the _STANDALONE_ macro defined, as in */
- /* */
- /* cc -c -D_STANDALONE_ ftraster.c */
- /* */
- /* The renderer can be initialized with a call to */
- /* `ft_standard_raster.raster_new'; a bitmap can be generated */
- /* with a call to `ft_standard_raster.raster_render'. */
- /* */
- /* See the comments and documentation in the file `ftimage.h' for more */
- /* details on how the raster works. */
- /* */
- /*************************************************************************/
- /*************************************************************************/
- /* */
- /* This is a rewrite of the FreeType 1.x scan-line converter */
- /* */
- /*************************************************************************/
- #ifdef _STANDALONE_
- #define FT_CONFIG_STANDARD_LIBRARY_H <stdlib.h>
- #include <string.h> /* for memset */
- #include "ftmisc.h"
- #include "ftimage.h"
- #else /* !_STANDALONE_ */
- #include <ft2build.h>
- #include "ftraster.h"
- #include FT_INTERNAL_CALC_H /* for FT_MulDiv only */
- #include "rastpic.h"
- #endif /* !_STANDALONE_ */
- /*************************************************************************/
- /* */
- /* A simple technical note on how the raster works */
- /* ----------------------------------------------- */
- /* */
- /* Converting an outline into a bitmap is achieved in several steps: */
- /* */
- /* 1 - Decomposing the outline into successive `profiles'. Each */
- /* profile is simply an array of scanline intersections on a given */
- /* dimension. A profile's main attributes are */
- /* */
- /* o its scanline position boundaries, i.e. `Ymin' and `Ymax' */
- /* */
- /* o an array of intersection coordinates for each scanline */
- /* between `Ymin' and `Ymax' */
- /* */
- /* o a direction, indicating whether it was built going `up' or */
- /* `down', as this is very important for filling rules */
- /* */
- /* o its drop-out mode */
- /* */
- /* 2 - Sweeping the target map's scanlines in order to compute segment */
- /* `spans' which are then filled. Additionally, this pass */
- /* performs drop-out control. */
- /* */
- /* The outline data is parsed during step 1 only. The profiles are */
- /* built from the bottom of the render pool, used as a stack. The */
- /* following graphics shows the profile list under construction: */
- /* */
- /* __________________________________________________________ _ _ */
- /* | | | | | */
- /* | profile | coordinates for | profile | coordinates for |--> */
- /* | 1 | profile 1 | 2 | profile 2 |--> */
- /* |_________|_________________|_________|_________________|__ _ _ */
- /* */
- /* ^ ^ */
- /* | | */
- /* start of render pool top */
- /* */
- /* The top of the profile stack is kept in the `top' variable. */
- /* */
- /* As you can see, a profile record is pushed on top of the render */
- /* pool, which is then followed by its coordinates/intersections. If */
- /* a change of direction is detected in the outline, a new profile is */
- /* generated until the end of the outline. */
- /* */
- /* Note that when all profiles have been generated, the function */
- /* Finalize_Profile_Table() is used to record, for each profile, its */
- /* bottom-most scanline as well as the scanline above its upmost */
- /* boundary. These positions are called `y-turns' because they (sort */
- /* of) correspond to local extrema. They are stored in a sorted list */
- /* built from the top of the render pool as a downwards stack: */
- /* */
- /* _ _ _______________________________________ */
- /* | | */
- /* <--| sorted list of | */
- /* <--| extrema scanlines | */
- /* _ _ __________________|____________________| */
- /* */
- /* ^ ^ */
- /* | | */
- /* maxBuff sizeBuff = end of pool */
- /* */
- /* This list is later used during the sweep phase in order to */
- /* optimize performance (see technical note on the sweep below). */
- /* */
- /* Of course, the raster detects whether the two stacks collide and */
- /* handles the situation properly. */
- /* */
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
- /** **/
- /** CONFIGURATION MACROS **/
- /** **/
- /*************************************************************************/
- /*************************************************************************/
- /* define DEBUG_RASTER if you want to compile a debugging version */
- /* #define DEBUG_RASTER */
- /* define FT_RASTER_OPTION_ANTI_ALIASING if you want to support */
- /* 5-levels anti-aliasing */
- /* #define FT_RASTER_OPTION_ANTI_ALIASING */
- /* The size of the two-lines intermediate bitmap used */
- /* for anti-aliasing, in bytes. */
- #define RASTER_GRAY_LINES 2048
- /*************************************************************************/
- /*************************************************************************/
- /** **/
- /** OTHER MACROS (do not change) **/
- /** **/
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
- /* */
- /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
- /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
- /* messages during execution. */
- /* */
- #undef FT_COMPONENT
- #define FT_COMPONENT trace_raster
- #ifdef _STANDALONE_
- /* This macro is used to indicate that a function parameter is unused. */
- /* Its purpose is simply to reduce compiler warnings. Note also that */
- /* simply defining it as `(void)x' doesn't avoid warnings with certain */
- /* ANSI compilers (e.g. LCC). */
- #define FT_UNUSED( x ) (x) = (x)
- /* Disable the tracing mechanism for simplicity -- developers can */
- /* activate it easily by redefining these two macros. */
- #ifndef FT_ERROR
- #define FT_ERROR( x ) do { } while ( 0 ) /* nothing */
- #endif
- #ifndef FT_TRACE
- #define FT_TRACE( x ) do { } while ( 0 ) /* nothing */
- #define FT_TRACE1( x ) do { } while ( 0 ) /* nothing */
- #define FT_TRACE6( x ) do { } while ( 0 ) /* nothing */
- #endif
- #define Raster_Err_None 0
- #define Raster_Err_Not_Ini -1
- #define Raster_Err_Overflow -2
- #define Raster_Err_Neg_Height -3
- #define Raster_Err_Invalid -4
- #define Raster_Err_Unsupported -5
- #define ft_memset memset
- #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, raster_new_, \
- raster_reset_, raster_set_mode_, \
- raster_render_, raster_done_ ) \
- const FT_Raster_Funcs class_ = \
- { \
- glyph_format_, \
- raster_new_, \
- raster_reset_, \
- raster_set_mode_, \
- raster_render_, \
- raster_done_ \
- };
- #else /* !_STANDALONE_ */
- #include FT_INTERNAL_OBJECTS_H
- #include FT_INTERNAL_DEBUG_H /* for FT_TRACE() and FT_ERROR() */
- #include "rasterrs.h"
- #define Raster_Err_None Raster_Err_Ok
- #define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized
- #define Raster_Err_Overflow Raster_Err_Raster_Overflow
- #define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height
- #define Raster_Err_Invalid Raster_Err_Invalid_Outline
- #define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph
- #endif /* !_STANDALONE_ */
- #ifndef FT_MEM_SET
- #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
- #endif
- #ifndef FT_MEM_ZERO
- #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count )
- #endif
- /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */
- /* typically a small value and the result of a*b is known to fit into */
- /* 32 bits. */
- #define FMulDiv( a, b, c ) ( (a) * (b) / (c) )
- /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
- /* for clipping computations. It simply uses the FT_MulDiv() function */
- /* defined in `ftcalc.h'. */
- #define SMulDiv FT_MulDiv
- /* The rasterizer is a very general purpose component; please leave */
- /* the following redefinitions there (you never know your target */
- /* environment). */
- #ifndef TRUE
- #define TRUE 1
- #endif
- #ifndef FALSE
- #define FALSE 0
- #endif
- #ifndef NULL
- #define NULL (void*)0
- #endif
- #ifndef SUCCESS
- #define SUCCESS 0
- #endif
- #ifndef FAILURE
- #define FAILURE 1
- #endif
- #define MaxBezier 32 /* The maximum number of stacked Bezier curves. */
- /* Setting this constant to more than 32 is a */
- /* pure waste of space. */
- #define Pixel_Bits 6 /* fractional bits of *input* coordinates */
- /*************************************************************************/
- /*************************************************************************/
- /** **/
- /** SIMPLE TYPE DECLARATIONS **/
- /** **/
- /*************************************************************************/
- /*************************************************************************/
- typedef int Int;
- typedef unsigned int UInt;
- typedef short Short;
- typedef unsigned short UShort, *PUShort;
- typedef long Long, *PLong;
- typedef unsigned char Byte, *PByte;
- typedef char Bool;
- typedef union Alignment_
- {
- long l;
- void* p;
- void (*f)(void);
- } Alignment, *PAlignment;
- typedef struct TPoint_
- {
- Long x;
- Long y;
- } TPoint;
- /* values for the `flags' bit field */
- #define Flow_Up 0x8
- #define Overshoot_Top 0x10
- #define Overshoot_Bottom 0x20
- /* States of each line, arc, and profile */
- typedef enum TStates_
- {
- Unknown_State,
- Ascending_State,
- Descending_State,
- Flat_State
- } TStates;
- typedef struct TProfile_ TProfile;
- typedef TProfile* PProfile;
- struct TProfile_
- {
- FT_F26Dot6 X; /* current coordinate during sweep */
- PProfile link; /* link to next profile (various purposes) */
- PLong offset; /* start of profile's data in render pool */
- unsigned flags; /* Bit 0-2: drop-out mode */
- /* Bit 3: profile orientation (up/down) */
- /* Bit 4: is top profile? */
- /* Bit 5: is bottom profile? */
- long height; /* profile's height in scanlines */
- long start; /* profile's starting scanline */
- unsigned countL; /* number of lines to step before this */
- /* profile becomes drawable */
- PProfile next; /* next profile in same contour, used */
- /* during drop-out control */
- };
- typedef PProfile TProfileList;
- typedef PProfile* PProfileList;
- /* Simple record used to implement a stack of bands, required */
- /* by the sub-banding mechanism */
- typedef struct black_TBand_
- {
- Short y_min; /* band's minimum */
- Short y_max; /* band's maximum */
- } black_TBand;
- #define AlignProfileSize \
- ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( long ) )
- #undef RAS_ARG
- #undef RAS_ARGS
- #undef RAS_VAR
- #undef RAS_VARS
- #ifdef FT_STATIC_RASTER
- #define RAS_ARGS /* void */
- #define RAS_ARG /* void */
- #define RAS_VARS /* void */
- #define RAS_VAR /* void */
- #define FT_UNUSED_RASTER do { } while ( 0 )
- #else /* !FT_STATIC_RASTER */
- #define RAS_ARGS black_PWorker worker,
- #define RAS_ARG black_PWorker worker
- #define RAS_VARS worker,
- #define RAS_VAR worker
- #define FT_UNUSED_RASTER FT_UNUSED( worker )
- #endif /* !FT_STATIC_RASTER */
- typedef struct black_TWorker_ black_TWorker, *black_PWorker;
- /* prototypes used for sweep function dispatch */
- typedef void
- Function_Sweep_Init( RAS_ARGS Short* min,
- Short* max );
- typedef void
- Function_Sweep_Span( RAS_ARGS Short y,
- FT_F26Dot6 x1,
- FT_F26Dot6 x2,
- PProfile left,
- PProfile right );
- typedef void
- Function_Sweep_Step( RAS_ARG );
- /* NOTE: These operations are only valid on 2's complement processors */
- #undef FLOOR
- #undef CEILING
- #undef TRUNC
- #undef SCALED
- #define FLOOR( x ) ( (x) & -ras.precision )
- #define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision )
- #define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits )
- #define FRAC( x ) ( (x) & ( ras.precision - 1 ) )
- #define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half )
- #define IS_BOTTOM_OVERSHOOT( x ) ( CEILING( x ) - x >= ras.precision_half )
- #define IS_TOP_OVERSHOOT( x ) ( x - FLOOR( x ) >= ras.precision_half )
- /* The most used variables are positioned at the top of the structure. */
- /* Thus, their offset can be coded with less opcodes, resulting in a */
- /* smaller executable. */
- struct black_TWorker_
- {
- Int precision_bits; /* precision related variables */
- Int precision;
- Int precision_half;
- Int precision_shift;
- Int precision_step;
- Int precision_jitter;
- Int scale_shift; /* == precision_shift for bitmaps */
- /* == precision_shift+1 for pixmaps */
- PLong buff; /* The profiles buffer */
- PLong sizeBuff; /* Render pool size */
- PLong maxBuff; /* Profiles buffer size */
- PLong top; /* Current cursor in buffer */
- FT_Error error;
- Int numTurns; /* number of Y-turns in outline */
- TPoint* arc; /* current Bezier arc pointer */
- UShort bWidth; /* target bitmap width */
- PByte bTarget; /* target bitmap buffer */
- PByte gTarget; /* target pixmap buffer */
- Long lastX, lastY;
- Long minY, maxY;
- UShort num_Profs; /* current number of profiles */
- Bool fresh; /* signals a fresh new profile which */
- /* `start' field must be completed */
- Bool joint; /* signals that the last arc ended */
- /* exactly on a scanline. Allows */
- /* removal of doublets */
- PProfile cProfile; /* current profile */
- PProfile fProfile; /* head of linked list of profiles */
- PProfile gProfile; /* contour's first profile in case */
- /* of impact */
- TStates state; /* rendering state */
- FT_Bitmap target; /* description of target bit/pixmap */
- FT_Outline outline;
- Long traceOfs; /* current offset in target bitmap */
- Long traceG; /* current offset in target pixmap */
- Short traceIncr; /* sweep's increment in target bitmap */
- Short gray_min_x; /* current min x during gray rendering */
- Short gray_max_x; /* current max x during gray rendering */
- /* dispatch variables */
- Function_Sweep_Init* Proc_Sweep_Init;
- Function_Sweep_Span* Proc_Sweep_Span;
- Function_Sweep_Span* Proc_Sweep_Drop;
- Function_Sweep_Step* Proc_Sweep_Step;
- Byte dropOutControl; /* current drop_out control method */
- Bool second_pass; /* indicates whether a horizontal pass */
- /* should be performed to control */
- /* drop-out accurately when calling */
- /* Render_Glyph. Note that there is */
- /* no horizontal pass during gray */
- /* rendering. */
- TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */
- black_TBand band_stack[16]; /* band stack used for sub-banding */
- Int band_top; /* band stack top */
- #ifdef FT_RASTER_OPTION_ANTI_ALIASING
- Byte* grays;
- Byte gray_lines[RASTER_GRAY_LINES];
- /* Intermediate table used to render the */
- /* graylevels pixmaps. */
- /* gray_lines is a buffer holding two */
- /* monochrome scanlines */
- Short gray_width; /* width in bytes of one monochrome */
- /* intermediate scanline of gray_lines. */
- /* Each gray pixel takes 2 bits long there */
- /* The gray_lines must hold 2 lines, thus with size */
- /* in bytes of at least `gray_width*2'. */
- #endif /* FT_RASTER_ANTI_ALIASING */
- };
- typedef struct black_TRaster_
- {
- char* buffer;
- long buffer_size;
- void* memory;
- black_PWorker worker;
- Byte grays[5];
- Short gray_width;
- } black_TRaster, *black_PRaster;
- #ifdef FT_STATIC_RASTER
- static black_TWorker cur_ras;
- #define ras cur_ras
- #else /* !FT_STATIC_RASTER */
- #define ras (*worker)
- #endif /* !FT_STATIC_RASTER */
- #ifdef FT_RASTER_OPTION_ANTI_ALIASING
- /* A lookup table used to quickly count set bits in four gray 2x2 */
- /* cells. The values of the table have been produced with the */
- /* following code: */
- /* */
- /* for ( i = 0; i < 256; i++ ) */
- /* { */
- /* l = 0; */
- /* j = i; */
- /* */
- /* for ( c = 0; c < 4; c++ ) */
- /* { */
- /* l <<= 4; */
- /* */
- /* if ( j & 0x80 ) l++; */
- /* if ( j & 0x40 ) l++; */
- /* */
- /* j = ( j << 2 ) & 0xFF; */
- /* } */
- /* printf( "0x%04X", l ); */
- /* } */
- /* */
- static const short count_table[256] =
- {
- 0x0000, 0x0001, 0x0001, 0x0002, 0x0010, 0x0011, 0x0011, 0x0012,
- 0x0010, 0x0011, 0x0011, 0x0012, 0x0020, 0x0021, 0x0021, 0x0022,
- 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
- 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
- 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
- 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
- 0x0200, 0x0201, 0x0201, 0x0202, 0x0210, 0x0211, 0x0211, 0x0212,
- 0x0210, 0x0211, 0x0211, 0x0212, 0x0220, 0x0221, 0x0221, 0x0222,
- 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
- 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
- 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
- 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
- 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
- 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
- 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
- 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
- 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
- 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
- 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
- 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
- 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
- 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
- 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
- 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
- 0x2000, 0x2001, 0x2001, 0x2002, 0x2010, 0x2011, 0x2011, 0x2012,
- 0x2010, 0x2011, 0x2011, 0x2012, 0x2020, 0x2021, 0x2021, 0x2022,
- 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
- 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
- 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
- 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
- 0x2200, 0x2201, 0x2201, 0x2202, 0x2210, 0x2211, 0x2211, 0x2212,
- 0x2210, 0x2211, 0x2211, 0x2212, 0x2220, 0x2221, 0x2221, 0x2222
- };
- #endif /* FT_RASTER_OPTION_ANTI_ALIASING */
- /*************************************************************************/
- /*************************************************************************/
- /** **/
- /** PROFILES COMPUTATION **/
- /** **/
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Set_High_Precision */
- /* */
- /* <Description> */
- /* Set precision variables according to param flag. */
- /* */
- /* <Input> */
- /* High :: Set to True for high precision (typically for ppem < 18), */
- /* false otherwise. */
- /* */
- static void
- Set_High_Precision( RAS_ARGS Int High )
- {
- /*
- * `precision_step' is used in `Bezier_Up' to decide when to split a
- * given y-monotonous Bezier arc that crosses a scanline before
- * approximating it as a straight segment. The default value of 32 (for
- * low accuracy) corresponds to
- *
- * 32 / 64 == 0.5 pixels ,
- *
- * while for the high accuracy case we have
- *
- * 256/ (1 << 12) = 0.0625 pixels .
- *
- * `precision_jitter' is an epsilon threshold used in
- * `Vertical_Sweep_Span' to deal with small imperfections in the Bezier
- * decomposition (after all, we are working with approximations only);
- * it avoids switching on additional pixels which would cause artifacts
- * otherwise.
- *
- * The value of `precision_jitter' has been determined heuristically.
- *
- */
- if ( High )
- {
- ras.precision_bits = 12;
- ras.precision_step = 256;
- ras.precision_jitter = 30;
- }
- else
- {
- ras.precision_bits = 6;
- ras.precision_step = 32;
- ras.precision_jitter = 2;
- }
- FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
- ras.precision = 1 << ras.precision_bits;
- ras.precision_half = ras.precision / 2;
- ras.precision_shift = ras.precision_bits - Pixel_Bits;
- }
- /*************************************************************************/
- /* */
- /* <Function> */
- /* New_Profile */
- /* */
- /* <Description> */
- /* Create a new profile in the render pool. */
- /* */
- /* <Input> */
- /* aState :: The state/orientation of the new profile. */
- /* */
- /* overshoot :: Whether the profile's unrounded start position */
- /* differs by at least a half pixel. */
- /* */
- /* <Return> */
- /* SUCCESS on success. FAILURE in case of overflow or of incoherent */
- /* profile. */
- /* */
- static Bool
- New_Profile( RAS_ARGS TStates aState,
- Bool overshoot )
- {
- if ( !ras.fProfile )
- {
- ras.cProfile = (PProfile)ras.top;
- ras.fProfile = ras.cProfile;
- ras.top += AlignProfileSize;
- }
- if ( ras.top >= ras.maxBuff )
- {
- ras.error = Raster_Err_Overflow;
- return FAILURE;
- }
- ras.cProfile->flags = 0;
- ras.cProfile->start = 0;
- ras.cProfile->height = 0;
- ras.cProfile->offset = ras.top;
- ras.cProfile->link = (PProfile)0;
- ras.cProfile->next = (PProfile)0;
- ras.cProfile->flags = ras.dropOutControl;
- switch ( aState )
- {
- case Ascending_State:
- ras.cProfile->flags |= Flow_Up;
- if ( overshoot )
- ras.cProfile->flags |= Overshoot_Bottom;
- FT_TRACE6(( "New ascending profile = %p\n", ras.cProfile ));
- break;
- case Descending_State:
- if ( overshoot )
- ras.cProfile->flags |= Overshoot_Top;
- FT_TRACE6(( "New descending profile = %p\n", ras.cProfile ));
- break;
- default:
- FT_ERROR(( "New_Profile: invalid profile direction\n" ));
- ras.error = Raster_Err_Invalid;
- return FAILURE;
- }
- if ( !ras.gProfile )
- ras.gProfile = ras.cProfile;
- ras.state = aState;
- ras.fresh = TRUE;
- ras.joint = FALSE;
- return SUCCESS;
- }
- /*************************************************************************/
- /* */
- /* <Function> */
- /* End_Profile */
- /* */
- /* <Description> */
- /* Finalize the current profile. */
- /* */
- /* <Input> */
- /* overshoot :: Whether the profile's unrounded end position differs */
- /* by at least a half pixel. */
- /* */
- /* <Return> */
- /* SUCCESS on success. FAILURE in case of overflow or incoherency. */
- /* */
- static Bool
- End_Profile( RAS_ARGS Bool overshoot )
- {
- Long h;
- PProfile oldProfile;
- h = (Long)( ras.top - ras.cProfile->offset );
- if ( h < 0 )
- {
- FT_ERROR(( "End_Profile: negative height encountered\n" ));
- ras.error = Raster_Err_Neg_Height;
- return FAILURE;
- }
- if ( h > 0 )
- {
- FT_TRACE6(( "Ending profile %p, start = %ld, height = %ld\n",
- ras.cProfile, ras.cProfile->start, h ));
- ras.cProfile->height = h;
- if ( overshoot )
- {
- if ( ras.cProfile->flags & Flow_Up )
- ras.cProfile->flags |= Overshoot_Top;
- else
- ras.cProfile->flags |= Overshoot_Bottom;
- }
- oldProfile = ras.cProfile;
- ras.cProfile = (PProfile)ras.top;
- ras.top += AlignProfileSize;
- ras.cProfile->height = 0;
- ras.cProfile->offset = ras.top;
- oldProfile->next = ras.cProfile;
- ras.num_Profs++;
- }
- if ( ras.top >= ras.maxBuff )
- {
- FT_TRACE1(( "overflow in End_Profile\n" ));
- ras.error = Raster_Err_Overflow;
- return FAILURE;
- }
- ras.joint = FALSE;
- return SUCCESS;
- }
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Insert_Y_Turn */
- /* */
- /* <Description> */
- /* Insert a salient into the sorted list placed on top of the render */
- /* pool. */
- /* */
- /* <Input> */
- /* New y scanline position. */
- /* */
- /* <Return> */
- /* SUCCESS on success. FAILURE in case of overflow. */
- /* */
- static Bool
- Insert_Y_Turn( RAS_ARGS Int y )
- {
- PLong y_turns;
- Int y2, n;
- n = ras.numTurns - 1;
- y_turns = ras.sizeBuff - ras.numTurns;
- /* look for first y value that is <= */
- while ( n >= 0 && y < y_turns[n] )
- n--;
- /* if it is <, simply insert it, ignore if == */
- if ( n >= 0 && y > y_turns[n] )
- while ( n >= 0 )
- {
- y2 = (Int)y_turns[n];
- y_turns[n] = y;
- y = y2;
- n--;
- }
- if ( n < 0 )
- {
- ras.maxBuff--;
- if ( ras.maxBuff <= ras.top )
- {
- ras.error = Raster_Err_Overflow;
- return FAILURE;
- }
- ras.numTurns++;
- ras.sizeBuff[-ras.numTurns] = y;
- }
- return SUCCESS;
- }
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Finalize_Profile_Table */
- /* */
- /* <Description> */
- /* Adjust all links in the profiles list. */
- /* */
- /* <Return> */
- /* SUCCESS on success. FAILURE in case of overflow. */
- /* */
- static Bool
- Finalize_Profile_Table( RAS_ARG )
- {
- Int bottom, top;
- UShort n;
- PProfile p;
- n = ras.num_Profs;
- p = ras.fProfile;
- if ( n > 1 && p )
- {
- while ( n > 0 )
- {
- if ( n > 1 )
- p->link = (PProfile)( p->offset + p->height );
- else
- p->link = NULL;
- if ( p->flags & Flow_Up )
- {
- bottom = (Int)p->start;
- top = (Int)( p->start + p->height - 1 );
- }
- else
- {
- bottom = (Int)( p->start - p->height + 1 );
- top = (Int)p->start;
- p->start = bottom;
- p->offset += p->height - 1;
- }
- if ( Insert_Y_Turn( RAS_VARS bottom ) ||
- Insert_Y_Turn( RAS_VARS top + 1 ) )
- return FAILURE;
- p = p->link;
- n--;
- }
- }
- else
- ras.fProfile = NULL;
- return SUCCESS;
- }
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Split_Conic */
- /* */
- /* <Description> */
- /* Subdivide one conic Bezier into two joint sub-arcs in the Bezier */
- /* stack. */
- /* */
- /* <Input> */
- /* None (subdivided Bezier is taken from the top of the stack). */
- /* */
- /* <Note> */
- /* This routine is the `beef' of this component. It is _the_ inner */
- /* loop that should be optimized to hell to get the best performance. */
- /* */
- static void
- Split_Conic( TPoint* base )
- {
- Long a, b;
- base[4].x = base[2].x;
- b = base[1].x;
- a = base[3].x = ( base[2].x + b ) / 2;
- b = base[1].x = ( base[0].x + b ) / 2;
- base[2].x = ( a + b ) / 2;
- base[4].y = base[2].y;
- b = base[1].y;
- a = base[3].y = ( base[2].y + b ) / 2;
- b = base[1].y = ( base[0].y + b ) / 2;
- base[2].y = ( a + b ) / 2;
- /* hand optimized. gcc doesn't seem to be too good at common */
- /* expression substitution and instruction scheduling ;-) */
- }
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Split_Cubic */
- /* */
- /* <Description> */
- /* Subdivide a third-order Bezier arc into two joint sub-arcs in the */
- /* Bezier stack. */
- /* */
- /* <Note> */
- /* This routine is the `beef' of the component. It is one of _the_ */
- /* inner loops that should be optimized like hell to get the best */
- /* performance. */
- /* */
- static void
- Split_Cubic( TPoint* base )
- {
- Long a, b, c, d;
- base[6].x = base[3].x;
- c = base[1].x;
- d = base[2].x;
- base[1].x = a = ( base[0].x + c + 1 ) >> 1;
- base[5].x = b = ( base[3].x + d + 1 ) >> 1;
- c = ( c + d + 1 ) >> 1;
- base[2].x = a = ( a + c + 1 ) >> 1;
- base[4].x = b = ( b + c + 1 ) >> 1;
- base[3].x = ( a + b + 1 ) >> 1;
- base[6].y = base[3].y;
- c = base[1].y;
- d = base[2].y;
- base[1].y = a = ( base[0].y + c + 1 ) >> 1;
- base[5].y = b = ( base[3].y + d + 1 ) >> 1;
- c = ( c + d + 1 ) >> 1;
- base[2].y = a = ( a + c + 1 ) >> 1;
- base[4].y = b = ( b + c + 1 ) >> 1;
- base[3].y = ( a + b + 1 ) >> 1;
- }
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Line_Up */
- /* */
- /* <Description> */
- /* Compute the x-coordinates of an ascending line segment and store */
- /* them in the render pool. */
- /* */
- /* <Input> */
- /* x1 :: The x-coordinate of the segment's start point. */
- /* */
- /* y1 :: The y-coordinate of the segment's start point. */
- /* */
- /* x2 :: The x-coordinate of the segment's end point. */
- /* */
- /* y2 :: The y-coordinate of the segment's end point. */
- /* */
- /* miny :: A lower vertical clipping bound value. */
- /* */
- /* maxy :: An upper vertical clipping bound value. */
- /* */
- /* <Return> */
- /* SUCCESS on success, FAILURE on render pool overflow. */
- /* */
- static Bool
- Line_Up( RAS_ARGS Long x1,
- Long y1,
- Long x2,
- Long y2,
- Long miny,
- Long maxy )
- {
- Long Dx, Dy;
- Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */
- Long Ix, Rx, Ax;
- PLong top;
- Dx = x2 - x1;
- Dy = y2 - y1;
- if ( Dy <= 0 || y2 < miny || y1 > maxy )
- return SUCCESS;
- if ( y1 < miny )
- {
- /* Take care: miny-y1 can be a very large value; we use */
- /* a slow MulDiv function to avoid clipping bugs */
- x1 += SMulDiv( Dx, miny - y1, Dy );
- e1 = (Int)TRUNC( miny );
- f1 = 0;
- }
- else
- {
- e1 = (Int)TRUNC( y1 );
- f1 = (Int)FRAC( y1 );
- }
- if ( y2 > maxy )
- {
- /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */
- e2 = (Int)TRUNC( maxy );
- f2 = 0;
- }
- else
- {
- e2 = (Int)TRUNC( y2 );
- f2 = (Int)FRAC( y2 );
- }
- if ( f1 > 0 )
- {
- if ( e1 == e2 )
- return SUCCESS;
- else
- {
- x1 += SMulDiv( Dx, ras.precision - f1, Dy );
- e1 += 1;
- }
- }
- else
- if ( ras.joint )
- {
- ras.top--;
- ras.joint = FALSE;
- }
- ras.joint = (char)( f2 == 0 );
- if ( ras.fresh )
- {
- ras.cProfile->start = e1;
- ras.fresh = FALSE;
- }
- size = e2 - e1 + 1;
- if ( ras.top + size >= ras.maxBuff )
- {
- ras.error = Raster_Err_Overflow;
- return FAILURE;
- }
- if ( Dx > 0 )
- {
- Ix = SMulDiv( ras.precision, Dx, Dy);
- Rx = ( ras.precision * Dx ) % Dy;
- Dx = 1;
- }
- else
- {
- Ix = SMulDiv( ras.precision, -Dx, Dy) * -1;
- Rx = ( ras.precision * -Dx ) % Dy;
- Dx = -1;
- }
- Ax = -Dy;
- top = ras.top;
- while ( size > 0 )
- {
- *top++ = x1;
- x1 += Ix;
- Ax += Rx;
- if ( Ax >= 0 )
- {
- Ax -= Dy;
- x1 += Dx;
- }
- size--;
- }
- ras.top = top;
- return SUCCESS;
- }
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Line_Down */
- /* */
- /* <Description> */
- /* Compute the x-coordinates of an descending line segment and store */
- /* them in the render pool. */
- /* */
- /* <Input> */
- /* x1 :: The x-coordinate of the segment's start point. */
- /* */
- /* y1 :: The y-coordinate of the segment's start point. */
- /* */
- /* x2 :: The x-coordinate of the segment's end point. */
- /* */
- /* y2 :: The y-coordinate of the segment's end point. */
- /* */
- /* miny :: A lower vertical clipping bound value. */
- /* */
- /* maxy :: An upper vertical clipping bound value. */
- /* */
- /* <Return> */
- /* SUCCESS on success, FAILURE on render pool overflow. */
- /* */
- static Bool
- Line_Down( RAS_ARGS Long x1,
- Long y1,
- Long x2,
- Long y2,
- Long miny,
- Long maxy )
- {
- Bool result, fresh;
- fresh = ras.fresh;
- result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny…