summaryrefslogtreecommitdiffstats
path: root/src/raster/ftraster.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/raster/ftraster.c')
-rw-r--r--src/raster/ftraster.c578
1 files changed, 354 insertions, 224 deletions
diff --git a/src/raster/ftraster.c b/src/raster/ftraster.c
index eb9c4a4..23ad592 100644
--- a/src/raster/ftraster.c
+++ b/src/raster/ftraster.c
@@ -49,6 +49,10 @@
#ifdef _STANDALONE_
+#define FT_CONFIG_STANDARD_LIBRARY_H <stdlib.h>
+
+#include <string.h> /* for memset */
+
#include "ftmisc.h"
#include "ftimage.h"
@@ -58,6 +62,8 @@
#include "ftraster.h"
#include FT_INTERNAL_CALC_H /* for FT_MulDiv only */
+#include "rastpic.h"
+
#endif /* !_STANDALONE_ */
@@ -72,13 +78,15 @@
/* 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 its scanline position boundaries, i.e. `Ymin' and `Ymax' */
/* */
/* o an array of intersection coordinates for each scanline */
- /* between `Ymin' and `Ymax'. */
+ /* between `Ymin' and `Ymax' */
/* */
/* o a direction, indicating whether it was built going `up' or */
- /* `down', as this is very important for filling rules. */
+ /* `down', as this is very important for filling rules */
+ /* */
+ /* o its drop-out mode */
/* */
/* 2 - Sweeping the target map's scanlines in order to compute segment */
/* `spans' which are then filled. Additionally, this pass */
@@ -88,15 +96,15 @@
/* 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 |--> */
- /* |_________|___________________|_________|_________________|__ _ _ */
+ /* __________________________________________________________ _ _ */
+ /* | | | | | */
+ /* | profile | coordinates for | profile | coordinates for |--> */
+ /* | 1 | profile 1 | 2 | profile 2 |--> */
+ /* |_________|_________________|_________|_________________|__ _ _ */
/* */
- /* ^ ^ */
- /* | | */
- /* start of render pool top */
+ /* ^ ^ */
+ /* | | */
+ /* start of render pool top */
/* */
/* The top of the profile stack is kept in the `top' variable. */
/* */
@@ -140,11 +148,11 @@
/*************************************************************************/
/* define DEBUG_RASTER if you want to compile a debugging version */
-#define xxxDEBUG_RASTER
+/* #define DEBUG_RASTER */
- /* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */
- /* 5-levels anti-aliasing */
-#undef FT_RASTER_OPTION_ANTI_ALIASING
+ /* define FT_RASTER_OPTION_ANTI_ALIASING if you want to support */
+ /* 5-levels anti-aliasing */
+/* #define FT_RASTER_OPTION_ANTI_ALIASING */
/* The size of the two-lines intermediate bitmap used */
/* for anti-aliasing, in bytes. */
@@ -197,9 +205,22 @@
#define Raster_Err_Invalid -4
#define Raster_Err_Unsupported -5
-#define ft_memset memset
+#define ft_memset memset
+
+#define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, raster_new_, \
+ raster_reset_, raster_set_mode_, \
+ raster_render_, raster_done_ ) \
+ const FT_Raster_Funcs class_ = \
+ { \
+ glyph_format_, \
+ raster_new_, \
+ raster_reset_, \
+ raster_set_mode_, \
+ raster_render_, \
+ raster_done_ \
+ };
-#else /* _STANDALONE_ */
+#else /* !_STANDALONE_ */
#include FT_INTERNAL_OBJECTS_H
@@ -215,7 +236,7 @@
#define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph
-#endif /* _STANDALONE_ */
+#endif /* !_STANDALONE_ */
#ifndef FT_MEM_SET
@@ -304,13 +325,10 @@
} TPoint;
- typedef enum TFlow_
- {
- Flow_None = 0,
- Flow_Up = 1,
- Flow_Down = -1
-
- } TFlow;
+ /* values for the `flags' bit field */
+#define Flow_Up 0x8
+#define Overshoot_Top 0x10
+#define Overshoot_Bottom 0x20
/* States of each line, arc, and profile */
@@ -329,18 +347,21 @@
struct TProfile_
{
- FT_F26Dot6 X; /* current coordinate during sweep */
- PProfile link; /* link to next profile - various purpose */
- PLong offset; /* start of profile's data in render pool */
- int flow; /* Profile orientation: Asc/Descending */
- long height; /* profile's height in scanlines */
- long start; /* profile's starting scanline */
-
- unsigned countL; /* number of lines to step before this */
- /* profile becomes drawable */
-
- PProfile next; /* next profile in same contour, used */
- /* during drop-out control */
+ FT_F26Dot6 X; /* current coordinate during sweep */
+ PProfile link; /* link to next profile (various purposes) */
+ PLong offset; /* start of profile's data in render pool */
+ unsigned flags; /* Bit 0-2: drop-out mode */
+ /* Bit 3: profile orientation (up/down) */
+ /* Bit 4: is top profile? */
+ /* Bit 5: is bottom profile? */
+ long height; /* profile's height in scanlines */
+ long start; /* profile's starting scanline */
+
+ unsigned countL; /* number of lines to step before this */
+ /* profile becomes drawable */
+
+ PProfile next; /* next profile in same contour, used */
+ /* during drop-out control */
};
typedef PProfile TProfileList;
@@ -373,7 +394,7 @@
#define FT_UNUSED_RASTER do { } while ( 0 )
-#else /* FT_STATIC_RASTER */
+#else /* !FT_STATIC_RASTER */
#define RAS_ARGS PWorker worker,
@@ -385,7 +406,7 @@
#define FT_UNUSED_RASTER FT_UNUSED( worker )
-#endif /* FT_STATIC_RASTER */
+#endif /* !FT_STATIC_RASTER */
typedef struct TWorker_ TWorker, *PWorker;
@@ -415,65 +436,68 @@
#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. */
+#define IS_BOTTOM_OVERSHOOT( x ) ( CEILING( x ) - x >= ras.precision_half )
+#define IS_TOP_OVERSHOOT( x ) ( x - FLOOR( x ) >= ras.precision_half )
+
+ /* The most used variables are positioned at the top of the structure. */
+ /* Thus, their offset can be coded with less opcodes, resulting in a */
+ /* smaller executable. */
struct TWorker_
{
- Int precision_bits; /* precision related variables */
- Int precision;
- Int precision_half;
- Long precision_mask;
- Int precision_shift;
- Int precision_step;
- Int precision_jitter;
-
- Int scale_shift; /* == precision_shift for bitmaps */
+ Int precision_bits; /* precision related variables */
+ Int precision;
+ Int precision_half;
+ Long precision_mask;
+ Int precision_shift;
+ Int precision_step;
+ Int precision_jitter;
+
+ Int scale_shift; /* == precision_shift for bitmaps */
/* == precision_shift+1 for pixmaps */
- PLong buff; /* The profiles buffer */
- PLong sizeBuff; /* Render pool size */
- PLong maxBuff; /* Profiles buffer size */
- PLong top; /* Current cursor in buffer */
+ PLong buff; /* The profiles buffer */
+ PLong sizeBuff; /* Render pool size */
+ PLong maxBuff; /* Profiles buffer size */
+ PLong top; /* Current cursor in buffer */
- FT_Error error;
+ FT_Error error;
- Int numTurns; /* number of Y-turns in outline */
+ Int numTurns; /* number of Y-turns in outline */
- TPoint* arc; /* current Bezier arc pointer */
+ TPoint* arc; /* current Bezier arc pointer */
- UShort bWidth; /* target bitmap width */
- PByte bTarget; /* target bitmap buffer */
- PByte gTarget; /* target pixmap buffer */
+ UShort bWidth; /* target bitmap width */
+ PByte bTarget; /* target bitmap buffer */
+ PByte gTarget; /* target pixmap buffer */
- Long lastX, lastY, minY, maxY;
+ Long lastX, lastY;
+ Long minY, maxY;
- UShort num_Profs; /* current number of profiles */
+ UShort num_Profs; /* current number of profiles */
- Bool fresh; /* signals a fresh new profile which */
- /* 'start' field must be completed */
- Bool joint; /* signals that the last arc ended */
+ Bool fresh; /* signals a fresh new profile which */
+ /* `start' field must be completed */
+ Bool joint; /* signals that the last arc ended */
/* exactly on a scanline. Allows */
/* removal of doublets */
- PProfile cProfile; /* current profile */
- PProfile fProfile; /* head of linked list of profiles */
- PProfile gProfile; /* contour's first profile in case */
+ PProfile cProfile; /* current profile */
+ PProfile fProfile; /* head of linked list of profiles */
+ PProfile gProfile; /* contour's first profile in case */
/* of impact */
- TStates state; /* rendering state */
+ TStates state; /* rendering state */
FT_Bitmap target; /* description of target bit/pixmap */
FT_Outline outline;
- Long traceOfs; /* current offset in target bitmap */
- Long traceG; /* current offset in target pixmap */
+ Long traceOfs; /* current offset in target bitmap */
+ Long traceG; /* current offset in target pixmap */
- Short traceIncr; /* sweep's increment in target bitmap */
+ Short traceIncr; /* sweep's increment in target bitmap */
- Short gray_min_x; /* current min x during gray rendering */
- Short gray_max_x; /* current max x during gray rendering */
+ Short gray_min_x; /* current min x during gray rendering */
+ Short gray_max_x; /* current max x during gray rendering */
/* dispatch variables */
@@ -482,31 +506,31 @@
Function_Sweep_Span* Proc_Sweep_Drop;
Function_Sweep_Step* Proc_Sweep_Step;
- Byte dropOutControl; /* current drop_out control method */
+ Byte dropOutControl; /* current drop_out control method */
- Bool second_pass; /* indicates whether a horizontal pass */
+ Bool second_pass; /* indicates whether a horizontal pass */
/* should be performed to control */
/* drop-out accurately when calling */
/* Render_Glyph. Note that there is */
/* no horizontal pass during gray */
/* rendering. */
- TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */
+ TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */
- 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 */
#ifdef FT_RASTER_OPTION_ANTI_ALIASING
- Byte* grays;
+ Byte* grays;
- Byte gray_lines[RASTER_GRAY_LINES];
+ 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 */
+ Short gray_width; /* width in bytes of one monochrome */
/* intermediate scanline of gray_lines. */
/* Each gray pixel takes 2 bits long there */
@@ -520,12 +544,12 @@
typedef struct TRaster_
{
- char* buffer;
- long buffer_size;
- void* memory;
- PWorker worker;
- Byte grays[5];
- Short gray_width;
+ char* buffer;
+ long buffer_size;
+ void* memory;
+ PWorker worker;
+ Byte grays[5];
+ Short gray_width;
} TRaster, *PRaster;
@@ -534,34 +558,72 @@
static TWorker cur_ras;
#define ras cur_ras
-#else
+#else /* !FT_STATIC_RASTER */
#define ras (*worker)
-#endif /* FT_STATIC_RASTER */
+#endif /* !FT_STATIC_RASTER */
#ifdef FT_RASTER_OPTION_ANTI_ALIASING
- static const char count_table[256] =
+ /* A lookup table used to quickly count set bits in four gray 2x2 */
+ /* cells. The values of the table have been produced with the */
+ /* following code: */
+ /* */
+ /* for ( i = 0; i < 256; i++ ) */
+ /* { */
+ /* l = 0; */
+ /* j = i; */
+ /* */
+ /* for ( c = 0; c < 4; c++ ) */
+ /* { */
+ /* l <<= 4; */
+ /* */
+ /* if ( j & 0x80 ) l++; */
+ /* if ( j & 0x40 ) l++; */
+ /* */
+ /* j = ( j << 2 ) & 0xFF; */
+ /* } */
+ /* printf( "0x%04X", l ); */
+ /* } */
+ /* */
+
+ static const short count_table[256] =
{
- 0 , 1 , 1 , 2 , 1 , 2 , 2 , 3 , 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4,
- 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5,
- 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5,
- 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6,
- 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5,
- 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6,
- 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6,
- 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7,
- 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5,
- 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6,
- 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6,
- 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7,
- 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6,
- 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7,
- 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7,
- 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 , 5 , 6 , 6 , 7 , 6 , 7 , 7 , 8
-a };
+ 0x0000, 0x0001, 0x0001, 0x0002, 0x0010, 0x0011, 0x0011, 0x0012,
+ 0x0010, 0x0011, 0x0011, 0x0012, 0x0020, 0x0021, 0x0021, 0x0022,
+ 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
+ 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
+ 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
+ 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
+ 0x0200, 0x0201, 0x0201, 0x0202, 0x0210, 0x0211, 0x0211, 0x0212,
+ 0x0210, 0x0211, 0x0211, 0x0212, 0x0220, 0x0221, 0x0221, 0x0222,
+ 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
+ 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
+ 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
+ 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
+ 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
+ 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
+ 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
+ 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
+ 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
+ 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
+ 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
+ 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
+ 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
+ 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
+ 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
+ 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
+ 0x2000, 0x2001, 0x2001, 0x2002, 0x2010, 0x2011, 0x2011, 0x2012,
+ 0x2010, 0x2011, 0x2011, 0x2012, 0x2020, 0x2021, 0x2021, 0x2022,
+ 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
+ 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
+ 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
+ 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
+ 0x2200, 0x2201, 0x2201, 0x2202, 0x2210, 0x2211, 0x2211, 0x2212,
+ 0x2210, 0x2211, 0x2211, 0x2212, 0x2220, 0x2221, 0x2221, 0x2222
+ };
#endif /* FT_RASTER_OPTION_ANTI_ALIASING */
@@ -593,9 +655,9 @@ a };
{
if ( High )
{
- ras.precision_bits = 10;
- ras.precision_step = 128;
- ras.precision_jitter = 24;
+ ras.precision_bits = 12;
+ ras.precision_step = 256;
+ ras.precision_jitter = 50;
}
else
{
@@ -622,14 +684,18 @@ a };
/* Create a new profile in the render pool. */
/* */
/* <Input> */
- /* aState :: The state/orientation of the new profile. */
+ /* aState :: The state/orientation of the new profile. */
+ /* */
+ /* overshoot :: Whether the profile's unrounded start position */
+ /* differs by at least a half pixel. */
/* */
/* <Return> */
/* SUCCESS on success. FAILURE in case of overflow or of incoherent */
/* profile. */
/* */
static Bool
- New_Profile( RAS_ARGS TStates aState )
+ New_Profile( RAS_ARGS TStates aState,
+ Bool overshoot )
{
if ( !ras.fProfile )
{
@@ -644,30 +710,36 @@ a };
return FAILURE;
}
+ ras.cProfile->flags = 0;
+ ras.cProfile->start = 0;
+ ras.cProfile->height = 0;
+ ras.cProfile->offset = ras.top;
+ ras.cProfile->link = (PProfile)0;
+ ras.cProfile->next = (PProfile)0;
+ ras.cProfile->flags = ras.dropOutControl;
+
switch ( aState )
{
case Ascending_State:
- ras.cProfile->flow = Flow_Up;
+ ras.cProfile->flags |= Flow_Up;
+ if ( overshoot )
+ ras.cProfile->flags |= Overshoot_Bottom;
+
FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile ));
break;
case Descending_State:
- ras.cProfile->flow = Flow_Down;
+ if ( overshoot )
+ ras.cProfile->flags |= Overshoot_Top;
FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile ));
break;
default:
- FT_ERROR(( "New_Profile: invalid profile direction!\n" ));
+ FT_ERROR(( "New_Profile: invalid profile direction\n" ));
ras.error = Raster_Err_Invalid;
return FAILURE;
}
- 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;
@@ -687,11 +759,15 @@ a };
/* <Description> */
/* Finalize the current profile. */
/* */
+ /* <Input> */
+ /* overshoot :: Whether the profile's unrounded end position differs */
+ /* by at least a half pixel. */
+ /* */
/* <Return> */
/* SUCCESS on success. FAILURE in case of overflow or incoherency. */
/* */
static Bool
- End_Profile( RAS_ARG )
+ End_Profile( RAS_ARGS Bool overshoot )
{
Long h;
PProfile oldProfile;
@@ -701,7 +777,7 @@ a };
if ( h < 0 )
{
- FT_ERROR(( "End_Profile: negative height encountered!\n" ));
+ FT_ERROR(( "End_Profile: negative height encountered\n" ));
ras.error = Raster_Err_Neg_Height;
return FAILURE;
}
@@ -711,15 +787,24 @@ a };
FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n",
(long)ras.cProfile, ras.cProfile->start, h ));
- oldProfile = ras.cProfile;
ras.cProfile->height = h;
- ras.cProfile = (PProfile)ras.top;
+ if ( overshoot )
+ {
+ if ( ras.cProfile->flags & Flow_Up )
+ ras.cProfile->flags |= Overshoot_Top;
+ else
+ ras.cProfile->flags |= Overshoot_Bottom;
+ }
- ras.top += AlignProfileSize;
+ oldProfile = ras.cProfile;
+ ras.cProfile = (PProfile)ras.top;
+
+ ras.top += AlignProfileSize;
ras.cProfile->height = 0;
ras.cProfile->offset = ras.top;
- oldProfile->next = ras.cProfile;
+
+ oldProfile->next = ras.cProfile;
ras.num_Profs++;
}
@@ -822,23 +907,21 @@ a };
else
p->link = NULL;
- switch ( p->flow )
+ if ( p->flags & Flow_Up )
+ {
+ bottom = (Int)p->start;
+ top = (Int)( p->start + p->height - 1 );
+ }
+ else
{
- case Flow_Down:
bottom = (Int)( p->start - p->height + 1 );
top = (Int)p->start;
p->start = bottom;
p->offset += p->height - 1;
- break;
-
- case Flow_Up:
- default:
- bottom = (Int)p->start;
- top = (Int)( p->start + p->height - 1 );
}
- if ( Insert_Y_Turn( RAS_VARS bottom ) ||
- Insert_Y_Turn( RAS_VARS top + 1 ) )
+ if ( Insert_Y_Turn( RAS_VARS bottom ) ||
+ Insert_Y_Turn( RAS_VARS top + 1 ) )
return FAILURE;
p = p->link;
@@ -1230,7 +1313,7 @@ a };
}
else
{
- *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x,
+ *top++ = arc[degree].x + FMulDiv( arc[0].x - arc[degree].x,
e - y1, y2 - y1 );
arc -= degree;
e += ras.precision;
@@ -1335,13 +1418,15 @@ a };
case Unknown_State:
if ( y > ras.lastY )
{
- if ( New_Profile( RAS_VARS Ascending_State ) )
+ if ( New_Profile( RAS_VARS Ascending_State,
+ IS_BOTTOM_OVERSHOOT( ras.lastY ) ) )
return FAILURE;
}
else
{
if ( y < ras.lastY )
- if ( New_Profile( RAS_VARS Descending_State ) )
+ if ( New_Profile( RAS_VARS Descending_State,
+ IS_TOP_OVERSHOOT( ras.lastY ) ) )
return FAILURE;
}
break;
@@ -1349,8 +1434,9 @@ a };
case Ascending_State:
if ( y < ras.lastY )
{
- if ( End_Profile( RAS_VAR ) ||
- New_Profile( RAS_VARS Descending_State ) )
+ if ( End_Profile( RAS_VARS IS_TOP_OVERSHOOT( ras.lastY ) ) ||
+ New_Profile( RAS_VARS Descending_State,
+ IS_TOP_OVERSHOOT( ras.lastY ) ) )
return FAILURE;
}
break;
@@ -1358,8 +1444,9 @@ a };
case Descending_State:
if ( y > ras.lastY )
{
- if ( End_Profile( RAS_VAR ) ||
- New_Profile( RAS_VARS Ascending_State ) )
+ if ( End_Profile( RAS_VARS IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ||
+ New_Profile( RAS_VARS Ascending_State,
+ IS_BOTTOM_OVERSHOOT( ras.lastY ) ) )
return FAILURE;
}
break;
@@ -1374,13 +1461,13 @@ a };
{
case Ascending_State:
if ( Line_Up( RAS_VARS ras.lastX, ras.lastY,
- x, y, ras.minY, ras.maxY ) )
+ x, y, ras.minY, ras.maxY ) )
return FAILURE;
break;
case Descending_State:
if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
- x, y, ras.minY, ras.maxY ) )
+ x, y, ras.minY, ras.maxY ) )
return FAILURE;
break;
@@ -1431,8 +1518,10 @@ a };
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[1].x = cx;
+ ras.arc[1].y = cy;
+ ras.arc[0].x = x;
+ ras.arc[0].y = y;
do
{
@@ -1472,13 +1561,17 @@ a };
state_bez = y1 < y3 ? Ascending_State : Descending_State;
if ( ras.state != state_bez )
{
+ Bool o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 )
+ : IS_TOP_OVERSHOOT( y1 );
+
+
/* finalize current profile if any */
- if ( ras.state != Unknown_State &&
- End_Profile( RAS_VAR ) )
+ if ( ras.state != Unknown_State &&
+ End_Profile( RAS_VARS o ) )
goto Fail;
/* create a new profile */
- if ( New_Profile( RAS_VARS state_bez ) )
+ if ( New_Profile( RAS_VARS state_bez, o ) )
goto Fail;
}
@@ -1547,9 +1640,12 @@ a };
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;
+ ras.arc[2].x = cx1;
+ ras.arc[2].y = cy1;
+ ras.arc[1].x = cx2;
+ ras.arc[1].y = cy2;
+ ras.arc[0].x = x;
+ ras.arc[0].y = y;
do
{
@@ -1601,11 +1697,16 @@ a };
/* detect a change of direction */
if ( ras.state != state_bez )
{
- if ( ras.state != Unknown_State &&
- End_Profile( RAS_VAR ) )
+ Bool o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 )
+ : IS_TOP_OVERSHOOT( y1 );
+
+
+ /* finalize current profile if any */
+ if ( ras.state != Unknown_State &&
+ End_Profile( RAS_VARS o ) )
goto Fail;
- if ( New_Profile( RAS_VARS state_bez ) )
+ if ( New_Profile( RAS_VARS state_bez, o ) )
goto Fail;
}
@@ -1698,8 +1799,13 @@ a };
v_control = v_start;
point = points + first;
- tags = ras.outline.tags + first;
- tag = FT_CURVE_TAG( tags[0] );
+ tags = ras.outline.tags + first;
+
+ /* set scan mode if necessary */
+ if ( tags[0] & FT_CURVE_TAG_HAS_SCANMODE )
+ ras.dropOutControl = (Byte)tags[0] >> 5;
+
+ tag = FT_CURVE_TAG( tags[0] );
/* A contour cannot start with a cubic control point! */
if ( tag == FT_CURVE_TAG_CUBIC )
@@ -1905,27 +2011,36 @@ a };
for ( i = 0; i < ras.outline.n_contours; i++ )
{
+ Bool o;
+
+
ras.state = Unknown_State;
ras.gProfile = NULL;
if ( Decompose_Curve( RAS_VARS (unsigned short)start,
- ras.outline.contours[i],
- flipped ) )
+ ras.outline.contours[i],
+ flipped ) )
return FAILURE;
start = ras.outline.contours[i] + 1;
- /* We must now see whether the extreme arcs join or not */
+ /* we must now check whether 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 )
+ if ( ras.gProfile &&
+ ( ras.gProfile->flags & Flow_Up ) ==
+ ( ras.cProfile->flags & Flow_Up ) )
ras.top--;
/* Note that ras.gProfile can be nil if the contour was too small */
/* to be drawn. */
lastProfile = ras.cProfile;
- if ( End_Profile( RAS_VAR ) )
+ if ( ras.cProfile->flags & Flow_Up )
+ o = IS_TOP_OVERSHOOT( ras.lastY );
+ else
+ o = IS_BOTTOM_OVERSHOOT( ras.lastY );
+ if ( End_Profile( RAS_VARS o ) )
return FAILURE;
/* close the `next profile in contour' linked list */
@@ -2045,7 +2160,7 @@ a };
while ( current )
{
current->X = *current->offset;
- current->offset += current->flow;
+ current->offset += current->flags & Flow_Up ? 1 : -1;
current->height--;
current = current->link;
}
@@ -2220,16 +2335,19 @@ a };
if ( e1 > e2 )
{
+ Int dropOutControl = left->flags & 7;
+
+
if ( e1 == e2 + ras.precision )
{
- switch ( ras.dropOutControl )
+ switch ( dropOutControl )
{
case 0: /* simple drop-outs including stubs */
pxl = e2;
break;
case 4: /* smart drop-outs including stubs */
- pxl = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
+ pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
break;
case 1: /* simple drop-outs excluding stubs */
@@ -2237,11 +2355,10 @@ a };
/* Drop-out Control Rules #4 and #6 */
- /* The spec is not very clear regarding those rules. It */
- /* presents a method that is way too costly to implement */
- /* while the general idea seems to get rid of `stubs'. */
+ /* The specification neither provides an exact definition */
+ /* of a `stub' nor gives exact rules to exclude them. */
/* */
- /* Here, we only get rid of stubs recognized if: */
+ /* Here the constraints we use to recognize a stub. */
/* */
/* upper stub: */
/* */
@@ -2255,27 +2372,31 @@ a };
/* - P_Left is the successor of P_Right in that contour */
/* - y is the bottom of P_Left */
/* */
+ /* We draw a stub if the following constraints are met. */
+ /* */
+ /* - for an upper or lower stub, there is top or bottom */
+ /* overshoot, respectively */
+ /* - the covered interval is greater or equal to a half */
+ /* pixel */
+
+ /* upper stub test */
+ if ( left->next == right &&
+ left->height <= 0 &&
+ !( left->flags & Overshoot_Top &&
+ x2 - x1 >= ras.precision_half ) )
+ return;
- /* 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 0
- if ( x2 - x1 < ras.precision_half )
-#endif
- {
- /* upper stub test */
- if ( left->next == right && left->height <= 0 )
- return;
-
- /* lower stub test */
- if ( right->next == left && left->start == y )
- return;
- }
+ /* lower stub test */
+ if ( right->next == left &&
+ left->start == y &&
+ !( left->flags & Overshoot_Bottom &&
+ x2 - x1 >= ras.precision_half ) )
+ return;
- if ( ras.dropOutControl == 1 )
+ if ( dropOutControl == 1 )
pxl = e2;
else
- pxl = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
+ pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
break;
default: /* modes 2, 3, 6, 7 */
@@ -2415,16 +2536,19 @@ a };
if ( e1 > e2 )
{
+ Int dropOutControl = left->flags & 7;
+
+
if ( e1 == e2 + ras.precision )
{
- switch ( ras.dropOutControl )
+ switch ( dropOutControl )
{
case 0: /* simple drop-outs including stubs */
pxl = e2;
break;
case 4: /* smart drop-outs including stubs */
- pxl = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
+ pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
break;
case 1: /* simple drop-outs excluding stubs */
@@ -2432,17 +2556,23 @@ a };
/* see Vertical_Sweep_Drop for details */
/* rightmost stub test */
- if ( left->next == right && left->height <= 0 )
+ if ( left->next == right &&
+ left->height <= 0 &&
+ !( left->flags & Overshoot_Top &&
+ x2 - x1 >= ras.precision_half ) )
return;
/* leftmost stub test */
- if ( right->next == left && left->start == y )
+ if ( right->next == left &&
+ left->start == y &&
+ !( left->flags & Overshoot_Bottom &&
+ x2 - x1 >= ras.precision_half ) )
return;
- if ( ras.dropOutControl == 1 )
+ if ( dropOutControl == 1 )
pxl = e2;
else
- pxl = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
+ pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
break;
default: /* modes 2, 3, 6, 7 */
@@ -2543,10 +2673,10 @@ a };
static void
Vertical_Gray_Sweep_Step( RAS_ARG )
{
- Int c1, c2;
- PByte pix, bit, bit2;
- char* count = (char*)count_table;
- Byte* grays;
+ Int c1, c2;
+ PByte pix, bit, bit2;
+ short* count = (short*)count_table;
+ Byte* grays;
ras.traceOfs += ras.gray_width;
@@ -2665,16 +2795,19 @@ a };
if ( e1 > e2 )
{
+ Int dropOutControl = left->flags & 7;
+
+
if ( e1 == e2 + ras.precision )
{
- switch ( ras.dropOutControl )
+ switch ( dropOutControl )
{
case 0: /* simple drop-outs including stubs */
e1 = e2;
break;
case 4: /* smart drop-outs including stubs */
- e1 = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
+ e1 = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
break;
case 1: /* simple drop-outs excluding stubs */
@@ -2689,10 +2822,10 @@ a };
if ( right->next == left && left->start == y )
return;
- if ( ras.dropOutControl == 1 )
+ if ( dropOutControl == 1 )
e1 = e2;
else
- e1 = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
+ e1 = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
break;
@@ -2806,7 +2939,7 @@ a };
y = min_Y;
y_height = 0;
- if ( ras.numTurns > 0 &&
+ if ( ras.numTurns > 0 &&
ras.sizeBuff[-ras.numTurns] == min_Y )
ras.numTurns--;
@@ -2824,16 +2957,10 @@ a };
{
DelOld( &waiting, P );
- switch ( P->flow )
- {
- case Flow_Up:
+ if ( P->flags & Flow_Up )
InsNew( &draw_left, P );
- break;
-
- case Flow_Down:
+ else
InsNew( &draw_right, P );
- break;
- }
}
P = Q;
@@ -2876,7 +3003,10 @@ a };
{
if ( e1 > e2 || e2 == e1 + ras.precision )
{
- if ( ras.dropOutControl != 2 )
+ Int dropOutControl = P_Left->flags & 7;
+
+
+ if ( dropOutControl != 2 )
{
/* a drop-out was detected */
@@ -3070,7 +3200,7 @@ a };
Set_High_Precision( RAS_VARS ras.outline.flags &
- FT_OUTLINE_HIGH_PRECISION );
+ FT_OUTLINE_HIGH_PRECISION );
ras.scale_shift = ras.precision_shift;
if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS )
@@ -3146,7 +3276,7 @@ a };
Set_High_Precision( RAS_VARS ras.outline.flags &
- FT_OUTLINE_HIGH_PRECISION );
+ FT_OUTLINE_HIGH_PRECISION );
ras.scale_shift = ras.precision_shift + 1;
if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS )
@@ -3234,7 +3364,6 @@ a };
raster->grays[n] = n * 255 / 4;
raster->gray_width = RASTER_GRAY_LINES / 2;
-
#else
FT_UNUSED( raster );
#endif
@@ -3411,23 +3540,24 @@ a };
#ifdef FT_RASTER_OPTION_ANTI_ALIASING
worker->grays = raster->grays;
worker->gray_width = raster->gray_width;
+
+ FT_MEM_ZERO( worker->gray_lines, worker->gray_width * 2 );
#endif
- return ( ( params->flags & FT_RASTER_FLAG_AA )
- ? Render_Gray_Glyph( RAS_VAR )
- : Render_Glyph( RAS_VAR ) );
+ return ( params->flags & FT_RASTER_FLAG_AA )
+ ? Render_Gray_Glyph( RAS_VAR )
+ : Render_Glyph( RAS_VAR );
}
- const FT_Raster_Funcs ft_standard_raster =
- {
+ FT_DEFINE_RASTER_FUNCS( ft_standard_raster,
FT_GLYPH_FORMAT_OUTLINE,
(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
- };
+ )
/* END */