ref: bd50295ca4c86ee46e330272078ac58cc60728d8
parent: 6d79f214e14f8b6d6e9c79cec491383223b37faf
author: David Turner <[email protected]>
date: Fri Sep 1 15:05:24 EDT 2006
* src/smooth/ftgrays.c: optmized the performance of the anti-aliased rasterizer. The speed gains is between 15% and 25%, depending on content
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,12 @@
2006-09-01 David Turner <[email protected]>
- * src/truetype/ttobjs.c: updated the TrueType loader to recognize
- a few fonts that require the automatic unpatented loader
+ * src/truetype/ttobjs.c: updated the TrueType loader to recognize
+ a few fonts that require the automatic unpatented loader
+ * src/smooth/ftgrays.c: optmized the performance of the anti-aliased
+ rasterizer. The speed gains is between 15% and 25%, depending on
+ content
+
2006-08-29 Dr. Werner Fink <[email protected]>
* configure: Make it possible to handle configure options which
@@ -1243,6 +1247,11 @@
structures and enumerations.
(FTC_CMapCache_Lookup) [FT_CONFIG_OPTION_OLD_INTERNALS]: New
compatibility code.
+
+ * src/cache/ftcbasic.c: fixed a silly bug that prevented our super-duper
+ "hack" to support rogue clients compiled against 2.1.7 to work correctly.
+ Probably explains the GNUstep crashes with the second release
+ candidate.
2006-02-23 Chia-I Wu <[email protected]>
--- a/src/smooth/ftgrays.c
+++ b/src/smooth/ftgrays.c
@@ -81,11 +81,6 @@
/*************************************************************************/
-
-/* experimental support for gamma correction within the rasterizer */
-#define xxxGRAYS_USE_GAMMA
-
-
/*************************************************************************/
/* */
/* The macro FT_COMPONENT is used in trace mode. It is an implicit */
@@ -257,32 +252,19 @@
/* maximal number of gray spans in a call to the span callback */
#define FT_MAX_GRAY_SPANS 32
+typedef struct TCell_* PCell;
-#ifdef GRAYS_COMPACT
+typedef struct TCell_
+{
+ int x;
+ int cover;
+ TArea area;
+ PCell next;
- typedef struct TCell_
- {
- short x : 14;
- short y : 14;
- int cover : PIXEL_BITS + 2;
- int area : PIXEL_BITS * 2 + 2;
+} TCell;
- } TCell, *PCell;
-#else /* GRAYS_COMPACT */
- typedef struct TCell_
- {
- TCoord x;
- TCoord y;
- int cover;
- TArea area;
-
- } TCell, *PCell;
-
-#endif /* GRAYS_COMPACT */
-
-
typedef struct TRaster_
{
PCell cells;
@@ -324,10 +306,12 @@
void* memory;
ft_jmp_buf jump_buffer;
-#ifdef GRAYS_USE_GAMMA
- unsigned char gamma[257];
-#endif
+ void* buffer;
+ long buffer_size;
+ PCell* ycells;
+ int ycount;
+
} TRaster, *PRaster;
@@ -339,8 +323,12 @@
gray_init_cells( RAS_ARG_ void* buffer,
long byte_size )
{
- ras.cells = (PCell)buffer;
- ras.max_cells = (int)( byte_size / sizeof ( TCell ) );
+ ras.buffer = buffer;
+ ras.buffer_size = byte_size;
+
+ ras.ycells = (PCell*) buffer;
+ ras.cells = NULL;
+ ras.max_cells = 0;
ras.num_cells = 0;
ras.area = 0;
ras.cover = 0;
@@ -396,6 +384,42 @@
/* */
/* Record the current cell in the table. */
/* */
+ static PCell*
+ gray_find_cell( RAS_ARG_ TCoord x,
+ TCoord y )
+ {
+ PCell *pnode, node;
+
+ pnode = &ras.ycells[y];
+ for (;;)
+ {
+ node = *pnode;
+ if ( node == NULL || node->x >= x )
+ break;
+
+ pnode = &node->next;
+ }
+ return pnode;
+ }
+
+
+ static PCell
+ gray_alloc_cell( RAS_ARG_ TCoord x )
+ {
+ PCell cell;
+
+ if ( ras.num_cells >= ras.max_cells )
+ ft_longjmp( ras.jump_buffer, 1 );
+
+ cell = ras.cells + ras.num_cells++;
+ cell->x = x;
+ cell->area = 0;
+ cell->cover = 0;
+
+ return cell;
+ }
+
+
static void
gray_record_cell( RAS_ARG )
{
@@ -404,18 +428,23 @@
if ( !ras.invalid && ( ras.area | ras.cover ) )
{
- if ( ras.num_cells >= ras.max_cells )
- ft_longjmp( ras.jump_buffer, 1 );
+ TCoord x = (TCoord)(ras.ex - ras.min_ex);
+ TCoord y = (TCoord)(ras.ey - ras.min_ey);
+ PCell *pparent = gray_find_cell( RAS_VAR_ x, y );
+ PCell cell = *pparent;
- cell = ras.cells + ras.num_cells++;
- cell->x = (TCoord)(ras.ex - ras.min_ex);
- cell->y = (TCoord)(ras.ey - ras.min_ey);
- cell->area = ras.area;
- cell->cover = ras.cover;
+ if ( cell == NULL || cell->x != x )
+ {
+ cell = gray_alloc_cell( RAS_VAR_ x );
+ cell->next = *pparent;
+ *pparent = cell;
+ }
+
+ cell->area += ras.area;
+ cell->cover += ras.cover;
}
}
-
/*************************************************************************/
/* */
/* Set the current cell to a new position. */
@@ -1036,199 +1065,8 @@
}
- /* a macro comparing two cell pointers. Returns true if a <= b. */
-#if 1
-#define PACK( a ) ( ( (long)(a)->y << 16 ) + (a)->x )
-#define LESS_THAN( a, b ) ( PACK( a ) < PACK( b ) )
-
-#else /* 1 */
-
-#define LESS_THAN( a, b ) ( (a)->y < (b)->y || \
- ( (a)->y == (b)->y && (a)->x < (b)->x ) )
-
-#endif /* 1 */
-
-#define SWAP_CELLS( a, b, temp ) do \
- { \
- temp = *(a); \
- *(a) = *(b); \
- *(b) = temp; \
- } while ( 0 )
-#define DEBUG_SORT
-#define QUICK_SORT
-
-#ifdef SHELL_SORT
-
- /* a simple shell sort algorithm that works directly on our */
- /* cells table */
- static void
- gray_shell_sort ( PCell cells,
- int count )
- {
- PCell i, j, limit = cells + count;
- TCell temp;
- int gap;
-
-
- /* compute initial gap */
- for ( gap = 0; ++gap < count; gap *= 3 )
- ;
-
- while ( gap /= 3 )
- {
- for ( i = cells + gap; i < limit; i++ )
- {
- for ( j = i - gap; ; j -= gap )
- {
- PCell k = j + gap;
-
-
- if ( LESS_THAN( j, k ) )
- break;
-
- SWAP_CELLS( j, k, temp );
-
- if ( j < cells + gap )
- break;
- }
- }
- }
- }
-
-#endif /* SHELL_SORT */
-
-
-#ifdef QUICK_SORT
-
- /* This is a non-recursive quicksort that directly process our cells */
- /* array. It should be faster than calling the stdlib qsort(), and we */
- /* can even tailor our insertion threshold... */
-
-#define QSORT_THRESHOLD 9 /* below this size, a sub-array will be sorted */
- /* through a normal insertion sort */
-
- static void
- gray_quick_sort( PCell cells,
- int count )
- {
- PCell stack[40]; /* should be enough ;-) */
- PCell* top; /* top of stack */
- PCell base, limit;
- TCell temp;
-
-
- limit = cells + count;
- base = cells;
- top = stack;
-
- for (;;)
- {
- int len = (int)( limit - base );
- PCell i, j, pivot;
-
-
- if ( len > QSORT_THRESHOLD )
- {
- /* we use base + len/2 as the pivot */
- pivot = base + len / 2;
- SWAP_CELLS( base, pivot, temp );
-
- i = base + 1;
- j = limit - 1;
-
- /* now ensure that *i <= *base <= *j */
- if ( LESS_THAN( j, i ) )
- SWAP_CELLS( i, j, temp );
-
- if ( LESS_THAN( base, i ) )
- SWAP_CELLS( base, i, temp );
-
- if ( LESS_THAN( j, base ) )
- SWAP_CELLS( base, j, temp );
-
- for (;;)
- {
- do i++; while ( LESS_THAN( i, base ) );
- do j--; while ( LESS_THAN( base, j ) );
-
- if ( i > j )
- break;
-
- SWAP_CELLS( i, j, temp );
- }
-
- SWAP_CELLS( base, j, temp );
-
- /* now, push the largest sub-array */
- if ( j - base > limit - i )
- {
- top[0] = base;
- top[1] = j;
- base = i;
- }
- else
- {
- top[0] = i;
- top[1] = limit;
- limit = j;
- }
- top += 2;
- }
- else
- {
- /* the sub-array is small, perform insertion sort */
- j = base;
- i = j + 1;
-
- for ( ; i < limit; j = i, i++ )
- {
- for ( ; LESS_THAN( j + 1, j ); j-- )
- {
- SWAP_CELLS( j + 1, j, temp );
- if ( j == base )
- break;
- }
- }
- if ( top > stack )
- {
- top -= 2;
- base = top[0];
- limit = top[1];
- }
- else
- break;
- }
- }
- }
-
-#endif /* QUICK_SORT */
-
-
-#ifdef DEBUG_GRAYS
-#ifdef DEBUG_SORT
-
static int
- gray_check_sort( PCell cells,
- int count )
- {
- PCell p, q;
-
-
- for ( p = cells + count - 2; p >= cells; p-- )
- {
- q = p + 1;
- if ( !LESS_THAN( p, q ) )
- return 0;
- }
- return 1;
- }
-
-#endif /* DEBUG_SORT */
-#endif /* DEBUG_GRAYS */
-
-
- static int
gray_move_to( const FT_Vector* to,
FT_Raster raster )
{
@@ -1301,10 +1139,6 @@
unsigned char coverage = spans->coverage;
-#ifdef GRAYS_USE_GAMMA
- coverage = raster->gamma[coverage];
-#endif
-
if ( coverage )
#if 1
FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len );
@@ -1320,37 +1154,7 @@
}
-#ifdef DEBUG_GRAYS
-
-#include <stdio.h>
-
static void
- gray_dump_cells( RAS_ARG )
- {
- PCell cell, limit;
- int y = -1;
-
-
- cell = ras.cells;
- limit = cell + ras.num_cells;
-
- for ( ; cell < limit; cell++ )
- {
- if ( cell->y != y )
- {
- fprintf( stderr, "\n%2d: ", cell->y );
- y = cell->y;
- }
- fprintf( stderr, "[%d %d %d]",
- cell->x, cell->area, cell->cover );
- }
- fprintf(stderr, "\n" );
- }
-
-#endif /* DEBUG_GRAYS */
-
-
- static void
gray_hline( RAS_ARG_ TCoord x,
TCoord y,
TPos area,
@@ -1449,99 +1253,47 @@
static void
gray_sweep( RAS_ARG_ const FT_Bitmap* target )
{
- TCoord x, y, cover;
- TArea area;
- PCell start, cur, limit;
+ int yindex;
FT_UNUSED( target );
-
if ( ras.num_cells == 0 )
return;
- cur = ras.cells;
- limit = cur + ras.num_cells;
-
- cover = 0;
- ras.span_y = -1;
ras.num_gray_spans = 0;
- for (;;)
+ for ( yindex = 0; yindex < ras.ycount; yindex++ )
{
- start = cur;
- y = start->y;
- x = start->x;
+ PCell cell = ras.ycells[yindex];
+ TCoord cover = 0;
+ TCoord x = 0;
- area = start->area;
- cover += start->cover;
-
- /* accumulate all start cells */
- for (;;)
+ for ( ; cell != NULL; cell = cell->next )
{
- ++cur;
- if ( cur >= limit || cur->y != start->y || cur->x != start->x )
- break;
+ TArea area;
- area += cur->area;
- cover += cur->cover;
- }
+ if ( cell->x > x && cover != 0 )
+ gray_hline( RAS_VAR_ x, yindex, cover*(ONE_PIXEL*2), cell->x - x );
- /* if the start cell has a non-null area, we must draw an */
- /* individual gray pixel there */
- if ( area && x >= 0 )
- {
- gray_hline( RAS_VAR_ x, y, cover * ( ONE_PIXEL * 2 ) - area, 1 );
- x++;
- }
+ cover += cell->cover;
+ area = cover*(ONE_PIXEL*2) - cell->area;
- if ( x < 0 )
- x = 0;
+ if ( area != 0 && cell->x >= 0 )
+ gray_hline( RAS_VAR_ cell->x, yindex, area, 1 );
- if ( cur < limit && start->y == cur->y )
- {
- /* draw a gray span between the start cell and the current one */
- if ( cur->x > x )
- gray_hline( RAS_VAR_ x, y,
- cover * ( ONE_PIXEL * 2 ), cur->x - x );
+ x = cell->x + 1;
}
- else
- {
- /* draw a gray span until the end of the clipping region */
- if ( cover && x < ras.max_ex - ras.min_ex )
- gray_hline( RAS_VAR_ x, y,
- cover * ( ONE_PIXEL * 2 ),
- (int)( ras.max_ex - x - ras.min_ex ) );
- cover = 0;
- }
- if ( cur >= limit )
- break;
+ if ( cover != 0 )
+ gray_hline( RAS_VAR_ x, yindex, cover*(ONE_PIXEL*2),
+ (ras.max_ex - x) );
}
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 );
-
-#ifdef DEBUG_GRAYS
-
- {
- int n;
- FT_Span* span;
-
-
- fprintf( stderr, "y=%3d ", ras.span_y );
- span = ras.gray_spans;
- for ( n = 0; n < ras.num_gray_spans; n++, span++ )
- fprintf( stderr, "[%d..%d]:%02x ",
- span->x, span->x + span->len - 1, span->coverage );
- fprintf( stderr, "\n" );
- }
-
-#endif /* DEBUG_GRAYS */
-
}
-
#ifdef _STANDALONE_
/*************************************************************************/
@@ -1893,32 +1645,41 @@
TPos bottom, top, middle;
int error;
+ {
+ PCell cells_max;
+ int yindex, ycount;
+ long cell_start, cell_mod;
+ ras.ycells = (PCell*)ras.buffer;
+ ras.ycount = band->max - band->min;
+
+ for ( yindex = 0; yindex < ras.ycount; yindex++ )
+ ras.ycells[yindex] = NULL;
+
+ cell_start = sizeof(PCell)*ras.ycount;
+ cell_mod = cell_start % sizeof(TCell);
+ if ( cell_mod > 0 )
+ cell_start += sizeof(TCell) - cell_mod;
+
+ cells_max = (PCell)(ras.buffer + ras.buffer_size);
+ ras.cells = (PCell)((char*)ras.buffer + cell_start);
+ if ( ras.cells >= cells_max )
+ goto ReduceBands;
+
+ ras.max_cells = (cells_max - ras.cells);
+ if (ras.max_cells < 2)
+ goto ReduceBands;
+ }
+
ras.num_cells = 0;
ras.invalid = 1;
ras.min_ey = band->min;
ras.max_ey = band->max;
-#if 1
error = gray_convert_glyph_inner( RAS_VAR );
-#else
- error = FT_Outline_Decompose( outline, &func_interface, &ras ) ||
- gray_record_cell( RAS_VAR );
-#endif
if ( !error )
{
-#ifdef SHELL_SORT
- gray_shell_sort( ras.cells, ras.num_cells );
-#else
- gray_quick_sort( ras.cells, ras.num_cells );
-#endif
-
-#ifdef DEBUG_GRAYS
- gray_check_sort( ras.cells, ras.num_cells );
- gray_dump_cells( RAS_VAR );
-#endif
-
gray_sweep( RAS_VAR_ &ras.target );
band--;
continue;
@@ -1926,6 +1687,7 @@
else if ( error != ErrRaster_MemoryOverflow )
return 1;
+ ReduceBands:
/* render pool overflow, we will reduce the render band by half */
bottom = band->min;
top = band->max;
@@ -1967,7 +1729,7 @@
const FT_Bitmap* target_map = params->target;
- if ( !raster || !raster->cells || !raster->max_cells )
+ if ( !raster || !raster->buffer || !raster->buffer_size )
return -1;
/* return immediately if the outline is empty */
@@ -2033,35 +1795,6 @@
/**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
/**** a static object. *****/
-
-#ifdef GRAYS_USE_GAMMA
-
- /* initialize the "gamma" table. Yes, this is really a crummy function */
- /* but the results look pretty good for something that simple. */
- /* */
-#define M_MAX 255
-#define M_X 128
-#define M_Y 192
-
- static void
- grays_init_gamma( PRaster raster )
- {
- unsigned int x, a;
-
-
- for ( x = 0; x < 256; x++ )
- {
- if ( x <= M_X )
- a = ( x * M_Y + M_X / 2) / M_X;
- else
- a = M_Y + ( ( x - M_X ) * ( M_MAX - M_Y ) +
- ( M_MAX - M_X ) / 2 ) / ( M_MAX - M_X );
-
- raster->gamma[x] = (unsigned char)a;
- }
- }
-
-#endif /* GRAYS_USE_GAMMA */
#ifdef _STANDALONE_