[libpng16] Avoid filter-selection heuristic sum calculations in cases where

only one filter is a candidate for selection. This trades off code size (added
png_setup_*_row_only() functions) for speed.
diff --git a/ANNOUNCE b/ANNOUNCE
index da4eebe..f506c83 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -45,6 +45,9 @@
     implemented in 1.7), however a simple safe fix here is to chose the lowest
     numbered filter in the list from png_set_filter (this only works if the
     first problem is also fixed) (John Bowler).
+  Avoid filter-selection heuristic sum calculations in cases where only one
+    filter is a candidate for selection. This trades off code size (added
+    png_setup_*_row_only() functions) for speed.
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
 (subscription required; visit
diff --git a/CHANGES b/CHANGES
index 2fc0222..ee7c0d5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -5616,6 +5616,9 @@
     implemented in 1.7), however a simple safe fix here is to chose the lowest
     numbered filter in the list from png_set_filter (this only works if the
     first problem is also fixed) (John Bowler).
+  Avoid filter-selection heuristic sum calculations in cases where only one
+    filter is a candidate for selection. This trades off code size (added
+    png_setup_*_row_only() functions) for speed.
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
 (subscription required; visit
diff --git a/pngwutil.c b/pngwutil.c
index 2e4d1a5..30b0a97 100644
--- a/pngwutil.c
+++ b/pngwutil.c
@@ -2278,6 +2278,28 @@
    return (sum);
 }
 
+static void /* PRIVATE */
+png_setup_sub_row_only(png_structrp png_ptr, const png_uint_32 bpp,
+    const png_size_t row_bytes)
+{
+   png_bytep rp, dp, lp;
+   png_size_t i;
+
+   png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB;
+
+   for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp;
+        i++, rp++, dp++)
+   {
+      *dp = *rp;
+   }
+
+   for (lp = png_ptr->row_buf + 1; i < row_bytes;
+      i++, rp++, lp++, dp++)
+   {
+      *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+   }
+}
+
 static png_size_t /* PRIVATE */
 png_setup_up_row(png_structrp png_ptr, const png_size_t row_bytes,
     const png_size_t lmins)
@@ -2302,6 +2324,21 @@
 
    return (sum);
 }
+static void /* PRIVATE */
+png_setup_up_row_only(png_structrp png_ptr, const png_size_t row_bytes)
+{
+   png_bytep rp, dp, pp;
+   png_size_t i;
+
+   png_ptr->try_row[0] = PNG_FILTER_VALUE_UP;
+
+   for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+       pp = png_ptr->prev_row + 1; i < row_bytes;
+       i++, rp++, pp++, dp++)
+   {
+      *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
+   }
+}
 
 static png_size_t /* PRIVATE */
 png_setup_avg_row(png_structrp png_ptr, const png_uint_32 bpp,
@@ -2335,6 +2372,27 @@
 
    return (sum);
 }
+static void /* PRIVATE */
+png_setup_avg_row_only(png_structrp png_ptr, const png_uint_32 bpp,
+      const png_size_t row_bytes)
+{
+   png_bytep rp, dp, pp, lp;
+   png_uint_32 i;
+
+   png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG;
+
+   for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+        pp = png_ptr->prev_row + 1; i < bpp; i++)
+   {
+      *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
+   }
+
+   for (lp = png_ptr->row_buf + 1; i < row_bytes; i++)
+   {
+      *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
+          & 0xff);
+   }
+}
 
 static png_size_t /* PRIVATE */
 png_setup_paeth_row(png_structrp png_ptr, const png_uint_32 bpp,
@@ -2389,6 +2447,48 @@
 
    return (sum);
 }
+static void /* PRIVATE */
+png_setup_paeth_row_only(png_structrp png_ptr, const png_uint_32 bpp,
+    const png_size_t row_bytes)
+{
+   png_bytep rp, dp, pp, cp, lp;
+   png_size_t i;
+
+   png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH;
+
+   for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+       pp = png_ptr->prev_row + 1; i < bpp; i++)
+   {
+      *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
+   }
+
+   for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes;
+        i++)
+   {
+      int a, b, c, pa, pb, pc, p;
+
+      b = *pp++;
+      c = *cp++;
+      a = *lp++;
+
+      p = b - c;
+      pc = a - c;
+
+#ifdef PNG_USE_ABS
+      pa = abs(p);
+      pb = abs(pc);
+      pc = abs(p + pc);
+#else
+      pa = p < 0 ? -p : p;
+      pb = pc < 0 ? -pc : pc;
+      pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+      p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+
+      *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
+   }
+}
 #endif /* WRITE_FILTER */
 
 void /* PRIVATE */
@@ -2476,10 +2576,7 @@
    if (filter_to_do == PNG_FILTER_SUB)
    /* It's the only filter so no testing is needed */
    {
-      /* Passing PNG_SIZE_MAX here and below prevents the 'setup' function
-       * breaking out of the loop when lmins is exceeded.
-       */
-      (void) png_setup_sub_row(png_ptr, bpp, row_bytes, PNG_SIZE_MAX);
+      png_setup_sub_row_only(png_ptr, bpp, row_bytes);
       best_row = png_ptr->try_row;
    }
 
@@ -2505,7 +2602,7 @@
    /* Up filter */
    if (filter_to_do == PNG_FILTER_UP)
    {
-      (void) png_setup_up_row(png_ptr, row_bytes, PNG_SIZE_MAX);
+      png_setup_up_row_only(png_ptr, row_bytes);
       best_row = png_ptr->try_row;
    }
 
@@ -2531,7 +2628,7 @@
    /* Avg filter */
    if (filter_to_do == PNG_FILTER_AVG)
    {
-      (void) png_setup_avg_row(png_ptr, bpp, row_bytes, PNG_SIZE_MAX);
+      png_setup_avg_row_only(png_ptr, bpp, row_bytes);
       best_row = png_ptr->try_row;
    }
 
@@ -2557,7 +2654,7 @@
    /* Paeth filter */
    if ((filter_to_do == PNG_FILTER_PAETH) != 0)
    {
-      (void) png_setup_paeth_row(png_ptr, bpp, row_bytes, PNG_SIZE_MAX);
+      png_setup_paeth_row_only(png_ptr, bpp, row_bytes);
       best_row = png_ptr->try_row;
    }