From 414f38c572e34bcd92d93cd0b1813de8572dd1c9 Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 16 May 2000 22:37:30 +0000 Subject: [PATCH] at last, fixed the bug, and re-enabled 5-gray levels support for backwards compatibility.. --- include/freetype/config/ftoption.h | 63 +- src/base/ftraster.c | 5158 +++++++++++----------------- 2 files changed, 2114 insertions(+), 3107 deletions(-) diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h index 3a7533023..45e2cd01c 100644 --- a/include/freetype/config/ftoption.h +++ b/include/freetype/config/ftoption.h @@ -140,21 +140,58 @@ /*************************************************************************/ /* */ + /* DLL Export Compilation */ + /* */ /* When compiling FreeType as a DLL, some systems/compilers need a */ - /* special keyword in front of each function definition instead of */ - /* `extern'. */ + /* special keyword in front OR after the return type of function */ + /* declarations. */ /* */ - /* The macros EXPORT_DEF and EXPORT_FUNC are thus used to define */ - /* exported library function interfaces and exported library functions */ - /* implementations respectively. */ + /* Two macros are used within the FreeType source code to define */ + /* exported library functions: EXPORT_DEF and EXPORT_FUNC */ /* */ - /* If not defined here, they automatically default to `extern' and void */ - /* later in this header file. */ + /* EXPORT_DEF(return_type) is used in a function declaration, as in: */ + /* */ + /* EXPORT_DEF(FT_Error) FT_Init_FreeType( FT_Library *alibrary ); */ + /* */ + /* */ + /* */ + /* EXPORT_FUNC(return_type) is used in a function definition, as in: */ + /* */ + /* EXPORT_FUNC(FT_Error) FT_Init_FreeType( FT_Library *alibrary ) */ + /* { */ + /* ... some code ... */ + /* return FT_Err_Ok; */ + /* } */ + /* */ + /* */ + /* You can provide your own implementation of EXPORT_DEF and EXPORT_FUNC */ + /* here if you want. If you leave them undefined, they'll later be */ + /* automatically defined as "extern return_type" to allow normal */ + /* compilation.. */ /* */ #undef EXPORT_DEF #undef EXPORT_FUNC + /*************************************************************************/ + /* */ + /* 5-levels Anti Aliasing support: */ + /* */ + /* FreeType 2 provides a new "smooth" renderer that is capable of */ + /* producing anti-aliased glyph bitmaps with up to 256 gray-levels. */ + /* */ + /* However, for compatibility purposes with FreeType 1.x, the standard */ + /* raster is still capable of generating anti-aliased bitmaps with 5 */ + /* gray levels. */ + /* */ + /* If you do not need this capability (i.e. if you always use the */ + /* "smooth" renderer for anti-aliased glyphs), we suggest you to */ + /* undefine this configuration macro, as it will save both code and */ + /* memory.. */ + /* */ +#define FT_CONFIG_OPTION_5_GRAY_LEVELS + + /*************************************************************************/ /* */ /* Debug level */ @@ -173,17 +210,6 @@ #undef FT_DEBUG_LEVEL_TRACE - /*************************************************************************/ - /* */ - /* Anti-aliasing support */ - /* */ - /* Undefine this macro only if you want to disable the anti-aliasing */ - /* support in FreeType. This will save you about 5 Kb of code. It */ - /* may be important for some embedded systems. */ - /* */ -#define FT_CONFIG_OPTION_ANTI_ALIAS - - /*************************************************************************/ /* */ /* Endianess performance improvement */ @@ -212,6 +238,7 @@ /* */ #define FT_CONFIG_OPTION_OLD_CALCS + /*************************************************************************/ /* */ /* The size in bytes of the render pool used by the scan-line */ diff --git a/src/base/ftraster.c b/src/base/ftraster.c index d68edfc25..93c25aff8 100644 --- a/src/base/ftraster.c +++ b/src/base/ftraster.c @@ -1,759 +1,27 @@ -/***************************************************************************/ -/* */ -/* ftraster.c */ -/* */ -/* The FreeType glyph rasterizer (body). */ -/* */ -/* Copyright 1996-2000 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. */ -/* */ -/***************************************************************************/ - - - /*************************************************************************/ - /* */ - /* The `raster' component implements FreeType's scan-line converter, the */ - /* one used to generate bitmaps and pixmaps from vectorial outline */ - /* descriptions. */ - /* */ - /* It has been rewritten entirely for FreeType 2.0, in order to become */ - /* completely independent of the rest of the library. It should now be */ - /* possible to include it more easily in all kinds of libraries and */ - /* applications, which do not necessarily need the font engines and API. */ - /* */ - /* This version contains the following features: */ - /* */ - /* - Support for third-order Bezier arcs. */ - /* */ - /* - Improved performance of the 5-levels anti-aliasing algorithm. */ - /* */ - /* - 17-levels anti-aliasing for smoother curves, though the difference */ - /* isn't always noticeable, depending on your palette. */ - /* */ - /* - An API to decompose a raster outline into a path (i.e., into a */ - /* a series of segments and arcs). */ - /* */ - /* Planned additions: */ - /* */ - /* - Getting rid of the second pass for horizontal drop-out detection. */ - /* I've got a few ideas, but I'll have to experiment in Pascal with */ - /* them. to avoid damaging of the rendering of glyphs at small sizes. */ - /* */ - /* - Adding a `composition' callback, which should be invoked during */ - /* anti-aliased rendering. In short, it will allow line-by-line */ - /* composition (i.e., transparencies, etc.) of the output in a fairly */ - /* portable way. Of course, a single sweep is required there. */ - /* */ - /*************************************************************************/ - -#define OLD - - -#define xxxDEBUG_RAS -#ifdef DEBUG_RAS -#include -#endif - +/******************************************************************* + * + * ftraster.c 1.5 + * + * The FreeType glyph rasterizer (body). + * + * Copyright 1996-2000 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 is a rewrite of the FreeType 1.x scan-line converter + * + * + * + ******************************************************************/ #include -#ifndef _STANDALONE_ -#include -#endif - -#ifndef UNUSED -#define UNUSED( arg ) ( (arg)=(arg) ) -#endif - -#undef FT_COMPONENT -#define FT_COMPONENT trace_raster - -#ifdef _STANDALONE_ - - /*************************************************************************/ - /* */ - /* The following defines are used when the raster is compiled as a */ - /* stand-alone object. Each of them is commented, and you're free to */ - /* toggle them to suit your needs. */ - /* */ - /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* FT_RASTER_INT_IS_32 */ - /* */ - /* Set this configuration macro to the unsigned type which has 32 */ - /* bits. */ - /* */ -#define FT_RASTER_INT_IS_32 - - - /*************************************************************************/ - /* */ - /* FT_RASTER_OPTION_ANTI_ALIAS */ - /* */ - /* Define this configuration macro if you want to support */ - /* anti-aliasing. */ - /* */ -#undef FT_RASTER_OPTION_ANTI_ALIAS - - - /*************************************************************************/ - /* */ - /* FT_RASTER_OPTION_CONIC_BEZIERS */ - /* */ - /* Define this configuration macro if your source outlines contain */ - /* second-order Bezier arcs. Typically, these are TrueType outlines. */ - /* */ -#define FT_RASTER_CONIC_BEZIERS - - - /*************************************************************************/ - /* */ - /* FT_RASTER_OPTION_CUBIC_BEZIERS */ - /* */ - /* Define this configuration macro if your source outlines contain */ - /* third-order Bezier arcs. Typically, these are Type1 outlines. */ - /* */ -#define FT_RASTER_CUBIC_BEZIERS - - - /*************************************************************************/ - /* */ - /* FT_RASTER_CONSTANT_PRECISION */ - /* */ - /* Define this configuration macro if you want to use a constant */ - /* precision for the internal sub-pixel coordinates. Otherwise, the */ - /* precision is either 64 or 1024 units per pixel, depending on the */ - /* outline's "high_precision" flag.. */ - /* */ - /* This results in a speed boost, but the macro can be undefined if */ - /* it results in rendering errors (mainly changed drop-outs).. */ - /* */ -#undef FT_RASTER_CONSTANT_PRECISION - - - /*************************************************************************/ - /* */ - /* FT_PRECISION_BITS */ - /* */ - /* When the macro FT_RASTER_CONSTANT_PRECISION is defined, this */ - /* constant holds the number of bits used for the internal sub-pixels */ - /* */ - /* This number should be at least 6, but use at least 8 if you */ - /* intend to generate small glyph images (use 6 for a printer, for */ - /* example..) */ - /* */ -#define FT_PRECISION_BITS 8 - - - /*************************************************************************/ - /* */ - /* FT_DYNAMIC_BEZIER_STEPS */ - /* */ - /* Set this macro to enable the bezier decomposition to be */ - /* dynamically computed. This is interesting when the precision is */ - /* constant, as it speeds things a bit while keeping a very good */ - /* accuracy on the bezier intersections.. */ - /* */ -#undef FT_DYNAMIC_BEZIER_STEPS - - -#else /* _STANDALONE_ */ - -#include -#include - - /*************************************************************************/ - /* */ - /* The following defines are used when the raster is compiled within the */ - /* FreeType base layer. Don't change these unless you really know what */ - /* you're doing. */ - /* */ - /*************************************************************************/ - - -#ifdef FT_CONFIG_OPTION_ANTI_ALIAS -#define FT_RASTER_OPTION_ANTI_ALIAS -#endif - -#define FT_RASTER_CONIC_BEZIERS -#define FT_RASTER_CUBIC_BEZIERS - -#define FT_RASTER_ANTI_ALIAS_5 -/* #define FT_RASTER_ANTI_ALIAS_17 */ - -#ifdef FT_CONFIG_OPTION_LITTLE_ENDIAN -#define FT_RASTER_LITTLE_ENDIAN -#endif - -#ifdef FT_CONFIG_OPTION_BIG_ENDIAN -#define FT_RASTER_BIG_ENDIAN -#endif - -#undef FT_RASTER_CONSTANT_PRECISION -#undef FT_DYNAMIC_BEZIER_STEPS -#define FT_PRECISION_BITS 8 - -#endif /* _STANDALONE_ */ - - -/* to keep the compiler happy */ -#ifndef FT_TRACE2 -#define FT_TRACE2(x) /*void*/ -#endif - -#ifndef FT_TRACE4 -#define FT_TRACE4(x) /* void */ -#endif - - /*************************************************************************/ - /* */ - /* FT_RASTER_ANY_ENDIAN indicates that no endianess was defined by one */ - /* of the configuration macros. */ - /* */ -#if !defined( FT_RASTER_LITTLE_ENDIAN ) && !defined( FT_RASTER_BIG_ENDIAN ) -#define FT_RASTER_ANY_ENDIAN -#endif - - - /*************************************************************************/ - /* */ - /* The rasterizer is a very general purpose component. Please leave the */ - /* following redefinitions here (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 UNUSED -#define UNUSED( arg ) ( (void)(arg) ) -#endif - - -#undef FAILURE -#define FAILURE TRUE - -#undef SUCCESS -#define SUCCESS FALSE - -#ifndef ABS -#define ABS(x) ( (x) < 0 ? -(x) : (x) ) -#endif - - /*************************************************************************/ - /* */ - /* Please don't touch the following macros. Their importance is */ - /* historical to FreeType, but they have some nice effects, like getting */ - /* rid of all `->' symbols when accessing the raster object (replacing */ - /* them with a simple `.'). */ - /* */ - /*************************************************************************/ - - /* used in function signatures to define the _first_ argument */ -#define RAS_ARG_ FT_Raster raster, -#define RAS_ARG FT_Raster raster - - /* used to call a function within this component, first parameter */ -#define RAS_VAR_ raster, -#define RAS_VAR raster - - /* used to access the current raster object, with a `.' instead of a */ - /* `->' */ -#define ras (*raster) - -#define UNUSED_RASTER (raster=raster); - - /*************************************************************************/ - /* */ - /* Error codes returned by the scan-line converter/raster. */ - /* */ -#define ErrRaster_Ok 0 -#define ErrRaster_Uninitialized_Object 1 -#define ErrRaster_Overflow 2 -#define ErrRaster_Negative_Height 3 -#define ErrRaster_Invalid_Outline 4 -#define ErrRaster_Invalid_Map 5 -#define ErrRaster_AntiAlias_Unsupported 6 -#define ErrRaster_Invalid_Pool 7 -#define ErrRaster_Unimplemented 8 -#define ErrRaster_Bad_Palette_Count 9 - - -#define Flow_Up 1 -#define Flow_Down -1 - -#define SET_High_Precision( p ) Set_High_Precision( RAS_VAR_ p ) - - - /*************************************************************************/ - /* */ - /* Fast MulDiv, as `b' is always < 64. Don't use intermediate */ - /* precision. */ - /* */ -#define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) - - - /*************************************************************************/ - /* */ - /* Define DEBUG_RASTER if you want to generate a debug version of the */ - /* rasterizer. This will progressively draw the glyphs while all the */ - /* computation are done directly on the graphics screen (the glyphs will */ - /* will be shown inverted). */ - /* */ - /* Note that DEBUG_RASTER should only be used for debugging with b/w */ - /* rendering, not with gray levels. */ - /* */ - /* The definition of DEBUG_RASTER should appear in the file */ - /* `ftconfig.h'. */ - /* */ -#ifdef DEBUG_RASTER - extern char* vio; /* A pointer to VRAM or display buffer */ -#endif - - - /*************************************************************************/ - /* */ - /* The maximum number of stacked Bezier curves. Setting this constant */ - /* to more than 32 is a pure waste of space. */ - /* */ -#define MaxBezier 32 - - - /*************************************************************************/ - /* */ - /* The number fractional bits of *input* coordinates. We always use the */ - /* 26.6 format (i.e, 6 bits for the fractional part), but hackers are */ - /* free to experiment with different values. */ - /* */ -#define INPUT_BITS 6 - - - /*************************************************************************/ - /* */ - /* An unsigned type that is exactly 32 bits on your platform. This */ - /* means `unsigned long' on 16-bit machines, and `unsigned int' on */ - /* others. */ - /* */ -#ifdef _STANDALONE_ -#if defined( FT_RASTER_INT_IS_32 ) - typedef unsigned int FT_Word32; -#elif defined( FT_RASTER_LONG_IS_32 ) - typedef unsigned long FT_Word32; -#else -#error "no 32bit type found - please check your configuration" -#endif -#endif - - - /*************************************************************************/ - /* */ - /* A pointer to an unsigned char. */ - /* */ - typedef unsigned char Byte, *PByte; - typedef int TResult; - - - /*************************************************************************/ - /* */ - /* The type of the pixel coordinates used within the render pool during */ - /* scan-line conversion. We use longs to store either 26.6 or 22.10 */ - /* fixed float values, depending on the `precision' we want to use */ - /* (i.e., low resp. high precision). These are ideals in order to */ - /* subdivise Bezier arcs in halves by simple additions and shifts. */ - /* */ - /* Note that this is an 8-bytes integer on 64 bits systems. */ - /* */ - typedef long TPos, *PPos; - - - /*************************************************************************/ - /* */ - /* The type of a scanline position/coordinate within a map. */ - /* */ - typedef int TScan, *PScan; - - - /*************************************************************************/ - /* */ - /* States and directions of each line, arc, and profile. */ - /* */ - typedef enum _TDirection - { - Unknown, - Ascending, - Descending, - Flat - - } TDirection; - - - struct _TProfile; - typedef struct _TProfile TProfile; - typedef TProfile* PProfile; - - - /*************************************************************************/ - /* */ - /* The `master' structure used for decomposing outlines. */ - /* */ - struct _TProfile - { - TPos X; /* current coordinate during sweep */ - PProfile link; /* link to next profile - various purpose */ - PPos offset; /* start of profile's data in render pool */ - int flow; /* Profile orientation: Asc/Descending */ - TScan height; /* profile's height in scanlines */ - TScan start; /* profile's starting scanline */ - - TScan 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; - - - /*************************************************************************/ - /* */ - /* A simple record used to implement a stack of bands, required by the */ - /* sub-banding mechanism. */ - /* */ - typedef struct _TBand - { - TScan y_min; /* band's minimum */ - TScan y_max; /* band's maximum */ - - } TBand; - - - /*************************************************************************/ - /* */ - /* The size in _TPos_ of a profile record in the render pool. */ - /* */ -#define AlignProfileSize \ - ( (sizeof ( TProfile ) + sizeof ( TPos ) - 1) / sizeof ( TPos ) ) - - - /*************************************************************************/ - /* */ - /* Prototypes used for sweep function dispatch. */ - /* */ - typedef void (*Function_Sweep_Init)( RAS_ARG_ int* min, - int* max ); - - typedef void (*Function_Sweep_Span)( RAS_ARG_ TScan y, - TPos x1, - TPos x2 ); - - typedef int (*Function_Test_Pixel)( RAS_ARG_ TScan y, - int x ); - - typedef void (*Function_Set_Pixel)( RAS_ARG_ TScan y, - int x, - int color ); - - typedef void (*Function_Sweep_Step)( RAS_ARG ); - - typedef struct Raster_Render_ - { - Function_Sweep_Init init; - Function_Sweep_Span span; - Function_Sweep_Step step; - Function_Test_Pixel test_pixel; - Function_Set_Pixel set_pixel; - - } Raster_Render; - - -#ifdef FT_RASTER_CONSTANT_PRECISION - - #define PRECISION_BITS FT_PRECISION_BITS - #define PRECISION (1 << PRECISION_BITS) - #define PRECISION_MASK (-1L << PRECISION_BITS) - #define PRECISION_HALF (PRECISION >> 1) - #define PRECISION_JITTER (PRECISION >> 5) - #define PRECISION_STEP PRECISION_HALF - -#else - - #define PRECISION_BITS ras.precision_bits - #define PRECISION ras.precision - #define PRECISION_MASK ras.precision_mask - #define PRECISION_HALF ras.precision_half - #define PRECISION_JITTER ras.precision_jitter - #define PRECISION_STEP ras.precision_step - -#endif - - /*************************************************************************/ - /* */ - /* Compute lowest integer coordinate below a given value. */ - /* */ -#define FLOOR( x ) ( (x) & PRECISION_MASK ) - - - /*************************************************************************/ - /* */ - /* Compute highest integer coordinate above a given value. */ - /* */ -#define CEILING( x ) ( ((x) + PRECISION - 1) & PRECISION_MASK ) - - - /*************************************************************************/ - /* */ - /* Get integer coordinate of a given 26.6 or 22.10 `x' coordinate -- no */ - /* rounding. */ - /* */ -#define TRUNC( x ) ( (signed long)(x) >> PRECISION_BITS ) - - - /*************************************************************************/ - /* */ - /* Get the fractional part of a given coordinate. */ - /* */ -#define FRAC( x ) ( (x) & (PRECISION-1) ) - - - /*************************************************************************/ - /* */ - /* Scale an `input coordinate' (as found in FT_Outline structures) into */ - /* a `work coordinate' which depends on current resolution and render */ - /* mode. */ - /* */ -#define SCALED( x ) ( ((x) << ras.scale_shift) - ras.scale_delta ) - - - /*************************************************************************/ - /* */ - /* DEBUG_PSET is used to plot a single pixel in VRam during debug mode. */ - /* */ -#ifdef DEBUG_RASTER -#define DEBUG_PSET Pset() -#else -#define DEBUG_PSET -#endif - - - /*************************************************************************/ - /* */ - /* This structure defines a point in a plane. */ - /* */ - typedef struct _TPoint - { - TPos x, y; - - } TPoint; - - - /*************************************************************************/ - /* */ - /* The most used variables are at the beginning of the structure. Thus, */ - /* their offset can be coded with less opcodes which results in a */ - /* smaller executable. */ - /* */ - struct FT_RasterRec_ - { - PPos cursor; /* Current cursor in render pool */ - - PPos pool; /* The render pool base address */ - PPos pool_size; /* The render pool's size */ - PPos pool_limit; /* Limit of profiles zone in pool */ - - int bit_width; /* target bitmap width */ - PByte bit_buffer; /* target bitmap buffer */ - PByte pix_buffer; /* target pixmap buffer */ - - TPoint last; - long minY, maxY; - - int error; - -#ifndef FT_RASTER_CONSTANT_PRECISION - int precision_bits; /* precision related variables */ - int precision; - int precision_half; - long precision_mask; - int precision_shift; - int precision_step; - int precision_jitter; -#endif - - FT_Outline* outline; - - int n_points; /* number of points in current glyph */ - int n_contours; /* number of contours in current glyph */ - int n_extrema; /* number of `extrema' scanlines */ - - TPoint* arc; /* current Bezier arc pointer */ - - int num_profs; /* current number of profiles */ - - char fresh; /* signals a fresh new profile which */ - /* `start' field must be completed */ - char joint; /* signals that the last arc ended */ - /* exactly on a scanline. Allows */ - /* removal of doublets */ - PProfile cur_prof; /* current profile */ - PProfile start_prof; /* head of linked list of profiles */ - PProfile first_prof; /* contour's first profile in case */ - /* of impact */ - TDirection state; /* rendering state */ - - FT_Bitmap target; /* description of target bit/pixmap */ - void* memory; - - int trace_bit; /* current offset in target bitmap */ - int trace_pix; /* current offset in target pixmap */ - int trace_incr; /* sweep's increment in target bitmap */ - - /* dispatch variables */ - - Raster_Render render; - - int scale_shift; /* == 0 for bitmaps */ - /* == 1 for 5-levels pixmaps */ - /* == 2 for 17-levels pixmaps */ - - int scale_delta; /* ras.precision_half for bitmaps */ - /* 0 for pixmaps */ - - char dropout_mode; /* current drop_out control method */ - - char 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. */ - - char flipped; /* this flag is set during the rendering to */ - /* indicate the second pass. */ - - TBand band_stack[16]; /* band stack used for sub-banding */ - int band_top; /* band stack top */ - - TPoint arcs[2 * MaxBezier + 1]; /* The Bezier stack */ - }; - - - -#ifdef DEBUG_RASTER - - /*************************************************************************/ - /* */ - /* */ - /* Pset */ - /* */ - /* */ - /* Used for debugging only. Plots a point in VRAM during rendering */ - /* (not afterwards). */ - /* */ - /* */ - /* This procedure relies on the value of cProfile->start, which may */ - /* not be set when Pset() is called sometimes. This will usually */ - /* result in a dot plotted on the first screen scanline (far away */ - /* from its original position). */ - /* */ - /* This `feature' reflects nothing wrong in the current */ - /* implementation, and the bitmap is rendered correctly, so don't */ - /* panic if you see `flying' dots in debugging mode. */ - /* */ - static - void Pset( RAS_ARG ) - { - long o; - long x; - - x = ras.cursor[-1]; - - switch ( ras.cur_prof->flow ) - { - case FT_Flow_Up: - o = Vio_ScanLineWidth * - ( ras.cursor - ras.cur_prof->offset + ras.cur_prof->start ) + - ( x / (PRECISION * 8) ); - break; - - case FT_Flow_Down: - o = Vio_ScanLineWidth * - ( ras.cur_prof->start - ras.cursor + ras.cur_prof->offset ) + - ( x / (PRECISION * 8) ); - break; - } - - if ( o > 0 ) - Vio[o] |= (unsigned)0x80 >> ( (x/PRECISION) & 7 ); - } - - - static - void Clear_Band( RAS_ARG_ TScan y1, - TScan y2 ) - { - MEM_Set( Vio + y1*Vio_ScanLineWidth, (y2-y1+1)*Vio_ScanLineWidth, 0 ); - } - -#endif /* DEBUG_RASTER */ - - - /*************************************************************************/ - /* */ - /* */ - /* Set_High_Precision */ - /* */ - /* */ - /* Sets precision variables according to the parameter flag. */ - /* */ - /* */ - /* High :: Set to True for high precision (typically for ppem < 18), */ - /* false otherwise. */ - /* */ - static - void Set_High_Precision( RAS_ARG_ char High ) - { -#ifdef FT_RASTER_CONSTANT_PRECISION - (void)High; - (void)&ras; -#else - if ( High ) - { - ras.precision_bits = 10; - ras.precision_step = 128; - ras.precision_jitter = 24; - } - else - { - ras.precision_bits = 6; - ras.precision_step = 32; - ras.precision_jitter = 2; - } - - ras.precision = 1L << ras.precision_bits; - ras.precision_half = ras.precision / 2; - ras.precision_shift = ras.precision_bits - INPUT_BITS; - ras.precision_mask = -ras.precision; -#endif - } +#include /* for FT_MulDiv only */ /*************************************************************************/ /* */ @@ -790,9 +58,9 @@ /* */ /* ^ ^ */ /* | | */ - /* start of render pool cursor */ + /* start of render pool top */ /* */ - /* The top of the profile stack is kept in the `cursor' variable. */ + /* 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 */ @@ -802,7 +70,7 @@ /* 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 `extrema' because they (sort */ + /* 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: */ /* */ @@ -814,7 +82,7 @@ /* */ /* ^ ^ */ /* | | */ - /* pool_limit end of render pool */ + /* 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). */ @@ -824,130 +92,505 @@ /* */ /*************************************************************************/ + /****************************************************************/ + /****************************************************************/ + /** **/ + /** CONFIGURATION MACROS **/ + /** **/ + /****************************************************************/ + /****************************************************************/ - /*************************************************************************/ - /* */ - /* */ - /* New_Profile */ - /* */ - /* */ - /* Creates a new Profile in the render pool. */ - /* */ - /* */ - /* aState :: The state/orientation of the new profile. */ - /* */ - /* */ - /* SUCCESS or FAILURE. */ - /* */ - static - TResult New_Profile( RAS_ARG_ TDirection direction ) +/* define DEBUG_RASTER if you want to compile a debugging version */ +#define xxxDEBUG_RASTER + +/* The default render pool size in bytes */ +#define RASTER_RENDER_POOL 8192 + +/* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */ +/* 5-levels anti-aliasing */ +#ifdef FT_CONFIG_OPTION_5_GRAY_LEVELS +#define FT_RASTER_OPTION_ANTI_ALIASING +#endif + +/* The size of the two-lines intermediate bitmap used */ +/* for anti-aliasing, in bytes.. */ +#define RASTER_GRAY_LINES 2048 + + + /****************************************************************/ + /****************************************************************/ + /** **/ + /** OTHER MACROS (do not change) **/ + /** **/ + /****************************************************************/ + /****************************************************************/ + +/* required by the tracing mode */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_raster + +#include + +#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_Gray_Unsupported -5 +#define Raster_Err_Unsupported -6 + +/* 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 in 32 bits. */ +#define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) + +/* On the other hand, SMulDiv is for "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 long ULong; + + typedef unsigned char Byte, *PByte; + typedef char Bool; + + typedef struct TPoint_ { - if ( ras.start_prof == NULL ) + Long x; + Long y; + + } TPoint; + + + typedef enum TFlow_ + { + Flow_None = 0, + Flow_Up = 1, + Flow_Down = -1 + + } TFlow; + + + /* States of each line, arc and profile */ + typedef enum TStates_ + { + Unknown, + Ascending, + Descending, + Flat + + } TStates; + + + typedef struct TProfile_ TProfile; + typedef TProfile* PProfile; + + struct TProfile_ + { + FT_F26Dot6 X; /* current coordinate during sweep */ + PProfile link; /* link to next profile - various purpose */ + PLong offset; /* start of profile's data in render pool */ + Int flow; /* Profile orientation: Asc/Descending */ + Long height; /* profile's height in scanlines */ + Long start; /* profile's starting scanline */ + + UShort 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 TBand_ + { + Short y_min; /* band's minimum */ + Short y_max; /* band's maximum */ + + } TBand; + + + +#define AlignProfileSize \ + (( sizeof(TProfile)+sizeof(long)-1 ) / sizeof(long)) + + + +#ifdef TT_STATIC_RASTER + +#define RAS_ARGS /* void */ +#define RAS_ARG /* void */ + +#define RAS_VARS /* void */ +#define RAS_VAR /* void */ + +#else + +#define RAS_ARGS TRaster_Instance* raster, +#define RAS_ARG TRaster_Instance* raster + +#define RAS_VARS raster, +#define RAS_VAR raster + +#endif + + + typedef struct TRaster_Instance_ TRaster_Instance; + + + /* 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 */ + +#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 ) + + /* Note that I have moved the location of some fields in the */ + /* structure to ensure that the most used variables are used */ + /* at the top. Thus, their offset can be coded with less */ + /* opcodes, and it results in a smaller executable. */ + + struct TRaster_Instance_ + { + Int precision_bits; /* precision related variables */ + Int precision; + Int precision_half; + Long precision_mask; + 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, 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 wether 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[2 * MaxBezier + 1]; /* The Bezier stack */ + + TBand band_stack[16]; /* band stack used for sub-banding */ + Int band_top; /* band stack top */ + + Int count_table[256]; /* Look-up table used to quickly count */ + /* set bits in a gray 2x2 cell */ + + void* memory; + +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + + Byte grays[5]; /* Palette of gray levels used for render */ + + 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 */ + +#if 0 + PByte flags; /* current flags table */ + PUShort outs; /* current outlines table */ + FT_Vector* coords; + + UShort nPoints; /* number of points in current glyph */ + Short nContours; /* number of contours in current glyph */ +#endif + + + }; + + +#ifdef FT_CONFIG_OPTION_STATIC_RASTER + + static TRaster_Instance cur_ras; + #define ras cur_ras + +#else + + #define ras (*raster) + +#endif /* FT_STATIC_RASTER */ + + /****************************************************************/ + /****************************************************************/ + /** **/ + /** PROFILES COMPUTATION **/ + /** **/ + /****************************************************************/ + /****************************************************************/ + + +/************************************************************************/ +/* */ +/* Function: Set_High_Precision */ +/* */ +/* Description: Sets 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 ) + { + if ( High ) { - ras.cur_prof = (PProfile)ras.cursor; /* current profile */ - ras.start_prof = ras.cur_prof; /* first profile in pool */ - ras.cursor += AlignProfileSize; /* record profile in buffer */ + ras.precision_bits = 10; + ras.precision_step = 128; + ras.precision_jitter = 24; + } + else + { + ras.precision_bits = 6; + ras.precision_step = 32; + ras.precision_jitter = 2; } - /* check for overflow */ - if ( ras.cursor >= ras.pool_limit ) + FT_TRACE7(( "Set_High_Precision(%s)\n", High ? "true" : "false" )); + + ras.precision = 1L << ras.precision_bits; + ras.precision_half = ras.precision / 2; + ras.precision_shift = ras.precision_bits - Pixel_Bits; + ras.precision_mask = -ras.precision; + } + + +/****************************************************************************/ +/* */ +/* Function: New_Profile */ +/* */ +/* Description: Creates a new Profile in the render pool. */ +/* */ +/* Input: aState state/orientation of the new Profile */ +/* */ +/* Returns: SUCCESS on success. */ +/* FAILURE in case of overflow or of incoherent Profile. */ +/* */ +/****************************************************************************/ + + static Bool New_Profile( RAS_ARGS TStates aState ) + { + if ( !ras.fProfile ) { - ras.error = ErrRaster_Overflow; + ras.cProfile = (PProfile)ras.top; + ras.fProfile = ras.cProfile; + ras.top += AlignProfileSize; + } + + if ( ras.top >= ras.maxBuff ) + { + ras.error = Raster_Err_Overflow; return FAILURE; } - /* record profile direction */ - switch ( direction ) + switch ( aState ) { case Ascending: - ras.cur_prof->flow = Flow_Up; + ras.cProfile->flow = Flow_Up; + FT_TRACE7(( "New ascending profile = %lx\n", (long)ras.cProfile )); break; case Descending: - ras.cur_prof->flow = Flow_Down; + ras.cProfile->flow = Flow_Down; + FT_TRACE7(( "New descending profile = %lx\n", (long)ras.cProfile )); break; default: - ras.error = ErrRaster_Invalid_Map; + FT_ERROR(( "Invalid profile direction in Raster:New_Profile !!\n" )); + ras.error = Raster_Err_Invalid; return FAILURE; } - /* initialize a few fields */ - { - PProfile cur = ras.cur_prof; + ras.cProfile->start = 0; + ras.cProfile->height = 0; + ras.cProfile->offset = ras.top; + ras.cProfile->link = (PProfile)0; + ras.cProfile->next = (PProfile)0; + if ( !ras.gProfile ) + ras.gProfile = ras.cProfile; - cur->start = 0; /* current start scanline */ - cur->height = 0; /* current height */ - cur->offset = ras.cursor; /* address of first coordinate */ - cur->link = (PProfile)0; /* link to next profile in pool */ - cur->next = (PProfile)0; /* link to next profile in contour */ - } - - /* record the first profile in a contour */ - if ( ras.first_prof == NULL ) - ras.first_prof = ras.cur_prof; - - ras.state = direction; - ras.fresh = TRUE; /* this profile has no coordinates yet */ - ras.joint = FALSE; + ras.state = aState; + ras.fresh = TRUE; + ras.joint = FALSE; return SUCCESS; } - /*************************************************************************/ - /* */ - /* */ - /* End_Profile */ - /* */ - /* */ - /* Finalizes the current Profile and computes its height. If it is */ - /* not 0, the profile's fields are updated and a new profile is */ - /* pushed on top of its coordinates. Otherwise the current profile */ - /* is kept and the recording of intersections is restarted. */ - /* */ - /* */ - /* SUCCESS or FAILURE. */ - /* */ - static - TResult End_Profile( RAS_ARG ) +/****************************************************************************/ +/* */ +/* Function: End_Profile */ +/* */ +/* Description: Finalizes the current Profile. */ +/* */ +/* Input: None */ +/* */ +/* Returns: SUCCESS on success. */ +/* FAILURE in case of overflow or incoherency. */ +/* */ +/****************************************************************************/ + + static Bool End_Profile( RAS_ARG ) { - int h; + Long h; + PProfile oldProfile; - h = ras.cursor - ras.cur_prof->offset; + h = ras.top - ras.cProfile->offset; if ( h < 0 ) { - /* This error should _never_ occur unless the raster is buggy */ - ras.error = ErrRaster_Negative_Height; + FT_ERROR(( "Negative height encountered in End_Profile!\n" )); + ras.error = Raster_Err_Neg_Height; return FAILURE; } if ( h > 0 ) { - PProfile old, new; + FT_TRACE1(( "Ending profile %lx, start = %ld, height = %ld\n", + (long)ras.cProfile, ras.cProfile->start, h )); - /* record scanline height in current profile, create a new one */ - /* and set a link from the old one to it */ - old = ras.cur_prof; - old->height = h; - ras.cur_prof = new = (PProfile)ras.cursor; + oldProfile = ras.cProfile; + ras.cProfile->height = h; + ras.cProfile = (PProfile)ras.top; - ras.cursor += AlignProfileSize; + ras.top += AlignProfileSize; - new->height = 0; - new->offset = ras.cursor; - old->next = new; - - ras.num_profs++; + ras.cProfile->height = 0; + ras.cProfile->offset = ras.top; + oldProfile->next = ras.cProfile; + ras.num_Profs++; } - /* check for overflow */ - if ( ras.cursor >= ras.pool_limit ) + if ( ras.top >= ras.maxBuff ) { - ras.error = ErrRaster_Overflow; + FT_TRACE1(( "overflow in End_Profile\n" )); + ras.error = Raster_Err_Overflow; return FAILURE; } @@ -957,85 +600,81 @@ } - /*************************************************************************/ - /* */ - /* */ - /* Insert_Extrema */ - /* */ - /* */ - /* Records that a given scanline contains at least one local */ - /* extremum. The table of extrema is placed at the end of the render */ - /* pool and grows downwards. It is used during the sweep phase. */ - /* */ - /* */ - /* y :: The coordinate of the scanline containing an extremum. */ - /* */ +/****************************************************************************/ +/* */ +/* Function: Insert_Y_Turn */ +/* */ +/* Description: Insert a salient into the sorted list placed on top */ +/* of the render pool */ +/* */ +/* Input: New y scanline position */ +/* */ +/****************************************************************************/ + static - TResult Insert_Extrema( RAS_ARG_ TScan y ) + Bool Insert_Y_Turn( RAS_ARGS Int y ) { - PPos extrema; - TScan y2; - int n; + PLong y_turns; + Int y2, n; + n = ras.numTurns-1; + y_turns = ras.sizeBuff - ras.numTurns; - FT_TRACE2(( "EXTREMA += %d", y )); - n = ras.n_extrema - 1; - extrema = ras.pool_size - ras.n_extrema; - - /* look for first y extremum that is <= */ - while ( n >= 0 && y < extrema[n] ) + /* 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 > extrema[n] ) + if ( n >= 0 && y > y_turns[n] ) while ( n >= 0 ) { - y2 = extrema[n]; - extrema[n] = y; + y2 = y_turns[n]; + y_turns[n] = y; y = y2; n--; } if ( n < 0 ) { - ras.pool_limit--; - ras.n_extrema++; - ras.pool_size[-ras.n_extrema] = y; - - if ( ras.pool_limit <= ras.cursor ) + if (ras.maxBuff <= ras.top) { - ras.error = ErrRaster_Overflow; + ras.error = Raster_Err_Overflow; return FAILURE; } + ras.maxBuff--; + ras.numTurns++; + ras.sizeBuff[-ras.numTurns] = y; } + return SUCCESS; } - /*************************************************************************/ - /* */ - /* */ - /* Finalize_Profile_Table */ - /* */ - /* */ - /* Adjusts all links in the profiles list. Called when the outline */ - /* parsing is done. */ - /* */ - /* */ - /* SUCCESS or FAILURE. */ - /* */ +/****************************************************************************/ +/* */ +/* Function: Finalize_Profile_Table */ +/* */ +/* Description: Adjusts all links in the Profiles list. */ +/* */ +/* Input: None */ +/* */ +/* Returns: None. */ +/* */ +/****************************************************************************/ + static - TResult Finalize_Profile_Table( RAS_ARG ) + Bool Finalize_Profile_Table( RAS_ARG ) { - int n, bottom, top; + Int bottom, top; + UShort n; PProfile p; - n = ras.num_profs; + n = ras.num_Profs; if ( n > 1 ) { - p = ras.start_prof; + p = ras.fProfile; while ( n > 0 ) { if ( n > 1 ) @@ -1045,25 +684,21 @@ switch ( p->flow ) { - case Flow_Down: - FT_TRACE2(( "FLOW DOWN (start = %d, height = %d)", - p->start, p->height )); - bottom = p->start - p->height+1; - top = p->start; - p->start = bottom; - p->offset += p->height-1; - break; + case Flow_Down: + bottom = p->start - p->height+1; + top = p->start; + p->start = bottom; + p->offset += p->height-1; + break; - case Flow_Up: - default: - FT_TRACE2(( "FLOW UP (start = %d, height = %d)", - p->start, p->height )); - bottom = p->start; - top = p->start + p->height-1; + case Flow_Up: + default: + bottom = p->start; + top = p->start + p->height-1; } - if ( Insert_Extrema( RAS_VAR_ bottom ) || - Insert_Extrema( RAS_VAR_ top+1 ) ) + if ( Insert_Y_Turn( RAS_VARS bottom ) || + Insert_Y_Turn( RAS_VARS top+1 ) ) return FAILURE; p = p->link; @@ -1071,589 +706,52 @@ } } else - ras.start_prof = NULL; + ras.fProfile = NULL; return SUCCESS; } - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /**** ****/ - /**** ****/ - /**** COMPUTE SCAN-LINE INTERSECTIONS FROM SEGMENTS ****/ - /**** ****/ - /**** ****/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ +/****************************************************************************/ +/* */ +/* Function: Split_Conic */ +/* */ +/* Description: Subdivides one conic bezier into two joint */ +/* sub-arcs in the Bezier stack. */ +/* */ +/* Input: None (subdivided bezier is taken from the top of the */ +/* stack). */ +/* */ +/* Returns: None. */ +/* */ +/* */ +/* 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. */ +/* */ +/****************************************************************************/ - - /*************************************************************************/ - /* */ - /* */ - /* Line_Up */ - /* */ - /* */ - /* Computes the scan-line intersections of an ascending line segment */ - /* and stores them in the render pool. */ - /* */ - /* */ - /* x1 :: The start x coordinate. */ - /* y1 :: The start y coordinate. */ - /* x2 :: The end x coordinate. */ - /* y2 :: The end y coordinate. */ - /* miny :: The minimum vertical grid coordinate. */ - /* maxy :: The maximum vertical grid coordinate. */ - /* */ - /* */ - /* SUCCESS or FAILURE. */ - /* */ - static - TResult Line_Up( RAS_ARG_ TPos x1, TPos y1, - TPos x2, TPos y2, - TPos miny, TPos maxy ) + static void Split_Conic( TPoint* base ) { - TPos Dx, Dy; - int e1, e2, f1, f2, size; - TPos Ix, Rx, Ax; - - PPos top; - - - Dx = x2 - x1; - Dy = y2 - y1; - - if ( Dy <= 0 || y2 < miny || y1 > maxy ) - return SUCCESS; - - /* clip to higher scanline when necessary */ - if ( y2 > maxy ) - { - /* x2 += FMulDiv( Dx, maxy-y2, Dy ); UNNECESSARY */ - e2 = TRUNC( maxy ); - f2 = 0; - } - else - { - e2 = TRUNC( y2 ); - f2 = FRAC( y2 ); - } - - /* clip to lower scanline when necessary */ - if ( y1 < miny ) - { -#ifdef OLD - x1 += FT_MulDiv( Dx, miny-y1, Dy ); - e1 = TRUNC( miny ); - f1 = 0; -#else - TPos x, y; - - /* we use a binary search to compute the lower - // clipping intersection. That's because we don't - // want to use an external function like FT_MulDiv - // to compute it directly. - */ - if ( y2 == miny ) goto Exit; - do - { - x = (x1 + x2) >> 1; - y = (y1 + y2) >> 1; - - if (y <= miny) - { - x1 = x; - y1 = y; - } - else - { - x2 = x; - y2 = y; - } - } - while ( y1 < miny ); - - e1 = TRUNC( miny ); - f1 = 0; -#endif - } - else - { - e1 = TRUNC( y1 ); - f1 = FRAC( y1 ); - } - - /* adjust start point so that we begin on an integer scanline position */ - if ( f1 > 0 ) - { - if ( e1 == e2 ) goto Exit; - else - { - x1 += FMulDiv( Dx, PRECISION - f1, Dy ); - e1 += 1; - } - } - else - if ( ras.joint ) - { - ras.cursor--; - ras.joint = FALSE; - } - - ras.joint = ( f2 == 0 ); - - /* if this is a `fresh' profile, record its starting scanline */ - if ( ras.fresh ) - { - ras.cur_prof->start = e1; - ras.fresh = FALSE; - } - - /* check for overflow */ - size = e2 - e1 + 1; - if ( ras.cursor + size >= ras.pool_limit ) - { - ras.error = ErrRaster_Overflow; - return FAILURE; - } - -#ifdef OLD - if ( Dx > 0 ) - { - Ix = ( PRECISION*Dx ) / Dy; - Rx = ( PRECISION*Dx ) % Dy; - Dx = 1; - } - else - { - Ix = -( (PRECISION*-Dx) / Dy ); - Rx = (PRECISION*-Dx) % Dy; - Dx = -1; - } - - Ax = -Dy; -#else - /* compute decision variables and push the intersections on top */ - /* of the render pool */ - Dx <<= PRECISION_BITS; - Ix = Dx / Dy; - Rx = Dx % Dy; - if (Rx < 0) - { - Ix --; - Rx += Dy; - } - - Ax = -Dy; - Rx <<= 1; - Dy <<= 1; -#endif - - top = ras.cursor; - - while ( size > 0 ) - { - *top++ = x1; - - DEBUG_PSET; - - x1 += Ix; - Ax += Rx; - if ( Ax >= 0 ) - { - Ax -= Dy; -#ifdef OLD - x1 += Dx; -#else - x1 ++; -#endif - } - size--; - } - - ras.cursor = top; - Exit: - return SUCCESS; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Line_Down */ - /* */ - /* */ - /* Computes the scan-line intersections of a descending line segment */ - /* and stores them in the render pool. */ - /* */ - /* */ - /* x1 :: The start x coordinate. */ - /* y1 :: The start y coordinate. */ - /* x2 :: The end x coordinate. */ - /* y2 :: The end y coordinate. */ - /* miny :: The minimum vertical grid coordinate. */ - /* maxy :: The maximum vertical grid coordinate. */ - /* */ - /* */ - /* SUCCESS or FAILURE. */ - /* */ - static - TResult Line_Down( RAS_ARG_ TPos x1, TPos y1, - TPos x2, TPos y2, - TPos miny, TPos maxy ) - { - TResult result, fresh; - - - /* simply invert the coordinates and call Line_Up */ - fresh = ras.fresh; - result = Line_Up( RAS_VAR_ x1, -y1, x2, -y2, -maxy, -miny ); - - /* if this was a fresh profile, invert the recorded start position */ - if ( fresh && !ras.fresh ) - ras.cur_prof->start = -ras.cur_prof->start; - - return result; - } - - - - - /* A function type describing the functions used to split bezier arcs */ - typedef void (*TSplitter)( TPoint* base ); - -#ifdef FT_DYNAMIC_BEZIER_STEPS - static - TPos Dynamic_Bezier_Threshold( RAS_ARG_ int degree, TPoint* arc ) - { - TPos min_x, max_x, min_y, max_y, A, B; - TPos wide_x, wide_y, threshold; - TPoint* cur = arc; - TPoint* limit = cur + degree; - - /* first of all, set the threshold to the maximum x or y extent */ - min_x = max_x = arc[0].x; - min_y = max_y = arc[0].y; - cur++; - for ( ; cur < limit; cur++ ) - { - TPos x = cur->x; - TPos y = cur->y; - - if ( x < min_x ) min_x = x; - if ( x > max_x ) max_x = x; - - if ( y < min_y ) min_y = y; - if ( y > max_y ) max_y = y; - } - wide_x = (max_x - min_x) << 4; - wide_y = (max_y - min_y) << 4; - - threshold = wide_x; - if (threshold < wide_y) threshold = wide_y; - - /* now compute the second and third order error values */ - - wide_x = arc[0].x + arc[1].x - arc[2].x*2; - wide_y = arc[0].y + arc[1].y - arc[2].y*2; - - if (wide_x < 0) wide_x = -wide_x; - if (wide_y < 0) wide_y = -wide_y; - - A = wide_x; if ( A < wide_y ) A = wide_y; - - if (degree >= 3) - { - wide_x = arc[3].x - arc[0].x + 3*(arc[2].x - arc[3].x); - wide_y = arc[3].y - arc[0].y + 3*(arc[2].y - arc[3].y); - - if (wide_x < 0) wide_x = -wide_x; - if (wide_y < 0) wide_y = -wide_y; - - B = wide_x; if ( B < wide_y ) B = wide_y; - } - else - B = 0; - - while ( A > 0 || B > 0 ) - { - threshold >>= 1; - A >>= 2; - B >>= 3; - } - - if (threshold < PRECISION_STEP) - threshold = PRECISION_STEP; - - return threshold; - } -#endif - - /*************************************************************************/ - /* */ - /* */ - /* Bezier_Up */ - /* */ - /* */ - /* Computes the scan-line intersections of an ascending second-order */ - /* Bezier arc and stores them in the render pool. The arc is taken */ - /* from the top of the stack. */ - /* */ - /* */ - /* miny :: The minimum vertical grid coordinate. */ - /* maxy :: The maximum vertical grid coordinate. */ - /* */ - /* */ - /* SUCCESS or FAILURE. */ - /* */ - static - TResult Bezier_Up( RAS_ARG_ int degree, - TSplitter splitter, - TPos miny, - TPos maxy ) - { - TPos y1, y2, e, e2, e0, threshold; - int f1; - - TPoint* arc; - TPoint* start_arc; - - PPos top; - - - arc = ras.arc; - y1 = arc[degree].y; - y2 = arc[0].y; - top = ras.cursor; - - if ( y2 < miny || y1 > maxy ) - goto Fin; - - e2 = FLOOR( y2 ); /* integer end y */ - -#ifdef OLD - if ( e2 > maxy ) - e2 = maxy; - - e0 = miny; -#else - if ( e2 > maxy ) - e2 = FLOOR(maxy); - - e0 = CEILING(miny); -#endif - - - if ( y1 < miny ) - { - e = e0; /* integer start y == current scanline */ - } - else - { - e = CEILING( y1 ); /* integer start y == current scanline */ - f1 = FRAC( y1 ); /* fractional shift of start y */ - e0 = e; /* first integer scanline to be pushed */ - - if ( f1 == 0 ) /* do we start on an integer scanline? */ - { - if ( ras.joint ) - { - top--; - ras.joint = FALSE; - } - - *top++ = arc[degree].x; /* write directly start position */ - - DEBUG_PSET; - - e += PRECISION; /* go to next scanline */ - } - } - - /* record start position if necessary */ - if ( ras.fresh ) - { - ras.cur_prof->start = TRUNC( e0 ); - ras.fresh = FALSE; - } - - /* exit if the current scanline is already above the max scanline */ - if ( e2 < e ) - goto Fin; - - /* check for overflow */ - if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.pool_limit ) - { - ras.cursor = top; - ras.error = ErrRaster_Overflow; - return FAILURE; - } - - -#ifdef FT_DYNAMIC_BEZIER_STEPS - /* compute dynamic bezier step threshold */ - threshold = Dynamic_Bezier_Threshold( RAS_VAR_ degree, arc ); -#else - threshold = PRECISION_STEP; -#endif - - start_arc = arc; - - /* loop while there is still an arc on the bezier stack */ - /* and the current scan line is below y max == e2 */ - while ( arc >= start_arc && e <= e2 ) - { - ras.joint = FALSE; - - y2 = arc[0].y; /* final y of the top-most arc */ - - if ( y2 > e ) /* the arc intercepts the current scanline */ - { - y1 = arc[degree].y; /* start y of top-most arc */ - -#ifdef OLD - if ( y2-y1 >= PRECISION_STEP ) -#else - if ( y2 >= e + PRECISION || y2 - y1 >= threshold ) -#endif - { - /* if the arc's height is too great, split it */ - splitter( arc ); - arc += degree; - } - else - { - /* otherwise, approximate it as a segment and compute */ - /* its intersection with the current scanline */ - *top++ = arc[degree].x + - FMulDiv( arc[0].x-arc[degree].x, - e - y1, - y2 - y1 ); - - DEBUG_PSET; - - arc -= degree; /* pop the arc */ - e += PRECISION; /* go to next scanline */ - } - } - else - { - if ( y2 == e ) /* if the arc falls on the scanline */ - { /* record its _joint_ intersection */ - ras.joint = TRUE; - *top++ = arc[0].x; - - DEBUG_PSET; - - e += PRECISION; /* go to next scanline */ - } - arc -= degree; /* pop the arc */ - } - } - - Fin: - ras.cursor = top; - ras.arc -= degree; - return SUCCESS; - } - - /*************************************************************************/ - /* */ - /* */ - /* Bezier_Down */ - /* */ - /* */ - /* Computes the scan-line intersections of a descending second-order */ - /* Bezier arc and stores them in the render pool. The arc is taken */ - /* from the top of the stack. */ - /* */ - /* */ - /* miny :: The minimum vertical grid coordinate. */ - /* maxy :: The maximum vertical grid coordinate. */ - /* */ - /* */ - /* SUCCESS or FAILURE. */ - /* */ - static - TResult Bezier_Down( RAS_ARG_ int degree, - TSplitter splitter, - TPos miny, - TPos maxy ) - { - TPoint* arc = ras.arc; - TResult result, fresh; - - arc[0].y = -arc[0].y; - arc[1].y = -arc[1].y; - arc[2].y = -arc[2].y; - if (degree > 2) - arc[3].y = -arc[3].y; - - fresh = ras.fresh; - - result = Bezier_Up( RAS_VAR_ degree, splitter, -maxy, -miny ); - - if ( fresh && !ras.fresh ) - ras.cur_prof->start = -ras.cur_prof->start; - - arc[0].y = -arc[0].y; - return result; - } - - - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /**** ****/ - /**** ****/ - /**** SPLITTING CONIC AND CUBIC BEZIERS IN HALF ****/ - /**** ****/ - /**** ****/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - - -#ifdef FT_RASTER_CONIC_BEZIERS - - /*************************************************************************/ - /* */ - /* */ - /* Split_Conic */ - /* */ - /* */ - /* Subdivides one second-order Bezier arc into two joint sub-arcs in */ - /* the Bezier stack. */ - /* */ - /* */ - /* 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_Conic( TPoint* base ) - { - TPos a, b; + Long a, b; base[4].x = base[2].x; b = base[1].x; - a = base[3].x = ( base[2].x + b + 1 ) >> 1; - b = base[1].x = ( base[0].x + b + 1 ) >> 1; - base[2].x = ( a + b + 1 ) >> 1; + 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 + 1 ) >> 1; - b = base[1].y = ( base[0].y + b + 1 ) >> 1; + 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 too good at common expression */ + /* substitution and instruction scheduling ;-) */ } -#endif - -#ifdef FT_RASTER_CUBIC_BEZIERS /*************************************************************************/ /* */ @@ -1671,8 +769,7 @@ static void Split_Cubic( TPoint* base ) { - TPos a, b, c, d; - + Long a, b, c, d; base[6].x = base[3].x; c = base[1].x; @@ -1695,286 +792,405 @@ base[3].y = ( a + b + 1 ) >> 1; } -#endif /* FT_RASTER_CUBIC_BEZIERS */ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /**** ****/ - /**** ****/ - /**** PROCESSING OUTLINE SEGMENTS ****/ - /**** ****/ - /**** ****/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ +/****************************************************************************/ +/* */ +/* Function: Line_Up */ +/* */ +/* Description: Computes the x-coordinates of an ascending line segment */ +/* and stores them in the render pool. */ +/* */ +/* Input: x1,y1,x2,y2 Segment start (x1,y1) and end (x2,y2) points */ +/* */ +/* Returns: SUCCESS on success. */ +/* FAILURE on Render Pool overflow. */ +/* */ +/****************************************************************************/ - - - /*************************************************************************/ - /* */ - /* */ - /* Check_Contour */ - /* */ - /* */ - /* Performs some checks at contour closure. */ - /* */ - /* */ - /* SUCCESS or FAILURE. */ - /* */ - static - TResult Check_Contour( RAS_ARG ) + static Bool Line_Up( RAS_ARGS Long x1, Long y1, + Long x2, Long y2, + Long miny, Long maxy ) { - PProfile lastProfile; + Long Dx, Dy; + Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */ + Long Ix, Rx, Ax; - /* Sometimes, the first and last profile in a contour join on */ - /* an integer scan-line; we must then remove the last intersection */ - /* from the last profile to get rid of doublets */ - if ( ( FRAC( ras.last.y ) == 0 && - ras.last.y >= ras.minY && - ras.last.y <= ras.maxY ) ) + PLong top; + + + Dx = x2 - x1; + Dy = y2 - y1; + + if ( Dy <= 0 || y2 < miny || y1 > maxy ) + return SUCCESS; + + if ( y1 < miny ) { - if ( ras.first_prof && ras.first_prof->flow == ras.cur_prof->flow ) - ras.cursor--; - } - - lastProfile = ras.cur_prof; - if ( End_Profile( RAS_VAR ) ) - return FAILURE; - - /* close the `next profile in contour' linked list */ - lastProfile->next = ras.first_prof; - - return SUCCESS; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Move_To */ - /* */ - /* */ - /* This function injects a new contour in the render pool. */ - /* */ - /* */ - /* to :: A pointer to the contour's first point. */ - /* raster :: A pointer to the current raster object. */ - /* */ - /* */ - /* Error code. 0 means success. */ - /* */ - /* */ - /* This function is used as a `FTRasterMoveTo_Func' by the outline */ - /* decomposer. */ - /* */ - static - int Move_To( FT_Vector* to, - FT_Raster raster ) - { - TPos scaled_x, scaled_y; - - - /* if there was already a contour being built, perform some checks */ - if ( ras.start_prof ) - if ( Check_Contour( RAS_VAR ) ) - return FAILURE; - - /* set the `current last point' */ - scaled_x = SCALED( to->x ); - scaled_y = SCALED( to->y ); - - if ( ras.flipped ) - { - ras.last.x = scaled_y; - ras.last.y = scaled_x; + /* 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 = TRUNC( miny ); + f1 = 0; } else { - ras.last.x = scaled_x; - ras.last.y = scaled_y; + e1 = TRUNC( y1 ); + f1 = FRAC( y1 ); } - ras.state = Unknown; - ras.first_prof = NULL; - - return SUCCESS; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Line_To */ - /* */ - /* */ - /* This function injects a new line segment in the render pool and */ - /* adjusts the profiles list accordingly. */ - /* */ - /* */ - /* to :: A pointer to the target position. */ - /* raster :: A pointer to the current raster object. */ - /* */ - /* */ - /* Error code. 0 means success. */ - /* */ - /* */ - /* This function is used as a `FTRasterLineTo_Func' by the outline */ - /* decomposer. */ - /* */ - static - int Line_To( FT_Vector* to, - FT_Raster raster ) - { - TPos x, scaled_x; - TPos y, scaled_y; - - - scaled_x = SCALED( to->x ); - scaled_y = SCALED( to->y ); - - if ( ras.flipped ) + if ( y2 > maxy ) { - x = scaled_y; - y = scaled_x; + /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */ + e2 = TRUNC( maxy ); + f2 = 0; } else { - x = scaled_x; - y = scaled_y; + e2 = TRUNC( y2 ); + f2 = FRAC( y2 ); } - /* First, detect a change of direction */ - if ( y != ras.last.y ) + if ( f1 > 0 ) { - TDirection new_state = ( (y > ras.last.y) ? Ascending : Descending ); - - - if ( ras.state != new_state ) + if ( e1 == e2 ) return SUCCESS; + else { - if ( ras.state != Unknown && - End_Profile( RAS_VAR ) ) - goto Fail; + x1 += FMulDiv( Dx, ras.precision - f1, Dy ); + e1 += 1; + } + } + else + if ( ras.joint ) + { + ras.top--; + ras.joint = FALSE; + } - if ( New_Profile( RAS_VAR_ new_state ) ) - goto Fail; + ras.joint = ( 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 = (ras.precision*Dx) / Dy; + Rx = (ras.precision*Dx) % Dy; + Dx = 1; + } + else + { + Ix = -( (ras.precision*-Dx) / Dy ); + 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; + } + + + 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 ); + + if ( fresh && !ras.fresh ) + ras.cProfile->start = -ras.cProfile->start; + + return result; + } + + +/****************************************************************************/ +/* */ +/* Function: Bezier_Up */ +/* */ +/* Description: Computes thes x-coordinates of an ascending bezier arc */ +/* and stores them in the render pool. */ +/* */ + + /* A function type describing the functions used to split bezier arcs */ + typedef void (*TSplitter)( TPoint* base ); + + static Bool Bezier_Up( RAS_ARGS Int degree, + TSplitter splitter, + Long miny, + Long maxy ) + { + Long y1, y2, e, e2, e0; + Short f1; + + TPoint* arc; + TPoint* start_arc; + + PLong top; + + + arc = ras.arc; + y1 = arc[degree].y; + y2 = arc[0].y; + top = ras.top; + + if ( y2 < miny || y1 > maxy ) + goto Fin; + + e2 = FLOOR( y2 ); + + if ( e2 > maxy ) + e2 = maxy; + + e0 = miny; + + if ( y1 < miny ) + e = miny; + else + { + e = CEILING( y1 ); + f1 = FRAC( y1 ); + e0 = e; + + if ( f1 == 0 ) + { + if ( ras.joint ) + { + top--; + ras.joint = FALSE; + } + + *top++ = arc[degree].x; + + e += ras.precision; } } - /* Then compute the lines */ + if ( ras.fresh ) + { + ras.cProfile->start = TRUNC( e0 ); + ras.fresh = FALSE; + } + + if ( e2 < e ) + goto Fin; + + if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff ) + { + ras.top = top; + ras.error = Raster_Err_Overflow; + return FAILURE; + } + + start_arc = arc; + + while ( arc >= start_arc && e <= e2 ) + { + ras.joint = FALSE; + + y2 = arc[0].y; + + if ( y2 > e ) + { + y1 = arc[degree].y; + if ( y2 - y1 >= ras.precision_step ) + { + splitter( arc ); + arc += degree; + } + else + { + *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x, + e - y1, y2 - y1 ); + arc -= degree; + e += ras.precision; + } + } + else + { + if ( y2 == e ) + { + ras.joint = TRUE; + *top++ = arc[0].x; + + e += ras.precision; + } + arc -= degree; + } + } + + Fin: + ras.top = top; + ras.arc -= degree; + return SUCCESS; + } + + +/****************************************************************************/ +/* */ +/* Function: Bezier_Down */ +/* */ +/* Description: Computes the x-coordinates of a descending bezier arc */ +/* and stores them in the render pool. */ +/* */ + + static Bool Bezier_Down( RAS_ARGS Int degree, + TSplitter splitter, + Long miny, + Long maxy ) + { + TPoint* arc = ras.arc; + Bool result, fresh; + + + arc[0].y = -arc[0].y; + arc[1].y = -arc[1].y; + arc[2].y = -arc[2].y; + if (degree > 2) + arc[3].y = -arc[3].y; + + fresh = ras.fresh; + + result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny ); + + if ( fresh && !ras.fresh ) + ras.cProfile->start = -ras.cProfile->start; + + arc[0].y = -arc[0].y; + return result; + } + + +/****************************************************************************/ +/* */ +/* Function: Line_To */ +/* */ +/* Description: Injects a new line segment and adjusts Profiles list. */ +/* */ +/* Input: x, y : segment endpoint (start point in LastX,LastY) */ +/* */ +/* Returns: SUCCESS on success. */ +/* FAILURE on Render Pool overflow or Incorrect Profile. */ +/* */ +/****************************************************************************/ + + static Bool Line_To( RAS_ARGS Long x, Long y ) + { + /* First, detect a change of direction */ + switch ( ras.state ) { + case Unknown: + if ( y > ras.lastY ) + { + if ( New_Profile( RAS_VARS Ascending ) ) return FAILURE; + } + else + { + if ( y < ras.lastY ) + if ( New_Profile( RAS_VARS Descending ) ) return FAILURE; + } + break; + case Ascending: - if ( Line_Up ( RAS_VAR_ ras.last.x, ras.last.y, - x, y, ras.minY, ras.maxY ) ) - goto Fail; + if ( y < ras.lastY ) + { + if ( End_Profile( RAS_VAR ) || + New_Profile( RAS_VARS Descending ) ) return FAILURE; + } break; case Descending: - if ( Line_Down( RAS_VAR_ ras.last.x, ras.last.y, - x, y, ras.minY, ras.maxY ) ) - goto Fail; + if ( y > ras.lastY ) + { + if ( End_Profile( RAS_VAR ) || + New_Profile( RAS_VARS Ascending ) ) return FAILURE; + } break; default: ; } - ras.last.x = x; - ras.last.y = y; + /* Then compute the lines */ + + switch ( ras.state ) + { + case Ascending: + if ( Line_Up ( RAS_VARS ras.lastX, ras.lastY, + x, y, ras.minY, ras.maxY ) ) + return FAILURE; + break; + + case Descending: + if ( Line_Down( RAS_VARS ras.lastX, ras.lastY, + x, y, ras.minY, ras.maxY ) ) + return FAILURE; + break; + + default: + ; + } + + ras.lastX = x; + ras.lastY = y; return SUCCESS; - - Fail: - return FAILURE; } -#ifdef FT_RASTER_CONIC_BEZIERS +/****************************************************************************/ +/* */ +/* Function: Conic_To */ +/* */ +/* Description: Injects a new conic arc and adjusts the profile list. */ +/* */ - /*************************************************************************/ - /* */ - /* */ - /* Push_Conic */ - /* */ - /* */ - /* Clears the Bezier stack and pushes a new arc on top of it. */ - /* */ - /* */ - /* p2 :: A pointer to the second (control) point. */ - /* p3 :: A pointer to the third (end) point. */ - /* */ - /* */ - /* The first point is taken as `raster->last', so it doesn't appear */ - /* in the signature. */ - /* */ - static - void Push_Conic( RAS_ARG_ FT_Vector* p2, - FT_Vector* p3 ) + static Bool Conic_To( RAS_ARGS Long cx, + Long cy, + Long x, + Long y ) { -#undef STORE -#define STORE( _arc, point ) \ - { \ - TPos x = SCALED( point->x ); \ - TPos y = SCALED( point->y ); \ - \ - \ - if ( ras.flipped ) \ - { \ - _arc.x = y; \ - _arc.y = x; \ - } \ - else \ - { \ - _arc.x = x; \ - _arc.y = y; \ - } \ - } - - TPoint* arc; + Long y1, y2, y3, x3, ymin, ymax; + TStates state_bez; - ras.arc = arc = ras.arcs; - - arc[2] = ras.last; - STORE( arc[1], p2 ); - STORE( arc[0], p3 ); -#undef STORE - } - - - /*************************************************************************/ - /* */ - /* */ - /* Conic_To */ - /* */ - /* */ - /* Injects a new conic Bezier arc and adjusts the profile list */ - /* accordingly. */ - /* */ - /* */ - /* control :: A pointer to an intermediate control point. */ - /* to :: A pointer to the end point. */ - /* raster :: A handle to the current raster object. */ - /* */ - /* */ - /* Error code. 0 means success. */ - /* */ - /* */ - /* This function is used as a `FTRasterConicTo_Func' by the outline */ - /* decomposer. */ - /* */ - static - int Conic_To( FT_Vector* control, - FT_Vector* to, - FT_Raster raster ) - { - TPos y1, y2, y3, x3, ymin, ymax; - TDirection state_bez; - - - Push_Conic( RAS_VAR_ control, to ); + ras.arc = ras.arcs; + ras.arc[2].x = ras.lastX; + ras.arc[2].y = ras.lastY; + ras.arc[1].x = cx; ras.arc[1].y = cy; + ras.arc[0].x = x; ras.arc[0].y = y; do { @@ -2020,141 +1236,55 @@ goto Fail; /* create a new profile */ - if ( New_Profile( RAS_VAR_ state_bez ) ) + if ( New_Profile( RAS_VARS state_bez ) ) goto Fail; } /* now call the appropriate routine */ if ( state_bez == Ascending ) { - if ( Bezier_Up( RAS_VAR_ 2, Split_Conic, ras.minY, ras.maxY ) ) + if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) goto Fail; } else - if ( Bezier_Down( RAS_VAR_ 2, Split_Conic, ras.minY, ras.maxY ) ) + if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) goto Fail; } } while ( ras.arc >= ras.arcs ); - ras.last.x = x3; - ras.last.y = y3; + ras.lastX = x3; + ras.lastY = y3; return SUCCESS; - Fail: return FAILURE; } -#else /* FT_RASTER_CONIC_BEZIERS */ +/****************************************************************************/ +/* */ +/* Function: Cubic_To */ +/* */ +/* Description: Injects a new cubic arc and adjusts the profile list. */ +/* */ - - static - int Conic_To( FT_Vector* control, - FT_Vector* to, - FT_Raster raster ) + static Bool Cubic_To( RAS_ARGS Long cx1, + Long cy1, + Long cx2, + Long cy2, + Long x, + Long y ) { - UNUSED( control ); - UNUSED( to ); - UNUSED( raster ); - - return ErrRaster_Invalid_Outline; - } - -#endif /* FT_RASTER_CONIC_BEZIERS */ + Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; + TStates state_bez; -#ifdef FT_RASTER_CUBIC_BEZIERS - - /*************************************************************************/ - /* */ - /* */ - /* Push_Cubic */ - /* */ - /* */ - /* Clears the Bezier stack and pushes a new third-order Bezier arc on */ - /* top of it. */ - /* */ - /* */ - /* p2 :: A pointer to the second (control) point. */ - /* p3 :: A pointer to the third (control) point. */ - /* p4 :: A pointer to the fourth (end) point. */ - /* */ - /* */ - /* The first point is taken as `raster->last', so it doesn't appear */ - /* in the signature. */ - /* */ - /* This is the same as Push_Conic(), except that it deals with */ - /* third-order Beziers. */ - /* */ - static - void Push_Cubic( RAS_ARG_ FT_Vector* p2, - FT_Vector* p3, - FT_Vector* p4 ) - { -#undef STORE -#define STORE( _arc, point ) \ - { \ - TPos x = SCALED( point->x ); \ - TPos y = SCALED( point->y ); \ - \ - if ( ras.flipped ) \ - { \ - _arc.x = y; \ - _arc.y = x; \ - } \ - else \ - { \ - _arc.x = x; \ - _arc.y = y; \ - } \ - } - - TPoint* arc; - ras.arc = arc = ras.arcs; - - arc[3] = ras.last; - STORE( arc[2], p2 ); - STORE( arc[1], p3 ); - STORE( arc[0], p4 ); - -#undef STORE - } - - - /*************************************************************************/ - /* */ - /* */ - /* Cubic_To */ - /* */ - /* */ - /* Injects a new cubic Bezier arc and adjusts the profile list */ - /* accordingly. */ - /* */ - /* */ - /* control1 :: A pointer to the first control point. */ - /* control2 :: A pointer to the second control point. */ - /* to :: A pointer to the end point. */ - /* raster :: A handle to the current raster object. */ - /* */ - /* */ - /* Error code. 0 means success. */ - /* */ - /* */ - /* This function is used as a `FTRasterCubicTo_Func' by the outline */ - /* decomposer. */ - /* */ - static - int Cubic_To( FT_Vector* control1, - FT_Vector* control2, - FT_Vector* to, - FT_Raster raster ) - { - TPos y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; - TDirection state_bez; - - - Push_Cubic( RAS_VAR_ control1, control2, to ); + ras.arc = ras.arcs; + ras.arc[3].x = ras.lastX; + ras.arc[3].y = ras.lastY; + ras.arc[2].x = cx1; ras.arc[2].y = cy1; + ras.arc[1].x = cx2; ras.arc[1].y = cy2; + ras.arc[0].x = x; ras.arc[0].y = y; do { @@ -2210,135 +1340,345 @@ End_Profile( RAS_VAR ) ) goto Fail; - if ( New_Profile( RAS_VAR_ state_bez ) ) + if ( New_Profile( RAS_VARS state_bez ) ) goto Fail; } /* compute intersections */ if ( state_bez == Ascending ) { - if ( Bezier_Up ( RAS_VAR_ 3, Split_Cubic, ras.minY, ras.maxY ) ) + if ( Bezier_Up ( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) goto Fail; } else - if ( Bezier_Down ( RAS_VAR_ 3, Split_Cubic, ras.minY, ras.maxY ) ) + if ( Bezier_Down ( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) goto Fail; } } while ( ras.arc >= ras.arcs ); - ras.last.x = x4; - ras.last.y = y4; + ras.lastX = x4; + ras.lastY = y4; return SUCCESS; - Fail: return FAILURE; } -#else /* FT_RASTER_CUBIC_BEZIERS */ +/****************************************************************************/ +/* */ +/* Function: Decompose_Curve */ +/* */ +/* Description: Scans the outline arays in order to emit individual */ +/* segments and beziers by calling Line_To() and Bezier_To(). */ +/* It handles all weird cases, like when the first point */ +/* is off the curve, or when there are simply no 'on' */ +/* points in the contour! */ +/* */ +/* Input: first, last : indexes of first and last point in */ +/* contour. */ +/* */ +/* Returns: SUCCESS on success. */ +/* FAILURE on error. */ +/* */ +/****************************************************************************/ + +#undef SWAP_ +#define SWAP_(x,y) { Long swap = x; x = y; y = swap; } - int Cubic_To( FT_Vector* control1, - FT_Vector* control2, - FT_Vector* to, - FT_Raster raster ) + static Bool Decompose_Curve( RAS_ARGS UShort first, + UShort last, + int flipped ) { - UNUSED( control1 ); - UNUSED( control2 ); - UNUSED( to ); - UNUSED( raster ); + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; - return ErrRaster_Invalid_Outline; - } + FT_Vector* points; + FT_Vector* point; + FT_Vector* limit; + char* tags; + char tag; /* current point's state */ -#endif /* FT_RASTER_CUBIC_BEZIERS */ + points = ras.outline.points; + limit = points + last; - - - /*************************************************************************/ - /* */ - /* */ - /* Convert_Glyph */ - /* */ - /* */ - /* Converts a glyph into a series of segments and arcs and makes a */ - /* profiles list with them. */ - /* */ - /* */ - /* outline :: The glyph outline. */ - /* */ - /* */ - /* SUCCESS or FAILURE. */ - /* */ - static - TResult Convert_Glyph( RAS_ARG_ FT_Outline* outline ) - { - static - FT_Outline_Funcs interface = + v_start.x = SCALED(points[first].x); + v_start.y = SCALED(points[first].y); + v_last.x = SCALED(points[last].x); + v_last.y = SCALED(points[last].y); + if (flipped) { - (FT_Outline_MoveTo_Func)Move_To, - (FT_Outline_LineTo_Func)Line_To, - (FT_Outline_ConicTo_Func)Conic_To, - (FT_Outline_CubicTo_Func)Cubic_To, - 0, - 0 - }; + SWAP_(v_start.x,v_start.y); + SWAP_(v_last.x,v_last.y); + } + + v_control = v_start; - /* Set up state in the raster object */ - ras.start_prof = NULL; - ras.joint = FALSE; - ras.fresh = FALSE; + point = points + first; + tags = ras.outline.tags + first; + tag = FT_CURVE_TAG( tags[0] ); - ras.pool_limit = ras.pool_size - AlignProfileSize; + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_Curve_Tag_Cubic ) + goto Invalid_Outline; - ras.n_extrema = 0; + /* check first point to determine origin */ + if ( tag == FT_Curve_Tag_Conic ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_Curve_Tag_On ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; - ras.cur_prof = (PProfile)ras.cursor; - ras.cur_prof->offset = ras.cursor; - ras.num_profs = 0; + v_last = v_start; + } + point--; + tags--; + } - /* Now decompose curve */ - if ( FT_Outline_Decompose( outline, &interface, &ras ) ) - return FAILURE; - /* XXX: the error condition is in ras.error */ + ras.lastX = v_start.x; + ras.lastY = v_start.y; - /* Check the last contour if needed */ - if ( Check_Contour( RAS_VAR ) ) + while (point < limit) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + switch (tag) + { + case FT_Curve_Tag_On: /* emit a single line_to */ + { + Long x, y; + + x = SCALED(point->x); + y = SCALED(point->y); + if (flipped) SWAP_(x,y); + + if (Line_To( RAS_VARS x, y )) goto Fail; + continue; + } + + + case FT_Curve_Tag_Conic: /* consume conic arcs */ + { + v_control.x = SCALED(point[0].x); + v_control.y = SCALED(point[0].y); + if (flipped) SWAP_(v_control.x,v_control.y); + + Do_Conic: + if (point < limit) + { + FT_Vector v_middle; + Long x, y; + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + x = SCALED(point[0].x); + y = SCALED(point[0].y); + if (flipped) SWAP_(x,y); + + if (tag == FT_Curve_Tag_On) + { + if (Conic_To( RAS_VARS v_control.x, v_control.y, x, y )) + goto Fail; + continue; + } + + if (tag != FT_Curve_Tag_Conic) + goto Invalid_Outline; + + v_middle.x = (v_control.x + x)/2; + v_middle.y = (v_control.y + y)/2; + + if (Conic_To( RAS_VARS v_control.x, v_control.y, + v_middle.x, v_middle.y )) goto Fail; + + v_control.x = x; + v_control.y = y; + goto Do_Conic; + } + + if (Conic_To( RAS_VARS v_control.x, v_control.y, + v_start.x, v_start.y )) goto Fail; + goto Close; + } + + default: /* FT_Curve_Tag_Cubic */ + { + Long x1, y1, x2, y2, x3, y3; + + if ( point+1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + x1 = SCALED(point[-2].x); + y1 = SCALED(point[-2].y); + x2 = SCALED(point[-1].x); + y2 = SCALED(point[-1].y); + x3 = SCALED(point[ 0].x); + y3 = SCALED(point[ 0].y); + if (flipped) + { + SWAP_(x1,y1); + SWAP_(x2,y2); + SWAP_(x3,y3); + } + if (point <= limit) + { + if (Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 )) + goto Fail; + continue; + } + + if (Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y )) + goto Fail; + goto Close; + } + } + } + + /* close the contour with a line segment */ + if (Line_To( RAS_VARS v_start.x, v_start.y )) + goto Fail; + + Close: + return SUCCESS; + + Invalid_Outline: + ras.error = Raster_Err_Invalid; + + Fail: + return FAILURE; + } + +/****************************************************************************/ +/* */ +/* Function: Convert_Glyph */ +/* */ +/* Description: Converts a glyph into a series of segments and arcs */ +/* and makes a Profiles list with them. */ +/* */ +/* Input: _xCoord, _yCoord : coordinates tables. */ +/* */ +/* Uses the 'Flag' table too. */ +/* */ +/* Returns: SUCCESS on success. */ +/* FAILURE if any error was encountered during rendering. */ +/* */ +/****************************************************************************/ + + static Bool Convert_Glyph( RAS_ARGS int flipped ) + { + Short i; + UShort start; + + PProfile lastProfile; + + + ras.fProfile = NULL; + ras.joint = FALSE; + ras.fresh = FALSE; + + ras.maxBuff = ras.sizeBuff - AlignProfileSize; + + ras.numTurns = 0; + + ras.cProfile = (PProfile)ras.top; + ras.cProfile->offset = ras.top; + ras.num_Profs = 0; + + start = 0; + + for ( i = 0; i < ras.outline.n_contours; i++ ) + { + ras.state = Unknown; + ras.gProfile = NULL; + + if ( Decompose_Curve( RAS_VARS start, ras.outline.contours[i], flipped ) ) + return FAILURE; + + start = ras.outline.contours[i] + 1; + + /* We must now see if the extreme arcs join or not */ + if ( ( FRAC( ras.lastY ) == 0 && + ras.lastY >= ras.minY && + ras.lastY <= ras.maxY ) ) + if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow ) + ras.top--; + /* Note that ras.gProfile can be nil if the contour was too small */ + /* to be drawn. */ + + lastProfile = ras.cProfile; + if ( End_Profile( RAS_VAR ) ) return FAILURE; + + /* close the 'next profile in contour' linked list */ + if ( ras.gProfile ) + lastProfile->next = ras.gProfile; + } + + if (Finalize_Profile_Table( RAS_VAR )) return FAILURE; - /* Finalize profiles list */ - return Finalize_Profile_Table( RAS_VAR ); + return (ras.top < ras.maxBuff ? SUCCESS : FAILURE ); } - /*************************************************************************/ - /* */ - /* Init_Linked */ - /* */ - /* Inits an empty linked list. */ - /* */ - static - void Init_Linked( TProfileList* l ) + /****************************************************************/ + /****************************************************************/ + /** **/ + /** SCAN-LINE SWEEPS AND DRAWING **/ + /** **/ + /****************************************************************/ + /****************************************************************/ + + +/************************************************/ +/* */ +/* Init_Linked */ +/* */ +/* Inits an empty linked list. */ +/* */ +/************************************************/ + + static void Init_Linked( TProfileList* l ) { *l = NULL; } - /*************************************************************************/ - /* */ - /* InsNew */ - /* */ - /* Inserts a new Profile in a linked list. */ - /* */ - static - void InsNew( PProfileList list, - PProfile profile ) +/************************************************/ +/* */ +/* InsNew : */ +/* */ +/* Inserts a new Profile in a linked list. */ +/* */ +/************************************************/ + + static void InsNew( PProfileList list, + PProfile profile ) { PProfile *old, current; - TPos x; + Long x; old = list; @@ -2358,15 +1698,16 @@ } - /*************************************************************************/ - /* */ - /* DelOld */ - /* */ - /* Removes an old Profile from a linked list. */ - /* */ - static - void DelOld( PProfileList list, - PProfile profile ) +/*************************************************/ +/* */ +/* DelOld : */ +/* */ +/* Removes an old Profile from a linked list. */ +/* */ +/*************************************************/ + + static void DelOld( PProfileList list, + PProfile profile ) { PProfile *old, current; @@ -2386,19 +1727,20 @@ current = *old; } - /* We should never reach this place, unless the Profile was not */ - /* part of the list. */ + /* we should never get there, unless the Profile was not part of */ + /* the list. */ } - /*************************************************************************/ - /* */ - /* Update */ - /* */ - /* Updates all X offsets of a drawing list. */ - /* */ - static - void Update( PProfile first ) +/************************************************/ +/* */ +/* Update : */ +/* */ +/* Update all X offsets of a drawing list */ +/* */ +/************************************************/ + + static void Update( PProfile first ) { PProfile current = first; @@ -2413,16 +1755,18 @@ } - /*************************************************************************/ - /* */ - /* Sort */ - /* */ - /* Sorts a trace list. In 95%, the list is already sorted. We need */ - /* an algorithm which is fast in this case. Bubble sort is enough */ - /* and simple to implement. */ - /* */ - static - void Sort( PProfileList list ) +/************************************************/ +/* */ +/* Sort : */ +/* */ +/* Sorts a trace list. In 95%, the list */ +/* is already sorted. We need an algorithm */ +/* which is fast in this case. Bubble sort */ +/* is enough and simple. */ +/* */ +/************************************************/ + + static void Sort( PProfileList list ) { PProfile *old, current, next; @@ -2464,98 +1808,70 @@ } - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /******** ********/ - /******** Vertical Bitmap Sweep Routines ********/ - /******** ********/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ +/***********************************************************************/ +/* */ +/* Vertical Sweep Procedure Set : */ +/* */ +/* These three routines are used during the vertical black/white */ +/* sweep phase by the generic Draw_Sweep() function. */ +/* */ +/***********************************************************************/ - - /*************************************************************************/ - /* */ - /* */ - /* Vertical_Sweep_Init */ - /* */ - /* */ - /* Initializes the vertical bitmap sweep. Called by the generic */ - /* sweep/draw routine before its loop. */ - /* */ - /* */ - /* min :: The address of the current minimum scanline. */ - /* max :: The address of the current maximum scanline. */ - /* */ - static - void Vertical_Sweep_Init( RAS_ARG_ int* min, int* max ) + static void Vertical_Sweep_Init( RAS_ARGS Short* min, Short* max ) { - long pitch; - - UNUSED( max ); - - pitch = ras.target.pitch; - - /* start from the bottom line, going up !! */ - ras.trace_bit = - *min * pitch; - ras.trace_incr = -pitch; - + Long pitch = ras.target.pitch; + + UNUSED(max); + + ras.traceIncr = (Short)- pitch; + ras.traceOfs = - *min * pitch; if (pitch > 0) - ras.trace_bit += pitch*(ras.target.rows-1); + ras.traceOfs += (ras.target.rows-1)*pitch; + + ras.gray_min_x = 0; + ras.gray_max_x = 0; } - /*************************************************************************/ - /* */ - /* */ - /* Vertical_Sweep_Span */ - /* */ - /* */ - /* Draws a single horizontal bitmap span during the vertical bitmap */ - /* sweep. */ - /* */ - /* */ - /* y :: The current scanline. */ - /* x1 :: The left span edge. */ - /* x2 :: The right span edge. */ - /* */ - static - void Vertical_Sweep_Span( RAS_ARG_ TScan y, - TPos x1, - TPos x2 ) + static void Vertical_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) { - TPos e1, e2; - int c1, c2; + Long e1, e2; + Short c1, c2; Byte f1, f2; - PByte target; + Byte* target; - UNUSED( y ); + UNUSED(y); + UNUSED(left); + UNUSED(right); /* Drop-out control */ + e1 = TRUNC( CEILING( x1 ) ); - - if ( x2 - x1 - PRECISION <= PRECISION_JITTER ) + + if ( x2-x1-ras.precision <= ras.precision_jitter ) e2 = e1; else e2 = TRUNC( FLOOR( x2 ) ); -#ifdef OLD - if ( e2 >= 0 && e1 < ras.bit_width ) -#else - if ( e1 <= e2 && e2 >= 0 && e1 < ras.bit_width ) -#endif + if ( e2 >= 0 && e1 < ras.bWidth ) { - if ( e1 < 0 ) e1 = 0; - if ( e2 >= ras.bit_width ) e2 = ras.bit_width - 1; + if ( e1 < 0 ) e1 = 0; + if ( e2 >= ras.bWidth ) e2 = ras.bWidth-1; - c1 = e1 >> 3; - c2 = e2 >> 3; + c1 = (Short)(e1 >> 3); + c2 = (Short)(e2 >> 3); f1 = ((unsigned char)0xFF >> (e1 & 7)); f2 = ~((unsigned char)0x7F >> (e2 & 7)); - target = ras.bit_buffer + ras.trace_bit + c1; + if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1; + if ( ras.gray_max_x < c2 ) ras.gray_max_x = c2; + + target = ras.bTarget + ras.traceOfs + c1; c2 -= c1; if ( c2 > 0 ) @@ -2579,828 +1895,543 @@ } - /*************************************************************************/ - /* */ - /* */ - /* Vertical_Test_Pixel */ - /* */ - /* */ - /* Tests a pixel `light' during the vertical bitmap sweep. Used */ - /* during drop-out control only. */ - /* */ - /* */ - /* y :: The current scanline. */ - /* x :: The current x coordinate. */ - /* */ - static - int Vertical_Test_Pixel( RAS_ARG_ TScan y, - int x ) + static void Vertical_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) { - int c1 = x >> 3; + Long e1, e2; + Short c1, f1; - UNUSED( y ); + /* Drop-out control */ - return ( x >= 0 && x < ras.bit_width && - ras.bit_buffer[ras.trace_bit + c1] & (0x80 >> (x & 7)) ); + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + + if ( e1 > e2 ) + { + if ( e1 == e2 + ras.precision ) + { + switch ( ras.dropOutControl ) + { + case 1: + e1 = e2; + break; + + case 4: + e1 = CEILING( (x1 + x2 + 1) / 2 ); + break; + + case 2: + case 5: + /* Drop-out Control Rule #4 */ + + /* The spec is not very clear regarding rule #4. It */ + /* presents a method that is way too costly to implement */ + /* while the general idea seems to get rid of 'stubs'. */ + /* */ + /* Here, we only get rid of stubs recognized when: */ + /* */ + /* upper stub: */ + /* */ + /* - P_Left and P_Right are in the same contour */ + /* - P_Right is the successor of P_Left in that contour */ + /* - y is the top of P_Left and P_Right */ + /* */ + /* lower stub: */ + /* */ + /* - P_Left and P_Right are in the same contour */ + /* - P_Left is the successor of P_Right in that contour */ + /* - y is the bottom of P_Left */ + /* */ + + /* FIXXXME : uncommenting this line solves the disappearing */ + /* bit problem in the '7' of verdana 10pts, but */ + /* makes a new one in the 'C' of arial 14pts */ + + /* if ( x2-x1 < ras.precision_half ) */ + { + /* upper stub test */ + + if ( left->next == right && left->height <= 0 ) return; + + /* lower stub test */ + + if ( right->next == left && left->start == y ) return; + } + + /* check that the rightmost pixel isn't set */ + + e1 = TRUNC( e1 ); + + c1 = (Short)(e1 >> 3); + f1 = e1 & 7; + + if ( e1 >= 0 && e1 < ras.bWidth && + ras.bTarget[ras.traceOfs + c1] & (0x80 >> f1) ) + return; + + if ( ras.dropOutControl == 2 ) + e1 = e2; + else + e1 = CEILING( (x1 + x2 + 1) / 2 ); + + break; + + default: + return; /* unsupported mode */ + } + } + else + return; + } + + e1 = TRUNC( e1 ); + + if ( e1 >= 0 && e1 < ras.bWidth ) + { + c1 = (Short)(e1 >> 3); + f1 = e1 & 7; + + if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1; + if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1; + + ras.bTarget[ras.traceOfs + c1] |= (char)(0x80 >> f1); + } } - /*************************************************************************/ - /* */ - /* */ - /* Vertical_Set_Pixel */ - /* */ - /* */ - /* Sets a single pixel in a bitmap during the vertical sweep. Used */ - /* during drop-out control. */ - /* */ - /* */ - /* y :: The current scanline. */ - /* x :: The current x coordinate. */ - /* color :: Ignored by this function. */ - /* */ - static - void Vertical_Set_Pixel( RAS_ARG_ int y, - int x, - int color ) + static void Vertical_Sweep_Step( RAS_ARG ) { - UNUSED( color ); - UNUSED( y ); - - if ( x >= 0 && x < ras.bit_width ) - ras.bit_buffer[ras.trace_bit+(x >> 3)] |= (char)(0x80 >> (x & 7)); + ras.traceOfs += ras.traceIncr; } - /*************************************************************************/ - /* */ - /* */ - /* Vertical_Sweep_Step */ - /* */ - /* */ - /* Called whenever the sweep jumps to another scanline. Only updates */ - /* the pointers in the vertical bitmap sweep. */ - /* */ - static - void Vertical_Sweep_Step( RAS_ARG ) +/***********************************************************************/ +/* */ +/* Horizontal Sweep Procedure Set : */ +/* */ +/* These three routines are used during the horizontal black/white */ +/* sweep phase by the generic Draw_Sweep() function. */ +/* */ +/***********************************************************************/ + + static void Horizontal_Sweep_Init( RAS_ARGS Short* min, Short* max ) { - ras.trace_bit += ras.trace_incr; - } - - - static - const Raster_Render vertical_render_mono = - { - &Vertical_Sweep_Init, - &Vertical_Sweep_Span, - &Vertical_Sweep_Step, - &Vertical_Test_Pixel, - &Vertical_Set_Pixel - }; - - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /******** ********/ - /******** Horizontal Bitmap Sweep Routines ********/ - /******** ********/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - - - /*************************************************************************/ - /* */ - /* */ - /* Horizontal_Sweep_Init */ - /* */ - /* */ - /* Initializes the horizontal bitmap sweep. Called by the generic */ - /* sweep/draw routine before its loop. */ - /* */ - /* */ - /* min :: The address of the current minimum pixel column. */ - /* max :: The address of the current maximum pixel column. */ - /* */ - static - void Horizontal_Sweep_Init( RAS_ARG_ int* min, - int* max ) - { - UNUSED( ras ); - UNUSED( min ); - UNUSED( max ); - /* nothing, really */ + UNUSED(raster); + UNUSED(min); + UNUSED(max); } - /*************************************************************************/ - /* */ - /* */ - /* Horizontal_Sweep_Span */ - /* */ - /* */ - /* Draws a single vertical bitmap span during the horizontal bitmap */ - /* sweep. Actually, this function is only used to check for weird */ - /* drop-out cases. */ - /* */ - /* */ - /* y :: The current pixel column. */ - /* x1 :: The top span edge. */ - /* x2 :: The bottom span edge. */ - /* */ - static - void Horizontal_Sweep_Span( RAS_ARG_ TScan y, - TPos x1, - TPos x2 ) + static void Horizontal_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) { - TPos e1, e2; - PByte bits; - Byte f1; + Long e1, e2; + PByte bits; + Byte f1; - UNUSED( y ); - - /* During the horizontal sweep, we only take care of drop-outs */ - if ( x2 - x1 < PRECISION ) + UNUSED(left); + UNUSED(right); + + if ( x2-x1 < ras.precision ) { e1 = CEILING( x1 ); - e2 = FLOOR( x2 ); + e2 = FLOOR ( x2 ); if ( e1 == e2 ) { - bits = ras.bit_buffer + (y >> 3); - f1 = (Byte)(0x80 >> (y & 7)); + bits = ras.bTarget + (y >> 3); + f1 = (Byte)(0x80 >> (y & 7)); e1 = TRUNC( e1 ); if ( e1 >= 0 && e1 < ras.target.rows ) { - long pitch = ras.target.pitch; - long offset = - pitch * e1; + PByte p; - if (pitch > 0) - offset += (ras.target.rows-1)*pitch; - - bits[offset] |= f1; + p = bits - e1*ras.target.pitch; + if (ras.target.pitch > 0) + p += (ras.target.rows-1)*ras.target.pitch; + + p[0] |= f1; } } } } - /*************************************************************************/ - /* */ - /* */ - /* Horizontal_Test_Pixel */ - /* */ - /* */ - /* Tests a pixel `light' during the horizontal bitmap sweep. Used */ - /* during drop-out control only. */ - /* */ - /* */ - /* y :: The current pixel column. */ - /* x :: The current row/scanline. */ - /* */ - static - int Horizontal_Test_Pixel( RAS_ARG_ int y, - int x ) + static void Horizontal_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) { - char* bits = (char*)ras.bit_buffer + (y >> 3); - int f1 = (Byte)(0x80 >> (y & 7)); - long pitch = ras.target.pitch; - long offset = - pitch * x; - - if (pitch > 0) - offset += (ras.target.rows-1)*pitch; - - return ( x >= 0 && x < ras.target.rows && (bits[0] & f1) ); - } + Long e1, e2; + PByte bits; + Byte f1; - /*************************************************************************/ - /* */ - /* */ - /* Horizontal_Set_Pixel */ - /* */ - /* */ - /* Sets a single pixel in a bitmap during the horizontal sweep. Used */ - /* during drop-out control. */ - /* */ - /* */ - /* y :: The current pixel column. */ - /* x :: The current row/scanline. */ - /* color :: Ignored by this function. */ - /* */ - static - void Horizontal_Set_Pixel( RAS_ARG_ int y, - int x, - int color ) - { - char* bits = (char*)ras.bit_buffer + (y >> 3); - int f1 = (Byte)(0x80 >> (y & 7)); + /* During the horizontal sweep, we only take care of drop-outs */ + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); - UNUSED( color ); - - if ( x >= 0 && x < ras.target.rows ) + if ( e1 > e2 ) { - long pitch = ras.target.pitch; - long offset = - x*pitch; - - if (pitch > 0) - offset += (ras.target.rows-1)*pitch; - - bits[offset] |= f1; - } - } - - - /*************************************************************************/ - /* */ - /* */ - /* Horizontal_Sweep_Step */ - /* */ - /* */ - /* Called whenever the sweep jumps to another pixel column. */ - /* */ - static - void Horizontal_Sweep_Step( RAS_ARG ) - { - UNUSED( ras.target ); - - /* Nothing, really */ - } - - - static - const Raster_Render horizontal_render_mono = - { - &Horizontal_Sweep_Init, - &Horizontal_Sweep_Span, - &Horizontal_Sweep_Step, - &Horizontal_Test_Pixel, - &Horizontal_Set_Pixel - }; - - - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /******** ********/ - /******** Anti-Aliased Vertical Bitmap Sweep Routines ********/ - /******** ********/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - -#ifdef FT_RASTER_OPTION_ANTI_ALIAS - - /*************************************************************************/ - /* */ - /* */ - /* Vertical_Gray_Sweep_Init */ - /* */ - /* */ - /* Initializes the vertical bitmap sweep. Called by the generic */ - /* sweep/draw routine before its loop. */ - /* */ - /* */ - /* min :: The address of the current minimum scanline. */ - /* max :: The address of the current maximum scanline. */ - /* */ - static - void Vertical_Gray_Sweep_Init( RAS_ARG_ int* min, int* max ) - { - long pitch; - - UNUSED( max ); - - pitch = ras.target.pitch; - - /* start from the bottom line, going up */ - ras.trace_incr = -pitch; - ras.trace_bit = - *min * pitch; - - if (pitch > 0) - ras.trace_bit += (ras.target.rows-1)*pitch; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Vertical_Gray_Sweep_Span */ - /* */ - /* */ - /* Draws a single horizontal bitmap span during the vertical bitmap */ - /* sweep. */ - /* */ - /* */ - /* y :: The current scanline. */ - /* x1 :: The left span edge. */ - /* x2 :: The right span edge. */ - /* */ - static - void Vertical_Gray_Sweep_Span( RAS_ARG_ TScan y, - TPos x1, - TPos x2 ) - { - TPos e1, e2; - int shift = PRECISION_BITS - 6; - PByte target; - - UNUSED( y ); - - x1 += PRECISION_HALF; - x2 += PRECISION_HALF; - - e1 = TRUNC( x1 ); - e2 = TRUNC( x2 ); - - if ( e1 <= e2 && e2 >= 0 && e1 < ras.bit_width ) - { - x1 = FRAC(x1) >> shift; - x2 = FRAC(x2) >> shift; - - if ( e1 < 0 ) + if ( e1 == e2 + ras.precision ) { - e1 = 0; - x1 = 0; - } - - if ( e2 > ras.bit_width ) - { - e2 = ras.bit_width-1; - x2 = 0; - } - - target = ras.bit_buffer + ras.trace_bit + e1; - e2 -= e1; - - if ( e2 > 0 ) - { - if (x1 > 0) target[0] += (Byte)(64-x1) << 1; - else target[0] = 127; - e2--; - while (e2 > 0) + switch ( ras.dropOutControl ) { - *(++target) = 127; - e2--; + case 1: + e1 = e2; + break; + + case 4: + e1 = CEILING( (x1 + x2 + 1) / 2 ); + break; + + case 2: + case 5: + + /* Drop-out Control Rule #4 */ + + /* The spec is not very clear regarding rule #4. It */ + /* presents a method that is way too costly to implement */ + /* while the general idea seems to get rid of 'stubs'. */ + /* */ + + /* rightmost stub test */ + + if ( left->next == right && left->height <= 0 ) return; + + /* leftmost stub test */ + + if ( right->next == left && left->start == y ) return; + + /* check that the rightmost pixel isn't set */ + + e1 = TRUNC( e1 ); + + bits = ras.bTarget + (y >> 3); + f1 = (Byte)(0x80 >> (y & 7)); + + bits -= e1*ras.target.pitch; + if (ras.target.pitch > 0) + bits += (ras.target.rows-1)*ras.target.pitch; + + if ( e1 >= 0 && + e1 < ras.target.rows && + *bits & f1 ) + return; + + if ( ras.dropOutControl == 2 ) + e1 = e2; + else + e1 = CEILING( (x1 + x2 + 1) / 2 ); + + break; + + default: + return; /* unsupported mode */ } - if (x2) - target[1] += (Byte)x2 << 1; } else - { - target[0] += (Byte)(x2-x1) << 1; - } + return; } - } - /*************************************************************************/ - /* */ - /* */ - /* Vertical_Gray_Test_Pixel */ - /* */ - /* */ - /* Tests a pixel `light' during the vertical bitmap sweep. Used */ - /* during drop-out control only. */ - /* */ - /* */ - /* y :: The current scanline. */ - /* x :: The current x coordinate. */ - /* */ - static - int Vertical_Gray_Test_Pixel( RAS_ARG_ TScan y, - int x ) - { - UNUSED_RASTER - UNUSED( y ); + bits = ras.bTarget + (y >> 3); + f1 = (Byte)(0x80 >> (y & 7)); -#if 0 - /* as a rule of thumb, do not add a drop-out if the current */ - /* gray level is over 0.5 */ + e1 = TRUNC( e1 ); - return ( x >= 0 && x < ras.bit_width && - ras.bit_buffer[ras.trace_bit + x] >= 64 ); -#else - UNUSED(x); - return 0; -#endif - } - - - /*************************************************************************/ - /* */ - /* */ - /* Vertical_Gray_Set_Pixel */ - /* */ - /* */ - /* Sets a single pixel in a bitmap during the vertical sweep. Used */ - /* during drop-out control. */ - /* */ - /* */ - /* y :: The current scanline. */ - /* x :: The current x coordinate. */ - /* color :: Ignored by this function. */ - /* */ - static - void Vertical_Gray_Set_Pixel( RAS_ARG_ int y, - int x, - int color ) - { - UNUSED( y ); - - if ( x >= 0 && x < ras.bit_width ) + if ( e1 >= 0 && e1 < ras.target.rows ) { - unsigned char* pixel; + bits -= e1*ras.target.pitch; + if (ras.target.pitch > 0) + bits += (ras.target.rows-1)*ras.target.pitch; - pixel = ras.bit_buffer + ras.trace_bit + x; - - /* do not add too much to the pixel gray level */ - color += *pixel; - if (color < 64) - color = 64; - - *pixel = ( color >= 127 ? 127 : (unsigned char)color ); + bits[0] |= f1; } } - /*************************************************************************/ - /* */ - /* */ - /* Vertical_Sweep_Step */ - /* */ - /* */ - /* Called whenever the sweep jumps to another scanline. Only updates */ - /* the pointers in the vertical bitmap sweep. */ - /* */ - static - void Vertical_Gray_Sweep_Step( RAS_ARG ) + static void Horizontal_Sweep_Step( RAS_ARG ) { - ras.trace_bit += ras.trace_incr; + /* Nothing, really */ + UNUSED(raster); } +#ifdef FT_RASTER_OPTION_ANTI_ALIASING - static - const Raster_Render vertical_render_gray = +/***********************************************************************/ +/* */ +/* Vertical Gray Sweep Procedure Set: */ +/* */ +/* These two routines are used during the vertical gray-levels */ +/* sweep phase by the generic Draw_Sweep() function. */ +/* */ +/* */ +/* NOTES: */ +/* */ +/* - The target pixmap's width *must* be a multiple of 4. */ +/* */ +/* - you have to use the function Vertical_Sweep_Span() for */ +/* the gray span call. */ +/* */ +/***********************************************************************/ + + static void Vertical_Gray_Sweep_Init( RAS_ARGS Short* min, Short* max ) { - &Vertical_Gray_Sweep_Init, - &Vertical_Gray_Sweep_Span, - &Vertical_Gray_Sweep_Step, - &Vertical_Gray_Test_Pixel, - &Vertical_Gray_Set_Pixel - }; + Long pitch, byte_len; + + *min = *min & -2; + *max = ( *max + 3 ) & -2; - - - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /******** ********/ - /******** Horizontal Bitmap Sweep Routines ********/ - /******** ********/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - - - /*************************************************************************/ - /* */ - /* */ - /* Horizontal_Sweep_Init */ - /* */ - /* */ - /* Initializes the horizontal bitmap sweep. Called by the generic */ - /* sweep/draw routine before its loop. */ - /* */ - /* */ - /* min :: The address of the current minimum pixel column. */ - /* max :: The address of the current maximum pixel column. */ - /* */ - static - void Horizontal_Gray_Sweep_Init( RAS_ARG_ int* min, - int* max ) - { - UNUSED( ras ); - UNUSED( min ); - UNUSED( max ); - - /* nothing, really */ - } - - - /*************************************************************************/ - /* */ - /* */ - /* Horizontal_Gray_Sweep_Span */ - /* */ - /* */ - /* Draws a single vertical bitmap span during the horizontal bitmap */ - /* sweep. */ - /* */ - /* */ - /* y :: The current scanline. */ - /* x1 :: The left span edge. */ - /* x2 :: The right span edge. */ - /* */ - static - void Horizontal_Gray_Sweep_Span( RAS_ARG_ TScan y, - TPos x1, - TPos x2 ) - { - TPos e1, e2; - int shift = PRECISION_BITS - 6; - int incr; - PByte bits; - Byte b; - - UNUSED( y ); - - x1 += PRECISION_HALF; - x2 += PRECISION_HALF; - - e1 = TRUNC( x1 ); - e2 = TRUNC( x2 ); - - if ( e1 <= e2 && e2 >= 0 && e1 < ras.bit_width ) + ras.traceOfs = 0; + pitch = ras.target.pitch; + byte_len = -pitch; + ras.traceIncr = (Short)byte_len; + ras.traceG = (*min/2)*byte_len; + if (pitch > 0) { - x1 = FRAC(x1) >> shift; - x2 = FRAC(x2) >> shift; + ras.traceG += (ras.target.rows-1)*pitch; + byte_len = -byte_len; + } - if ( e1 < 0 ) + ras.gray_min_x = (Short)byte_len; + ras.gray_max_x = -(Short)byte_len; + } + + + static void Vertical_Gray_Sweep_Step( RAS_ARG ) + { + Int c1, c2; + PByte pix, bit, bit2; + Int* count = ras.count_table; + Byte* grays; + + + ras.traceOfs += ras.gray_width; + + if ( ras.traceOfs > ras.gray_width ) + { + pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4; + grays = ras.grays; + + if ( ras.gray_max_x >= 0 ) { - e1 = 0; - x1 = 0; - } - - if ( e2 >= ras.bit_width ) - { - e2 = ras.bit_width; - x2 = 0; - } - - incr = -ras.target.pitch; - bits = ras.bit_buffer + y; - bits += incr * e1; - if (incr < 0) - bits -= incr*(ras.target.rows-1); - - e2 -= e1; - - if ( e2 > 0 ) - { - b = bits[0]; - if (b < 127) b++; - b = (Byte)((64-x1) + (b >> 1)); - bits[0] = b; - - if ( e2 < 24 ) + Long last_pixel = ras.target.width-1; + Int last_cell = last_pixel >> 2; + Int last_bit = last_pixel & 3; + Bool over = 0; + + if (ras.gray_max_x >= last_cell && last_bit != 3) { - e2--; - while (e2 > 0) + ras.gray_max_x = last_cell-1; + over = 1; + } + + if ( ras.gray_min_x < 0 ) + ras.gray_min_x = 0; + + bit = ras.bTarget + ras.gray_min_x; + bit2 = bit + ras.gray_width; + + c1 = ras.gray_max_x - ras.gray_min_x; + + while ( c1 >= 0 ) + { + c2 = count[*bit] + count[*bit2]; + + if ( c2 ) { - bits += incr; - b = bits[0]; + pix[0] = grays[(c2 >> 12) & 0x000F]; + pix[1] = grays[(c2 >> 8 ) & 0x000F]; + pix[2] = grays[(c2 >> 4 ) & 0x000F]; + pix[3] = grays[ c2 & 0x000F]; - if (b < 127) - bits[0] = (Byte)(63+((b+1) >> 1)); + *bit = 0; + *bit2 = 0; + } - e2--; + bit ++; + bit2++; + pix += 4; + c1 --; + } + + if (over) + { + c2 = count[*bit] + count[*bit2]; + if (c2) + { + switch (last_bit) + { + case 2: pix[2] = grays[(c2 >> 4 ) & 0x000F]; + case 1: pix[1] = grays[(c2 >> 8 ) & 0x000F]; + default: pix[0] = grays[(c2 >> 12) & 0x000F]; + } + + *bit = 0; + *bit2 = 0; } } - else - bits += incr*(e2-1); + } - if (x2) + ras.traceOfs = 0; + ras.traceG += ras.traceIncr; + + ras.gray_min_x = 32000; + ras.gray_max_x = -32000; + } + } + + + static void Horizontal_Gray_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + /* nothing, really */ + UNUSED(raster); + UNUSED(y); + UNUSED(x1); + UNUSED(x2); + UNUSED(left); + UNUSED(right); + } + + static void Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + PByte pixel; + Byte color; + + + /* During the horizontal sweep, we only take care of drop-outs */ + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + + if ( e1 > e2 ) + { + if ( e1 == e2 + ras.precision ) + { + switch ( ras.dropOutControl ) { - bits += incr; - b = bits[0]; - if (b < 127) b++; - b = (Byte)(x2 + (b >> 1)); - bits[0] = b; + case 1: + e1 = e2; + break; + + case 4: + e1 = CEILING( (x1 + x2 + 1) / 2 ); + break; + + case 2: + case 5: + + /* Drop-out Control Rule #4 */ + + /* The spec is not very clear regarding rule #4. It */ + /* presents a method that is way too costly to implement */ + /* while the general idea seems to get rid of 'stubs'. */ + /* */ + + /* rightmost stub test */ + if ( left->next == right && left->height <= 0 ) return; + + /* leftmost stub test */ + if ( right->next == left && left->start == y ) return; + + if ( ras.dropOutControl == 2 ) + e1 = e2; + else + e1 = CEILING( (x1 + x2 + 1) / 2 ); + + break; + + default: + return; /* unsupported mode */ } } else + return; + } + + if ( e1 >= 0 ) + { + if ( x2 - x1 >= ras.precision_half ) + color = ras.grays[2]; + else + color = ras.grays[1]; + + e1 = TRUNC( e1 ) / 2; + if ( e1 < ras.target.rows ) { - b = bits[0]; - if (b < 127) b++; - b = (Byte)((b >> 1)+(x2-x1)); - bits[0] = b; + pixel = ras.gTarget - e1*ras.target.pitch + y/2; + if (ras.target.pitch > 0) + pixel += (ras.target.rows-1)*ras.target.pitch; + + if (pixel[0] == ras.grays[0]) + pixel[0] = color; } } } +#endif /* FT_RASTER_OPTION_ANTI_ALIASING */ - /*************************************************************************/ - /* */ - /* */ - /* Horizontal_Gray_Test_Pixel */ - /* */ - /* */ - /* Tests a pixel `light' during the horizontal bitmap sweep. Used */ - /* during drop-out control only. */ - /* */ - /* */ - /* y :: The current pixel column. */ - /* x :: The current row/scanline. */ - /* */ - static - int Horizontal_Gray_Test_Pixel( RAS_ARG_ int y, - int x ) + +/********************************************************************/ +/* */ +/* Generic Sweep Drawing routine */ +/* */ +/********************************************************************/ + + static Bool Draw_Sweep( RAS_ARG ) { -#if 0 - unsigned char* pixel = (unsigned char*)ras.bit_buffer + y; - - if ( ras.target.flow == Flow_Down ) - pixel += (ras.target.rows-1 - x) * ras.target.cols; - else - pixel += x * ras.target.cols; - - return ( x >= 0 && x < ras.target.rows && - *pixel >= 64 ); -#else - UNUSED_RASTER - UNUSED(y); - UNUSED(x); - return 0; -#endif - } - - - /*************************************************************************/ - /* */ - /* */ - /* Horizontal_Set_Pixel */ - /* */ - /* */ - /* Sets a single pixel in a bitmap during the horizontal sweep. Used */ - /* during drop-out control. */ - /* */ - /* */ - /* y :: The current pixel column. */ - /* x :: The current row/scanline. */ - /* color :: Ignored by this function. */ - /* */ - static - void Horizontal_Gray_Set_Pixel( RAS_ARG_ int y, - int x, - int color ) - { - unsigned char* pixel = (unsigned char*)ras.bit_buffer + y; - - if ( x >= 0 && x < ras.target.rows ) - { - long pitch = ras.target.pitch; - - pixel -= pitch*x; - if (pitch > 0) - pixel += pitch*(ras.target.rows-1); - - color += *pixel; - if (color < 64) - color = 64; - - *pixel = (color >= 127 ? 127 : (unsigned char)color ); - } - } - - - static - void Gray_Ignore( void ) - { - ; - } - - - static - const Raster_Render horizontal_render_gray = - { - &Horizontal_Gray_Sweep_Init, - &Horizontal_Gray_Sweep_Span, - - (Function_Sweep_Step) &Gray_Ignore, - &Horizontal_Gray_Test_Pixel, - &Horizontal_Gray_Set_Pixel, - }; - -#endif /* FT_RASTER_OPTION_ANTI_ALIAS */ - - - /*************************************************************************/ - /* */ - /* A technical note to explain how the scanline sweep is performed: */ - /* */ - /* The function Draw_Sweep() is used to sweep the scanlines of the */ - /* target bitmap or pixmap. For each scanline, it must do the */ - /* following: */ - /* */ - /* - Get the set of all outline intersections for the current */ - /* scanline. */ - /* */ - /* - Sort these intersections (in increasing order). */ - /* */ - /* - Pair intersections to create spans (horizontal pixel segments) */ - /* that are then `drawn' by calling a `sweep_span' function. */ - /* */ - /* - Check for dropouts: If a span is too small to be drawn, it must */ - /* be re-adjusted in order to make it visible again. */ - /* */ - /* The sweep starts from the bottom of the outline (ymin) and goes */ - /* upwards (to ymax). Thus, the function manages the following: */ - /* */ - /* - A linked list of the profiles which are above the current */ - /* scanline. It is called the `wait' list as it contains all the */ - /* profiles waiting to be `activated' during the sweep. It contains */ - /* all profiles initially. */ - /* */ - /* - A linked list of the profiles covering the current scanline, */ - /* i.e., all the profiles that contain an intersection for the */ - /* current scanline. It is called the `draw' list. */ - /* */ - /* A profile travels from the wait list to the draw list if the */ - /* current scanline reaches its bottom border (its ymin). It is also */ - /* removed from the draw list (and becomes unlisted) when the current */ - /* scanline reaches the scanline above its upper border (its ymax). */ - /* */ - /* These positions correspond to the `extrema' table built by */ - /* Finalize_Profile_Table(). */ - /* */ - /* The draw list is always sorted in increasing order of the X */ - /* coordinates. We use a bubble sort because it is easy to implement */ - /* on a linked list, and because in 95% cases, the list is already */ - /* correctly sorted when going from one scanline to the other. */ - /* */ - /* The extrema table gives the scanline coordinates at which at least */ - /* one profile must be removed from the `draw' list, or another one */ - /* must be moved from the `wait' to `draw' lists. */ - /* */ - /* Note that when a dropout is detected, the corresponding span is not */ - /* drawn immediately but kept on a temporary list. All dropout spans */ - /* are drawn after the regular spans on a given scanline. This is a */ - /* requirement of the TrueType specification to properly implement */ - /* some drop-out control modes -- yes, it's weird! */ - /* */ - /* Finally, the parser contains four function pointers that are called */ - /* by Draw_Sweep(). Each rendering mode (monochrome, anti-aliased-5, */ - /* and anti-aliased-17) provide its own set of such functions. These */ - /* are: */ - /* */ - /* sweep_init: Called only when the sweep starts. Used to set */ - /* up some variables. */ - /* */ - /* sweep_span: Used to draw a horizontal span on the current */ - /* scanline. */ - /* */ - /* sweep_test_pixel: Used to test a pixel's intensity, as it is */ - /* required for drop-out control. */ - /* */ - /* sweep_put_pixel: Used to write a single pixel when a drop-out */ - /* needs to be lighted/drawn. */ - /* */ - /*************************************************************************/ - - - /*************************************************************************/ - /* */ - /* Generic Sweep Drawing routine */ - /* */ - static - TResult Draw_Sweep( RAS_ARG ) - { - TScan y, y_change, y_height; + Short y, y_change, y_height; PProfile P, Q, P_Left, P_Right; - TScan min_Y, max_Y, top, bottom, dropouts; + Short min_Y, max_Y, top, bottom, dropouts; - TPos x1, x2, e1, e2; + Long x1, x2, xs, e1, e2; TProfileList wait; - TProfileList draw; + TProfileList draw_left, draw_right; - #ifdef DEBUG_RAS - int y_set = 0; - #endif /* Init empty linked lists */ - Init_Linked( &wait ); - Init_Linked( &draw ); - /* first, compute min and max Y -- and add profiles to the wait list */ - P = ras.start_prof; - max_Y = TRUNC( ras.minY ); - min_Y = TRUNC( ras.maxY ); + Init_Linked( &wait ); + + Init_Linked( &draw_left ); + Init_Linked( &draw_right ); + + /* first, compute min and max Y */ + + P = ras.fProfile; + max_Y = (short)TRUNC( ras.minY ); + min_Y = (short)TRUNC( ras.maxY ); while ( P ) { Q = P->link; - bottom = P->start; - top = P->start + P->height-1; + bottom = (Short)P->start; + top = (Short)P->start + P->height-1; if ( min_Y > bottom ) min_Y = bottom; if ( max_Y < top ) max_Y = top; @@ -3411,20 +2442,21 @@ P = Q; } - /* Check the extrema table */ - if ( ras.n_extrema == 0 ) + /* Check the Y-turns */ + if ( ras.numTurns == 0 ) { - ras.error = ErrRaster_Invalid_Outline; + ras.error = Raster_Err_Invalid; return FAILURE; } /* Now inits the sweep */ - FT_TRACE2(( "draw_sweep: initialize sweep\n" )); - ras.render.init( RAS_VAR_ &min_Y, &max_Y ); - FT_TRACE2(( " init min_y = %d, max_y = %d\n", min_Y, max_Y )); + + ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y ); /* Then compute the distance of each profile from min_Y */ + P = wait; + while ( P ) { P->countL = P->start - min_Y; @@ -3432,490 +2464,429 @@ } /* Let's go */ + y = min_Y; y_height = 0; - if ( ras.n_extrema > 0 && - ras.pool_size[-ras.n_extrema] == min_Y ) - ras.n_extrema--; + if ( ras.numTurns > 0 && + ras.sizeBuff[-ras.numTurns] == min_Y ) + ras.numTurns--; - FT_TRACE2(( "starting loop with n_extrema = %d", ras.n_extrema )); - while ( ras.n_extrema > 0 ) + while ( ras.numTurns > 0 ) { - PProfile prof = wait; - - /* look in the wait list for new activations */ - while ( prof ) - { - PProfile next = prof->link; - prof->countL -= y_height; - if ( prof->countL == 0 ) + P = wait; + + while ( P ) + { + Q = P->link; + P->countL -= y_height; + if ( P->countL == 0 ) { - /* move the profile from the wait list to the draw list */ - DelOld( &wait, prof ); - InsNew( &draw, prof ); + DelOld( &wait, P ); + + switch ( P->flow ) + { + case Flow_Up: InsNew( &draw_left, P ); break; + case Flow_Down: InsNew( &draw_right, P ); break; + } } - prof = next; + + P = Q; } - /* Sort the draw list */ - Sort( &draw ); + /* Sort the drawing lists */ - /* compute next y extremum scanline; we won't change the */ - /* elements of the wait and draw lists until there */ - y_change = ras.pool_size[-ras.n_extrema--]; + Sort( &draw_left ); + Sort( &draw_right ); + + y_change = (Short)ras.sizeBuff[-ras.numTurns--]; y_height = y_change - y; - FT_TRACE2(( ">>> y = %d, y_change = %d, y_height = %d", - y, y_change, y_height )); - while ( y < y_change ) { - int window; - PProfile left; - /* Let's trace */ + dropouts = 0; - /* skip to next line if there is no active profile there */ - if ( !draw ) goto Next_Line; + P_Left = draw_left; + P_Right = draw_right; - left = draw; - window = left->flow; - prof = left->link; - - FT_TRACE2(( ">>> line y = %d", y )); - - while ( prof ) + while ( P_Left ) { - PProfile next = prof->link; + x1 = P_Left ->X; + x2 = P_Right->X; - window += prof->flow; - - if ( window == 0 ) + if ( x1 > x2 ) { - x1 = left->X; - x2 = prof->X; + xs = x1; + x1 = x2; + x2 = xs; + } - if ( x1 > x2 ) + if ( x2-x1 <= ras.precision ) + { + e1 = FLOOR( x1 ); + e2 = CEILING( x2 ); + + if ( ras.dropOutControl != 0 && + (e1 > e2 || e2 == e1 + ras.precision) ) { - TPos xs = x1; + /* a drop out was detected */ - x1 = x2; - x2 = xs; + P_Left ->X = x1; + P_Right->X = x2; + + /* mark profile for drop-out processing */ + P_Left->countL = 1; + dropouts++; + + goto Skip_To_Next; } + } - if ( x2 - x1 <= PRECISION && ras.dropout_mode ) - { - e1 = CEILING( x1 ); - e2 = FLOOR( x2 ); - - if ( e1 > e2 || e2 == e1 + PRECISION ) - { - /* a drop out was detected */ - left->X = x1; - prof->X = x2; - - /* mark profiles for drop-out processing */ - left->countL = 1; - prof->countL = 2; - dropouts++; - goto Skip_To_Next; - } - } - - FT_TRACE2(( "drawing span ( y=%d, x1=%d, x2=%d )", y, x1, x2 )); - #ifdef DEBUG_RAS - if (!y_set) - { - y_set = 1; - fprintf( stderr, "%3d", y ); - } - fprintf( stderr, " [%.2f-%.2f]", x1*1.0/PRECISION, x2*1.0/PRECISION ); - #endif - ras.render.span( RAS_VAR_ y, x1, x2 ); + ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right ); Skip_To_Next: - left = next; - } - prof = next; + + P_Left = P_Left->link; + P_Right = P_Right->link; } /* now perform the dropouts _after_ the span drawing */ /* drop-outs processing has been moved out of the loop */ /* for performance tuning */ - if ( dropouts > 0 ) + if (dropouts > 0) goto Scan_DropOuts; Next_Line: - ras.render.step( RAS_VAR ); + + ras.Proc_Sweep_Step( RAS_VAR ); y++; - #ifdef DEBUG_RAS - if (y_set) - { - fprintf( stderr, "\n" ); - y_set = 0; - } - #endif if ( y < y_change ) - Sort( &draw ); + { + Sort( &draw_left ); + Sort( &draw_right ); + } - FT_TRACE4(( "line sorted for next operation" )); } /* Now finalize the profiles that needs it */ - FT_TRACE2(( "finalizing profiles..." )); { - PProfile prof, next; - - prof = draw; - while ( prof ) + PProfile Q, P; + P = draw_left; + while ( P ) { - next = prof->link; - if (prof->height == 0) - DelOld( &draw, prof ); - prof = next; + Q = P->link; + if ( P->height == 0 ) + DelOld( &draw_left, P ); + P = Q; } } - FT_TRACE2(( "profiles finalized for this run" )); + { + PProfile Q, P = draw_right; + while ( P ) + { + Q = P->link; + if ( P->height == 0 ) + DelOld( &draw_right, P ); + P = Q; + } + } } /* for gray-scaling, flushes the bitmap scanline cache */ while ( y <= max_Y ) { - ras.render.step( RAS_VAR ); + ras.Proc_Sweep_Step( RAS_VAR ); y++; } return SUCCESS; - Scan_DropOuts : - P_Left = draw; + P_Left = draw_left; + P_Right = draw_right; - while ( dropouts > 0 ) + while ( P_Left ) { - TPos e1, e2; - PProfile left, right; - - while ( P_Left->countL != 1 ) - P_Left = P_Left->link; - P_Right = P_Left->link; - while ( P_Right->countL != 2 ) - P_Right = P_Right->link; - - P_Left->countL = 0; - P_Right->countL = 0; - - /* Now perform the dropout control */ - x1 = P_Left->X; - x2 = P_Right->X; - - left = ( ras.flipped ? P_Right : P_Left ); - right = ( ras.flipped ? P_Left : P_Right ); - - FT_TRACE2(( "performing drop-out control ( x1= %d, x2 = %d )", - x1, x2 )); - - #ifdef DEBUG_RAS - if (!y_set) + if ( P_Left->countL ) { - y_set = 1; - fprintf( stderr, "%3d", y ); - } - fprintf( stderr, " <%.2f-%.2f>", P_Left->X*1.0/PRECISION, P_Right->X*1.0/PRECISION ); - #endif - - e1 = CEILING( x1 ); - e2 = FLOOR ( x2 ); - - if ( e1 > e2 ) - { - if ( e1 == e2 + PRECISION ) - { - switch ( ras.dropout_mode ) - { - case 1: - e1 = e2; - break; - - case 4: - e1 = CEILING( (x1 + x2 + 1) / 2 ); - break; - - case 2: - case 5: - /* Drop-out Control Rule #4 */ - - /* The spec is not very clear regarding rule #4. It */ - /* presents a method that is way too costly to implement */ - /* while the general idea seems to get rid of `stubs'. */ - /* */ - /* Here, we only get rid of stubs recognized when: */ - /* */ - /* upper stub: */ - /* */ - /* - P_Left and P_Right are in the same contour */ - /* - P_Right is the successor of P_Left in that contour */ - /* - y is the top of P_Left and P_Right */ - /* */ - /* lower stub: */ - /* */ - /* - P_Left and P_Right are in the same contour */ - /* - P_Left is the successor of P_Right in that contour */ - /* - y is the bottom of P_Left */ - /* */ - - /* upper stub test */ - if ( ( left->next == right && left->height <= 0 ) || - - /* lower stub test */ - ( right->next == left && left->start == y ) || - - /* check that the rightmost pixel isn't set */ - ras.render.test_pixel( RAS_VAR_ y, TRUNC(e1)) ) - goto Next_Dropout; - - if ( ras.dropout_mode == 2 ) - e1 = e2; - else - e1 = CEILING( (x1 + x2 + 1)/2 ); - - break; - - default: - goto Next_Dropout; /* Unsupported mode */ - } - } - else - goto Next_Dropout; + P_Left->countL = 0; + /* dropouts--; -- this is useful when debugging only */ + ras.Proc_Sweep_Drop( RAS_VARS y, + P_Left->X, + P_Right->X, + P_Left, + P_Right ); } - FT_TRACE2(( " -> setting pixel" )); - ras.render.set_pixel( RAS_VAR_ y, - TRUNC( e1 ), - (x2 - x1) >> ras.scale_shift ); - Next_Dropout: - - dropouts--; + P_Left = P_Left->link; + P_Right = P_Right->link; } + goto Next_Line; } - /*************************************************************************/ - /* */ - /* */ - /* Render_Single_Pass */ - /* */ - /* */ - /* Performs one sweep with sub-banding. */ - /* */ - /* */ - /* flipped :: whether or not we have to flip. */ - /* */ - /* */ - /* Error code. 0 means success. */ - /* */ - static - int Render_Single_Pass( RAS_ARG_ int flipped ) +/****************************************************************************/ +/* */ +/* Function: Render_Single_Pass */ +/* */ +/* Description: Performs one sweep with sub-banding. */ +/* */ +/* Input: _XCoord, _YCoord : x and y coordinates arrays */ +/* */ +/* Returns: SUCCESS on success */ +/* FAILURE if any error was encountered during render. */ +/* */ +/****************************************************************************/ + + static FT_Error Render_Single_Pass( RAS_ARGS Bool flipped ) { - TBand* band; + Short i, j, k; - ras.flipped = flipped; - - band = ras.band_stack; - - FT_TRACE2(( "raster: entering render_single_pass (flipped = %d)\n", - flipped )); - - while ( band >= ras.band_stack ) + while ( ras.band_top >= 0 ) { - ras.maxY = ((long)band[0].y_max << PRECISION_BITS) - 1; - ras.minY = (long)band[0].y_min << PRECISION_BITS; + ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision; + ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision; - ras.cursor = ras.pool; - ras.error = 0; + ras.top = ras.buff; - FT_TRACE2(( "raster: band = [ %d, %d ]\n", - band[0].y_min, - band[0].y_max )); + ras.error = Raster_Err_None; - if ( Convert_Glyph( RAS_VAR_ ras.outline ) ) + if ( Convert_Glyph( RAS_VARS flipped ) ) { - int bottom, top, half; + if ( ras.error != Raster_Err_Overflow ) return FAILURE; - - if ( ras.error != ErrRaster_Overflow ) - return FAILURE; - ras.error = ErrRaster_Ok; - - FT_TRACE2(( "conversion failure, performing sub-banding\n" )); + ras.error = Raster_Err_None; /* sub-banding */ -#ifdef DEBUG_RASTER - ClearBand( RAS_VAR_ TRUNC( ras.minY ), TRUNC( ras.maxY ) ); -#endif + #ifdef DEBUG_RASTER + ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) ); + #endif - bottom = band[0].y_min; - top = band[0].y_max; - half = ( top - bottom ) >> 1; + i = ras.band_stack[ras.band_top].y_min; + j = ras.band_stack[ras.band_top].y_max; - if ( band >= ras.band_stack + 7 || half == 0 ) + k = ( i + j ) / 2; + + if ( ras.band_top >= 7 || k < i ) { - ras.band_top = 0; - ras.error = ErrRaster_Invalid_Outline; + ras.band_top = 0; + ras.error = Raster_Err_Invalid; return ras.error; } - band[1].y_min = bottom + half; - band[1].y_max = top; - band[0].y_max = bottom + half; + ras.band_stack[ras.band_top+1].y_min = k; + ras.band_stack[ras.band_top+1].y_max = j; - band ++; + ras.band_stack[ras.band_top].y_max = k - 1; + + ras.band_top++; } else { - FT_TRACE2(( "conversion succeeded, span drawing sweep\n" )); -#if 1 /* for debugging */ - if ( ras.start_prof ) - if ( Draw_Sweep( RAS_VAR ) ) - return ras.error; -#endif - band --; + if ( ras.fProfile ) + if ( Draw_Sweep( RAS_VAR ) ) return ras.error; + ras.band_top--; } } - FT_TRACE2(( "raster: exiting render_single_pass\n" )); - - return SUCCESS; /* success */ + return FT_Err_Ok; } - static - int Raster_Render1( FT_Raster raster ) +/****************************************************************************/ +/* */ +/* Function: Render_Glyph */ +/* */ +/* Description: Renders a glyph in a bitmap. Sub-banding if needed. */ +/* */ +/* Input: AGlyph Glyph record */ +/* */ +/* Returns: SUCCESS on success. */ +/* FAILURE if any error was encountered during rendering. */ +/* */ +/****************************************************************************/ + + LOCAL_FUNC + FT_Error Render_Glyph( RAS_ARG ) { - int error; + FT_Error error; + Set_High_Precision( RAS_VARS ras.outline.flags & ft_outline_high_precision ); + ras.scale_shift = ras.precision_shift; + ras.dropOutControl = 2; + ras.second_pass = !(ras.outline.flags & ft_outline_single_pass); - if ( ras.target.width > ABS(ras.target.pitch)*8 ) - return ErrRaster_Invalid_Map; - - ras.scale_shift = PRECISION_BITS - INPUT_BITS; - ras.scale_delta = PRECISION_HALF; /* Vertical Sweep */ + ras.Proc_Sweep_Init = Vertical_Sweep_Init; + ras.Proc_Sweep_Span = Vertical_Sweep_Span; + ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; + ras.Proc_Sweep_Step = Vertical_Sweep_Step; + ras.band_top = 0; ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = ras.target.rows; + ras.band_stack[0].y_max = ras.target.rows - 1; - ras.render = vertical_render_mono; - ras.bit_width = ras.target.width; - ras.bit_buffer = (unsigned char*)ras.target.buffer; + ras.bWidth = ras.target.width; + ras.bTarget = (Byte*)ras.target.buffer; - if ( (error = Render_Single_Pass( RAS_VAR_ 0 )) != 0 ) + if ( (error = Render_Single_Pass( RAS_VARS 0 )) != 0 ) return error; /* Horizontal Sweep */ - - if ( ras.second_pass && ras.dropout_mode != 0 ) + if ( ras.second_pass && ras.dropOutControl != 0 ) { - ras.render = horizontal_render_mono; + ras.Proc_Sweep_Init = Horizontal_Sweep_Init; + ras.Proc_Sweep_Span = Horizontal_Sweep_Span; + ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop; + ras.Proc_Sweep_Step = Horizontal_Sweep_Step; + ras.band_top = 0; ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = ras.target.width; + ras.band_stack[0].y_max = ras.target.width - 1; - if ( (error = Render_Single_Pass( RAS_VAR_ 1 )) != 0 ) + if ( (error = Render_Single_Pass( RAS_VARS 1 )) != 0 ) return error; } - return ErrRaster_Ok; + return FT_Err_Ok; } -#ifdef FT_RASTER_OPTION_ANTI_ALIAS +/****************************************************************************/ +/* */ +/* Function: Render_Gray_Glyph */ +/* */ +/* Description: Renders a glyph with grayscaling. Sub-banding if needed. */ +/* */ +/* Input: AGlyph Glyph record */ +/* */ +/* Returns: SUCCESS on success */ +/* FAILURE if any error was encountered during rendering. */ +/* */ +/****************************************************************************/ - - static - int Raster_Render8( FT_Raster raster ) +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + LOCAL_FUNC + FT_Error Render_Gray_Glyph( RAS_ARG ) { - int error; + Long pixel_width; + FT_Error error; + + Set_High_Precision( RAS_VARS ras.outline.flags & ft_outline_high_precision ); + ras.scale_shift = ras.precision_shift+1; + ras.dropOutControl = 2; + ras.second_pass = !(ras.outline.flags & ft_outline_single_pass); - if ( ras.target.width > ABS(ras.target.pitch) ) - return ErrRaster_Invalid_Map; /* Vertical Sweep */ + ras.band_top = 0; ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = ras.target.rows; + ras.band_stack[0].y_max = 2 * ras.target.rows - 1; - ras.scale_shift = PRECISION_BITS - INPUT_BITS; - ras.scale_delta = PRECISION_HALF; - ras.dropout_mode = 2; + ras.bWidth = ras.gray_width; + pixel_width = 2*((ras.target.width + 3) >> 2); + + if ( ras.bWidth > pixel_width ) + ras.bWidth = pixel_width; - ras.render = vertical_render_gray; - ras.bit_width = ras.target.width; - ras.bit_buffer = (unsigned char*)ras.target.buffer; - ras.pix_buffer = (unsigned char*)ras.target.buffer; + ras.bWidth = ras.bWidth * 8; + ras.bTarget = (Byte*)ras.gray_lines; + ras.gTarget = (Byte*)ras.target.buffer; - error = Render_Single_Pass( RAS_VAR_ 0 ); - if ( error ) + ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init; + ras.Proc_Sweep_Span = Vertical_Sweep_Span; + ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; + ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step; + + error = Render_Single_Pass( RAS_VARS 0 ); + if (error) return error; -#if 1 /* Horizontal Sweep */ - ras.render = horizontal_render_gray; - ras.band_top = 0; - ras.bit_width = ras.target.rows; - ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = ras.target.width; + if ( ras.second_pass && ras.dropOutControl != 0 ) + { + ras.Proc_Sweep_Init = Horizontal_Sweep_Init; + ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span; + ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop; + ras.Proc_Sweep_Step = Horizontal_Sweep_Step; - return Render_Single_Pass( RAS_VAR_ 1 ); + ras.band_top = 0; + ras.band_stack[0].y_min = 0; + ras.band_stack[0].y_max = ras.target.width * 2 - 1; + + error = Render_Single_Pass( RAS_VARS 1 ); + if (error) + return error; + } + + return FT_Err_Ok; + } #else - return 0; -#endif - } - - -#else /* FT_RASTER_OPTION_ANTI_ALIAS */ - - - static - int Raster_Render8( FT_Raster raster ) + LOCAL_FUNC + FT_Error Render_Gray_Glyph( RAS_ARG ) { - return ErrRaster_Unimplemented; + UNUSED_RASTER + return Raster_Err_Unsupported; } +#endif -#endif /* FT_RASTER_OPTION_ANTI_ALIAS */ - + static void ft_black_init( TRaster_Instance* raster ) + { + FT_UInt n; + FT_ULong c; + + /* setup count table */ + for ( n = 0; n < 256; n++ ) + { + c = (n & 0x55) + ((n & 0xAA) >> 1); + c = ((c << 6) & 0x3000) | + ((c << 4) & 0x0300) | + ((c << 2) & 0x0030) | + (c & 0x0003); + + raster->count_table[n] = c; + } + + /* set default 5-levels gray palette */ + for ( n = 0; n < 5; n++ ) + raster->grays[n] = (n*127/4); + + raster->gray_width = RASTER_GRAY_LINES/2; + } /**** RASTER OBJECT CREATION : in standalone mode, we simply use *****/ /**** a static object .. *****/ #ifdef _STANDALONE_ static - int ft_raster_new( void* memory, FT_Raster *araster ) + int ft_black_new( void* memory, FT_Raster *araster ) { static FT_RasterRec_ the_raster; *araster = &the_raster; memset( &the_raster, sizeof(the_raster), 0 ); + ft_black_init( &the_raster ); return 0; } static - void ft_raster_done( FT_Raster raster ) + void ft_black_done( FT_Raster raster ) { /* nothing */ raster->init = 0; @@ -3926,15 +2897,17 @@ Scan_DropOuts : #include static - int ft_raster_new( FT_Memory memory, FT_Raster* araster ) + int ft_black_new( FT_Memory memory, TRaster_Instance* *araster ) { - FT_Error error; - FT_Raster raster; + FT_Error error; + TRaster_Instance* raster; *araster = 0; if ( !ALLOC( raster, sizeof(*raster) )) { raster->memory = memory; + ft_black_init( raster ); + *araster = raster; } @@ -3942,7 +2915,7 @@ Scan_DropOuts : } static - void ft_raster_done( FT_Raster raster ) + void ft_black_done( TRaster_Instance* raster ) { FT_Memory memory = (FT_Memory)raster->memory; FREE( raster ); @@ -3951,71 +2924,78 @@ Scan_DropOuts : #endif - static void ft_raster_reset( FT_Raster raster, - const char* pool_base, - long pool_size ) + static void ft_black_reset( TRaster_Instance* raster, + const char* pool_base, + long pool_size ) { if ( raster && pool_base && pool_size >= 4096 ) { /* save the pool */ - raster->pool = (PPos)pool_base; - raster->pool_size = raster->pool + pool_size / sizeof ( TPos ); + raster->buff = (PLong)pool_base; + raster->sizeBuff = raster->buff + pool_size / sizeof (Long); } } + static void ft_black_set_mode( TRaster_Instance* raster, + unsigned long mode, + const char* palette ) + { + if (mode==FT_MAKE_TAG('p','a','l','5')) + { + /* set 5-levels gray palette */ + raster->grays[0] = palette[0]; + raster->grays[1] = palette[1]; + raster->grays[2] = palette[2]; + raster->grays[3] = palette[3]; + raster->grays[4] = palette[4]; + } + } + static - int ft_raster_render( FT_Raster raster, - FT_Raster_Params* params ) + int ft_black_render( TRaster_Instance* raster, + FT_Raster_Params* params ) { FT_Outline* outline = (FT_Outline*)params->source; FT_Bitmap* target_map = params->target; - if ( !raster || !raster->pool || !raster->pool_size ) - return ErrRaster_Uninitialized_Object; + if ( !raster || !raster->buff || !raster->sizeBuff ) + return Raster_Err_Not_Ini; if ( !outline || !outline->contours || !outline->points ) - return ErrRaster_Invalid_Outline; + return Raster_Err_Invalid; /* return immediately if the outline is empty */ if ( outline->n_points == 0 || outline->n_contours <= 0 ) - return ErrRaster_Ok; + return Raster_Err_None; if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 ) - return ErrRaster_Invalid_Outline; + return Raster_Err_Invalid; if ( !target_map || !target_map->buffer ) - return ErrRaster_Invalid_Map; - - ras.outline = outline; - ras.target = *target_map; - - /* Note that we always use drop-out mode 2, because it seems that */ - /* it's the only way to do to get results consistent with Windows */ - /* rendering.. */ - ras.dropout_mode = 2; - - ras.second_pass = (outline->flags & ft_outline_single_pass) == 0; - SET_High_Precision( (char)((outline->flags & ft_outline_high_precision)!= 0) ); + return Raster_Err_Invalid; /* this version of the raster does not support direct rendering, sorry */ if ( params->flags & ft_raster_flag_direct ) - return ErrRaster_Unimplemented; + return Raster_Err_Unsupported; - return ( params->flags & ft_raster_flag_aa - ? Raster_Render8( raster ) - : Raster_Render1( raster ) ); + ras.outline = *outline; + ras.target = *target_map; + + return ( params->flags & ft_raster_flag_aa + ? Render_Gray_Glyph( raster ) + : Render_Glyph( raster ) ); } FT_Raster_Funcs ft_default_raster = { ft_glyph_format_outline, - (FT_Raster_New_Func) ft_raster_new, - (FT_Raster_Reset_Func) ft_raster_reset, - (FT_Raster_Set_Mode_Func) 0, - (FT_Raster_Render_Func) ft_raster_render, - (FT_Raster_Done_Func) ft_raster_done + (FT_Raster_New_Func) ft_black_new, + (FT_Raster_Reset_Func) ft_black_reset, + (FT_Raster_Set_Mode_Func) ft_black_set_mode, + (FT_Raster_Render_Func) ft_black_render, + (FT_Raster_Done_Func) ft_black_done };