[smooth] Reduce copying during integration phase.

We now record `cover' and `area' directly into the linked list. This
makes rendering faster by 10% or even more at larger sizes.

* src/smooth/ftgrays.c (FT_INTEGRATE): Write directly.
(gray_TWorker): Add direct cell reference and remove unused fields.
(gray_set_cell): Consolidate the linked list management and pointers.
(gray_convert_glyph, gray_convert_glyph_inner): Updated.
diff --git a/ChangeLog b/ChangeLog
index bc4d291..ef2a65d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2021-03-11  Alexei Podtelezhnikov  <apodtele@gmail.com>
+
+	[smooth] Reduce copying during integration phase.
+
+	We now record `cover' and `area' directly into the linked list. This
+	makes rendering faster by 10% or even more at larger sizes.
+
+	* src/smooth/ftgrays.c (FT_INTEGRATE): Write directly.
+	(gray_TWorker): Add direct cell reference and remove unused fields.
+	(gray_set_cell): Consolidate the linked list management and pointers.
+	(gray_convert_glyph, gray_convert_glyph_inner): Updated.
+
 2021-03-10  Alexei Podtelezhnikov  <apodtele@gmail.com>
 
 	* src/smooth/ftgrays.c (FT_INTEGRATE): New convenience macro.
diff --git a/src/smooth/ftgrays.c b/src/smooth/ftgrays.c
index 5e3d453..8ea7230 100644
--- a/src/smooth/ftgrays.c
+++ b/src/smooth/ftgrays.c
@@ -447,14 +447,10 @@
   {
     ft_jmp_buf  jump_buffer;
 
-    TCoord  ex, ey;
     TCoord  min_ex, max_ex;
     TCoord  min_ey, max_ey;
 
-    TArea   area;
-    TCoord  cover;
-    int     invalid;
-
+    PCell       cell;
     PCell*      ycells;
     PCell       cells;
     FT_PtrDist  max_cells;
@@ -483,8 +479,9 @@
   static gray_TWorker  ras;
 #endif
 
-#define FT_INTEGRATE( ras, a, b )                         \
-           ras.cover += (a), ras.area += (a) * (TArea)(b)
+#define FT_INTEGRATE( ras, a, b )                                       \
+           if ( ras.cell )                                              \
+             ras.cell->cover += (a), ras.cell->area += (a) * (TArea)(b)
 
 
   typedef struct gray_TRaster_
@@ -523,59 +520,15 @@
 
   /**************************************************************************
    *
-   * Record the current cell in the linked list.
-   */
-  static void
-  gray_record_cell( RAS_ARG )
-  {
-    PCell  *pcell, cell;
-    TCoord  x = ras.ex;
-
-
-    pcell = &ras.ycells[ras.ey - ras.min_ey];
-    while ( ( cell = *pcell ) )
-    {
-      if ( cell->x > x )
-        break;
-
-      if ( cell->x == x )
-        goto Found;
-
-      pcell = &cell->next;
-    }
-
-    if ( ras.num_cells >= ras.max_cells )
-      ft_longjmp( ras.jump_buffer, 1 );
-
-    /* insert new cell */
-    cell        = ras.cells + ras.num_cells++;
-    cell->x     = x;
-    cell->area  = ras.area;
-    cell->cover = ras.cover;
-
-    cell->next  = *pcell;
-    *pcell      = cell;
-
-    return;
-
-  Found:
-    /* update old cell */
-    cell->area  += ras.area;
-    cell->cover += ras.cover;
-  }
-
-
-  /**************************************************************************
-   *
    * 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:                       */
+    /* 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     */
@@ -583,17 +536,42 @@
     /* Note that if a cell is to the left of the clipping region, it is    */
     /* actually set to the (min_ex-1) horizontal position.                 */
 
-    /* record the current one if it is valid and substantial */
-    if ( !ras.invalid && ( ras.area || ras.cover ) )
-      gray_record_cell( RAS_VAR );
+    if ( ey >= ras.max_ey || ey < ras.min_ey || ex >= ras.max_ex )
+      ras.cell = NULL;
+    else
+    {
+      PCell  *pcell, cell;
 
-    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 );
+      ex = FT_MAX( ex, ras.min_ex - 1 );
+
+      pcell = &ras.ycells[ey - ras.min_ey];
+      while ( ( cell = *pcell ) )
+      {
+        if ( cell->x > ex )
+          break;
+
+        if ( cell->x == ex )
+          goto Found;
+
+        pcell = &cell->next;
+      }
+
+      if ( ras.num_cells >= ras.max_cells )
+        ft_longjmp( ras.jump_buffer, 1 );
+
+      /* insert new cell */
+      cell        = ras.cells + ras.num_cells++;
+      cell->x     = ex;
+      cell->area  = 0;
+      cell->cover = 0;
+
+      cell->next  = *pcell;
+      *pcell      = cell;
+
+    Found:
+      ras.cell = cell;
+    }
   }
 
 
@@ -1631,9 +1609,6 @@
       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,
@@ -1702,7 +1677,7 @@
         FT_MEM_ZERO( ras.ycells, height * sizeof ( PCell ) );
 
         ras.num_cells = 0;
-        ras.invalid   = 1;
+        ras.cell      = NULL;
         ras.min_ey    = band[1];
         ras.max_ey    = band[0];