[smooth] Clean up the null cell usage.

Put the null cell at the end of the pool and store it explicitly so that
we can use it as both the limit and the dumpster.

* src/smooth/ftgrays.c (gray_TWorker): Store the last `cell_null` and
remove unnecesary fields.
(NULL_CELL_PTR, CELL_IS_NULL): Remove in favor of explicit `cell_null`.
(gray_dump_cells, gray_set_cell, gray_sweep{,_direct}): Update callers.
(gray_convert_glyph_inner): Trace remaining cells (oh well).
(gray_convert_glyph): Set up `cell_null` and slightly improve the pool
management.
This commit is contained in:
Alexei Podtelezhnikov 2021-08-20 23:40:49 -04:00
parent 6e9d8d314f
commit d62d583d92
1 changed files with 26 additions and 45 deletions

View File

@ -479,14 +479,11 @@ typedef ptrdiff_t FT_PtrDist;
PCell cell; /* current cell */
PCell cell_free; /* call allocation next free slot */
PCell cell_limit; /* cell allocation limit */
PCell cell_null; /* last cell, used as dumpster and limit */
PCell* ycells; /* array of cell linked-lists; one per */
/* vertical coordinate in the current band */
PCell cells; /* cell storage area */
FT_PtrDist max_cells; /* cell storage capacity */
TPos x, y; /* last point position */
FT_Outline outline; /* input outline */
@ -507,22 +504,10 @@ typedef ptrdiff_t FT_PtrDist;
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 = ADD_INT( ras.cell->cover, a ), \
@ -553,7 +538,7 @@ typedef ptrdiff_t FT_PtrDist;
printf( "%3d:", y );
for ( ; !CELL_IS_NULL( cell ); cell = cell->next )
for ( ; cell != ras.cell_null; cell = cell->next )
printf( " (%3d, c:%4d, a:%6d)",
cell->x, cell->cover, cell->area );
printf( "\n" );
@ -572,7 +557,7 @@ typedef ptrdiff_t FT_PtrDist;
TCoord ey )
{
/* 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 */
/* a dumpster null cell for everything outside of the clipping region */
/* during the render phase. This means that: */
/* */
/* . the new vertical position must be within min_ey..max_ey-1. */
@ -585,7 +570,7 @@ typedef ptrdiff_t FT_PtrDist;
if ( ey_index < 0 || ey_index >= ras.count_ey || ex >= ras.max_ex )
ras.cell = NULL_CELL_PTR( ras );
ras.cell = ras.cell_null;
else
{
PCell* pcell = ras.ycells + ey_index;
@ -609,7 +594,7 @@ typedef ptrdiff_t FT_PtrDist;
/* insert new cell */
cell = ras.cell_free++;
if ( cell >= ras.cell_limit )
if ( cell >= ras.cell_null )
ft_longjmp( ras.jump_buffer, 1 );
cell->x = ex;
@ -1483,7 +1468,7 @@ typedef ptrdiff_t FT_PtrDist;
unsigned char* line = ras.target.origin - ras.target.pitch * y;
for ( ; !CELL_IS_NULL( cell ); cell = cell->next )
for ( ; cell != ras.cell_null; cell = cell->next )
{
TArea area;
@ -1534,7 +1519,7 @@ typedef ptrdiff_t FT_PtrDist;
TArea cover = 0;
for ( ; !CELL_IS_NULL( cell ); cell = cell->next )
for ( ; cell != ras.cell_null; cell = cell->next )
{
TArea area;
@ -1914,11 +1899,11 @@ typedef ptrdiff_t FT_PtrDist;
if ( continued )
FT_Trace_Enable();
FT_TRACE7(( "band [%d..%d]: %ld cell%s\n",
FT_TRACE7(( "band [%d..%d]: %ld cell%s remaining/\n",
ras.min_ey,
ras.max_ey,
ras.cell_free - ras.cells,
ras.cell_free - ras.cells == 1 ? "" : "s" ));
ras.cell_null - ras.cell_free,
ras.cell_null - ras.cell_free == 1 ? "" : "s" ));
}
else
{
@ -1948,7 +1933,16 @@ typedef ptrdiff_t FT_PtrDist;
int continued = 0;
/* Initialize the null cell at the end of the poll. */
ras.cell_null = buffer + FT_MAX_GRAY_POOL - 1;
ras.cell_null->x = CELL_MAX_X_VALUE;
ras.cell_null->area = 0;
ras.cell_null->cover = 0;
ras.cell_null->next = NULL;;
/* set up vertical bands */
ras.ycells = (PCell*)buffer;
if ( height > n )
{
/* two divisions rounded up */
@ -1956,23 +1950,6 @@ typedef ptrdiff_t FT_PtrDist;
height = ( height + n - 1 ) / n;
}
/* 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;;
for ( y = yMin; y < yMax; )
{
ras.min_ey = y;
@ -1991,10 +1968,14 @@ typedef ptrdiff_t FT_PtrDist;
for ( w = 0; w < width; ++w )
ras.ycells[w] = null_cell;
ras.ycells[w] = ras.cell_null;
ras.cell_free = ras.cells + 1; /* NOTE: Skip over the null cell. */
ras.cell = null_cell;
/* memory management: skip ycells */
n = ( width * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) /
sizeof ( TCell );
ras.cell_free = buffer + n;
ras.cell = ras.cell_null;
ras.min_ey = band[1];
ras.max_ey = band[0];
ras.count_ey = width;