Introduce CPDF_Array::Find().

Then implement Contains() in terms of Find(). Then use it in one place,
and avoid some casting.

Change-Id: I28225ca94c4544914aaac6a43c7661a7e30ab60f
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/87390
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_array.cpp b/core/fpdfapi/parser/cpdf_array.cpp
index 10d8538..708e677 100644
--- a/core/fpdfapi/parser/cpdf_array.cpp
+++ b/core/fpdfapi/parser/cpdf_array.cpp
@@ -88,12 +88,16 @@
                     GetNumberAt(3), GetNumberAt(4), GetNumberAt(5));
 }
 
-bool CPDF_Array::Contains(const CPDF_Object* pThat) const {
-  for (size_t i = 0; i < m_Objects.size(); ++i) {
+absl::optional<size_t> CPDF_Array::Find(const CPDF_Object* pThat) const {
+  for (size_t i = 0; i < size(); ++i) {
     if (GetDirectObjectAt(i) == pThat)
-      return true;
+      return i;
   }
-  return false;
+  return absl::nullopt;
+}
+
+bool CPDF_Array::Contains(const CPDF_Object* pThat) const {
+  return Find(pThat).has_value();
 }
 
 CPDF_Object* CPDF_Array::GetObjectAt(size_t index) {
diff --git a/core/fpdfapi/parser/cpdf_array.h b/core/fpdfapi/parser/cpdf_array.h
index 5c0c255..6761a97 100644
--- a/core/fpdfapi/parser/cpdf_array.h
+++ b/core/fpdfapi/parser/cpdf_array.h
@@ -7,6 +7,8 @@
 #ifndef CORE_FPDFAPI_PARSER_CPDF_ARRAY_H_
 #define CORE_FPDFAPI_PARSER_CPDF_ARRAY_H_
 
+#include <stddef.h>
+
 #include <set>
 #include <type_traits>
 #include <utility>
@@ -16,6 +18,7 @@
 #include "core/fpdfapi/parser/cpdf_object.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/retain_ptr.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/base/check.h"
 
 // Arrays never contain nullptrs for objects within bounds, but some of the
@@ -69,6 +72,7 @@
   CFX_FloatRect GetRect() const;
   CFX_Matrix GetMatrix() const;
 
+  absl::optional<size_t> Find(const CPDF_Object* pThat) const;
   bool Contains(const CPDF_Object* pThat) const;
 
   // Creates object owned by the array, returns unowned pointer to it.
diff --git a/core/fpdfapi/parser/cpdf_array_unittest.cpp b/core/fpdfapi/parser/cpdf_array_unittest.cpp
index a70599d..72621e2 100644
--- a/core/fpdfapi/parser/cpdf_array_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_array_unittest.cpp
@@ -189,6 +189,29 @@
   }
 }
 
+TEST(cpdf_array, Find) {
+  auto arr = pdfium::MakeRetain<CPDF_Array>();
+  auto dict0 = pdfium::MakeRetain<CPDF_Dictionary>();
+  auto dict1 = pdfium::MakeRetain<CPDF_Dictionary>();
+  auto dict2 = pdfium::MakeRetain<CPDF_Dictionary>();
+  arr->Append(dict0);
+  arr->Append(dict1);
+
+  absl::optional<size_t> maybe_found = arr->Find(nullptr);
+  EXPECT_FALSE(maybe_found.has_value());
+
+  maybe_found = arr->Find(dict0.Get());
+  ASSERT_TRUE(maybe_found.has_value());
+  EXPECT_EQ(0u, maybe_found.value());
+
+  maybe_found = arr->Find(dict1.Get());
+  ASSERT_TRUE(maybe_found.has_value());
+  EXPECT_EQ(1u, maybe_found.value());
+
+  maybe_found = arr->Find(dict2.Get());
+  EXPECT_FALSE(maybe_found.has_value());
+}
+
 TEST(cpdf_array, Contains) {
   auto arr = pdfium::MakeRetain<CPDF_Array>();
   auto dict0 = pdfium::MakeRetain<CPDF_Dictionary>();
diff --git a/core/fpdfdoc/cpdf_interactiveform.cpp b/core/fpdfdoc/cpdf_interactiveform.cpp
index 16cc1dd..e50f7e1 100644
--- a/core/fpdfdoc/cpdf_interactiveform.cpp
+++ b/core/fpdfdoc/cpdf_interactiveform.cpp
@@ -30,8 +30,10 @@
 #include "core/fxcrt/fx_codepage.h"
 #include "core/fxge/cfx_substfont.h"
 #include "core/fxge/fx_font.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/base/check.h"
 #include "third_party/base/containers/contains.h"
+#include "third_party/base/numerics/safe_conversions.h"
 
 namespace {
 
@@ -698,19 +700,18 @@
 
 int CPDF_InteractiveForm::FindFieldInCalculationOrder(
     const CPDF_FormField* pField) {
-  if (!m_pFormDict || !pField)
+  if (!m_pFormDict)
     return -1;
 
   CPDF_Array* pArray = m_pFormDict->GetArrayFor("CO");
   if (!pArray)
     return -1;
 
-  for (size_t i = 0; i < pArray->size(); i++) {
-    CPDF_Object* pElement = pArray->GetDirectObjectAt(i);
-    if (pElement == pField->GetDict())
-      return i;
-  }
-  return -1;
+  absl::optional<size_t> maybe_found = pArray->Find(pField->GetDict());
+  if (!maybe_found.has_value())
+    return -1;
+
+  return pdfium::base::checked_cast<int>(maybe_found.value());
 }
 
 RetainPtr<CPDF_Font> CPDF_InteractiveForm::GetFormFont(
diff --git a/fxjs/cjs_field.cpp b/fxjs/cjs_field.cpp
index bf23543..aef9db0 100644
--- a/fxjs/cjs_field.cpp
+++ b/fxjs/cjs_field.cpp
@@ -950,8 +950,8 @@
 
   CPDFSDK_InteractiveForm* pRDForm = m_pFormFillEnv->GetInteractiveForm();
   CPDF_InteractiveForm* pForm = pRDForm->GetInteractiveForm();
-  return CJS_Result::Success(pRuntime->NewNumber(
-      static_cast<int32_t>(pForm->FindFieldInCalculationOrder(pFormField))));
+  return CJS_Result::Success(
+      pRuntime->NewNumber(pForm->FindFieldInCalculationOrder(pFormField)));
 }
 
 CJS_Result CJS_Field::set_calc_order_index(CJS_Runtime* pRuntime,