CStretchEngine: Minimize PixelWeight bounds checks

CHECK() that we are always setting the start and end pixel range
within the allocated weight array. Then replace an expensive function
with one based on these values.

There is still some work in progressive_renderer.cpp before making all
members private.

Change-Id: Ibffc53b3e1c3706414a01b6e5e8f638f16e70643
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/81985
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxge/dib/cstretchengine.cpp b/core/fxge/dib/cstretchengine.cpp
index 85a293e..86d29ed 100644
--- a/core/fxge/dib/cstretchengine.cpp
+++ b/core/fxge/dib/cstretchengine.cpp
@@ -40,10 +40,6 @@
 
 CStretchEngine::CWeightTable::~CWeightTable() = default;
 
-size_t CStretchEngine::CWeightTable::GetPixelWeightCount() const {
-  return PixelWeight::WeightCountFromTotalBytes(m_ItemSizeBytes);
-}
-
 bool CStretchEngine::CWeightTable::Calc(int dest_len,
                                         int dest_min,
                                         int dest_max,
@@ -85,12 +81,13 @@
       PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel);
       double src_pos = dest_pixel * scale + scale / 2 + base;
       if (bilinear) {
-        pixel_weights.m_SrcStart =
+        int src_start =
             static_cast<int>(floor(static_cast<float>(src_pos) - 1.0f / 2));
-        pixel_weights.m_SrcEnd =
+        int src_end =
             static_cast<int>(floor(static_cast<float>(src_pos) + 1.0f / 2));
-        pixel_weights.m_SrcStart = std::max(pixel_weights.m_SrcStart, src_min);
-        pixel_weights.m_SrcEnd = std::min(pixel_weights.m_SrcEnd, src_max - 1);
+        src_start = std::max(src_start, src_min);
+        src_end = std::min(src_end, src_max - 1);
+        pixel_weights.SetStartEnd(src_start, src_end, weight_count);
         if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {
           pixel_weights.m_Weights[0] = kFixedPointOne;
         } else {
@@ -101,8 +98,9 @@
         }
       } else {
         int pixel_pos = static_cast<int>(floor(static_cast<float>(src_pos)));
-        pixel_weights.m_SrcStart = std::max(pixel_pos, src_min);
-        pixel_weights.m_SrcEnd = std::min(pixel_pos, src_max - 1);
+        int src_start = std::max(pixel_pos, src_min);
+        int src_end = std::min(pixel_pos, src_max - 1);
+        pixel_weights.SetStartEnd(src_start, src_end, weight_count);
         pixel_weights.m_Weights[0] = kFixedPointOne;
       }
     }
@@ -119,12 +117,10 @@
     end_i = std::min(end_i, src_max - 1);
     if (start_i > end_i) {
       start_i = std::min(start_i, src_max - 1);
-      pixel_weights.m_SrcStart = start_i;
-      pixel_weights.m_SrcEnd = start_i;
+      pixel_weights.SetStartEnd(start_i, start_i, weight_count);
       continue;
     }
-    pixel_weights.m_SrcStart = start_i;
-    pixel_weights.m_SrcEnd = end_i;
+    pixel_weights.SetStartEnd(start_i, end_i, weight_count);
     for (int j = start_i; j <= end_i; ++j) {
       double dest_start = (j - base) / scale;
       double dest_end = (j + 1 - base) / scale;
@@ -138,7 +134,7 @@
         break;
       }
       size_t idx = j - start_i;
-      if (idx >= GetPixelWeightCount())
+      if (idx >= weight_count)
         return false;
 
       pixel_weights.m_Weights[idx] = FixedFromFloat(weight);
@@ -154,16 +150,6 @@
       &m_WeightTables[(pixel - m_DestMin) * m_ItemSizeBytes]);
 }
 
-uint32_t CStretchEngine::CWeightTable::GetValueFromPixelWeight(
-    PixelWeight* pWeight,
-    int index) const {
-  if (index < pWeight->m_SrcStart)
-    return 0;
-
-  size_t idx = index - pWeight->m_SrcStart;
-  return idx < GetPixelWeightCount() ? pWeight->m_Weights[idx] : 0;
-}
-
 CStretchEngine::CStretchEngine(ScanlineComposerIface* pDestBitmap,
                                FXDIB_Format dest_format,
                                int dest_width,
@@ -321,8 +307,7 @@
           PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
           uint32_t dest_a = 0;
           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
-            uint32_t pixel_weight =
-                m_WeightTable.GetValueFromPixelWeight(pWeights, j);
+            uint32_t pixel_weight = pWeights->GetWeight(j);
             if (src_scan[j / 8] & (1 << (7 - j % 8)))
               dest_a += pixel_weight * 255;
           }
@@ -335,8 +320,7 @@
           PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
           uint32_t dest_a = 0;
           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
-            uint32_t pixel_weight =
-                m_WeightTable.GetValueFromPixelWeight(pWeights, j);
+            uint32_t pixel_weight = pWeights->GetWeight(j);
             dest_a += pixel_weight * src_scan[j];
           }
           *dest_scan++ = PixelFromFixed(dest_a);
@@ -349,8 +333,7 @@
           uint32_t dest_a = 0;
           uint32_t dest_r = 0;
           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
-            uint32_t pixel_weight =
-                m_WeightTable.GetValueFromPixelWeight(pWeights, j);
+            uint32_t pixel_weight = pWeights->GetWeight(j);
             pixel_weight = pixel_weight * src_scan_mask[j] / 255;
             dest_r += pixel_weight * src_scan[j];
             dest_a += pixel_weight;
@@ -367,8 +350,7 @@
           uint32_t dest_g = 0;
           uint32_t dest_b = 0;
           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
-            uint32_t pixel_weight =
-                m_WeightTable.GetValueFromPixelWeight(pWeights, j);
+            uint32_t pixel_weight = pWeights->GetWeight(j);
             unsigned long argb = m_pSrcPalette[src_scan[j]];
             if (m_DestFormat == FXDIB_Format::kRgb) {
               dest_r += pixel_weight * static_cast<uint8_t>(argb >> 16);
@@ -394,8 +376,7 @@
           uint32_t dest_g = 0;
           uint32_t dest_b = 0;
           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
-            uint32_t pixel_weight =
-                m_WeightTable.GetValueFromPixelWeight(pWeights, j);
+            uint32_t pixel_weight = pWeights->GetWeight(j);
             pixel_weight = pixel_weight * src_scan_mask[j] / 255;
             unsigned long argb = m_pSrcPalette[src_scan[j]];
             dest_b += pixel_weight * static_cast<uint8_t>(argb >> 24);
@@ -417,8 +398,7 @@
           uint32_t dest_g = 0;
           uint32_t dest_b = 0;
           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
-            uint32_t pixel_weight =
-                m_WeightTable.GetValueFromPixelWeight(pWeights, j);
+            uint32_t pixel_weight = pWeights->GetWeight(j);
             const uint8_t* src_pixel = src_scan + j * Bpp;
             dest_b += pixel_weight * (*src_pixel++);
             dest_g += pixel_weight * (*src_pixel++);
@@ -439,8 +419,7 @@
           uint32_t dest_g = 0;
           uint32_t dest_b = 0;
           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
-            uint32_t pixel_weight =
-                m_WeightTable.GetValueFromPixelWeight(pWeights, j);
+            uint32_t pixel_weight = pWeights->GetWeight(j);
             const uint8_t* src_pixel = src_scan + j * Bpp;
             if (m_DestFormat == FXDIB_Format::kArgb) {
               pixel_weight = pixel_weight * src_pixel[3] / 255;
@@ -494,7 +473,7 @@
               m_InterBuf.data() + (col - m_DestClip.left) * DestBpp;
           uint32_t dest_a = 0;
           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
-            uint32_t pixel_weight = table.GetValueFromPixelWeight(pWeights, j);
+            uint32_t pixel_weight = pWeights->GetWeight(j);
             dest_a +=
                 pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch];
           }
@@ -512,7 +491,7 @@
           uint32_t dest_a = 0;
           uint32_t dest_k = 0;
           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
-            uint32_t pixel_weight = table.GetValueFromPixelWeight(pWeights, j);
+            uint32_t pixel_weight = pWeights->GetWeight(j);
             dest_k +=
                 pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch];
             dest_a += pixel_weight *
@@ -533,7 +512,7 @@
           uint32_t dest_g = 0;
           uint32_t dest_b = 0;
           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
-            uint32_t pixel_weight = table.GetValueFromPixelWeight(pWeights, j);
+            uint32_t pixel_weight = pWeights->GetWeight(j);
             const uint8_t* src_pixel =
                 src_scan + (j - m_SrcClip.top) * m_InterPitch;
             dest_b += pixel_weight * (*src_pixel++);
@@ -560,7 +539,7 @@
           uint32_t dest_g = 0;
           uint32_t dest_b = 0;
           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
-            uint32_t pixel_weight = table.GetValueFromPixelWeight(pWeights, j);
+            uint32_t pixel_weight = pWeights->GetWeight(j);
             const uint8_t* src_pixel =
                 src_scan + (j - m_SrcClip.top) * m_InterPitch;
             int mask_v = 255;
diff --git a/core/fxge/dib/cstretchengine.h b/core/fxge/dib/cstretchengine.h
index 87153bc..e860014 100644
--- a/core/fxge/dib/cstretchengine.h
+++ b/core/fxge/dib/cstretchengine.h
@@ -60,9 +60,6 @@
           static_cast<const CWeightTable*>(this)->GetPixelWeight(pixel));
     }
 
-    uint32_t GetValueFromPixelWeight(PixelWeight* pWeight, int index) const;
-    size_t GetPixelWeightCount() const;
-
    private:
     int m_DestMin = 0;
     size_t m_ItemSizeBytes = 0;
diff --git a/core/fxge/dib/fx_dib.cpp b/core/fxge/dib/fx_dib.cpp
index 315388b..9bdc12d 100644
--- a/core/fxge/dib/fx_dib.cpp
+++ b/core/fxge/dib/fx_dib.cpp
@@ -47,13 +47,6 @@
   return total_bytes.ValueOrDie();
 }
 
-// static
-size_t PixelWeight::WeightCountFromTotalBytes(size_t total_bytes) {
-  const size_t extra_bytes =
-      total_bytes > sizeof(PixelWeight) ? total_bytes - sizeof(PixelWeight) : 0;
-  return 1 + extra_bytes / sizeof(m_Weights[0]);
-}
-
 FXDIB_ResampleOptions::FXDIB_ResampleOptions() = default;
 
 bool FXDIB_ResampleOptions::HasAnyOptions() const {
diff --git a/core/fxge/dib/fx_dib.h b/core/fxge/dib/fx_dib.h
index 4485176..fe05b98 100644
--- a/core/fxge/dib/fx_dib.h
+++ b/core/fxge/dib/fx_dib.h
@@ -13,6 +13,7 @@
 #include <utility>
 
 #include "core/fxcrt/fx_coordinates.h"
+#include "third_party/base/check_op.h"
 
 #if defined(PDF_ENABLE_XFA)
 #include "core/fxcrt/widestring.h"
@@ -31,10 +32,21 @@
 
 struct PixelWeight {
   static size_t TotalBytesForWeightCount(size_t weight_count);
-  static size_t WeightCountFromTotalBytes(size_t total_bytes);
+
+  void SetStartEnd(int src_start, int src_end, size_t weight_count) {
+    CHECK_LT(static_cast<size_t>(src_end - src_start), weight_count);
+    m_SrcStart = src_start;
+    m_SrcEnd = src_end;
+  }
+
+  uint32_t GetWeight(int pixel) const {
+    CHECK_GE(pixel, m_SrcStart);
+    CHECK_LE(pixel, m_SrcEnd);
+    return m_Weights[pixel - m_SrcStart];
+  }
 
   int m_SrcStart;
-  int m_SrcEnd;
+  int m_SrcEnd;           // Note: inclusive.
   uint32_t m_Weights[1];  // Not really 1, variable size.
 };