ref: 414f38c572e34bcd92d93cd0b1813de8572dd1c9
parent: 33aab6e5b6c14d3cf2c4334f79a8debf959c9e38
author: David Turner <[email protected]>
date: Tue May 16 18:37:30 EDT 2000
at last, fixed the bug, and re-enabled 5-gray levels support for backwards compatibility..
--- a/include/freetype/config/ftoption.h
+++ b/include/freetype/config/ftoption.h
@@ -140,17 +140,35 @@
/*************************************************************************/
/* */
+ /* 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
@@ -157,6 +175,25 @@
/*************************************************************************/
/* */
+ /* 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 */
/* */
/* FreeType can be compiled in debug or trace mode. In debug mode, */
@@ -175,17 +212,6 @@
/*************************************************************************/
/* */
- /* 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 */
/* */
/* FreeType is completely endian-independent, and can thus be compiled */
@@ -211,6 +237,7 @@
/* soon.. */
/* */
#define FT_CONFIG_OPTION_OLD_CALCS
+
/*************************************************************************/
/* */
--- a/src/base/ftraster.c
+++ b/src/base/ftraster.c
@@ -1,235 +1,160 @@
-/***************************************************************************/
-/* */
-/* 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. */
-/* */
-/***************************************************************************/
+/*******************************************************************
+ *
+ * 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
+ *
+ *
+ *
+ ******************************************************************/
-
- /*************************************************************************/
- /* */
- /* 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 <stdio.h>
-#endif
-
-
#include <freetype/ftraster.h>
-#ifndef _STANDALONE_
-#include <freetype/internal/ftdebug.h>
-#endif
+#include <freetype/internal/ftcalc.h> /* for FT_MulDiv only */
-#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. */
+ /* A simple technical note on how the raster works: */
/* */
- /*************************************************************************/
-
- /*************************************************************************/
+ /* Converting an outline into a bitmap is achieved in several steps */
+ /* which are: */
/* */
- /* FT_RASTER_INT_IS_32 */
+ /* 1 - Decomposing the outline into successive `profiles'. Each */
+ /* profile is simply an array of scanline intersections on a given */
+ /* dimension. A profile's main attributes are */
/* */
- /* Set this configuration macro to the unsigned type which has 32 */
- /* bits. */
+ /* o its scanline position boundaries, i.e. `Ymin' and `Ymax'. */
/* */
-#define FT_RASTER_INT_IS_32
-
-
- /*************************************************************************/
+ /* o an array of intersection coordinates for each scanline */
+ /* between `Ymin' and `Ymax'. */
/* */
- /* FT_RASTER_OPTION_ANTI_ALIAS */
+ /* o a direction, indicating wether is was built going `up' or */
+ /* `down', as this is very important for filling rules. */
/* */
- /* Define this configuration macro if you want to support */
- /* anti-aliasing. */
+ /* 2 - Sweeping the target map's scanlines in order to compute segment */
+ /* `spans' which are then filled. Additionaly, this pass performs */
+ /* drop-out control. */
/* */
-#undef FT_RASTER_OPTION_ANTI_ALIAS
-
-
- /*************************************************************************/
+ /* The outline data is parsed during step 1 only. The profiles are */
+ /* built from the bottom of the render pool, used as a stack. The */
+ /* following graphics shows the profile list under construction: */
/* */
- /* FT_RASTER_OPTION_CONIC_BEZIERS */
+ /* ____________________________________________________________ _ _ */
+ /* | | | | | */
+ /* | profile | coordinates for | profile | coordinates for |--> */
+ /* | 1 | profile 1 | 2 | profile 2 |--> */
+ /* |_________|___________________|_________|_________________|__ _ _ */
/* */
- /* Define this configuration macro if your source outlines contain */
- /* second-order Bezier arcs. Typically, these are TrueType outlines. */
+ /* ^ ^ */
+ /* | | */
+ /* start of render pool top */
/* */
-#define FT_RASTER_CONIC_BEZIERS
-
-
- /*************************************************************************/
+ /* The top of the profile stack is kept in the `top' variable. */
/* */
- /* FT_RASTER_OPTION_CUBIC_BEZIERS */
+ /* As you can see, a profile record is pushed on top of the render */
+ /* pool, which is then followed by its coordinates/intersections. If */
+ /* a change of direction is detected in the outline, a new profile is */
+ /* generated until the end of the outline. */
/* */
- /* Define this configuration macro if your source outlines contain */
- /* third-order Bezier arcs. Typically, these are Type1 outlines. */
+ /* Note that when all profiles have been generated, the function */
+ /* Finalize_Profile_Table() is used to record, for each profile, its */
+ /* bottom-most scanline as well as the scanline above its upmost */
+ /* boundary. These positions are called `y-turns' because they (sort */
+ /* of) correspond to local extrema. They are stored in a sorted list */
+ /* built from the top of the render pool as a downwards stack: */
/* */
-#define FT_RASTER_CUBIC_BEZIERS
-
-
- /*************************************************************************/
+ /* _ _ _______________________________________ */
+ /* | | */
+ /* <--| sorted list of | */
+ /* <--| extrema scanlines | */
+ /* _ _ __________________|____________________| */
/* */
- /* FT_RASTER_CONSTANT_PRECISION */
+ /* ^ ^ */
+ /* | | */
+ /* maxBuff sizeBuff = end of pool */
/* */
- /* 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 list is later used during the sweep phase in order to */
+ /* optimize performance (see technical note on the sweep below). */
/* */
- /* This results in a speed boost, but the macro can be undefined if */
- /* it results in rendering errors (mainly changed drop-outs).. */
+ /* Of course, the raster detects whether the two stacks collide and */
+ /* handles the situation propertly. */
/* */
-#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
+ /****************************************************************/
+ /****************************************************************/
+ /** **/
+ /** CONFIGURATION MACROS **/
+ /** **/
+ /****************************************************************/
+ /****************************************************************/
- /*************************************************************************/
- /* */
- /* 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
+/* 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
-#else /* _STANDALONE_ */
-
-#include <freetype/freetype.h>
-#include <freetype/config/ftconfig.h>
-
- /*************************************************************************/
- /* */
- /* 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
+/* 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
-#define FT_RASTER_CONIC_BEZIERS
-#define FT_RASTER_CUBIC_BEZIERS
+/* The size of the two-lines intermediate bitmap used */
+/* for anti-aliasing, in bytes.. */
+#define RASTER_GRAY_LINES 2048
-#define FT_RASTER_ANTI_ALIAS_5
-/* #define FT_RASTER_ANTI_ALIAS_17 */
-#ifdef FT_CONFIG_OPTION_LITTLE_ENDIAN
-#define FT_RASTER_LITTLE_ENDIAN
-#endif
+ /****************************************************************/
+ /****************************************************************/
+ /** **/
+ /** OTHER MACROS (do not change) **/
+ /** **/
+ /****************************************************************/
+ /****************************************************************/
-#ifdef FT_CONFIG_OPTION_BIG_ENDIAN
-#define FT_RASTER_BIG_ENDIAN
-#endif
+/* required by the tracing mode */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_raster
-#undef FT_RASTER_CONSTANT_PRECISION
-#undef FT_DYNAMIC_BEZIER_STEPS
-#define FT_PRECISION_BITS 8
+#include <freetype/internal/ftdebug.h>
-#endif /* _STANDALONE_ */
+#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) )
-/* to keep the compiler happy */
-#ifndef FT_TRACE2
-#define FT_TRACE2(x) /*void*/
-#endif
+/* 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
-#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 there (you never know your target */
+/* environment). */
- /*************************************************************************/
- /* */
- /* 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
@@ -242,192 +167,84 @@
#define NULL (void*)0
#endif
-
-#ifndef UNUSED
-#define UNUSED( arg ) ( (void)(arg) )
+#ifndef SUCCESS
+#define SUCCESS 0
#endif
-
-#undef FAILURE
-#define FAILURE TRUE
-
-#undef SUCCESS
-#define SUCCESS FALSE
-
-#ifndef ABS
-#define ABS(x) ( (x) < 0 ? -(x) : (x) )
+#ifndef FAILURE
+#define FAILURE 1
#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
+#define MaxBezier 32 /* The maximum number of stacked Bezier curves. */
+ /* Setting this constant to more than 32 is a */
+ /* pure waste of space. */
- /* used to call a function within this component, first parameter */
-#define RAS_VAR_ raster,
-#define RAS_VAR raster
+#define Pixel_Bits 6 /* fractional bits of *input* coordinates */
- /* used to access the current raster object, with a `.' instead of a */
- /* `->' */
-#define ras (*raster)
+ /****************************************************************/
+ /****************************************************************/
+ /** **/
+ /** 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;
-#define UNUSED_RASTER (raster=raster);
+ typedef struct TPoint_
+ {
+ Long x;
+ Long y;
+
+ } TPoint;
- /*************************************************************************/
- /* */
- /* 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
+ typedef enum TFlow_
+ {
+ Flow_None = 0,
+ Flow_Up = 1,
+ Flow_Down = -1
+
+ } TFlow;
-#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
+ /* States of each line, arc and profile */
+ typedef enum TStates_
{
Unknown,
Ascending,
Descending,
Flat
+
+ } TStates;
- } TDirection;
-
- struct _TProfile;
- typedef struct _TProfile TProfile;
+ typedef struct TProfile_ TProfile;
typedef TProfile* PProfile;
-
- /*************************************************************************/
- /* */
- /* The `master' structure used for decomposing outlines. */
- /* */
- struct _TProfile
+ 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 */
+ 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 */
- TScan countL; /* number of lines to step before this */
- /* profile becomes drawable */
+ UShort countL; /* number of lines to step before this */
+ /* profile becomes drawable */
- PProfile next; /* next profile in same contour, used */
- /* during drop-out control */
+ PProfile next; /* next profile in same contour, used */
+ /* during drop-out control */
};
typedef PProfile TProfileList;
@@ -434,307 +251,212 @@
typedef PProfile* PProfileList;
- /*************************************************************************/
- /* */
- /* A simple record used to implement a stack of bands, required by the */
- /* sub-banding mechanism. */
- /* */
- typedef struct _TBand
+ /* 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 */
-
+ Short y_min; /* band's minimum */
+ Short 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 ) )
+#define AlignProfileSize \
+ (( sizeof(TProfile)+sizeof(long)-1 ) / sizeof(long))
- /*************************************************************************/
- /* */
- /* 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 );
+#ifdef TT_STATIC_RASTER
- typedef void (*Function_Set_Pixel)( RAS_ARG_ TScan y,
- int x,
- int color );
+#define RAS_ARGS /* void */
+#define RAS_ARG /* void */
- typedef void (*Function_Sweep_Step)( RAS_ARG );
+#define RAS_VARS /* void */
+#define RAS_VAR /* void */
- 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
+#define RAS_ARGS TRaster_Instance* raster,
+#define RAS_ARG TRaster_Instance* raster
+#define RAS_VARS raster,
+#define RAS_VAR raster
+
#endif
- /*************************************************************************/
- /* */
- /* Compute lowest integer coordinate below a given value. */
- /* */
-#define FLOOR( x ) ( (x) & PRECISION_MASK )
+ typedef struct TRaster_Instance_ TRaster_Instance;
- /*************************************************************************/
- /* */
- /* Compute highest integer coordinate above a given value. */
- /* */
-#define CEILING( x ) ( ((x) + PRECISION - 1) & PRECISION_MASK )
+ /* prototypes used for sweep function dispatch */
+ typedef void Function_Sweep_Init( RAS_ARGS Short* min,
+ Short* max );
- /*************************************************************************/
- /* */
- /* Get integer coordinate of a given 26.6 or 22.10 `x' coordinate -- no */
- /* rounding. */
- /* */
-#define TRUNC( x ) ( (signed long)(x) >> PRECISION_BITS )
+ 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 );
- /*************************************************************************/
- /* */
- /* Get the fractional part of a given coordinate. */
- /* */
-#define FRAC( x ) ( (x) & (PRECISION-1) )
+/* NOTE: These operations are only valid on 2's complement processors */
- /*************************************************************************/
- /* */
- /* 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 )
+#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. */
- /*************************************************************************/
- /* */
- /* 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
+ struct TRaster_Instance_
{
- TPos x, y;
+ Int precision_bits; /* precision related variables */
+ Int precision;
+ Int precision_half;
+ Long precision_mask;
+ Int precision_shift;
+ Int precision_step;
+ Int precision_jitter;
- } TPoint;
+ 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 */
- /*************************************************************************/
- /* */
- /* 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 */
+ FT_Error error;
- 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 numTurns; /* number of Y-turns in outline */
- int bit_width; /* target bitmap width */
- PByte bit_buffer; /* target bitmap buffer */
- PByte pix_buffer; /* target pixmap buffer */
+ TPoint* arc; /* current Bezier arc pointer */
- TPoint last;
- long minY, maxY;
+ UShort bWidth; /* target bitmap width */
+ PByte bTarget; /* target bitmap buffer */
+ PByte gTarget; /* target pixmap buffer */
- int error;
+ Long lastX, lastY, minY, maxY;
-#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
+ UShort num_Profs; /* current number of profiles */
- 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 */
+ 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 cur_prof; /* current profile */
- PProfile start_prof; /* head of linked list of profiles */
- PProfile first_prof; /* contour's first profile in case */
+ PProfile cProfile; /* current profile */
+ PProfile fProfile; /* head of linked list of profiles */
+ PProfile gProfile; /* contour's first profile in case */
/* of impact */
- TDirection state; /* rendering state */
+ TStates state; /* rendering state */
- FT_Bitmap target; /* description of target bit/pixmap */
- void* memory;
+ FT_Bitmap target; /* description of target bit/pixmap */
+ FT_Outline outline;
- 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 */
+ Long traceOfs; /* current offset in target bitmap */
+ Long traceG; /* current offset in target pixmap */
- /* dispatch variables */
+ Short traceIncr; /* sweep's increment in target bitmap */
- Raster_Render render;
+ Short gray_min_x; /* current min x during gray rendering */
+ Short gray_max_x; /* current max x during gray rendering */
- int scale_shift; /* == 0 for bitmaps */
- /* == 1 for 5-levels pixmaps */
- /* == 2 for 17-levels pixmaps */
+ /* dispatch variables */
- int scale_delta; /* ras.precision_half for bitmaps */
- /* 0 for pixmaps */
+ Function_Sweep_Init* Proc_Sweep_Init;
+ Function_Sweep_Span* Proc_Sweep_Span;
+ Function_Sweep_Span* Proc_Sweep_Drop;
+ Function_Sweep_Step* Proc_Sweep_Step;
- char dropout_mode; /* current drop_out control method */
+ Byte dropOutControl; /* current drop_out control method */
- char second_pass; /* indicates whether a horizontal pass */
+ 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 */
- 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 */
- 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 */
- TPoint arcs[2 * MaxBezier + 1]; /* The Bezier stack */
- };
+ void* memory;
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+ Byte grays[5]; /* Palette of gray levels used for render */
-#ifdef DEBUG_RASTER
+ 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 */
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Pset */
- /* */
- /* <Description> */
- /* Used for debugging only. Plots a point in VRAM during rendering */
- /* (not afterwards). */
- /* */
- /* <Note> */
- /* 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;
+ /* The gray_lines must hold 2 lines, thus with size */
+ /* in bytes of at least 'gray_width*2' */
- x = ras.cursor[-1];
+#endif /* FT_RASTER_ANTI_ALIASING */
+
+#if 0
+ PByte flags; /* current flags table */
+ PUShort outs; /* current outlines table */
+ FT_Vector* coords;
- 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;
+ UShort nPoints; /* number of points in current glyph */
+ Short nContours; /* number of contours in current glyph */
+#endif
- 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 );
- }
+#ifdef FT_CONFIG_OPTION_STATIC_RASTER
-#endif /* DEBUG_RASTER */
+ static TRaster_Instance cur_ras;
+ #define ras cur_ras
+
+#else
+ #define ras (*raster)
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Set_High_Precision */
- /* */
- /* <Description> */
- /* Sets precision variables according to the parameter flag. */
- /* */
- /* <Input> */
- /* High :: Set to True for high precision (typically for ppem < 18), */
- /* false otherwise. */
- /* */
- static
- void Set_High_Precision( RAS_ARG_ char High )
+#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 )
{
-#ifdef FT_RASTER_CONSTANT_PRECISION
- (void)High;
- (void)&ras;
-#else
if ( High )
{
ras.precision_bits = 10;
@@ -748,206 +470,127 @@
ras.precision_jitter = 2;
}
+ 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 - INPUT_BITS;
+ ras.precision_shift = ras.precision_bits - Pixel_Bits;
ras.precision_mask = -ras.precision;
-#endif
}
- /*************************************************************************/
- /* */
- /* A simple technical note on how the raster works: */
- /* */
- /* Converting an outline into a bitmap is achieved in several steps */
- /* which are: */
- /* */
- /* 1 - Decomposing the outline into successive `profiles'. Each */
- /* profile is simply an array of scanline intersections on a given */
- /* dimension. A profile's main attributes are */
- /* */
- /* o its scanline position boundaries, i.e. `Ymin' and `Ymax'. */
- /* */
- /* o an array of intersection coordinates for each scanline */
- /* between `Ymin' and `Ymax'. */
- /* */
- /* o a direction, indicating wether is was built going `up' or */
- /* `down', as this is very important for filling rules. */
- /* */
- /* 2 - Sweeping the target map's scanlines in order to compute segment */
- /* `spans' which are then filled. Additionaly, this pass performs */
- /* drop-out control. */
- /* */
- /* The outline data is parsed during step 1 only. The profiles are */
- /* built from the bottom of the render pool, used as a stack. The */
- /* following graphics shows the profile list under construction: */
- /* */
- /* ____________________________________________________________ _ _ */
- /* | | | | | */
- /* | profile | coordinates for | profile | coordinates for |--> */
- /* | 1 | profile 1 | 2 | profile 2 |--> */
- /* |_________|___________________|_________|_________________|__ _ _ */
- /* */
- /* ^ ^ */
- /* | | */
- /* start of render pool cursor */
- /* */
- /* The top of the profile stack is kept in the `cursor' variable. */
- /* */
- /* As you can see, a profile record is pushed on top of the render */
- /* pool, which is then followed by its coordinates/intersections. If */
- /* a change of direction is detected in the outline, a new profile is */
- /* generated until the end of the outline. */
- /* */
- /* Note that when all profiles have been generated, the function */
- /* Finalize_Profile_Table() is used to record, for each profile, its */
- /* bottom-most scanline as well as the scanline above its upmost */
- /* boundary. These positions are called `extrema' because they (sort */
- /* of) correspond to local extrema. They are stored in a sorted list */
- /* built from the top of the render pool as a downwards stack: */
- /* */
- /* _ _ _______________________________________ */
- /* | | */
- /* <--| sorted list of | */
- /* <--| extrema scanlines | */
- /* _ _ __________________|____________________| */
- /* */
- /* ^ ^ */
- /* | | */
- /* pool_limit end of render pool */
- /* */
- /* This list is later used during the sweep phase in order to */
- /* optimize performance (see technical note on the sweep below). */
- /* */
- /* Of course, the raster detects whether the two stacks collide and */
- /* handles the situation propertly. */
- /* */
- /*************************************************************************/
+/****************************************************************************/
+/* */
+/* 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. */
+/* */
+/****************************************************************************/
- /*************************************************************************/
- /* */
- /* <Function> */
- /* New_Profile */
- /* */
- /* <Description> */
- /* Creates a new Profile in the render pool. */
- /* */
- /* <Input> */
- /* aState :: The state/orientation of the new profile. */
- /* */
- /* <Return> */
- /* SUCCESS or FAILURE. */
- /* */
- static
- TResult New_Profile( RAS_ARG_ TDirection direction )
+ static Bool New_Profile( RAS_ARGS TStates aState )
{
- if ( ras.start_prof == NULL )
+ if ( !ras.fProfile )
{
- 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.cProfile = (PProfile)ras.top;
+ ras.fProfile = ras.cProfile;
+ ras.top += AlignProfileSize;
}
- /* check for overflow */
- if ( ras.cursor >= ras.pool_limit )
+ if ( ras.top >= ras.maxBuff )
{
- ras.error = ErrRaster_Overflow;
+ 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 */
- }
+ ras.state = aState;
+ ras.fresh = TRUE;
+ ras.joint = FALSE;
- /* 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;
-
return SUCCESS;
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* End_Profile */
- /* */
- /* <Description> */
- /* 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. */
- /* */
- /* <Return> */
- /* 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,41 +600,36 @@
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Insert_Extrema */
- /* */
- /* <Description> */
- /* 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. */
- /* */
- /* <Input> */
- /* 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--;
}
@@ -998,44 +636,45 @@
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;
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Finalize_Profile_Table */
- /* */
- /* <Description> */
- /* Adjusts all links in the profiles list. Called when the outline */
- /* parsing is done. */
- /* */
- /* <Return> */
- /* 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,57 +706,119 @@
}
}
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. */
+/* */
+/****************************************************************************/
+ static void Split_Conic( TPoint* base )
+ {
+ Long a, b;
+
+ base[4].x = base[2].x;
+ b = base[1].x;
+ a = base[3].x = ( base[2].x + b ) / 2;
+ b = base[1].x = ( base[0].x + b ) / 2;
+ base[2].x = ( a + b ) / 2;
+
+ base[4].y = base[2].y;
+ b = base[1].y;
+ a = base[3].y = ( base[2].y + b ) / 2;
+ b = base[1].y = ( base[0].y + b ) / 2;
+ base[2].y = ( a + b ) / 2;
+
+ /* hand optimized. gcc doesn't seem too good at common expression */
+ /* substitution and instruction scheduling ;-) */
+ }
+
+
/*************************************************************************/
/* */
- /* <Function> */
- /* Line_Up */
+ /* <Function> Split_Cubic */
/* */
/* <Description> */
- /* Computes the scan-line intersections of an ascending line segment */
- /* and stores them in the render pool. */
+ /* Subdivides a third-order Bezier arc into two joint sub-arcs in */
+ /* the Bezier stack. */
/* */
- /* <Input> */
- /* 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. */
+ /* <Note> */
+ /* This routine is the `beef' of the component. It is one of _the_ */
+ /* inner loops that should be optimized like hell to get the best */
+ /* performance. */
/* */
- /* <Return> */
- /* SUCCESS or FAILURE. */
- /* */
static
- TResult Line_Up( RAS_ARG_ TPos x1, TPos y1,
- TPos x2, TPos y2,
- TPos miny, TPos maxy )
+ void Split_Cubic( TPoint* base )
{
- TPos Dx, Dy;
- int e1, e2, f1, f2, size;
- TPos Ix, Rx, Ax;
+ Long a, b, c, d;
- PPos top;
+ base[6].x = base[3].x;
+ c = base[1].x;
+ d = base[2].x;
+ base[1].x = a = ( base[0].x + c + 1 ) >> 1;
+ base[5].x = b = ( base[3].x + d + 1 ) >> 1;
+ c = ( c + d + 1 ) >> 1;
+ base[2].x = a = ( a + c + 1 ) >> 1;
+ base[4].x = b = ( b + c + 1 ) >> 1;
+ base[3].x = ( a + b + 1 ) >> 1;
+ base[6].y = base[3].y;
+ c = base[1].y;
+ d = base[2].y;
+ base[1].y = a = ( base[0].y + c + 1 ) >> 1;
+ base[5].y = b = ( base[3].y + d + 1 ) >> 1;
+ c = ( c + d + 1 ) >> 1;
+ base[2].y = a = ( a + c + 1 ) >> 1;
+ base[4].y = b = ( b + c + 1 ) >> 1;
+ base[3].y = ( a + b + 1 ) >> 1;
+ }
+
+
+/****************************************************************************/
+/* */
+/* Function: Line_Up */
+/* */
+/* Description: 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. */
+/* */
+/****************************************************************************/
+
+ static Bool Line_Up( RAS_ARGS Long x1, Long y1,
+ Long x2, Long y2,
+ Long miny, Long maxy )
+ {
+ Long Dx, Dy;
+ Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */
+ Long Ix, Rx, Ax;
+
+ PLong top;
+
+
Dx = x2 - x1;
Dy = y2 - y1;
@@ -1128,70 +825,38 @@
if ( Dy <= 0 || y2 < miny || y1 > maxy )
return SUCCESS;
- /* clip to higher scanline when necessary */
- if ( y2 > maxy )
+ if ( y1 < miny )
{
- /* x2 += FMulDiv( Dx, maxy-y2, Dy ); UNNECESSARY */
- e2 = TRUNC( maxy );
- f2 = 0;
+ /* 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
{
- e2 = TRUNC( y2 );
- f2 = FRAC( y2 );
+ e1 = TRUNC( y1 );
+ f1 = FRAC( y1 );
}
- /* clip to lower scanline when necessary */
- if ( y1 < miny )
+ if ( y2 > maxy )
{
-#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
+ /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */
+ e2 = TRUNC( maxy );
+ f2 = 0;
}
else
{
- e1 = TRUNC( y1 );
- f1 = FRAC( y1 );
+ e2 = TRUNC( y2 );
+ f2 = FRAC( y2 );
}
- /* adjust start point so that we begin on an integer scanline position */
if ( f1 > 0 )
{
- if ( e1 == e2 ) goto Exit;
+ if ( e1 == e2 ) return SUCCESS;
else
{
- x1 += FMulDiv( Dx, PRECISION - f1, Dy );
+ x1 += FMulDiv( Dx, ras.precision - f1, Dy );
e1 += 1;
}
}
@@ -1198,265 +863,127 @@
else
if ( ras.joint )
{
- ras.cursor--;
+ ras.top--;
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.cProfile->start = e1;
ras.fresh = FALSE;
}
- /* check for overflow */
size = e2 - e1 + 1;
- if ( ras.cursor + size >= ras.pool_limit )
+ if ( ras.top + size >= ras.maxBuff )
{
- ras.error = ErrRaster_Overflow;
+ ras.error = Raster_Err_Overflow;
return FAILURE;
}
-#ifdef OLD
if ( Dx > 0 )
{
- Ix = ( PRECISION*Dx ) / Dy;
- Rx = ( PRECISION*Dx ) % Dy;
+ Ix = (ras.precision*Dx) / Dy;
+ Rx = (ras.precision*Dx) % Dy;
Dx = 1;
}
else
{
- Ix = -( (PRECISION*-Dx) / Dy );
- Rx = (PRECISION*-Dx) % Dy;
+ Ix = -( (ras.precision*-Dx) / Dy );
+ Rx = (ras.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
+ Ax = -Dy;
+ top = ras.top;
- 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:
+ ras.top = top;
return SUCCESS;
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Line_Down */
- /* */
- /* <Description> */
- /* Computes the scan-line intersections of a descending line segment */
- /* and stores them in the render pool. */
- /* */
- /* <Input> */
- /* 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. */
- /* */
- /* <Return> */
- /* SUCCESS or FAILURE. */
- /* */
- static
- TResult Line_Down( RAS_ARG_ TPos x1, TPos y1,
- TPos x2, TPos y2,
- TPos miny, TPos maxy )
+ static Bool Line_Down( RAS_ARGS Long x1, Long y1,
+ Long x2, Long y2,
+ Long miny, Long maxy )
{
- TResult result, fresh;
+ Bool 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 */
+ result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
+
if ( fresh && !ras.fresh )
- ras.cur_prof->start = -ras.cur_prof->start;
+ 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 );
-#ifdef FT_DYNAMIC_BEZIER_STEPS
- static
- TPos Dynamic_Bezier_Threshold( RAS_ARG_ int degree, TPoint* arc )
+ static Bool Bezier_Up( RAS_ARGS Int degree,
+ TSplitter splitter,
+ Long miny,
+ Long maxy )
{
- TPos min_x, max_x, min_y, max_y, A, B;
- TPos wide_x, wide_y, threshold;
- TPoint* cur = arc;
- TPoint* limit = cur + degree;
+ Long y1, y2, e, e2, e0;
+ Short f1;
- /* 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
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Bezier_Up */
- /* */
- /* <Description> */
- /* 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. */
- /* */
- /* <Input> */
- /* miny :: The minimum vertical grid coordinate. */
- /* maxy :: The maximum vertical grid coordinate. */
- /* */
- /* <Return> */
- /* 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;
+ PLong top;
arc = ras.arc;
y1 = arc[degree].y;
y2 = arc[0].y;
- top = ras.cursor;
+ top = ras.top;
if ( y2 < miny || y1 > maxy )
goto Fin;
- e2 = FLOOR( y2 ); /* integer end y */
+ e2 = FLOOR( y2 );
-#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 */
- }
+ e = miny;
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 */
+ e = CEILING( y1 );
+ f1 = FRAC( y1 );
+ e0 = e;
- if ( f1 == 0 ) /* do we start on an integer scanline? */
+ if ( f1 == 0 )
{
if ( ras.joint )
{
@@ -1464,127 +991,89 @@
ras.joint = FALSE;
}
- *top++ = arc[degree].x; /* write directly start position */
+ *top++ = arc[degree].x;
- DEBUG_PSET;
-
- e += PRECISION; /* go to next scanline */
+ e += ras.precision;
}
}
- /* record start position if necessary */
if ( ras.fresh )
{
- ras.cur_prof->start = TRUNC( e0 );
+ ras.cProfile->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 )
+ if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
{
- ras.cursor = top;
- ras.error = ErrRaster_Overflow;
+ ras.top = top;
+ ras.error = Raster_Err_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 */
+ y2 = arc[0].y;
- if ( y2 > e ) /* the arc intercepts the current scanline */
+ if ( y2 > e )
{
- 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
+ y1 = arc[degree].y;
+ if ( y2 - y1 >= ras.precision_step )
{
- /* 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 */
+ *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x,
+ e - y1, y2 - y1 );
+ arc -= degree;
+ e += ras.precision;
}
}
else
{
- if ( y2 == e ) /* if the arc falls on the scanline */
- { /* record its _joint_ intersection */
+ if ( y2 == e )
+ {
ras.joint = TRUE;
*top++ = arc[0].x;
- DEBUG_PSET;
-
- e += PRECISION; /* go to next scanline */
+ e += ras.precision;
}
- arc -= degree; /* pop the arc */
+ arc -= degree;
}
}
Fin:
- ras.cursor = top;
- ras.arc -= degree;
+ ras.top = top;
+ ras.arc -= degree;
return SUCCESS;
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Bezier_Down */
- /* */
- /* <Description> */
- /* 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. */
- /* */
- /* <Input> */
- /* miny :: The minimum vertical grid coordinate. */
- /* maxy :: The maximum vertical grid coordinate. */
- /* */
- /* <Return> */
- /* SUCCESS or FAILURE. */
- /* */
- static
- TResult Bezier_Down( RAS_ARG_ int degree,
- TSplitter splitter,
- TPos miny,
- TPos maxy )
+
+/****************************************************************************/
+/* */
+/* 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;
- TResult result, fresh;
+ Bool result, fresh;
+
arc[0].y = -arc[0].y;
arc[1].y = -arc[1].y;
arc[2].y = -arc[2].y;
@@ -1593,10 +1082,10 @@
fresh = ras.fresh;
- result = Bezier_Up( RAS_VAR_ degree, splitter, -maxy, -miny );
+ result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny );
if ( fresh && !ras.fresh )
- ras.cur_prof->start = -ras.cur_prof->start;
+ ras.cProfile->start = -ras.cProfile->start;
arc[0].y = -arc[0].y;
return result;
@@ -1603,278 +1092,71 @@
}
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
- /**** ****/
- /**** ****/
- /**** SPLITTING CONIC AND CUBIC BEZIERS IN HALF ****/
- /**** ****/
- /**** ****/
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
+/****************************************************************************/
+/* */
+/* 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. */
+/* */
+/****************************************************************************/
-
-#ifdef FT_RASTER_CONIC_BEZIERS
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Split_Conic */
- /* */
- /* <Description> */
- /* Subdivides one second-order Bezier arc into two joint sub-arcs in */
- /* the Bezier stack. */
- /* */
- /* <Note> */
- /* This routine is the `beef' of the component. It is one of _the_ */
- /* inner loops that should be optimized like hell to get the best */
- /* performance. */
- /* */
- static
- void Split_Conic( TPoint* base )
+ static Bool Line_To( RAS_ARGS Long x, Long y )
{
- TPos a, b;
+ /* First, detect a change of direction */
-
- 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;
-
- 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;
- base[2].y = ( a + b ) / 2;
- }
-
-#endif
-
-#ifdef FT_RASTER_CUBIC_BEZIERS
-
- /*************************************************************************/
- /* */
- /* <Function> Split_Cubic */
- /* */
- /* <Description> */
- /* Subdivides a third-order Bezier arc into two joint sub-arcs in */
- /* the Bezier stack. */
- /* */
- /* <Note> */
- /* This routine is the `beef' of the component. It is one of _the_ */
- /* inner loops that should be optimized like hell to get the best */
- /* performance. */
- /* */
- static
- void Split_Cubic( TPoint* base )
- {
- TPos a, b, c, d;
-
-
- base[6].x = base[3].x;
- c = base[1].x;
- d = base[2].x;
- base[1].x = a = ( base[0].x + c + 1 ) >> 1;
- base[5].x = b = ( base[3].x + d + 1 ) >> 1;
- c = ( c + d + 1 ) >> 1;
- base[2].x = a = ( a + c + 1 ) >> 1;
- base[4].x = b = ( b + c + 1 ) >> 1;
- base[3].x = ( a + b + 1 ) >> 1;
-
- base[6].y = base[3].y;
- c = base[1].y;
- d = base[2].y;
- base[1].y = a = ( base[0].y + c + 1 ) >> 1;
- base[5].y = b = ( base[3].y + d + 1 ) >> 1;
- c = ( c + d + 1 ) >> 1;
- base[2].y = a = ( a + c + 1 ) >> 1;
- base[4].y = b = ( b + c + 1 ) >> 1;
- base[3].y = ( a + b + 1 ) >> 1;
- }
-
-#endif /* FT_RASTER_CUBIC_BEZIERS */
-
-
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
- /**** ****/
- /**** ****/
- /**** PROCESSING OUTLINE SEGMENTS ****/
- /**** ****/
- /**** ****/
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
-
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Check_Contour */
- /* */
- /* <Description> */
- /* Performs some checks at contour closure. */
- /* */
- /* <Return> */
- /* SUCCESS or FAILURE. */
- /* */
- static
- TResult Check_Contour( RAS_ARG )
- {
- PProfile lastProfile;
-
- /* 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 ) )
+ switch ( ras.state )
{
- if ( ras.first_prof && ras.first_prof->flow == ras.cur_prof->flow )
- ras.cursor--;
- }
+ 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;
- 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;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Move_To */
- /* */
- /* <Description> */
- /* This function injects a new contour in the render pool. */
- /* */
- /* <Input> */
- /* to :: A pointer to the contour's first point. */
- /* raster :: A pointer to the current raster object. */
- /* */
- /* <Return> */
- /* Error code. 0 means success. */
- /* */
- /* <Note> */
- /* 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;
- }
- else
- {
- ras.last.x = scaled_x;
- ras.last.y = scaled_y;
- }
-
- ras.state = Unknown;
- ras.first_prof = NULL;
-
- return SUCCESS;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Line_To */
- /* */
- /* <Description> */
- /* This function injects a new line segment in the render pool and */
- /* adjusts the profiles list accordingly. */
- /* */
- /* <Input> */
- /* to :: A pointer to the target position. */
- /* raster :: A pointer to the current raster object. */
- /* */
- /* <Return> */
- /* Error code. 0 means success. */
- /* */
- /* <Note> */
- /* 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 )
- {
- x = scaled_y;
- y = scaled_x;
- }
- else
- {
- x = scaled_x;
- y = scaled_y;
- }
-
- /* First, detect a change of direction */
- if ( y != ras.last.y )
- {
- TDirection new_state = ( (y > ras.last.y) ? Ascending : Descending );
-
-
- if ( ras.state != new_state )
+ case Ascending:
+ if ( y < ras.lastY )
{
- if ( ras.state != Unknown &&
- End_Profile( RAS_VAR ) )
- goto Fail;
+ if ( End_Profile( RAS_VAR ) ||
+ New_Profile( RAS_VARS Descending ) ) return FAILURE;
+ }
+ break;
- if ( New_Profile( RAS_VAR_ new_state ) )
- goto Fail;
+ case Descending:
+ if ( y > ras.lastY )
+ {
+ if ( End_Profile( RAS_VAR ) ||
+ New_Profile( RAS_VARS Ascending ) ) return FAILURE;
}
+ break;
+
+ default:
+ ;
}
/* Then compute the lines */
+
switch ( ras.state )
{
case Ascending:
- if ( Line_Up ( RAS_VAR_ ras.last.x, ras.last.y,
- x, y, ras.minY, ras.maxY ) )
- goto Fail;
+ if ( Line_Up ( RAS_VARS ras.lastX, ras.lastY,
+ x, y, ras.minY, ras.maxY ) )
+ 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 ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
+ x, y, ras.minY, ras.maxY ) )
+ return FAILURE;
break;
default:
@@ -1881,101 +1163,35 @@
;
}
- ras.last.x = x;
- ras.last.y = y;
+ 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. */
+/* */
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Push_Conic */
- /* */
- /* <Description> */
- /* Clears the Bezier stack and pushes a new arc on top of it. */
- /* */
- /* <Input> */
- /* p2 :: A pointer to the second (control) point. */
- /* p3 :: A pointer to the third (end) point. */
- /* */
- /* <Note> */
- /* 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; \
- } \
- }
+ Long y1, y2, y3, x3, ymin, ymax;
+ TStates state_bez;
- TPoint* arc;
+ 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;
- ras.arc = arc = ras.arcs;
-
- arc[2] = ras.last;
- STORE( arc[1], p2 );
- STORE( arc[0], p3 );
-#undef STORE
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Conic_To */
- /* */
- /* <Description> */
- /* Injects a new conic Bezier arc and adjusts the profile list */
- /* accordingly. */
- /* */
- /* <Input> */
- /* control :: A pointer to an intermediate control point. */
- /* to :: A pointer to the end point. */
- /* raster :: A handle to the current raster object. */
- /* */
- /* <Return> */
- /* Error code. 0 means success. */
- /* */
- /* <Note> */
- /* 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 );
-
do
{
y1 = ras.arc[2].y;
@@ -2020,7 +1236,7 @@
goto Fail;
/* create a new profile */
- if ( New_Profile( RAS_VAR_ state_bez ) )
+ if ( New_Profile( RAS_VARS state_bez ) )
goto Fail;
}
@@ -2027,135 +1243,49 @@
/* 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 );
+ Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2;
+ TStates state_bez;
- return ErrRaster_Invalid_Outline;
- }
-#endif /* FT_RASTER_CONIC_BEZIERS */
+ 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;
-
-#ifdef FT_RASTER_CUBIC_BEZIERS
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Push_Cubic */
- /* */
- /* <Description> */
- /* Clears the Bezier stack and pushes a new third-order Bezier arc on */
- /* top of it. */
- /* */
- /* <Input> */
- /* p2 :: A pointer to the second (control) point. */
- /* p3 :: A pointer to the third (control) point. */
- /* p4 :: A pointer to the fourth (end) point. */
- /* */
- /* <Note> */
- /* 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
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Cubic_To */
- /* */
- /* <Description> */
- /* Injects a new cubic Bezier arc and adjusts the profile list */
- /* accordingly. */
- /* */
- /* <Input> */
- /* 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. */
- /* */
- /* <Return> */
- /* Error code. 0 means success. */
- /* */
- /* <Note> */
- /* 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 );
-
do
{
y1 = ras.arc[3].y;
@@ -2210,7 +1340,7 @@
End_Profile( RAS_VAR ) )
goto Fail;
- if ( New_Profile( RAS_VAR_ state_bez ) )
+ if ( New_Profile( RAS_VARS state_bez ) )
goto Fail;
}
@@ -2217,128 +1347,338 @@
/* 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;
+ 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)
+ {
+ SWAP_(v_start.x,v_start.y);
+ SWAP_(v_last.x,v_last.y);
+ }
+
+ v_control = v_start;
+ point = points + first;
+ tags = ras.outline.tags + first;
+ tag = FT_CURVE_TAG( tags[0] );
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Convert_Glyph */
- /* */
- /* <Description> */
- /* Converts a glyph into a series of segments and arcs and makes a */
- /* profiles list with them. */
- /* */
- /* <InOut> */
- /* outline :: The glyph outline. */
- /* */
- /* <Return> */
- /* SUCCESS or FAILURE. */
- /* */
- static
- TResult Convert_Glyph( RAS_ARG_ FT_Outline* outline )
+ /* A contour cannot start with a cubic control point! */
+ if ( tag == FT_Curve_Tag_Cubic )
+ goto Invalid_Outline;
+
+ /* 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;
+
+ v_last = v_start;
+ }
+ point--;
+ tags--;
+ }
+
+ ras.lastX = v_start.x;
+ ras.lastY = v_start.y;
+
+ 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 )
{
- static
- FT_Outline_Funcs interface =
+ 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++ )
{
- (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
- };
+ ras.state = Unknown;
+ ras.gProfile = NULL;
- /* Set up state in the raster object */
- ras.start_prof = NULL;
- ras.joint = FALSE;
- ras.fresh = FALSE;
+ if ( Decompose_Curve( RAS_VARS start, ras.outline.contours[i], flipped ) )
+ return FAILURE;
- ras.pool_limit = ras.pool_size - AlignProfileSize;
+ start = ras.outline.contours[i] + 1;
- ras.n_extrema = 0;
+ /* 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. */
- ras.cur_prof = (PProfile)ras.cursor;
- ras.cur_prof->offset = ras.cursor;
- ras.num_profs = 0;
+ lastProfile = ras.cProfile;
+ if ( End_Profile( RAS_VAR ) ) return FAILURE;
- /* Now decompose curve */
- if ( FT_Outline_Decompose( outline, &interface, &ras ) )
- return FAILURE;
- /* XXX: the error condition is in ras.error */
+ /* close the 'next profile in contour' linked list */
+ if ( ras.gProfile )
+ lastProfile->next = ras.gProfile;
+ }
- /* Check the last contour if needed */
- if ( Check_Contour( RAS_VAR ) )
+ 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. */
+/* */
+/***********************************************************************/
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Vertical_Sweep_Init */
- /* */
- /* <Description> */
- /* Initializes the vertical bitmap sweep. Called by the generic */
- /* sweep/draw routine before its loop. */
- /* */
- /* <Input> */
- /* 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;
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Vertical_Sweep_Span */
- /* */
- /* <Description> */
- /* Draws a single horizontal bitmap span during the vertical bitmap */
- /* sweep. */
- /* */
- /* <Input> */
- /* 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 @@
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Vertical_Test_Pixel */
- /* */
- /* <Description> */
- /* Tests a pixel `light' during the vertical bitmap sweep. Used */
- /* during drop-out control only. */
- /* */
- /* <Input> */
- /* 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;
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Vertical_Set_Pixel */
- /* */
- /* <Description> */
- /* Sets a single pixel in a bitmap during the vertical sweep. Used */
- /* during drop-out control. */
- /* */
- /* <Input> */
- /* 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 )
- {
- UNUSED( color );
- UNUSED( y );
+ case 4:
+ e1 = CEILING( (x1 + x2 + 1) / 2 );
+ break;
- if ( x >= 0 && x < ras.bit_width )
- ras.bit_buffer[ras.trace_bit+(x >> 3)] |= (char)(0x80 >> (x & 7));
- }
+ 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 */
+ /* */
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Vertical_Sweep_Step */
- /* */
- /* <Description> */
- /* Called whenever the sweep jumps to another scanline. Only updates */
- /* the pointers in the vertical bitmap sweep. */
- /* */
- static
- void Vertical_Sweep_Step( RAS_ARG )
- {
- ras.trace_bit += ras.trace_incr;
- }
+ /* 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 */
- static
- const Raster_Render vertical_render_mono =
- {
- &Vertical_Sweep_Init,
- &Vertical_Sweep_Span,
- &Vertical_Sweep_Step,
- &Vertical_Test_Pixel,
- &Vertical_Set_Pixel
- };
+ if ( left->next == right && left->height <= 0 ) return;
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
- /******** ********/
- /******** Horizontal Bitmap Sweep Routines ********/
- /******** ********/
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
+ /* lower stub test */
+ if ( right->next == left && left->start == y ) return;
+ }
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Horizontal_Sweep_Init */
- /* */
- /* <Description> */
- /* Initializes the horizontal bitmap sweep. Called by the generic */
- /* sweep/draw routine before its loop. */
- /* */
- /* <Input> */
- /* 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 );
+ /* check that the rightmost pixel isn't set */
- /* nothing, really */
- }
+ e1 = TRUNC( e1 );
+ c1 = (Short)(e1 >> 3);
+ f1 = e1 & 7;
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Horizontal_Sweep_Span */
- /* */
- /* <Description> */
- /* Draws a single vertical bitmap span during the horizontal bitmap */
- /* sweep. Actually, this function is only used to check for weird */
- /* drop-out cases. */
- /* */
- /* <Input> */
- /* 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 )
- {
- TPos e1, e2;
- PByte bits;
- Byte f1;
+ if ( e1 >= 0 && e1 < ras.bWidth &&
+ ras.bTarget[ras.traceOfs + c1] & (0x80 >> f1) )
+ return;
- UNUSED( y );
+ if ( ras.dropOutControl == 2 )
+ e1 = e2;
+ else
+ e1 = CEILING( (x1 + x2 + 1) / 2 );
- /* During the horizontal sweep, we only take care of drop-outs */
- if ( x2 - x1 < PRECISION )
- {
- e1 = CEILING( x1 );
- e2 = FLOOR( x2 );
+ break;
- if ( e1 == e2 )
- {
- bits = ras.bit_buffer + (y >> 3);
- f1 = (Byte)(0x80 >> (y & 7));
+ default:
+ return; /* unsupported mode */
+ }
+ }
+ else
+ return;
+ }
- e1 = TRUNC( e1 );
+ e1 = TRUNC( e1 );
- if ( e1 >= 0 && e1 < ras.target.rows )
- {
- long pitch = ras.target.pitch;
- long offset = - pitch * e1;
+ if ( e1 >= 0 && e1 < ras.bWidth )
+ {
+ c1 = (Short)(e1 >> 3);
+ f1 = e1 & 7;
- if (pitch > 0)
- offset += (ras.target.rows-1)*pitch;
+ if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
+ if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1;
- bits[offset] |= f1;
- }
- }
+ ras.bTarget[ras.traceOfs + c1] |= (char)(0x80 >> f1);
}
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Horizontal_Test_Pixel */
- /* */
- /* <Description> */
- /* Tests a pixel `light' during the horizontal bitmap sweep. Used */
- /* during drop-out control only. */
- /* */
- /* <Input> */
- /* y :: The current pixel column. */
- /* x :: The current row/scanline. */
- /* */
- static
- int Horizontal_Test_Pixel( RAS_ARG_ int y,
- int x )
+ static void Vertical_Sweep_Step( RAS_ARG )
{
- char* bits = (char*)ras.bit_buffer + (y >> 3);
- int f1 = (Byte)(0x80 >> (y & 7));
- long pitch = ras.target.pitch;
- long offset = - pitch * x;
+ ras.traceOfs += ras.traceIncr;
+ }
- if (pitch > 0)
- offset += (ras.target.rows-1)*pitch;
- return ( x >= 0 && x < ras.target.rows && (bits[0] & f1) );
+/***********************************************************************/
+/* */
+/* 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 )
+ {
+ /* nothing, really */
+ UNUSED(raster);
+ UNUSED(min);
+ UNUSED(max);
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Horizontal_Set_Pixel */
- /* */
- /* <Description> */
- /* Sets a single pixel in a bitmap during the horizontal sweep. Used */
- /* during drop-out control. */
- /* */
- /* <Input> */
- /* 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 )
+ static void Horizontal_Sweep_Span( 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 e1, e2;
+ PByte bits;
+ Byte f1;
+ UNUSED(left);
+ UNUSED(right);
+
+ if ( x2-x1 < ras.precision )
+ {
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
- UNUSED( color );
+ if ( e1 == e2 )
+ {
+ bits = ras.bTarget + (y >> 3);
+ f1 = (Byte)(0x80 >> (y & 7));
- if ( x >= 0 && x < ras.target.rows )
- {
- long pitch = ras.target.pitch;
- long offset = - x*pitch;
+ e1 = TRUNC( e1 );
- if (pitch > 0)
- offset += (ras.target.rows-1)*pitch;
+ if ( e1 >= 0 && e1 < ras.target.rows )
+ {
+ PByte p;
- 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;
+ }
+ }
}
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Horizontal_Sweep_Step */
- /* */
- /* <Description> */
- /* Called whenever the sweep jumps to another pixel column. */
- /* */
- static
- void Horizontal_Sweep_Step( RAS_ARG )
+ static void Horizontal_Sweep_Drop( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
{
- UNUSED( ras.target );
+ Long e1, e2;
+ PByte bits;
+ Byte f1;
- /* Nothing, really */
- }
+ /* During the horizontal sweep, we only take care of drop-outs */
- static
- const Raster_Render horizontal_render_mono =
- {
- &Horizontal_Sweep_Init,
- &Horizontal_Sweep_Span,
- &Horizontal_Sweep_Step,
- &Horizontal_Test_Pixel,
- &Horizontal_Set_Pixel
- };
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+ if ( e1 > e2 )
+ {
+ if ( e1 == e2 + ras.precision )
+ {
+ switch ( ras.dropOutControl )
+ {
+ case 1:
+ e1 = e2;
+ break;
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
- /******** ********/
- /******** Anti-Aliased Vertical Bitmap Sweep Routines ********/
- /******** ********/
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
+ case 4:
+ e1 = CEILING( (x1 + x2 + 1) / 2 );
+ break;
-#ifdef FT_RASTER_OPTION_ANTI_ALIAS
+ case 2:
+ case 5:
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Vertical_Gray_Sweep_Init */
- /* */
- /* <Description> */
- /* Initializes the vertical bitmap sweep. Called by the generic */
- /* sweep/draw routine before its loop. */
- /* */
- /* <Input> */
- /* 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;
+ /* Drop-out Control Rule #4 */
- UNUSED( max );
+ /* 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'. */
+ /* */
- pitch = ras.target.pitch;
+ /* rightmost stub test */
- /* start from the bottom line, going up */
- ras.trace_incr = -pitch;
- ras.trace_bit = - *min * pitch;
+ if ( left->next == right && left->height <= 0 ) return;
- if (pitch > 0)
- ras.trace_bit += (ras.target.rows-1)*pitch;
- }
+ /* leftmost stub test */
+ if ( right->next == left && left->start == y ) return;
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Vertical_Gray_Sweep_Span */
- /* */
- /* <Description> */
- /* Draws a single horizontal bitmap span during the vertical bitmap */
- /* sweep. */
- /* */
- /* <Input> */
- /* 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;
+ /* check that the rightmost pixel isn't set */
- UNUSED( y );
+ e1 = TRUNC( e1 );
- x1 += PRECISION_HALF;
- x2 += PRECISION_HALF;
+ bits = ras.bTarget + (y >> 3);
+ f1 = (Byte)(0x80 >> (y & 7));
- e1 = TRUNC( x1 );
- e2 = TRUNC( x2 );
+ bits -= e1*ras.target.pitch;
+ if (ras.target.pitch > 0)
+ bits += (ras.target.rows-1)*ras.target.pitch;
- if ( e1 <= e2 && e2 >= 0 && e1 < ras.bit_width )
- {
- x1 = FRAC(x1) >> shift;
- x2 = FRAC(x2) >> shift;
+ if ( e1 >= 0 &&
+ e1 < ras.target.rows &&
+ *bits & f1 )
+ return;
- if ( e1 < 0 )
- {
- e1 = 0;
- x1 = 0;
- }
+ if ( ras.dropOutControl == 2 )
+ e1 = e2;
+ else
+ e1 = CEILING( (x1 + x2 + 1) / 2 );
- if ( e2 > ras.bit_width )
- {
- e2 = ras.bit_width-1;
- x2 = 0;
- }
+ break;
- 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)
- {
- *(++target) = 127;
- e2--;
+ default:
+ return; /* unsupported mode */
}
- if (x2)
- target[1] += (Byte)x2 << 1;
}
else
- {
- target[0] += (Byte)(x2-x1) << 1;
- }
+ return;
}
- }
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Vertical_Gray_Test_Pixel */
- /* */
- /* <Description> */
- /* Tests a pixel `light' during the vertical bitmap sweep. Used */
- /* during drop-out control only. */
- /* */
- /* <Input> */
- /* 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
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Vertical_Gray_Set_Pixel */
- /* */
- /* <Description> */
- /* Sets a single pixel in a bitmap during the vertical sweep. Used */
- /* during drop-out control. */
- /* */
- /* <Input> */
- /* 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;
}
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Vertical_Sweep_Step */
- /* */
- /* <Description> */
- /* 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_Init,
- &Vertical_Gray_Sweep_Span,
- &Vertical_Gray_Sweep_Step,
- &Vertical_Gray_Test_Pixel,
- &Vertical_Gray_Set_Pixel
- };
+/***********************************************************************/
+/* */
+/* 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. */
+/* */
+/***********************************************************************/
-
-
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
- /******** ********/
- /******** Horizontal Bitmap Sweep Routines ********/
- /******** ********/
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Horizontal_Sweep_Init */
- /* */
- /* <Description> */
- /* Initializes the horizontal bitmap sweep. Called by the generic */
- /* sweep/draw routine before its loop. */
- /* */
- /* <Input> */
- /* 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 )
+ static void Vertical_Gray_Sweep_Init( RAS_ARGS Short* min, Short* max )
{
- UNUSED( ras );
- UNUSED( min );
- UNUSED( max );
+ Long pitch, byte_len;
+
+ *min = *min & -2;
+ *max = ( *max + 3 ) & -2;
- /* nothing, really */
+ ras.traceOfs = 0;
+ pitch = ras.target.pitch;
+ byte_len = -pitch;
+ ras.traceIncr = (Short)byte_len;
+ ras.traceG = (*min/2)*byte_len;
+ if (pitch > 0)
+ {
+ ras.traceG += (ras.target.rows-1)*pitch;
+ byte_len = -byte_len;
+ }
+
+ ras.gray_min_x = (Short)byte_len;
+ ras.gray_max_x = -(Short)byte_len;
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Horizontal_Gray_Sweep_Span */
- /* */
- /* <Description> */
- /* Draws a single vertical bitmap span during the horizontal bitmap */
- /* sweep. */
- /* */
- /* <Input> */
- /* 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 )
+ static void Vertical_Gray_Sweep_Step( RAS_ARG )
{
- TPos e1, e2;
- int shift = PRECISION_BITS - 6;
- int incr;
- PByte bits;
- Byte b;
+ Int c1, c2;
+ PByte pix, bit, bit2;
+ Int* count = ras.count_table;
+ Byte* grays;
- UNUSED( y );
- x1 += PRECISION_HALF;
- x2 += PRECISION_HALF;
+ ras.traceOfs += ras.gray_width;
- e1 = TRUNC( x1 );
- e2 = TRUNC( x2 );
-
- if ( e1 <= e2 && e2 >= 0 && e1 < ras.bit_width )
+ if ( ras.traceOfs > ras.gray_width )
{
- x1 = FRAC(x1) >> shift;
- x2 = FRAC(x2) >> shift;
+ pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4;
+ grays = ras.grays;
- if ( e1 < 0 )
+ if ( ras.gray_max_x >= 0 )
{
- e1 = 0;
- x1 = 0;
- }
+ 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)
+ {
+ ras.gray_max_x = last_cell-1;
+ over = 1;
+ }
- if ( e2 >= ras.bit_width )
- {
- e2 = ras.bit_width;
- x2 = 0;
- }
+ if ( ras.gray_min_x < 0 )
+ ras.gray_min_x = 0;
- incr = -ras.target.pitch;
- bits = ras.bit_buffer + y;
- bits += incr * e1;
- if (incr < 0)
- bits -= incr*(ras.target.rows-1);
+ bit = ras.bTarget + ras.gray_min_x;
+ bit2 = bit + ras.gray_width;
- e2 -= e1;
+ c1 = ras.gray_max_x - ras.gray_min_x;
- if ( e2 > 0 )
- {
- b = bits[0];
- if (b < 127) b++;
- b = (Byte)((64-x1) + (b >> 1));
- bits[0] = b;
-
- if ( e2 < 24 )
+ while ( c1 >= 0 )
{
- e2--;
- while (e2 > 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));
-
- e2--;
+ *bit = 0;
+ *bit2 = 0;
}
- }
- else
- bits += incr*(e2-1);
- if (x2)
+ bit ++;
+ bit2++;
+ pix += 4;
+ c1 --;
+ }
+
+ if (over)
{
- bits += incr;
- b = bits[0];
- if (b < 127) b++;
- b = (Byte)(x2 + (b >> 1));
- bits[0] = b;
+ 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
- {
- b = bits[0];
- if (b < 127) b++;
- b = (Byte)((b >> 1)+(x2-x1));
- bits[0] = b;
- }
+
+ ras.traceOfs = 0;
+ ras.traceG += ras.traceIncr;
+
+ ras.gray_min_x = 32000;
+ ras.gray_max_x = -32000;
}
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Horizontal_Gray_Test_Pixel */
- /* */
- /* <Description> */
- /* Tests a pixel `light' during the horizontal bitmap sweep. Used */
- /* during drop-out control only. */
- /* */
- /* <Input> */
- /* y :: The current pixel column. */
- /* x :: The current row/scanline. */
- /* */
- static
- int Horizontal_Gray_Test_Pixel( RAS_ARG_ int y,
- int x )
+ static void Horizontal_Gray_Sweep_Span( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
{
-#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
+ /* nothing, really */
+ UNUSED(raster);
UNUSED(y);
- UNUSED(x);
- return 0;
-#endif
+ UNUSED(x1);
+ UNUSED(x2);
+ UNUSED(left);
+ UNUSED(right);
}
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Horizontal_Set_Pixel */
- /* */
- /* <Description> */
- /* Sets a single pixel in a bitmap during the horizontal sweep. Used */
- /* during drop-out control. */
- /* */
- /* <Input> */
- /* 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 )
+ static void Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
{
- unsigned char* pixel = (unsigned char*)ras.bit_buffer + y;
+ Long e1, e2;
+ PByte pixel;
+ Byte color;
- if ( x >= 0 && x < ras.target.rows )
+
+ /* During the horizontal sweep, we only take care of drop-outs */
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+
+ if ( e1 > e2 )
{
- long pitch = ras.target.pitch;
+ if ( e1 == e2 + ras.precision )
+ {
+ switch ( ras.dropOutControl )
+ {
+ case 1:
+ e1 = e2;
+ break;
- pixel -= pitch*x;
- if (pitch > 0)
- pixel += pitch*(ras.target.rows-1);
+ case 4:
+ e1 = CEILING( (x1 + x2 + 1) / 2 );
+ break;
- color += *pixel;
- if (color < 64)
- color = 64;
+ case 2:
+ case 5:
- *pixel = (color >= 127 ? 127 : (unsigned char)color );
- }
- }
+ /* 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'. */
+ /* */
- static
- void Gray_Ignore( void )
- {
- ;
- }
+ /* rightmost stub test */
+ if ( left->next == right && left->height <= 0 ) return;
+ /* leftmost stub test */
+ if ( right->next == left && left->start == y ) return;
- static
- const Raster_Render horizontal_render_gray =
- {
- &Horizontal_Gray_Sweep_Init,
- &Horizontal_Gray_Sweep_Span,
+ if ( ras.dropOutControl == 2 )
+ e1 = e2;
+ else
+ e1 = CEILING( (x1 + x2 + 1) / 2 );
- (Function_Sweep_Step) &Gray_Ignore,
- &Horizontal_Gray_Test_Pixel,
- &Horizontal_Gray_Set_Pixel,
- };
+ break;
-#endif /* FT_RASTER_OPTION_ANTI_ALIAS */
+ default:
+ return; /* unsupported mode */
+ }
+ }
+ else
+ return;
+ }
+ if ( e1 >= 0 )
+ {
+ if ( x2 - x1 >= ras.precision_half )
+ color = ras.grays[2];
+ else
+ color = ras.grays[1];
- /*************************************************************************/
- /* */
- /* 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. */
- /* */
- /*************************************************************************/
+ e1 = TRUNC( e1 ) / 2;
+ if ( e1 < ras.target.rows )
+ {
+ 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;
+ }
+ }
+ }
- /*************************************************************************/
- /* */
- /* Generic Sweep Drawing routine */
- /* */
- static
- TResult Draw_Sweep( RAS_ARG )
+#endif /* FT_RASTER_OPTION_ANTI_ALIASING */
+
+
+/********************************************************************/
+/* */
+/* Generic Sweep Drawing routine */
+/* */
+/********************************************************************/
+
+ static Bool 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( &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 */
+ P = wait;
- /* look in the wait list for new activations */
- while ( prof )
+ while ( P )
{
- PProfile next = prof->link;
-
- prof->countL -= y_height;
- if ( prof->countL == 0 )
+ 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 ( x1 > x2 )
+ {
+ xs = x1;
+ x1 = x2;
+ x2 = xs;
+ }
- if ( window == 0 )
+ if ( x2-x1 <= ras.precision )
{
- x1 = left->X;
- x2 = prof->X;
+ e1 = FLOOR( x1 );
+ e2 = CEILING( x2 );
- if ( x1 > 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;
- if ( x2 - x1 <= PRECISION && ras.dropout_mode )
- {
- e1 = CEILING( x1 );
- e2 = FLOOR( x2 );
+ /* mark profile for drop-out processing */
+ P_Left->countL = 1;
+ dropouts++;
- 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;
- }
+ 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)
+
+ if ( y < y_change )
{
- fprintf( stderr, "\n" );
- y_set = 0;
+ Sort( &draw_left );
+ Sort( &draw_right );
}
- #endif
- if ( y < y_change )
- Sort( &draw );
-
- 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 );
+ 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 );
}
- 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;
- }
-
- 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;
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Render_Single_Pass */
- /* */
- /* <Description> */
- /* Performs one sweep with sub-banding. */
- /* */
- /* <Input> */
- /* flipped :: whether or not we have to flip. */
- /* */
- /* <Returns> */
- /* 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;
+ ras.error = Raster_Err_None;
- if ( ras.error != ErrRaster_Overflow )
- return FAILURE;
- ras.error = ErrRaster_Ok;
-
- FT_TRACE2(( "conversion failure, performing sub-banding\n" ));
-
/* 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;
- if ( ras.target.width > ABS(ras.target.pitch) )
- return ErrRaster_Invalid_Map;
+ 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);
+
/* 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 );
-#else
- return 0;
-#endif
- }
+ 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;
+ }
-#else /* FT_RASTER_OPTION_ANTI_ALIAS */
-
-
- static
- int Raster_Render8( FT_Raster raster )
+ return FT_Err_Ok;
+ }
+#else
+ 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 @@
#include <freetype/internal/ftobjs.h>
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 @@
}
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,60 +2924,67 @@
#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;
+ return Raster_Err_Invalid;
- 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) );
-
/* 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 ) );
}
@@ -4011,11 +2991,11 @@
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
};