ref: d62d583d9228fda1d9b6509d44d0293d7aaaa62e
parent: 6e9d8d314ff6ab23177b9162c0b96616460bb84e
author: Alexei Podtelezhnikov <[email protected]>
date: Fri Aug 20 19:40:49 EDT 2021
[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.
--- a/src/smooth/ftgrays.c
+++ b/src/smooth/ftgrays.c
@@ -479,14 +479,11 @@
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,23 +504,11 @@
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 ), \
ras.cell->area = ADD_INT( ras.cell->area, (a) * (TArea)(b) )
@@ -553,7 +538,7 @@
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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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;