summaryrefslogtreecommitdiff
path: root/Build/source/libs/freetype2/freetype-src/src/smooth/ftgrays.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/freetype2/freetype-src/src/smooth/ftgrays.c')
-rw-r--r--Build/source/libs/freetype2/freetype-src/src/smooth/ftgrays.c744
1 files changed, 236 insertions, 508 deletions
diff --git a/Build/source/libs/freetype2/freetype-src/src/smooth/ftgrays.c b/Build/source/libs/freetype2/freetype-src/src/smooth/ftgrays.c
index 86118fb36ff..681900fd400 100644
--- a/Build/source/libs/freetype2/freetype-src/src/smooth/ftgrays.c
+++ b/Build/source/libs/freetype2/freetype-src/src/smooth/ftgrays.c
@@ -4,7 +4,7 @@
*
* A new `perfect' anti-aliasing renderer (body).
*
- * Copyright (C) 2000-2021 by
+ * Copyright (C) 2000-2020 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
@@ -168,11 +168,10 @@
typedef ptrdiff_t FT_PtrDist;
-#define Smooth_Err_Ok 0
-#define Smooth_Err_Invalid_Outline -1
-#define Smooth_Err_Cannot_Render_Glyph -2
-#define Smooth_Err_Invalid_Argument -3
-#define Smooth_Err_Raster_Overflow -4
+#define ErrRaster_Invalid_Mode -2
+#define ErrRaster_Invalid_Outline -1
+#define ErrRaster_Invalid_Argument -3
+#define ErrRaster_Memory_Overflow -4
#define FT_BEGIN_HEADER
#define FT_END_HEADER
@@ -230,18 +229,18 @@ typedef ptrdiff_t FT_PtrDist;
#define FT_ERROR( varformat ) FT_Message varformat
#endif
-#define FT_THROW( e ) \
- ( FT_Throw( FT_ERR_CAT( Smooth_Err_, e ), \
- __LINE__, \
- __FILE__ ) | \
- FT_ERR_CAT( Smooth_Err_, e ) )
+#define FT_THROW( e ) \
+ ( FT_Throw( FT_ERR_CAT( ErrRaster_, e ), \
+ __LINE__, \
+ __FILE__ ) | \
+ FT_ERR_CAT( ErrRaster_, e ) )
#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 */
-#define FT_THROW( e ) FT_ERR_CAT( Smooth_Err_, e )
+#define FT_THROW( e ) FT_ERR_CAT( ErrRaster_, e )
#endif /* !FT_DEBUG_LEVEL_TRACE */
@@ -287,6 +286,10 @@ typedef ptrdiff_t FT_PtrDist;
#include "ftsmerrs.h"
+#define Smooth_Err_Invalid_Mode Smooth_Err_Cannot_Render_Glyph
+#define Smooth_Err_Memory_Overflow Smooth_Err_Out_Of_Memory
+#define ErrRaster_Memory_Overflow Smooth_Err_Out_Of_Memory
+
#endif /* !STANDALONE_ */
@@ -389,41 +392,6 @@ typedef ptrdiff_t FT_PtrDist;
( sizeof( long ) * FT_CHAR_BIT - PIXEL_BITS ) )
- /* Scale area and apply fill rule to calculate the coverage byte. */
- /* The top fill bit is used for the non-zero rule. The eighth */
- /* fill bit is used for the even-odd rule. The higher coverage */
- /* bytes are either clamped for the non-zero-rule or discarded */
- /* later for the even-odd rule. */
-#define FT_FILL_RULE( coverage, area, fill ) \
- FT_BEGIN_STMNT \
- coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); \
- if ( coverage & fill ) \
- coverage = ~coverage; \
- if ( coverage > 255 && fill & INT_MIN ) \
- coverage = 255; \
- FT_END_STMNT
-
-
- /* It is faster to write small spans byte-by-byte than calling */
- /* `memset'. This is mainly due to the cost of the function call. */
-#define FT_GRAY_SET( d, s, count ) \
- FT_BEGIN_STMNT \
- unsigned char* q = d; \
- switch ( count ) \
- { \
- case 7: *q++ = (unsigned char)s; /* fall through */ \
- case 6: *q++ = (unsigned char)s; /* fall through */ \
- case 5: *q++ = (unsigned char)s; /* fall through */ \
- case 4: *q++ = (unsigned char)s; /* fall through */ \
- case 3: *q++ = (unsigned char)s; /* fall through */ \
- case 2: *q++ = (unsigned char)s; /* fall through */ \
- case 1: *q = (unsigned char)s; /* fall through */ \
- case 0: break; \
- default: FT_MEM_SET( d, s, count ); \
- } \
- FT_END_STMNT
-
-
/**************************************************************************
*
* TYPE DEFINITIONS
@@ -464,7 +432,7 @@ typedef ptrdiff_t FT_PtrDist;
#endif
/* FT_Span buffer size for direct rendering only */
-#define FT_MAX_GRAY_SPANS 16
+#define FT_MAX_GRAY_SPANS 10
#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */
@@ -479,27 +447,28 @@ typedef ptrdiff_t FT_PtrDist;
{
ft_jmp_buf jump_buffer;
- TCoord min_ex, max_ex; /* min and max integer pixel coordinates */
+ TCoord ex, ey;
+ TCoord min_ex, max_ex;
TCoord min_ey, max_ey;
- TCoord count_ey; /* same as (max_ey - min_ey) */
-
- PCell cell; /* current cell */
- PCell cell_free; /* call allocation next free slot */
- PCell cell_limit; /* cell allocation limit */
- PCell* ycells; /* array of cell linked-lists; one per */
- /* vertical coordinate in the current band */
+ TArea area;
+ TCoord cover;
+ int invalid;
- PCell cells; /* cell storage area */
- FT_PtrDist max_cells; /* cell storage capacity */
+ PCell* ycells;
+ PCell cells;
+ FT_PtrDist max_cells;
+ FT_PtrDist num_cells;
- TPos x, y; /* last point position */
+ TPos x, y;
- FT_Outline outline; /* input outline */
- TPixmap target; /* target pixmap */
+ FT_Outline outline;
+ TPixmap target;
FT_Raster_Span_Func render_span;
void* render_span_data;
+ FT_Span spans[FT_MAX_GRAY_SPANS];
+ int num_spans;
} gray_TWorker, *gray_PWorker;
@@ -507,36 +476,17 @@ typedef ptrdiff_t FT_PtrDist;
#pragma warning( pop )
#endif
+
#ifndef FT_STATIC_RASTER
#define ras (*worker)
#else
static gray_TWorker ras;
#endif
- /*
- * Return a pointer to the 'null cell', used as a sentinel at the end of
- * all `ycells` linked lists. Its x coordinate should be maximal to
- * ensure no NULL checks are necessary when looking for an insertion point
- * in `gray_set_cell`. Other loops should check the cell pointer with
- * CELL_IS_NULL() to detect the end of the list.
- */
-#define NULL_CELL_PTR( ras ) (ras).cells
-
- /* The |x| value of the null cell. Must be the largest possible */
- /* integer value stored in a `TCell.x` field. */
-#define CELL_MAX_X_VALUE INT_MAX
-
- /* Return true iff |cell| points to the null cell. */
-#define CELL_IS_NULL( cell ) ( (cell)->x == CELL_MAX_X_VALUE )
-
-
-#define FT_INTEGRATE( ras, a, b ) \
- ras.cell->cover += (a), ras.cell->area += (a) * (TArea)(b)
-
typedef struct gray_TRaster_
{
- void* memory;
+ void* memory;
} gray_TRaster, *gray_PRaster;
@@ -558,7 +508,7 @@ typedef ptrdiff_t FT_PtrDist;
printf( "%3d:", y );
- for ( ; !CELL_IS_NULL( cell ); cell = cell->next )
+ for ( ; cell != NULL; cell = cell->next )
printf( " (%3d, c:%4d, a:%6d)",
cell->x, cell->cover, cell->area );
printf( "\n" );
@@ -570,63 +520,77 @@ typedef ptrdiff_t FT_PtrDist;
/**************************************************************************
*
- * Set the current cell to a new position.
+ * Record the current cell in the linked list.
*/
static void
- gray_set_cell( RAS_ARG_ TCoord ex,
- TCoord ey )
+ gray_record_cell( RAS_ARG )
{
- /* Move the cell pointer to a new position in the linked list. We use */
- /* NULL to indicate that the cell is outside of the clipping region */
- /* during the render phase. This means that: */
- /* */
- /* . the new vertical position must be within min_ey..max_ey-1. */
- /* . the new horizontal position must be strictly less than max_ex */
- /* */
- /* Note that if a cell is to the left of the clipping region, it is */
- /* actually set to the (min_ex-1) horizontal position. */
-
- TCoord ey_index = ey - ras.min_ey;
+ PCell *pcell, cell;
+ TCoord x = ras.ex;
- if ( ey_index < 0 || ey_index >= ras.count_ey || ex >= ras.max_ex )
- ras.cell = NULL_CELL_PTR( ras );
- else
+ pcell = &ras.ycells[ras.ey - ras.min_ey];
+ while ( ( cell = *pcell ) )
{
- PCell* pcell = ras.ycells + ey_index;
- PCell cell;
+ if ( cell->x > x )
+ break;
+ if ( cell->x == x )
+ goto Found;
- ex = FT_MAX( ex, ras.min_ex - 1 );
+ pcell = &cell->next;
+ }
- while ( 1 )
- {
- cell = *pcell;
+ if ( ras.num_cells >= ras.max_cells )
+ ft_longjmp( ras.jump_buffer, 1 );
- if ( cell->x > ex )
- break;
+ /* insert new cell */
+ cell = ras.cells + ras.num_cells++;
+ cell->x = x;
+ cell->area = ras.area;
+ cell->cover = ras.cover;
- if ( cell->x == ex )
- goto Found;
+ cell->next = *pcell;
+ *pcell = cell;
- pcell = &cell->next;
- }
+ return;
- /* insert new cell */
- cell = ras.cell_free++;
- if ( cell >= ras.cell_limit )
- ft_longjmp( ras.jump_buffer, 1 );
+ Found:
+ /* update old cell */
+ cell->area += ras.area;
+ cell->cover += ras.cover;
+ }
- cell->x = ex;
- cell->area = 0;
- cell->cover = 0;
- cell->next = *pcell;
- *pcell = cell;
+ /**************************************************************************
+ *
+ * Set the current cell to a new position.
+ */
+ static void
+ gray_set_cell( RAS_ARG_ TCoord ex,
+ TCoord ey )
+ {
+ /* Move the cell pointer to a new position. We set the `invalid' */
+ /* flag to indicate that the cell isn't part of those we're interested */
+ /* in during the render phase. This means that: */
+ /* */
+ /* . the new vertical position must be within min_ey..max_ey-1. */
+ /* . the new horizontal position must be strictly less than max_ex */
+ /* */
+ /* Note that if a cell is to the left of the clipping region, it is */
+ /* actually set to the (min_ex-1) horizontal position. */
- Found:
- ras.cell = cell;
- }
+ /* record the current one if it is valid and substantial */
+ if ( !ras.invalid && ( ras.area || ras.cover ) )
+ gray_record_cell( RAS_VAR );
+
+ ras.area = 0;
+ ras.cover = 0;
+ ras.ex = FT_MAX( ex, ras.min_ex - 1 );
+ ras.ey = ey;
+
+ ras.invalid = ( ey >= ras.max_ey || ey < ras.min_ey ||
+ ex >= ras.max_ex );
}
@@ -691,9 +655,10 @@ typedef ptrdiff_t FT_PtrDist;
/* XXX: y-delta and x-delta below should be related. */
FT_DIV_MOD( TCoord, p, dx, delta, mod );
- FT_INTEGRATE( ras, delta, fx1 + first );
- y1 += delta;
- ex1 += incr;
+ ras.area += (TArea)( ( fx1 + first ) * delta );
+ ras.cover += delta;
+ y1 += delta;
+ ex1 += incr;
gray_set_cell( RAS_VAR_ ex1, ey );
if ( ex1 != ex2 )
@@ -714,9 +679,10 @@ typedef ptrdiff_t FT_PtrDist;
delta++;
}
- FT_INTEGRATE( ras, delta, ONE_PIXEL );
- y1 += delta;
- ex1 += incr;
+ ras.area += (TArea)( ONE_PIXEL * delta );
+ ras.cover += delta;
+ y1 += delta;
+ ex1 += incr;
gray_set_cell( RAS_VAR_ ex1, ey );
} while ( ex1 != ex2 );
}
@@ -724,7 +690,10 @@ typedef ptrdiff_t FT_PtrDist;
fx1 = ONE_PIXEL - first;
End:
- FT_INTEGRATE( ras, y2 - y1, fx1 + fx2 );
+ dy = y2 - y1;
+
+ ras.area += (TArea)( ( fx1 + fx2 ) * dy );
+ ras.cover += dy;
}
@@ -767,6 +736,7 @@ typedef ptrdiff_t FT_PtrDist;
{
TCoord ex = TRUNC( ras.x );
TCoord two_fx = FRACT( ras.x ) << 1;
+ TArea area;
if ( dy > 0)
@@ -780,23 +750,27 @@ typedef ptrdiff_t FT_PtrDist;
incr = -1;
}
- delta = first - fy1;
- FT_INTEGRATE( ras, delta, two_fx);
- ey1 += incr;
+ delta = first - fy1;
+ ras.area += (TArea)two_fx * delta;
+ ras.cover += delta;
+ ey1 += incr;
gray_set_cell( RAS_VAR_ ex, ey1 );
delta = first + first - ONE_PIXEL;
+ area = (TArea)two_fx * delta;
while ( ey1 != ey2 )
{
- FT_INTEGRATE( ras, delta, two_fx);
- ey1 += incr;
+ ras.area += area;
+ ras.cover += delta;
+ ey1 += incr;
gray_set_cell( RAS_VAR_ ex, ey1 );
}
- delta = fy2 - ONE_PIXEL + first;
- FT_INTEGRATE( ras, delta, two_fx);
+ delta = fy2 - ONE_PIXEL + first;
+ ras.area += (TArea)two_fx * delta;
+ ras.cover += delta;
goto End;
}
@@ -909,7 +883,8 @@ typedef ptrdiff_t FT_PtrDist;
do
{
fy2 = ONE_PIXEL;
- FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 );
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * fx1 * 2;
fy1 = 0;
ey1++;
gray_set_cell( RAS_VAR_ ex1, ey1 );
@@ -918,7 +893,8 @@ typedef ptrdiff_t FT_PtrDist;
do
{
fy2 = 0;
- FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 );
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * fx1 * 2;
fy1 = ONE_PIXEL;
ey1--;
gray_set_cell( RAS_VAR_ ex1, ey1 );
@@ -936,297 +912,72 @@ typedef ptrdiff_t FT_PtrDist;
/* also easily updated when moving from one cell to the next. */
do
{
- if ( prod - dx * ONE_PIXEL > 0 &&
- prod <= 0 ) /* left */
+ if ( prod <= 0 &&
+ prod - dx * ONE_PIXEL > 0 ) /* left */
{
fx2 = 0;
fy2 = FT_UDIV( -prod, -dx );
prod -= dy * ONE_PIXEL;
- FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
fx1 = ONE_PIXEL;
fy1 = fy2;
ex1--;
}
- else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 &&
- prod - dx * ONE_PIXEL <= 0 ) /* up */
+ else if ( prod - dx * ONE_PIXEL <= 0 &&
+ prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 ) /* up */
{
prod -= dx * ONE_PIXEL;
fx2 = FT_UDIV( -prod, dy );
fy2 = ONE_PIXEL;
- FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
fx1 = fx2;
fy1 = 0;
ey1++;
}
- else if ( prod + dy * ONE_PIXEL >= 0 &&
- prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 ) /* right */
+ else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 &&
+ prod + dy * ONE_PIXEL >= 0 ) /* right */
{
prod += dy * ONE_PIXEL;
fx2 = ONE_PIXEL;
fy2 = FT_UDIV( prod, dx );
- FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
fx1 = 0;
fy1 = fy2;
ex1++;
}
- else /* ( prod > 0 &&
- prod + dy * ONE_PIXEL < 0 ) down */
+ else /* ( prod + dy * ONE_PIXEL < 0 &&
+ prod > 0 ) down */
{
fx2 = FT_UDIV( prod, -dy );
fy2 = 0;
prod += dx * ONE_PIXEL;
- FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
fx1 = fx2;
fy1 = ONE_PIXEL;
ey1--;
}
gray_set_cell( RAS_VAR_ ex1, ey1 );
-
} while ( ex1 != ex2 || ey1 != ey2 );
}
fx2 = FRACT( to_x );
fy2 = FRACT( to_y );
- FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
End:
- ras.x = to_x;
- ras.y = to_y;
+ ras.x = to_x;
+ ras.y = to_y;
}
#endif
- /*
- * Benchmarking shows that using DDA to flatten the quadratic Bézier arcs
- * is slightly faster in the following cases:
- *
- * - When the host CPU is 64-bit.
- * - When SSE2 SIMD registers and instructions are available (even on
- * x86).
- *
- * For other cases, using binary splits is actually slightly faster.
- */
-#if defined( __SSE2__ ) || \
- defined( __x86_64__ ) || \
- defined( __aarch64__ ) || \
- defined( _M_AMD64 ) || \
- defined( _M_ARM64 )
-# define BEZIER_USE_DDA 1
-#else
-# define BEZIER_USE_DDA 0
-#endif
-
- /*
- * For now, the code that depends on `BEZIER_USE_DDA` requires `FT_Int64`
- * to be defined. If `FT_LONG64` is not defined, meaning there is no
- * 64-bit type available, disable it to avoid compilation errors. See for
- * example https://gitlab.freedesktop.org/freetype/freetype/-/issues/1071.
- */
-#if !defined( FT_LONG64 )
-# undef BEZIER_USE_DDA
-# define BEZIER_USE_DDA 0
-#endif
-
-#if BEZIER_USE_DDA
-
-#ifdef __SSE2__
-# include <emmintrin.h>
-#endif
-
- static void
- gray_render_conic( RAS_ARG_ const FT_Vector* control,
- const FT_Vector* to )
- {
- FT_Vector p0, p1, p2;
- TPos dx, dy;
- int shift;
-
- FT_Int64 ax, ay, bx, by;
- FT_Int64 rx, ry;
- FT_Int64 qx, qy;
- FT_Int64 px, py;
-
- FT_UInt count;
-
-
- p0.x = ras.x;
- p0.y = ras.y;
- p1.x = UPSCALE( control->x );
- p1.y = UPSCALE( control->y );
- p2.x = UPSCALE( to->x );
- p2.y = UPSCALE( to->y );
-
- /* short-cut the arc that crosses the current band */
- if ( ( TRUNC( p0.y ) >= ras.max_ey &&
- TRUNC( p1.y ) >= ras.max_ey &&
- TRUNC( p2.y ) >= ras.max_ey ) ||
- ( TRUNC( p0.y ) < ras.min_ey &&
- TRUNC( p1.y ) < ras.min_ey &&
- TRUNC( p2.y ) < ras.min_ey ) )
- {
- ras.x = p2.x;
- ras.y = p2.y;
- return;
- }
-
- dx = FT_ABS( p0.x + p2.x - 2 * p1.x );
- dy = FT_ABS( p0.y + p2.y - 2 * p1.y );
- if ( dx < dy )
- dx = dy;
-
- if ( dx <= ONE_PIXEL / 4 )
- {
- gray_render_line( RAS_VAR_ p2.x, p2.y );
- return;
- }
-
- /* We can calculate the number of necessary bisections because */
- /* each bisection predictably reduces deviation exactly 4-fold. */
- /* Even 32-bit deviation would vanish after 16 bisections. */
- shift = 0;
- do
- {
- dx >>= 2;
- shift += 1;
-
- } while ( dx > ONE_PIXEL / 4 );
-
- /*
- * The (P0,P1,P2) arc equation, for t in [0,1] range:
- *
- * P(t) = P0*(1-t)^2 + P1*2*t*(1-t) + P2*t^2
- *
- * P(t) = P0 + 2*(P1-P0)*t + (P0+P2-2*P1)*t^2
- * = P0 + 2*B*t + A*t^2
- *
- * for A = P0 + P2 - 2*P1
- * and B = P1 - P0
- *
- * Let's consider the difference when advancing by a small
- * parameter h:
- *
- * Q(h,t) = P(t+h) - P(t) = 2*B*h + A*h^2 + 2*A*h*t
- *
- * And then its own difference:
- *
- * R(h,t) = Q(h,t+h) - Q(h,t) = 2*A*h*h = R (constant)
- *
- * Since R is always a constant, it is possible to compute
- * successive positions with:
- *
- * P = P0
- * Q = Q(h,0) = 2*B*h + A*h*h
- * R = 2*A*h*h
- *
- * loop:
- * P += Q
- * Q += R
- * EMIT(P)
- *
- * To ensure accurate results, perform computations on 64-bit
- * values, after scaling them by 2^32:
- *
- * R << 32 = 2 * A << (32 - N - N)
- * = A << (33 - 2 *N)
- *
- * Q << 32 = (2 * B << (32 - N)) + (A << (32 - N - N))
- * = (B << (33 - N)) + (A << (32 - N - N))
- */
-
-#ifdef __SSE2__
- /* Experience shows that for small shift values, */
- /* SSE2 is actually slower. */
- if ( shift > 2 )
- {
- union
- {
- struct { FT_Int64 ax, ay, bx, by; } i;
- struct { __m128i a, b; } vec;
-
- } u;
-
- union
- {
- struct { FT_Int32 px_lo, px_hi, py_lo, py_hi; } i;
- __m128i vec;
-
- } v;
-
- __m128i a, b;
- __m128i r, q, q2;
- __m128i p;
-
-
- u.i.ax = p0.x + p2.x - 2 * p1.x;
- u.i.ay = p0.y + p2.y - 2 * p1.y;
- u.i.bx = p1.x - p0.x;
- u.i.by = p1.y - p0.y;
-
- a = _mm_load_si128( &u.vec.a );
- b = _mm_load_si128( &u.vec.b );
-
- r = _mm_slli_epi64( a, 33 - 2 * shift );
- q = _mm_slli_epi64( b, 33 - shift );
- q2 = _mm_slli_epi64( a, 32 - 2 * shift );
-
- q = _mm_add_epi64( q2, q );
-
- v.i.px_lo = 0;
- v.i.px_hi = p0.x;
- v.i.py_lo = 0;
- v.i.py_hi = p0.y;
-
- p = _mm_load_si128( &v.vec );
-
- for ( count = ( 1U << shift ); count > 0; count-- )
- {
- p = _mm_add_epi64( p, q );
- q = _mm_add_epi64( q, r );
-
- _mm_store_si128( &v.vec, p );
-
- gray_render_line( RAS_VAR_ v.i.px_hi, v.i.py_hi );
- }
-
- return;
- }
-#endif /* __SSE2__ */
-
- ax = p0.x + p2.x - 2 * p1.x;
- ay = p0.y + p2.y - 2 * p1.y;
- bx = p1.x - p0.x;
- by = p1.y - p0.y;
-
- rx = ax << ( 33 - 2 * shift );
- ry = ay << ( 33 - 2 * shift );
-
- qx = ( bx << ( 33 - shift ) ) + ( ax << ( 32 - 2 * shift ) );
- qy = ( by << ( 33 - shift ) ) + ( ay << ( 32 - 2 * shift ) );
-
- px = (FT_Int64)p0.x << 32;
- py = (FT_Int64)p0.y << 32;
-
- for ( count = 1U << shift; count > 0; count-- )
- {
- px += qx;
- py += qy;
- qx += rx;
- qy += ry;
-
- gray_render_line( RAS_VAR_ (FT_Pos)( px >> 32 ),
- (FT_Pos)( py >> 32 ) );
- }
- }
-
-#else /* !BEZIER_USE_DDA */
-
- /*
- * Note that multiple attempts to speed up the function below
- * with SSE2 intrinsics, using various data layouts, have turned
- * out to be slower than the non-SIMD code below.
- */
static void
gray_split_conic( FT_Vector* base )
{
@@ -1312,17 +1063,7 @@ typedef ptrdiff_t FT_PtrDist;
} while ( --draw );
}
-#endif /* !BEZIER_USE_DDA */
-
- /*
- * For cubic Bézier, binary splits are still faster than DDA
- * because the splits are adaptive to how quickly each sub-arc
- * approaches their chord trisection points.
- *
- * It might be useful to experiment with SSE2 to speed up
- * `gray_split_cubic`, though.
- */
static void
gray_split_cubic( FT_Vector* base )
{
@@ -1464,62 +1205,94 @@ typedef ptrdiff_t FT_PtrDist;
static void
- gray_sweep( RAS_ARG )
+ gray_hline( RAS_ARG_ TCoord x,
+ TCoord y,
+ TArea coverage,
+ TCoord acount )
{
- int fill = ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ? 0x100 : INT_MIN;
- int coverage;
- int y;
+ /* scale the coverage from 0..(ONE_PIXEL*ONE_PIXEL*2) to 0..256 */
+ coverage >>= PIXEL_BITS * 2 + 1 - 8;
-
- for ( y = ras.min_ey; y < ras.max_ey; y++ )
+ /* compute the line's coverage depending on the outline fill rule */
+ if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL )
{
- PCell cell = ras.ycells[y - ras.min_ey];
- TCoord x = ras.min_ex;
- TArea cover = 0;
- TArea area;
+ coverage &= 511;
- unsigned char* line = ras.target.origin - ras.target.pitch * y;
+ if ( coverage >= 256 )
+ coverage = 511 - coverage;
+ }
+ else /* default non-zero winding rule */
+ {
+ if ( coverage < 0 )
+ coverage = ~coverage; /* the same as -coverage - 1 */
+ if ( coverage >= 256 )
+ coverage = 255;
+ }
- for ( ; !CELL_IS_NULL( cell ); cell = cell->next )
- {
- if ( cover != 0 && cell->x > x )
- {
- FT_FILL_RULE( coverage, cover, fill );
- FT_GRAY_SET( line + x, coverage, cell->x - x );
- }
+ if ( ras.num_spans >= 0 ) /* for FT_RASTER_FLAG_DIRECT only */
+ {
+ FT_Span* span = ras.spans + ras.num_spans++;
- cover += (TArea)cell->cover * ( ONE_PIXEL * 2 );
- area = cover - cell->area;
- if ( area != 0 && cell->x >= ras.min_ex )
- {
- FT_FILL_RULE( coverage, area, fill );
- line[cell->x] = (unsigned char)coverage;
- }
+ span->x = (short)x;
+ span->len = (unsigned short)acount;
+ span->coverage = (unsigned char)coverage;
- x = cell->x + 1;
+ if ( ras.num_spans == FT_MAX_GRAY_SPANS )
+ {
+ /* flush the span buffer and reset the count */
+ ras.render_span( y, ras.num_spans, ras.spans, ras.render_span_data );
+ ras.num_spans = 0;
}
+ }
+ else
+ {
+ unsigned char* q = ras.target.origin - ras.target.pitch * y + x;
+ unsigned char c = (unsigned char)coverage;
- if ( cover != 0 ) /* only if cropped */
+
+ /* For small-spans it is faster to do it by ourselves than
+ * calling `memset'. This is mainly due to the cost of the
+ * function call.
+ */
+ switch ( acount )
{
- FT_FILL_RULE( coverage, cover, fill );
- FT_GRAY_SET( line + x, coverage, ras.max_ex - x );
+ case 7:
+ *q++ = c;
+ /* fall through */
+ case 6:
+ *q++ = c;
+ /* fall through */
+ case 5:
+ *q++ = c;
+ /* fall through */
+ case 4:
+ *q++ = c;
+ /* fall through */
+ case 3:
+ *q++ = c;
+ /* fall through */
+ case 2:
+ *q++ = c;
+ /* fall through */
+ case 1:
+ *q = c;
+ /* fall through */
+ case 0:
+ break;
+ default:
+ FT_MEM_SET( q, c, acount );
}
}
}
static void
- gray_sweep_direct( RAS_ARG )
+ gray_sweep( RAS_ARG )
{
- int fill = ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ? 0x100 : INT_MIN;
- int coverage;
int y;
- FT_Span span[FT_MAX_GRAY_SPANS];
- int n = 0;
-
for ( y = ras.min_ey; y < ras.max_ey; y++ )
{
@@ -1529,62 +1302,28 @@ typedef ptrdiff_t FT_PtrDist;
TArea area;
- for ( ; !CELL_IS_NULL( cell ); cell = cell->next )
+ for ( ; cell != NULL; cell = cell->next )
{
if ( cover != 0 && cell->x > x )
- {
- FT_FILL_RULE( coverage, cover, fill );
-
- span[n].coverage = (unsigned char)coverage;
- span[n].x = (short)x;
- span[n].len = (unsigned short)( cell->x - x );
-
- if ( ++n == FT_MAX_GRAY_SPANS )
- {
- /* flush the span buffer and reset the count */
- ras.render_span( y, n, span, ras.render_span_data );
- n = 0;
- }
- }
+ gray_hline( RAS_VAR_ x, y, cover, cell->x - x );
cover += (TArea)cell->cover * ( ONE_PIXEL * 2 );
area = cover - cell->area;
if ( area != 0 && cell->x >= ras.min_ex )
- {
- FT_FILL_RULE( coverage, area, fill );
-
- span[n].coverage = (unsigned char)coverage;
- span[n].x = (short)cell->x;
- span[n].len = 1;
-
- if ( ++n == FT_MAX_GRAY_SPANS )
- {
- /* flush the span buffer and reset the count */
- ras.render_span( y, n, span, ras.render_span_data );
- n = 0;
- }
- }
+ gray_hline( RAS_VAR_ cell->x, y, area, 1 );
x = cell->x + 1;
}
- if ( cover != 0 ) /* only if cropped */
- {
- FT_FILL_RULE( coverage, cover, fill );
-
- span[n].coverage = (unsigned char)coverage;
- span[n].x = (short)x;
- span[n].len = (unsigned short)( ras.max_ex - x );
+ if ( cover != 0 )
+ gray_hline( RAS_VAR_ x, y, cover, ras.max_ex - x );
- ++n;
- }
-
- if ( n )
+ if ( ras.num_spans > 0 ) /* for FT_RASTER_FLAG_DIRECT only */
{
/* flush the span buffer and reset the count */
- ras.render_span( y, n, span, ras.render_span_data );
- n = 0;
+ ras.render_span( y, ras.num_spans, ras.spans, ras.render_span_data );
+ ras.num_spans = 0;
}
}
}
@@ -1865,7 +1604,7 @@ typedef ptrdiff_t FT_PtrDist;
}
FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
- return Smooth_Err_Ok;
+ return 0;
Exit:
FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n", error ));
@@ -1906,15 +1645,18 @@ typedef ptrdiff_t FT_PtrDist;
if ( continued )
FT_Trace_Enable();
+ if ( !ras.invalid )
+ gray_record_cell( RAS_VAR );
+
FT_TRACE7(( "band [%d..%d]: %ld cell%s\n",
ras.min_ey,
ras.max_ey,
- ras.cell_free - ras.cells,
- ras.cell_free - ras.cells == 1 ? "" : "s" ));
+ ras.num_cells,
+ ras.num_cells == 1 ? "" : "s" ));
}
else
{
- error = FT_THROW( Raster_Overflow );
+ error = FT_THROW( Memory_Overflow );
FT_TRACE7(( "band [%d..%d]: to be bisected\n",
ras.min_ey, ras.max_ey ));
@@ -1951,19 +1693,9 @@ typedef ptrdiff_t FT_PtrDist;
/* memory management */
n = ( height * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) / sizeof ( TCell );
- ras.cells = buffer + n;
- ras.max_cells = (FT_PtrDist)( FT_MAX_GRAY_POOL - n );
- ras.cell_limit = ras.cells + ras.max_cells;
- ras.ycells = (PCell*)buffer;
-
- /* Initialize the null cell at the start of the `cells` array. */
- /* Note that this requires `ras.cell_free` initialization to skip */
- /* over the first entry in the array. */
- PCell null_cell = NULL_CELL_PTR( ras );
- null_cell->x = CELL_MAX_X_VALUE;
- null_cell->area = 0;
- null_cell->cover = 0;
- null_cell->next = NULL;;
+ ras.cells = buffer + n;
+ ras.max_cells = (FT_PtrDist)( FT_MAX_GRAY_POOL - n );
+ ras.ycells = (PCell*)buffer;
for ( y = yMin; y < yMax; )
{
@@ -1978,33 +1710,27 @@ typedef ptrdiff_t FT_PtrDist;
do
{
TCoord width = band[0] - band[1];
- TCoord w;
int error;
- for ( w = 0; w < width; ++w )
- ras.ycells[w] = null_cell;
+ FT_MEM_ZERO( ras.ycells, height * sizeof ( PCell ) );
- ras.cell_free = ras.cells + 1; /* NOTE: Skip over the null cell. */
- ras.cell = null_cell;
+ ras.num_cells = 0;
+ ras.invalid = 1;
ras.min_ey = band[1];
ras.max_ey = band[0];
- ras.count_ey = width;
error = gray_convert_glyph_inner( RAS_VAR, continued );
continued = 1;
if ( !error )
{
- if ( ras.render_span ) /* for FT_RASTER_FLAG_DIRECT only */
- gray_sweep_direct( RAS_VAR );
- else
- gray_sweep( RAS_VAR );
+ gray_sweep( RAS_VAR );
band--;
continue;
}
- else if ( error != Smooth_Err_Raster_Overflow )
- return error;
+ else if ( error != ErrRaster_Memory_Overflow )
+ return 1;
/* render pool overflow; we will reduce the render band by half */
width >>= 1;
@@ -2013,7 +1739,7 @@ typedef ptrdiff_t FT_PtrDist;
if ( width == 0 )
{
FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));
- return FT_THROW( Raster_Overflow );
+ return 1;
}
band++;
@@ -2022,7 +1748,7 @@ typedef ptrdiff_t FT_PtrDist;
} while ( band >= bands );
}
- return Smooth_Err_Ok;
+ return 0;
}
@@ -2043,14 +1769,14 @@ typedef ptrdiff_t FT_PtrDist;
/* this version does not support monochrome rendering */
if ( !( params->flags & FT_RASTER_FLAG_AA ) )
- return FT_THROW( Cannot_Render_Glyph );
+ return FT_THROW( Invalid_Mode );
if ( !outline )
return FT_THROW( Invalid_Outline );
/* return immediately if the outline is empty */
if ( outline->n_points == 0 || outline->n_contours <= 0 )
- return Smooth_Err_Ok;
+ return 0;
if ( !outline->contours || !outline->points )
return FT_THROW( Invalid_Outline );
@@ -2064,10 +1790,11 @@ typedef ptrdiff_t FT_PtrDist;
if ( params->flags & FT_RASTER_FLAG_DIRECT )
{
if ( !params->gray_spans )
- return Smooth_Err_Ok;
+ return 0;
ras.render_span = (FT_Raster_Span_Func)params->gray_spans;
ras.render_span_data = params->user;
+ ras.num_spans = 0;
ras.min_ex = params->clip_box.xMin;
ras.min_ey = params->clip_box.yMin;
@@ -2082,7 +1809,7 @@ typedef ptrdiff_t FT_PtrDist;
/* nothing to do */
if ( !target_map->width || !target_map->rows )
- return Smooth_Err_Ok;
+ return 0;
if ( !target_map->buffer )
return FT_THROW( Invalid_Argument );
@@ -2097,6 +1824,7 @@ typedef ptrdiff_t FT_PtrDist;
ras.render_span = (FT_Raster_Span_Func)NULL;
ras.render_span_data = NULL;
+ ras.num_spans = -1; /* invalid */
ras.min_ex = 0;
ras.min_ey = 0;
@@ -2106,7 +1834,7 @@ typedef ptrdiff_t FT_PtrDist;
/* exit if nothing to do */
if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey )
- return Smooth_Err_Ok;
+ return 0;
return gray_convert_glyph( RAS_VAR );
}