/* */
/* A new `perfect' anti-aliasing renderer (body). */
/* */
-/* Copyright 2000-2001, 2002, 2003, 2005, 2006, 2007 by */
+/* Copyright 2000-2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009, 2010 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
#define FT_COMPONENT trace_smooth
+#ifdef _STANDALONE_
-#ifdef _STANDALONE_
+ /* define this to dump debugging information */
+/* #define FT_DEBUG_LEVEL_TRACE */
+
-#include <string.h> /* for ft_memcpy() */
+#ifdef FT_DEBUG_LEVEL_TRACE
+#include <stdio.h>
+#include <stdarg.h>
+#endif
+
+#include <stddef.h>
+#include <string.h>
#include <setjmp.h>
#include <limits.h>
#define FT_UINT_MAX UINT_MAX
+#define FT_INT_MAX INT_MAX
#define ft_memset memset
#define ft_longjmp longjmp
#define ft_jmp_buf jmp_buf
+typedef ptrdiff_t FT_PtrDist;
+
#define ErrRaster_Invalid_Mode -2
#define ErrRaster_Invalid_Outline -1
#include "ftimage.h"
#include "ftgrays.h"
+
/* This macro is used to indicate that a function parameter is unused. */
/* Its purpose is simply to reduce compiler warnings. Note also that */
/* simply defining it as `(void)x' doesn't avoid warnings with certain */
/* ANSI compilers (e.g. LCC). */
#define FT_UNUSED( x ) (x) = (x)
- /* Disable the tracing mechanism for simplicity -- developers can */
- /* activate it easily by redefining these two macros. */
+
+ /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+ void
+ FT_Message( const char* fmt,
+ ... )
+ {
+ va_list ap;
+
+
+ va_start( ap, fmt );
+ vfprintf( stderr, fmt, ap );
+ va_end( ap );
+ }
+
+ /* we don't handle tracing levels in stand-alone mode; */
+#ifndef FT_TRACE5
+#define FT_TRACE5( varformat ) FT_Message varformat
+#endif
+#ifndef FT_TRACE7
+#define FT_TRACE7( varformat ) FT_Message varformat
+#endif
#ifndef FT_ERROR
-#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */
+#define FT_ERROR( varformat ) FT_Message varformat
#endif
-#ifndef FT_TRACE
-#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */
-#endif
+#else /* !FT_DEBUG_LEVEL_TRACE */
+
+#define FT_TRACE5( x ) do { } while ( 0 ) /* nothing */
+#define FT_TRACE7( x ) do { } while ( 0 ) /* nothing */
+#define FT_ERROR( x ) do { } while ( 0 ) /* nothing */
+
+#endif /* !FT_DEBUG_LEVEL_TRACE */
+
+
+#define FT_DEFINE_OUTLINE_FUNCS( class_, \
+ move_to_, line_to_, \
+ conic_to_, cubic_to_, \
+ shift_, delta_ ) \
+ static const FT_Outline_Funcs class_ = \
+ { \
+ move_to_, \
+ line_to_, \
+ conic_to_, \
+ cubic_to_, \
+ shift_, \
+ delta_ \
+ };
+
+#define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, \
+ raster_new_, raster_reset_, \
+ raster_set_mode_, raster_render_, \
+ raster_done_ ) \
+ const FT_Raster_Funcs class_ = \
+ { \
+ glyph_format_, \
+ raster_new_, \
+ raster_reset_, \
+ raster_set_mode_, \
+ raster_render_, \
+ raster_done_ \
+ };
#else /* !_STANDALONE_ */
+
#include <ft2build.h>
#include "ftgrays.h"
#include FT_INTERNAL_OBJECTS_H
#include "ftsmerrs.h"
-#define ErrRaster_Invalid_Mode Smooth_Err_Cannot_Render_Glyph
-#define ErrRaster_Invalid_Outline Smooth_Err_Invalid_Outline
-#define ErrRaster_Memory_Overflow Smooth_Err_Out_Of_Memory
-#define ErrRaster_Invalid_Argument Smooth_Err_Bad_Argument
+#include "ftspic.h"
-#endif /* !_STANDALONE_ */
+#define ErrRaster_Invalid_Mode Smooth_Err_Cannot_Render_Glyph
+#define ErrRaster_Invalid_Outline Smooth_Err_Invalid_Outline
+#define ErrRaster_Memory_Overflow Smooth_Err_Out_Of_Memory
+#define ErrRaster_Invalid_Argument Smooth_Err_Invalid_Argument
+#endif /* !_STANDALONE_ */
#ifndef FT_MEM_SET
#define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count )
#endif
- /* define this to dump debugging information */
-#define xxxDEBUG_GRAYS
-
-
/* as usual, for the speed hungry :-) */
#ifndef FT_STATIC_RASTER
-
#define RAS_ARG PWorker worker
#define RAS_ARG_ PWorker worker,
#define RAS_VAR worker
#define RAS_VAR_ worker,
-#define ras (*worker)
-
-
#else /* FT_STATIC_RASTER */
-
#define RAS_ARG /* empty */
#define RAS_ARG_ /* empty */
#define RAS_VAR /* empty */
#define RAS_VAR_ /* empty */
- static TWorker ras;
-
-
#endif /* FT_STATIC_RASTER */
/* need to define them to "float" or "double" when experimenting with */
/* new algorithms */
- typedef int TCoord; /* integer scanline/pixel coordinate */
+ typedef long TCoord; /* integer scanline/pixel coordinate */
typedef long TPos; /* sub-pixel coordinate */
/* determine the type used to store cell areas. This normally takes at */
typedef struct TCell_
{
- int x;
- int cover;
+ TPos x; /* same with TWorker.ex */
+ TCoord cover; /* same with TWorker.cover */
TArea area;
PCell next;
TPos count_ex, count_ey;
TArea area;
- int cover;
+ TCoord cover;
int invalid;
PCell cells;
- int max_cells;
- int num_cells;
+ FT_PtrDist max_cells;
+ FT_PtrDist num_cells;
TCoord cx, cy;
TPos x, y;
int band_size;
int band_shoot;
- int conic_level;
- int cubic_level;
ft_jmp_buf jump_buffer;
long buffer_size;
PCell* ycells;
- int ycount;
+ TPos ycount;
} TWorker, *PWorker;
+#ifndef FT_STATIC_RASTER
+#define ras (*worker)
+#else
+ static TWorker ras;
+#endif
+
+
typedef struct TRaster_
{
void* buffer;
gray_find_cell( RAS_ARG )
{
PCell *pcell, cell;
- int x = ras.ex;
+ TPos x = ras.ex;
- if ( x > ras.max_ex )
- x = ras.max_ex;
+ if ( x > ras.count_ex )
+ x = ras.count_ex;
pcell = &ras.ycells[ras.ey];
for (;;)
TPos x2,
TCoord y2 )
{
- TCoord ex1, ex2, fx1, fx2, delta;
+ TCoord ex1, ex2, fx1, fx2, delta, mod, lift, rem;
long p, first, dx;
- int incr, lift, mod, rem;
+ int incr;
dx = x2 - x1;
if ( ex1 == ex2 )
{
delta = y2 - y1;
- ras.area += (TArea)( fx1 + fx2 ) * delta;
+ ras.area += (TArea)(( fx1 + fx2 ) * delta);
ras.cover += delta;
return;
}
mod += (TCoord)dx;
}
- ras.area += (TArea)( fx1 + first ) * delta;
+ ras.area += (TArea)(( fx1 + first ) * delta);
ras.cover += delta;
ex1 += incr;
delta++;
}
- ras.area += (TArea)ONE_PIXEL * delta;
+ ras.area += (TArea)(ONE_PIXEL * delta);
ras.cover += delta;
y1 += delta;
ex1 += incr;
}
delta = y2 - y1;
- ras.area += (TArea)( fx2 + ONE_PIXEL - first ) * delta;
+ ras.area += (TArea)(( fx2 + ONE_PIXEL - first ) * delta);
ras.cover += delta;
}
gray_render_line( RAS_ARG_ TPos to_x,
TPos to_y )
{
- TCoord ey1, ey2, fy1, fy2;
+ TCoord ey1, ey2, fy1, fy2, mod;
TPos dx, dy, x, x2;
long p, first;
- int delta, rem, mod, lift, incr;
+ int delta, rem, lift, incr;
ey1 = TRUNC( ras.last_ey );
{
TCoord ex = TRUNC( ras.x );
TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 );
- TPos area;
+ TArea area;
first = ONE_PIXEL;
ras.cover += delta;
ey1 += incr;
- gray_set_cell( &ras, ex, ey1 );
+ gray_set_cell( RAS_VAR_ ex, ey1 );
delta = (int)( first + first - ONE_PIXEL );
area = (TArea)two_fx * delta;
ras.cover += delta;
ey1 += incr;
- gray_set_cell( &ras, ex, ey1 );
+ gray_set_cell( RAS_VAR_ ex, ey1 );
}
delta = (int)( fy2 - ONE_PIXEL + first );
FT_Vector* arc;
- dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 );
- if ( dx < 0 )
- dx = -dx;
- dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 );
- if ( dy < 0 )
- dy = -dy;
+ arc = ras.bez_stack;
+ arc[0].x = UPSCALE( to->x );
+ arc[0].y = UPSCALE( to->y );
+ arc[1].x = UPSCALE( control->x );
+ arc[1].y = UPSCALE( control->y );
+ arc[2].x = ras.x;
+ arc[2].y = ras.y;
+
+ dx = FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x );
+ dy = FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y );
if ( dx < dy )
dx = dy;
- level = 1;
- dx = dx / ras.conic_level;
- while ( dx > 0 )
+ if ( dx <= ONE_PIXEL / 4 )
{
- dx >>= 2;
- level++;
+ gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
+ return;
}
- /* a shortcut to speed things up */
- if ( level <= 1 )
+ level = 0;
+ while ( dx > ONE_PIXEL / 4 )
{
- /* we compute the mid-point directly in order to avoid */
- /* calling gray_split_conic() */
- TPos to_x, to_y, mid_x, mid_y;
-
-
- to_x = UPSCALE( to->x );
- to_y = UPSCALE( to->y );
- mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
- mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
-
- gray_render_line( RAS_VAR_ mid_x, mid_y );
- gray_render_line( RAS_VAR_ to_x, to_y );
-
- return;
+ dx >>= 2;
+ level++;
}
- arc = ras.bez_stack;
levels = ras.lev_stack;
- top = 0;
levels[0] = level;
-
- arc[0].x = UPSCALE( to->x );
- arc[0].y = UPSCALE( to->y );
- arc[1].x = UPSCALE( control->x );
- arc[1].y = UPSCALE( control->y );
- arc[2].x = ras.x;
- arc[2].y = ras.y;
+ top = 0;
while ( top >= 0 )
{
}
Draw:
- {
- TPos to_x, to_y, mid_x, mid_y;
-
-
- to_x = arc[0].x;
- to_y = arc[0].y;
- mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
- mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
-
- gray_render_line( RAS_VAR_ mid_x, mid_y );
- gray_render_line( RAS_VAR_ to_x, to_y );
-
- top--;
- arc -= 2;
- }
+ gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
+ top--;
+ arc -= 2;
}
return;
const FT_Vector* control2,
const FT_Vector* to )
{
- TPos dx, dy, da, db;
- int top, level;
- int* levels;
FT_Vector* arc;
- dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 );
- if ( dx < 0 )
- dx = -dx;
- dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 );
- if ( dy < 0 )
- dy = -dy;
- if ( dx < dy )
- dx = dy;
- da = dx;
-
- dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x );
- if ( dx < 0 )
- dx = -dx;
- dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y );
- if ( dy < 0 )
- dy = -dy;
- if ( dx < dy )
- dx = dy;
- db = dx;
-
- level = 1;
- da = da / ras.cubic_level;
- db = db / ras.conic_level;
- while ( da > 0 || db > 0 )
- {
- da >>= 2;
- db >>= 3;
- level++;
- }
-
- if ( level <= 1 )
- {
- TPos to_x, to_y, mid_x, mid_y;
-
-
- to_x = UPSCALE( to->x );
- to_y = UPSCALE( to->y );
- mid_x = ( ras.x + to_x +
- 3 * UPSCALE( control1->x + control2->x ) ) / 8;
- mid_y = ( ras.y + to_y +
- 3 * UPSCALE( control1->y + control2->y ) ) / 8;
-
- gray_render_line( RAS_VAR_ mid_x, mid_y );
- gray_render_line( RAS_VAR_ to_x, to_y );
- return;
- }
-
arc = ras.bez_stack;
arc[0].x = UPSCALE( to->x );
arc[0].y = UPSCALE( to->y );
arc[3].x = ras.x;
arc[3].y = ras.y;
- levels = ras.lev_stack;
- top = 0;
- levels[0] = level;
-
- while ( top >= 0 )
+ for (;;)
{
- level = levels[top];
- if ( level > 1 )
- {
- /* check that the arc crosses the current band */
- TPos min, max, y;
+ /* Check that the arc crosses the current band. */
+ TPos min, max, y;
- min = max = arc[0].y;
- y = arc[1].y;
- if ( y < min ) min = y;
- if ( y > max ) max = y;
- y = arc[2].y;
- if ( y < min ) min = y;
- if ( y > max ) max = y;
- y = arc[3].y;
- if ( y < min ) min = y;
- if ( y > max ) max = y;
- if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
- goto Draw;
- gray_split_cubic( arc );
- arc += 3;
- top ++;
- levels[top] = levels[top - 1] = level - 1;
- continue;
- }
+ min = max = arc[0].y;
- Draw:
- {
- TPos to_x, to_y, mid_x, mid_y;
+ y = arc[1].y;
+ if ( y < min )
+ min = y;
+ if ( y > max )
+ max = y;
+
+ y = arc[2].y;
+ if ( y < min )
+ min = y;
+ if ( y > max )
+ max = y;
+ y = arc[3].y;
+ if ( y < min )
+ min = y;
+ if ( y > max )
+ max = y;
- to_x = arc[0].x;
- to_y = arc[0].y;
- mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
- mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
+ if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey )
+ goto Draw;
- gray_render_line( RAS_VAR_ mid_x, mid_y );
- gray_render_line( RAS_VAR_ to_x, to_y );
- top --;
- arc -= 3;
+ /* Decide whether to split or draw. See `Rapid Termination */
+ /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */
+ /* F. Hain, at */
+ /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */
+
+ {
+ TPos dx, dy, dx_, dy_;
+ TPos dx1, dy1, dx2, dy2;
+ TPos L, s, s_limit;
+
+
+ /* dx and dy are x and y components of the P0-P3 chord vector. */
+ dx = arc[3].x - arc[0].x;
+ dy = arc[3].y - arc[0].y;
+
+ /* L is an (under)estimate of the Euclidean distance P0-P3. */
+ /* */
+ /* If dx >= dy, then r = sqrt(dx^2 + dy^2) can be overestimated */
+ /* with least maximum error by */
+ /* */
+ /* r_upperbound = dx + (sqrt(2) - 1) * dy , */
+ /* */
+ /* where sqrt(2) - 1 can be (over)estimated by 107/256, giving an */
+ /* error of no more than 8.4%. */
+ /* */
+ /* Similarly, some elementary calculus shows that r can be */
+ /* underestimated with least maximum error by */
+ /* */
+ /* r_lowerbound = sqrt(2 + sqrt(2)) / 2 * dx */
+ /* + sqrt(2 - sqrt(2)) / 2 * dy . */
+ /* */
+ /* 236/256 and 97/256 are (under)estimates of the two algebraic */
+ /* numbers, giving an error of no more than 8.1%. */
+
+ dx_ = FT_ABS( dx );
+ dy_ = FT_ABS( dy );
+
+ /* This is the same as */
+ /* */
+ /* L = ( 236 * FT_MAX( dx_, dy_ ) */
+ /* + 97 * FT_MIN( dx_, dy_ ) ) >> 8; */
+ L = ( dx_ > dy_ ? 236 * dx_ + 97 * dy_
+ : 97 * dx_ + 236 * dy_ ) >> 8;
+
+ /* Avoid possible arithmetic overflow below by splitting. */
+ if ( L > 32767 )
+ goto Split;
+
+ /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */
+ s_limit = L * (TPos)( ONE_PIXEL / 6 );
+
+ /* s is L * the perpendicular distance from P1 to the line P0-P3. */
+ dx1 = arc[1].x - arc[0].x;
+ dy1 = arc[1].y - arc[0].y;
+ s = FT_ABS( dy * dx1 - dx * dy1 );
+
+ if ( s > s_limit )
+ goto Split;
+
+ /* s is L * the perpendicular distance from P2 to the line P0-P3. */
+ dx2 = arc[2].x - arc[0].x;
+ dy2 = arc[2].y - arc[0].y;
+ s = FT_ABS( dy * dx2 - dx * dy2 );
+
+ if ( s > s_limit )
+ goto Split;
+
+ /* If P1 or P2 is outside P0-P3, split the curve. */
+ if ( dy * dy1 + dx * dx1 < 0 ||
+ dy * dy2 + dx * dx2 < 0 ||
+ dy * (arc[3].y - arc[1].y) + dx * (arc[3].x - arc[1].x) < 0 ||
+ dy * (arc[3].y - arc[2].y) + dx * (arc[3].x - arc[2].x) < 0 )
+ goto Split;
+
+ /* No reason to split. */
+ goto Draw;
}
- }
- return;
- }
+ Split:
+ gray_split_cubic( arc );
+ arc += 3;
+ continue;
+
+ Draw:
+ gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
+ if ( arc == ras.bez_stack )
+ return;
+
+ arc -= 3;
+ }
+ }
static int
/* record current cell, if any */
- gray_record_cell( worker );
+ gray_record_cell( RAS_VAR );
/* start to a new position */
x = UPSCALE( to->x );
y = UPSCALE( to->y );
- gray_start_cell( worker, TRUNC( x ), TRUNC( y ) );
+ gray_start_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) );
worker->x = x;
worker->y = y;
gray_line_to( const FT_Vector* to,
PWorker worker )
{
- gray_render_line( worker, UPSCALE( to->x ), UPSCALE( to->y ) );
+ gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
return 0;
}
const FT_Vector* to,
PWorker worker )
{
- gray_render_conic( worker, control, to );
+ gray_render_conic( RAS_VAR_ control, to );
return 0;
}
const FT_Vector* to,
PWorker worker )
{
- gray_render_cubic( worker, control1, control2, to );
+ gray_render_cubic( RAS_VAR_ control1, control2, to );
return 0;
}
/* first of all, compute the scanline offset */
p = (unsigned char*)map->buffer - y * map->pitch;
if ( map->pitch >= 0 )
- p += ( map->rows - 1 ) * map->pitch;
+ p += (unsigned)( ( map->rows - 1 ) * map->pitch );
for ( ; count > 0; count--, spans++ )
{
gray_hline( RAS_ARG_ TCoord x,
TCoord y,
TPos area,
- int acount )
+ TCoord acount )
{
FT_Span* span;
int count;
x += (TCoord)ras.min_ex;
/* FT_Span.x is a 16-bit short, so limit our coordinates appropriately */
- if ( x >= 32768 )
+ if ( x >= 32767 )
x = 32767;
+ /* FT_Span.y is an integer, so limit our coordinates appropriately */
+ if ( y >= FT_INT_MAX )
+ y = FT_INT_MAX;
+
if ( coverage )
{
/* see whether we can add this span to the current list */
if ( ras.render_span && count > 0 )
ras.render_span( ras.span_y, count, ras.gray_spans,
ras.render_span_data );
- /* ras.render_span( span->y, ras.gray_spans, count ); */
-#ifdef DEBUG_GRAYS
+#ifdef FT_DEBUG_LEVEL_TRACE
- if ( ras.span_y >= 0 )
+ if ( count > 0 )
{
int n;
- fprintf( stderr, "y=%3d ", ras.span_y );
+ FT_TRACE7(( "y = %3d ", ras.span_y ));
span = ras.gray_spans;
for ( n = 0; n < count; n++, span++ )
- fprintf( stderr, "[%d..%d]:%02x ",
- span->x, span->x + span->len - 1, span->coverage );
- fprintf( stderr, "\n" );
+ FT_TRACE7(( "[%d..%d]:%02x ",
+ span->x, span->x + span->len - 1, span->coverage ));
+ FT_TRACE7(( "\n" ));
}
-#endif /* DEBUG_GRAYS */
+#endif /* FT_DEBUG_LEVEL_TRACE */
ras.num_gray_spans = 0;
- ras.span_y = y;
+ ras.span_y = (int)y;
count = 0;
span = ras.gray_spans;
}
-#ifdef DEBUG_GRAYS
+#ifdef FT_DEBUG_LEVEL_TRACE
- /* to be called while in the debugger */
+ /* to be called while in the debugger -- */
+ /* this function causes a compiler warning since it is unused otherwise */
+ static void
gray_dump_cells( RAS_ARG )
{
int yindex;
printf( "%3d:", yindex );
for ( cell = ras.ycells[yindex]; cell != NULL; cell = cell->next )
- printf( " (%3d, c:%4d, a:%6d)", cell->x, cell->cover, cell->area );
+ printf( " (%3ld, c:%4ld, a:%6d)", cell->x, cell->cover, cell->area );
printf( "\n" );
}
}
-#endif /* DEBUG_GRAYS */
+#endif /* FT_DEBUG_LEVEL_TRACE */
static void
ras.num_gray_spans = 0;
+ FT_TRACE7(( "gray_sweep: start\n" ));
+
for ( yindex = 0; yindex < ras.ycount; yindex++ )
{
PCell cell = ras.ycells[yindex];
for ( ; cell != NULL; cell = cell->next )
{
- TArea area;
+ TPos area;
if ( cell->x > x && cover != 0 )
if ( ras.render_span && ras.num_gray_spans > 0 )
ras.render_span( ras.span_y, ras.num_gray_spans,
ras.gray_spans, ras.render_span_data );
+
+ FT_TRACE7(( "gray_sweep: end\n" ));
}
/*************************************************************************/
/* */
- /* The following function should only compile in stand_alone mode, */
+ /* The following function should only compile in stand-alone mode, */
/* i.e., when building this component without the rest of FreeType. */
/* */
/*************************************************************************/
/* FT_Outline_Decompose */
/* */
/* <Description> */
- /* Walks over an outline's structure to decompose it into individual */
- /* segments and Bezier arcs. This function is also able to emit */
+ /* Walk over an outline's structure to decompose it into individual */
+ /* segments and Bézier arcs. This function is also able to emit */
/* `move to' and `close to' operations to indicate the start and end */
/* of new contours in the outline. */
/* */
/* <Input> */
/* outline :: A pointer to the source target. */
/* */
- /* func_interface :: A table of `emitters', i.e,. function pointers */
+ /* func_interface :: A table of `emitters', i.e., function pointers */
/* called during decomposition to indicate path */
/* operations. */
/* */
+ /* <InOut> */
/* user :: A typeless pointer which is passed to each */
/* emitter during the decomposition. It can be */
/* used to store the state during the */
/* <Return> */
/* Error code. 0 means success. */
/* */
- static
- int FT_Outline_Decompose( const FT_Outline* outline,
- const FT_Outline_Funcs* func_interface,
- void* user )
+ static int
+ FT_Outline_Decompose( const FT_Outline* outline,
+ const FT_Outline_Funcs* func_interface,
+ void* user )
{
#undef SCALED
-#if 0
#define SCALED( x ) ( ( (x) << shift ) - delta )
-#else
-#define SCALED( x ) (x)
-#endif
FT_Vector v_last;
FT_Vector v_control;
FT_Vector* limit;
char* tags;
+ int error;
+
int n; /* index of contour in outline */
int first; /* index of first point in contour */
- int error;
char tag; /* current point's state */
-#if 0
- int shift = func_interface->shift;
- TPos delta = func_interface->delta;
-#endif
+ int shift;
+ TPos delta;
+
+ if ( !outline || !func_interface )
+ return ErrRaster_Invalid_Argument;
+ shift = func_interface->shift;
+ delta = func_interface->delta;
first = 0;
for ( n = 0; n < outline->n_contours; n++ )
int last; /* index of last point in contour */
+ FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
+
last = outline->contours[n];
+ if ( last < 0 )
+ goto Invalid_Outline;
limit = outline->points + last;
- v_start = outline->points[first];
- v_last = outline->points[last];
-
+ v_start = outline->points[first];
v_start.x = SCALED( v_start.x );
v_start.y = SCALED( v_start.y );
- v_last.x = SCALED( v_last.x );
- v_last.y = SCALED( v_last.y );
+ v_last = outline->points[last];
+ v_last.x = SCALED( v_last.x );
+ v_last.y = SCALED( v_last.y );
v_control = v_start;
point = outline->points + first;
- tags = outline->tags + first;
+ tags = outline->tags + first;
tag = FT_CURVE_TAG( tags[0] );
/* A contour cannot start with a cubic control point! */
tags--;
}
+ FT_TRACE5(( " move to (%.2f, %.2f)\n",
+ v_start.x / 64.0, v_start.y / 64.0 ));
error = func_interface->move_to( &v_start, user );
if ( error )
goto Exit;
vec.x = SCALED( point->x );
vec.y = SCALED( point->y );
+ FT_TRACE5(( " line to (%.2f, %.2f)\n",
+ vec.x / 64.0, vec.y / 64.0 ));
error = func_interface->line_to( &vec, user );
if ( error )
goto Exit;
}
case FT_CURVE_TAG_CONIC: /* consume conic arcs */
- {
- v_control.x = SCALED( point->x );
- v_control.y = SCALED( point->y );
+ v_control.x = SCALED( point->x );
+ v_control.y = SCALED( point->y );
- Do_Conic:
- if ( point < limit )
- {
- FT_Vector vec;
- FT_Vector v_middle;
-
-
- point++;
- tags++;
- tag = FT_CURVE_TAG( tags[0] );
-
- vec.x = SCALED( point->x );
- vec.y = SCALED( point->y );
+ Do_Conic:
+ if ( point < limit )
+ {
+ FT_Vector vec;
+ FT_Vector v_middle;
- if ( tag == FT_CURVE_TAG_ON )
- {
- error = func_interface->conic_to( &v_control, &vec,
- user );
- if ( error )
- goto Exit;
- continue;
- }
- if ( tag != FT_CURVE_TAG_CONIC )
- goto Invalid_Outline;
+ point++;
+ tags++;
+ tag = FT_CURVE_TAG( tags[0] );
- v_middle.x = ( v_control.x + vec.x ) / 2;
- v_middle.y = ( v_control.y + vec.y ) / 2;
+ vec.x = SCALED( point->x );
+ vec.y = SCALED( point->y );
- error = func_interface->conic_to( &v_control, &v_middle,
- user );
+ if ( tag == FT_CURVE_TAG_ON )
+ {
+ FT_TRACE5(( " conic to (%.2f, %.2f)"
+ " with control (%.2f, %.2f)\n",
+ vec.x / 64.0, vec.y / 64.0,
+ v_control.x / 64.0, v_control.y / 64.0 ));
+ error = func_interface->conic_to( &v_control, &vec, user );
if ( error )
goto Exit;
-
- v_control = vec;
- goto Do_Conic;
+ continue;
}
- error = func_interface->conic_to( &v_control, &v_start,
- user );
- goto Close;
+ if ( tag != FT_CURVE_TAG_CONIC )
+ goto Invalid_Outline;
+
+ v_middle.x = ( v_control.x + vec.x ) / 2;
+ v_middle.y = ( v_control.y + vec.y ) / 2;
+
+ FT_TRACE5(( " conic to (%.2f, %.2f)"
+ " with control (%.2f, %.2f)\n",
+ v_middle.x / 64.0, v_middle.y / 64.0,
+ v_control.x / 64.0, v_control.y / 64.0 ));
+ error = func_interface->conic_to( &v_control, &v_middle, user );
+ if ( error )
+ goto Exit;
+
+ v_control = vec;
+ goto Do_Conic;
}
+ FT_TRACE5(( " conic to (%.2f, %.2f)"
+ " with control (%.2f, %.2f)\n",
+ v_start.x / 64.0, v_start.y / 64.0,
+ v_control.x / 64.0, v_control.y / 64.0 ));
+ error = func_interface->conic_to( &v_control, &v_start, user );
+ goto Close;
+
default: /* FT_CURVE_TAG_CUBIC */
{
FT_Vector vec1, vec2;
vec.x = SCALED( point->x );
vec.y = SCALED( point->y );
+ FT_TRACE5(( " cubic to (%.2f, %.2f)"
+ " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
+ vec.x / 64.0, vec.y / 64.0,
+ vec1.x / 64.0, vec1.y / 64.0,
+ vec2.x / 64.0, vec2.y / 64.0 ));
error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
if ( error )
goto Exit;
continue;
}
+ FT_TRACE5(( " cubic to (%.2f, %.2f)"
+ " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
+ v_start.x / 64.0, v_start.y / 64.0,
+ vec1.x / 64.0, vec1.y / 64.0,
+ vec2.x / 64.0, vec2.y / 64.0 ));
error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
goto Close;
}
}
/* close the contour with a line segment */
+ FT_TRACE5(( " line to (%.2f, %.2f)\n",
+ v_start.x / 64.0, v_start.y / 64.0 ));
error = func_interface->line_to( &v_start, user );
Close:
first = last + 1;
}
+ FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
return 0;
Exit:
+ FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error ));
return error;
Invalid_Outline:
} TBand;
-
- static int
- gray_convert_glyph_inner( RAS_ARG )
- {
- static
- const FT_Outline_Funcs func_interface =
- {
+ FT_DEFINE_OUTLINE_FUNCS(func_interface,
(FT_Outline_MoveTo_Func) gray_move_to,
(FT_Outline_LineTo_Func) gray_line_to,
(FT_Outline_ConicTo_Func)gray_conic_to,
(FT_Outline_CubicTo_Func)gray_cubic_to,
0,
0
- };
+ )
+
+ static int
+ gray_convert_glyph_inner( RAS_ARG )
+ {
volatile int error = 0;
+#ifdef FT_CONFIG_OPTION_PIC
+ FT_Outline_Funcs func_interface;
+ Init_Class_func_interface(&func_interface);
+#endif
+
if ( ft_setjmp( ras.jump_buffer ) == 0 )
{
error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
gray_record_cell( RAS_VAR );
}
else
- {
error = ErrRaster_Memory_Overflow;
- }
return error;
}
ras.count_ex = ras.max_ex - ras.min_ex;
ras.count_ey = ras.max_ey - ras.min_ey;
- /* simple heuristic used to speed-up the bezier decomposition -- see */
- /* the code in gray_render_conic() and gray_render_cubic() for more */
- /* details */
- ras.conic_level = 32;
- ras.cubic_level = 16;
-
- {
- int level = 0;
-
-
- if ( ras.count_ex > 24 || ras.count_ey > 24 )
- level++;
- if ( ras.count_ex > 120 || ras.count_ey > 120 )
- level++;
-
- ras.conic_level <<= level;
- ras.cubic_level <<= level;
- }
-
- /* setup vertical bands */
+ /* set up vertical bands */
num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size );
- if ( num_bands == 0 ) num_bands = 1;
- if ( num_bands >= 39 ) num_bands = 39;
+ if ( num_bands == 0 )
+ num_bands = 1;
+ if ( num_bands >= 39 )
+ num_bands = 39;
ras.band_shoot = 0;
/* be some problems. */
if ( middle == bottom )
{
-#ifdef DEBUG_GRAYS
- fprintf( stderr, "Rotten glyph!\n" );
+#ifdef FT_DEBUG_LEVEL_TRACE
+ FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));
#endif
return 1;
}
if ( !raster || !raster->buffer || !raster->buffer_size )
return ErrRaster_Invalid_Argument;
+ if ( !outline )
+ return ErrRaster_Invalid_Outline;
+
/* return immediately if the outline is empty */
if ( outline->n_points == 0 || outline->n_contours <= 0 )
return 0;
- if ( !outline || !outline->contours || !outline->points )
+ if ( !outline->contours || !outline->points )
return ErrRaster_Invalid_Outline;
if ( outline->n_points !=
worker = raster->worker;
/* if direct mode is not set, we must have a target bitmap */
- if ( ( params->flags & FT_RASTER_FLAG_DIRECT ) == 0 )
+ if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )
{
if ( !target_map )
return ErrRaster_Invalid_Argument;
return ErrRaster_Invalid_Mode;
/* compute clipping box */
- if ( ( params->flags & FT_RASTER_FLAG_DIRECT ) == 0 )
+ if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )
{
/* compute clip box from target pixmap */
ras.clip_box.xMin = 0;
ras.clip_box.yMax = target_map->rows;
}
else if ( params->flags & FT_RASTER_FLAG_CLIP )
- {
ras.clip_box = params->clip_box;
- }
else
{
ras.clip_box.xMin = -32768L;
ras.clip_box.yMax = 32767L;
}
- gray_init_cells( worker, raster->buffer, raster->buffer_size );
+ gray_init_cells( RAS_VAR_ raster->buffer, raster->buffer_size );
- ras.outline = *outline;
- ras.num_cells = 0;
- ras.invalid = 1;
- ras.band_size = raster->band_size;
+ ras.outline = *outline;
+ ras.num_cells = 0;
+ ras.invalid = 1;
+ ras.band_size = raster->band_size;
ras.num_gray_spans = 0;
- if ( target_map )
- ras.target = *target_map;
-
- ras.render_span = (FT_Raster_Span_Func)gray_render_span;
- ras.render_span_data = &ras;
-
if ( params->flags & FT_RASTER_FLAG_DIRECT )
{
ras.render_span = (FT_Raster_Span_Func)params->gray_spans;
ras.render_span_data = params->user;
}
+ else
+ {
+ ras.target = *target_map;
+ ras.render_span = (FT_Raster_Span_Func)gray_render_span;
+ ras.render_span_data = &ras;
+ }
- return gray_convert_glyph( worker );
+ return gray_convert_glyph( RAS_VAR );
}
- /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
- /**** a static object. *****/
+ /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/
+ /**** a static object. *****/
#ifdef _STANDALONE_
FT_UNUSED( raster );
}
-#else /* _STANDALONE_ */
+#else /* !_STANDALONE_ */
static int
gray_raster_new( FT_Memory memory,
FT_Raster* araster )
{
FT_Error error;
- PRaster raster;
+ PRaster raster = NULL;
*araster = 0;
FT_FREE( raster );
}
-#endif /* _STANDALONE_ */
+#endif /* !_STANDALONE_ */
static void
}
- const FT_Raster_Funcs ft_grays_raster =
- {
+ FT_DEFINE_RASTER_FUNCS(ft_grays_raster,
FT_GLYPH_FORMAT_OUTLINE,
(FT_Raster_New_Func) gray_raster_new,
(FT_Raster_Set_Mode_Func)0,
(FT_Raster_Render_Func) gray_raster_render,
(FT_Raster_Done_Func) gray_raster_done
- };
+ )
/* END */
+
+
+/* Local Variables: */
+/* coding: utf-8 */
+/* End: */