Use span<float> in CPDF_Function::v_Call().

Get some better bounds checking as a result.

-- Use Optional in place of out param.
-- Prefer std::fill(0.0f) over memset(0) for float arrays.

Change-Id: I982345a3099f7e9c06dd2c909e415a6c27007587
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/82550
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_colorspace.cpp b/core/fpdfapi/page/cpdf_colorspace.cpp
index c8ca89d..49c687a 100644
--- a/core/fpdfapi/page/cpdf_colorspace.cpp
+++ b/core/fpdfapi/page/cpdf_colorspace.cpp
@@ -1284,9 +1284,8 @@
 
   // Using at least 16 elements due to the call m_pAltCS->GetRGB() below.
   std::vector<float> results(std::max(m_pFunc->CountOutputs(), 16u));
-  int nresults = 0;
-  if (!m_pFunc->Call(pBuf.data(), 1, results.data(), &nresults) ||
-      nresults == 0)
+  uint32_t nresults = m_pFunc->Call(pBuf.first(1), results).value_or(0);
+  if (nresults == 0)
     return false;
 
   if (m_pAltCS)
@@ -1352,12 +1351,12 @@
 
   // Using at least 16 elements due to the call m_pAltCS->GetRGB() below.
   std::vector<float> results(std::max(m_pFunc->CountOutputs(), 16u));
-  int nresults = 0;
-  if (!m_pFunc->Call(pBuf.data(), CountComponents(), results.data(),
-                     &nresults) ||
-      nresults == 0) {
+  uint32_t nresults =
+      m_pFunc->Call(pBuf.first(CountComponents()), pdfium::make_span(results))
+          .value_or(0);
+
+  if (nresults == 0)
     return false;
-  }
 
   return m_pAltCS->GetRGB(results, R, G, B);
 }
diff --git a/core/fpdfapi/page/cpdf_expintfunc.cpp b/core/fpdfapi/page/cpdf_expintfunc.cpp
index 0e946f5..08afb91 100644
--- a/core/fpdfapi/page/cpdf_expintfunc.cpp
+++ b/core/fpdfapi/page/cpdf_expintfunc.cpp
@@ -53,7 +53,8 @@
   return true;
 }
 
-bool CPDF_ExpIntFunc::v_Call(const float* inputs, float* results) const {
+bool CPDF_ExpIntFunc::v_Call(pdfium::span<const float> inputs,
+                             pdfium::span<float> results) const {
   for (uint32_t i = 0; i < m_nInputs; i++) {
     for (uint32_t j = 0; j < m_nOrigOutputs; j++) {
       results[i * m_nOrigOutputs + j] =
diff --git a/core/fpdfapi/page/cpdf_expintfunc.h b/core/fpdfapi/page/cpdf_expintfunc.h
index be29695..c31ad8b 100644
--- a/core/fpdfapi/page/cpdf_expintfunc.h
+++ b/core/fpdfapi/page/cpdf_expintfunc.h
@@ -17,10 +17,11 @@
   CPDF_ExpIntFunc();
   ~CPDF_ExpIntFunc() override;
 
-  // CPDF_Function
+  // CPDF_Function:
   bool v_Init(const CPDF_Object* pObj,
               std::set<const CPDF_Object*>* pVisited) override;
-  bool v_Call(const float* inputs, float* results) const override;
+  bool v_Call(pdfium::span<const float> inputs,
+              pdfium::span<float> results) const override;
 
   uint32_t GetOrigOutputs() const { return m_nOrigOutputs; }
   float GetExponent() const { return m_Exponent; }
diff --git a/core/fpdfapi/page/cpdf_function.cpp b/core/fpdfapi/page/cpdf_function.cpp
index a8c6463..feafc5c 100644
--- a/core/fpdfapi/page/cpdf_function.cpp
+++ b/core/fpdfapi/page/cpdf_function.cpp
@@ -126,30 +126,27 @@
   return true;
 }
 
-bool CPDF_Function::Call(const float* inputs,
-                         uint32_t ninputs,
-                         float* results,
-                         int* nresults) const {
-  if (m_nInputs != ninputs)
-    return false;
+Optional<uint32_t> CPDF_Function::Call(pdfium::span<const float> inputs,
+                                       pdfium::span<float> results) const {
+  if (m_nInputs != inputs.size())
+    return pdfium::nullopt;
 
-  *nresults = m_nOutputs;
   std::vector<float> clamped_inputs(m_nInputs);
   for (uint32_t i = 0; i < m_nInputs; i++) {
     clamped_inputs[i] =
         pdfium::clamp(inputs[i], m_Domains[i * 2], m_Domains[i * 2 + 1]);
   }
-  if (!v_Call(clamped_inputs.data(), results))
-    return false;
+  if (!v_Call(clamped_inputs, results))
+    return pdfium::nullopt;
 
   if (m_Ranges.empty())
-    return true;
+    return m_nOutputs;
 
   for (uint32_t i = 0; i < m_nOutputs; i++) {
     results[i] =
         pdfium::clamp(results[i], m_Ranges[i * 2], m_Ranges[i * 2 + 1]);
   }
-  return true;
+  return m_nOutputs;
 }
 
 // See PDF Reference 1.7, page 170.
diff --git a/core/fpdfapi/page/cpdf_function.h b/core/fpdfapi/page/cpdf_function.h
index 03c21aa..7b6fcc3 100644
--- a/core/fpdfapi/page/cpdf_function.h
+++ b/core/fpdfapi/page/cpdf_function.h
@@ -11,6 +11,9 @@
 #include <set>
 #include <vector>
 
+#include "third_party/base/optional.h"
+#include "third_party/base/span.h"
+
 class CPDF_ExpIntFunc;
 class CPDF_Object;
 class CPDF_SampledFunc;
@@ -31,10 +34,8 @@
 
   virtual ~CPDF_Function();
 
-  bool Call(const float* inputs,
-            uint32_t ninputs,
-            float* results,
-            int* nresults) const;
+  Optional<uint32_t> Call(pdfium::span<const float> inputs,
+                          pdfium::span<float> results) const;
   uint32_t CountInputs() const { return m_nInputs; }
   uint32_t CountOutputs() const { return m_nOutputs; }
   float GetDomain(int i) const { return m_Domains[i]; }
@@ -60,7 +61,8 @@
   bool Init(const CPDF_Object* pObj, std::set<const CPDF_Object*>* pVisited);
   virtual bool v_Init(const CPDF_Object* pObj,
                       std::set<const CPDF_Object*>* pVisited) = 0;
-  virtual bool v_Call(const float* inputs, float* results) const = 0;
+  virtual bool v_Call(pdfium::span<const float> inputs,
+                      pdfium::span<float> results) const = 0;
 
   const Type m_Type;
   uint32_t m_nInputs;
diff --git a/core/fpdfapi/page/cpdf_meshstream.cpp b/core/fpdfapi/page/cpdf_meshstream.cpp
index 7d7085f..60759f0 100644
--- a/core/fpdfapi/page/cpdf_meshstream.cpp
+++ b/core/fpdfapi/page/cpdf_meshstream.cpp
@@ -203,10 +203,9 @@
   }
 
   float result[kMaxComponents] = {};
-  int nResults;
   for (const auto& func : m_funcs) {
     if (func && func->CountOutputs() <= kMaxComponents)
-      func->Call(color_value, 1, result, &nResults);
+      func->Call(pdfium::make_span(color_value, 1), result);
   }
 
   m_pCS->GetRGB(result, &r, &g, &b);
diff --git a/core/fpdfapi/page/cpdf_psfunc.cpp b/core/fpdfapi/page/cpdf_psfunc.cpp
index f4d00dc..b365cee 100644
--- a/core/fpdfapi/page/cpdf_psfunc.cpp
+++ b/core/fpdfapi/page/cpdf_psfunc.cpp
@@ -20,7 +20,8 @@
   return m_PS.Parse(pAcc->GetSpan());
 }
 
-bool CPDF_PSFunc::v_Call(const float* inputs, float* results) const {
+bool CPDF_PSFunc::v_Call(pdfium::span<const float> inputs,
+                         pdfium::span<float> results) const {
   m_PS.Reset();
   for (uint32_t i = 0; i < m_nInputs; i++)
     m_PS.Push(inputs[i]);
diff --git a/core/fpdfapi/page/cpdf_psfunc.h b/core/fpdfapi/page/cpdf_psfunc.h
index b81c2e7..8fb454f 100644
--- a/core/fpdfapi/page/cpdf_psfunc.h
+++ b/core/fpdfapi/page/cpdf_psfunc.h
@@ -19,10 +19,11 @@
   CPDF_PSFunc();
   ~CPDF_PSFunc() override;
 
-  // CPDF_Function
+  // CPDF_Function:
   bool v_Init(const CPDF_Object* pObj,
               std::set<const CPDF_Object*>* pVisited) override;
-  bool v_Call(const float* inputs, float* results) const override;
+  bool v_Call(pdfium::span<const float> inputs,
+              pdfium::span<float> results) const override;
 
  private:
   mutable CPDF_PSEngine m_PS;  // Pre-initialized scratch space for v_Call().
diff --git a/core/fpdfapi/page/cpdf_sampledfunc.cpp b/core/fpdfapi/page/cpdf_sampledfunc.cpp
index 297ffd0..9cd764c 100644
--- a/core/fpdfapi/page/cpdf_sampledfunc.cpp
+++ b/core/fpdfapi/page/cpdf_sampledfunc.cpp
@@ -99,7 +99,8 @@
   return true;
 }
 
-bool CPDF_SampledFunc::v_Call(const float* inputs, float* results) const {
+bool CPDF_SampledFunc::v_Call(pdfium::span<const float> inputs,
+                              pdfium::span<float> results) const {
   int pos = 0;
   CFX_FixedBufGrow<float, 16> encoded_input_buf(m_nInputs);
   float* encoded_input = encoded_input_buf;
diff --git a/core/fpdfapi/page/cpdf_sampledfunc.h b/core/fpdfapi/page/cpdf_sampledfunc.h
index fa129ac..f9d226b 100644
--- a/core/fpdfapi/page/cpdf_sampledfunc.h
+++ b/core/fpdfapi/page/cpdf_sampledfunc.h
@@ -31,10 +31,11 @@
   CPDF_SampledFunc();
   ~CPDF_SampledFunc() override;
 
-  // CPDF_Function
+  // CPDF_Function:
   bool v_Init(const CPDF_Object* pObj,
               std::set<const CPDF_Object*>* pVisited) override;
-  bool v_Call(const float* inputs, float* results) const override;
+  bool v_Call(pdfium::span<const float> inputs,
+              pdfium::span<float> results) const override;
 
   const std::vector<SampleEncodeInfo>& GetEncodeInfo() const {
     return m_EncodeInfo;
diff --git a/core/fpdfapi/page/cpdf_stitchfunc.cpp b/core/fpdfapi/page/cpdf_stitchfunc.cpp
index 4f55048..737ff5f 100644
--- a/core/fpdfapi/page/cpdf_stitchfunc.cpp
+++ b/core/fpdfapi/page/cpdf_stitchfunc.cpp
@@ -105,7 +105,8 @@
   return true;
 }
 
-bool CPDF_StitchFunc::v_Call(const float* inputs, float* results) const {
+bool CPDF_StitchFunc::v_Call(pdfium::span<const float> inputs,
+                             pdfium::span<float> results) const {
   float input = inputs[0];
   size_t i;
   for (i = 0; i < m_pSubFunctions.size() - 1; i++) {
@@ -114,7 +115,7 @@
   }
   input = Interpolate(input, m_bounds[i], m_bounds[i + 1], m_encode[i * 2],
                       m_encode[i * 2 + 1]);
-  int nresults;
-  return m_pSubFunctions[i]->Call(&input, kRequiredNumInputs, results,
-                                  &nresults);
+  return m_pSubFunctions[i]
+      ->Call(pdfium::make_span(&input, 1), results)
+      .has_value();
 }
diff --git a/core/fpdfapi/page/cpdf_stitchfunc.h b/core/fpdfapi/page/cpdf_stitchfunc.h
index 761c9ba..c6f3e36 100644
--- a/core/fpdfapi/page/cpdf_stitchfunc.h
+++ b/core/fpdfapi/page/cpdf_stitchfunc.h
@@ -18,10 +18,11 @@
   CPDF_StitchFunc();
   ~CPDF_StitchFunc() override;
 
-  // CPDF_Function
+  // CPDF_Function:
   bool v_Init(const CPDF_Object* pObj,
               std::set<const CPDF_Object*>* pVisited) override;
-  bool v_Call(const float* inputs, float* results) const override;
+  bool v_Call(pdfium::span<const float> inputs,
+              pdfium::span<float> results) const override;
 
   const std::vector<std::unique_ptr<CPDF_Function>>& GetSubFunctions() const {
     return m_pSubFunctions;
diff --git a/core/fpdfapi/render/cpdf_docrenderdata.cpp b/core/fpdfapi/render/cpdf_docrenderdata.cpp
index 69af157..5e3e070 100644
--- a/core/fpdfapi/render/cpdf_docrenderdata.cpp
+++ b/core/fpdfapi/render/cpdf_docrenderdata.cpp
@@ -6,6 +6,7 @@
 
 #include "core/fpdfapi/render/cpdf_docrenderdata.h"
 
+#include <algorithm>
 #include <array>
 #include <memory>
 #include <utility>
@@ -79,9 +80,8 @@
       return nullptr;
   }
 
-  int noutput;
   float output[kMaxOutputs];
-  memset(output, 0, sizeof(output));
+  std::fill(std::begin(output), std::end(output), 0.0f);
 
   bool bIdentity = true;
   std::vector<uint8_t, FxAllocAllocator<uint8_t>> samples_r(
@@ -100,7 +100,7 @@
           samples[i][v] = v;
           continue;
         }
-        pFuncs[i]->Call(&input, 1, output, &noutput);
+        pFuncs[i]->Call(pdfium::make_span(&input, 1), output);
         size_t o = FXSYS_roundf(output[0] * 255);
         if (o != v)
           bIdentity = false;
@@ -109,7 +109,7 @@
       continue;
     }
     if (pFuncs[0]->CountOutputs() <= kMaxOutputs)
-      pFuncs[0]->Call(&input, 1, output, &noutput);
+      pFuncs[0]->Call(pdfium::make_span(&input, 1), output);
     size_t o = FXSYS_roundf(output[0] * 255);
     if (o != v)
       bIdentity = false;
diff --git a/core/fpdfapi/render/cpdf_rendershading.cpp b/core/fpdfapi/render/cpdf_rendershading.cpp
index 8fb867b..bf012f5 100644
--- a/core/fpdfapi/render/cpdf_rendershading.cpp
+++ b/core/fpdfapi/render/cpdf_rendershading.cpp
@@ -69,13 +69,14 @@
   float diff = t_max - t_min;
   for (int i = 0; i < kShadingSteps; ++i) {
     float input = diff * i / kShadingSteps + t_min;
-    int offset = 0;
+    pdfium::span<float> result_span = pdfium::make_span(result_array);
     for (const auto& func : funcs) {
-      if (func) {
-        int nresults = 0;
-        if (func->Call(&input, 1, &result_array[offset], &nresults))
-          offset += nresults;
-      }
+      if (!func)
+        continue;
+      Optional<uint32_t> nresults =
+          func->Call(pdfium::make_span(&input, 1), result_span);
+      if (nresults.has_value())
+        result_span = result_span.subspan(nresults.value());
     }
     float R = 0.0f;
     float G = 0.0f;
@@ -295,16 +296,15 @@
       if (pos.x < xmin || pos.x > xmax || pos.y < ymin || pos.y > ymax)
         continue;
 
-      float input[] = {pos.x, pos.y};
-      int offset = 0;
+      float input[2] = {pos.x, pos.y};
+      pdfium::span<float> result_span = pdfium::make_span(result_array);
       for (const auto& func : funcs) {
-        if (func) {
-          int nresults;
-          if (func->Call(input, 2, &result_array[offset], &nresults))
-            offset += nresults;
-        }
+        if (!func)
+          continue;
+        Optional<uint32_t> nresults = func->Call(input, result_span);
+        if (nresults.has_value())
+          result_span = result_span.subspan(nresults.value());
       }
-
       float R = 0.0f;
       float G = 0.0f;
       float B = 0.0f;
diff --git a/core/fpdfapi/render/cpdf_renderstatus.cpp b/core/fpdfapi/render/cpdf_renderstatus.cpp
index ea817a2..afecf66 100644
--- a/core/fpdfapi/render/cpdf_renderstatus.cpp
+++ b/core/fpdfapi/render/cpdf_renderstatus.cpp
@@ -1448,8 +1448,7 @@
     std::vector<float> results(pFunc->CountOutputs());
     for (size_t i = 0; i < transfers.size(); ++i) {
       float input = i / 255.0f;
-      int nresult;
-      pFunc->Call(&input, 1, results.data(), &nresult);
+      pFunc->Call(pdfium::make_span(&input, 1), results);
       transfers[i] = FXSYS_roundf(results[0] * 255);
     }
   } else {