Add FPDFText_GetTextObject() API

Add an API that maps (FPDF_TEXTPAGE, int /*page_index*/) to
FPDF_PAGEOBJECT. This will make it unnecessary to have both
FPDFText_Foo() and FPDFTextObject_Foo(). Use the new API to help replace
the experimental FPDFText_GetTextRenderMode() API. Convert the tests for
FPDFText_GetTextRenderMode() to use FPDFText_GetTextObject() and
FPDFTextObj_GetTextRenderMode() instead.

To make the implementation work without resorting to using const_cast(),
change several CPDF_PageObject pointers in CPDF_TextPage to be
non-const.

Bug: 353484288
Change-Id: I15cd83d3ff3d1c4fa07c8b0a98a7b798150f05fc
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/121790
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Tom Sepez <tsepez@google.com>
diff --git a/core/fpdftext/cpdf_textpage.cpp b/core/fpdftext/cpdf_textpage.cpp
index d7b2ff8..1e4b6de 100644
--- a/core/fpdftext/cpdf_textpage.cpp
+++ b/core/fpdftext/cpdf_textpage.cpp
@@ -473,12 +473,17 @@
 }
 
 const CPDF_TextPage::CharInfo& CPDF_TextPage::GetCharInfo(size_t index) const {
-  CHECK(index < m_CharList.size());
+  CHECK_LT(index, m_CharList.size());
+  return m_CharList[index];
+}
+
+CPDF_TextPage::CharInfo& CPDF_TextPage::GetCharInfo(size_t index) {
+  CHECK_LT(index, m_CharList.size());
   return m_CharList[index];
 }
 
 float CPDF_TextPage::GetCharFontSize(size_t index) const {
-  CHECK(index < m_CharList.size());
+  CHECK_LT(index, m_CharList.size());
   return GetFontSize(m_CharList[index].m_pTextObj);
 }
 
@@ -872,7 +877,7 @@
 }
 
 void CPDF_TextPage::ProcessMarkedContent(const TransformedTextObject& obj) {
-  const CPDF_TextObject* pTextObj = obj.m_pTextObj;
+  CPDF_TextObject* pTextObj = obj.m_pTextObj;
   const CPDF_ContentMarks* pMarks = pTextObj->GetContentMarks();
   const size_t nContentMarks = pMarks->CountItems();
   WideString actText;
@@ -950,7 +955,7 @@
 }
 
 void CPDF_TextPage::ProcessTextObject(const TransformedTextObject& obj) {
-  const CPDF_TextObject* pTextObj = obj.m_pTextObj;
+  CPDF_TextObject* pTextObj = obj.m_pTextObj;
   if (fabs(pTextObj->GetRect().Width()) < kSizeEpsilon)
     return;
 
diff --git a/core/fpdftext/cpdf_textpage.h b/core/fpdftext/cpdf_textpage.h
index 93c4080..5ec92c6 100644
--- a/core/fpdftext/cpdf_textpage.h
+++ b/core/fpdftext/cpdf_textpage.h
@@ -55,7 +55,7 @@
     CharType m_CharType = CharType::kNormal;
     CFX_PointF m_Origin;
     CFX_FloatRect m_CharBox;
-    UnownedPtr<const CPDF_TextObject> m_pTextObj;
+    UnownedPtr<CPDF_TextObject> m_pTextObj;
     CFX_Matrix m_Matrix;
   };
 
@@ -69,6 +69,7 @@
 
   // These methods CHECK() to make sure |index| is within bounds.
   const CharInfo& GetCharInfo(size_t index) const;
+  CharInfo& GetCharInfo(size_t index);
   float GetCharFontSize(size_t index) const;
   CFX_FloatRect GetCharLooseBounds(size_t index) const;
 
@@ -107,7 +108,7 @@
     TransformedTextObject(const TransformedTextObject& that);
     ~TransformedTextObject();
 
-    UnownedPtr<const CPDF_TextObject> m_pTextObj;
+    UnownedPtr<CPDF_TextObject> m_pTextObj;
     CFX_Matrix m_formMatrix;
   };
 
diff --git a/fpdfsdk/fpdf_text.cpp b/fpdfsdk/fpdf_text.cpp
index 79bed84..818ca40 100644
--- a/fpdfsdk/fpdf_text.cpp
+++ b/fpdfsdk/fpdf_text.cpp
@@ -74,6 +74,17 @@
   return charinfo.m_Unicode;
 }
 
+FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
+FPDFText_GetTextObject(FPDF_TEXTPAGE text_page, int index) {
+  CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
+  if (!textpage) {
+    return nullptr;
+  }
+
+  return FPDFPageObjectFromCPDFPageObject(
+      textpage->GetCharInfo(index).m_pTextObj);
+}
+
 FPDF_EXPORT int FPDF_CALLCONV FPDFText_IsGenerated(FPDF_TEXTPAGE text_page,
                                                    int index) {
   CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
@@ -153,20 +164,6 @@
   return charinfo.m_pTextObj->GetFont()->GetFontWeight();
 }
 
-FPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV
-FPDFText_GetTextRenderMode(FPDF_TEXTPAGE text_page, int index) {
-  CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
-  if (!textpage)
-    return FPDF_TEXTRENDERMODE_UNKNOWN;
-
-  const CPDF_TextPage::CharInfo& charinfo = textpage->GetCharInfo(index);
-  if (!charinfo.m_pTextObj)
-    return FPDF_TEXTRENDERMODE_UNKNOWN;
-
-  return static_cast<FPDF_TEXT_RENDERMODE>(
-      charinfo.m_pTextObj->GetTextRenderMode());
-}
-
 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
 FPDFText_GetFillColor(FPDF_TEXTPAGE text_page,
                       int index,
diff --git a/fpdfsdk/fpdf_text_embeddertest.cpp b/fpdfsdk/fpdf_text_embeddertest.cpp
index fc3f59b..a4c7ab9 100644
--- a/fpdfsdk/fpdf_text_embeddertest.cpp
+++ b/fpdfsdk/fpdf_text_embeddertest.cpp
@@ -1618,24 +1618,29 @@
   FPDF_PAGE page = LoadPage(0);
   ASSERT_TRUE(page);
 
-  FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
-  ASSERT_TRUE(text_page);
+  {
+    ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
+    ASSERT_TRUE(text_page);
 
-  ASSERT_EQ(12, FPDFText_CountChars(text_page));
+    ASSERT_EQ(12, FPDFText_CountChars(text_page.get()));
 
-  ASSERT_EQ(FPDF_TEXTRENDERMODE_UNKNOWN,
-            FPDFText_GetTextRenderMode(nullptr, 0));
-  ASSERT_EQ(FPDF_TEXTRENDERMODE_UNKNOWN,
-            FPDFText_GetTextRenderMode(text_page, -1));
-  ASSERT_EQ(FPDF_TEXTRENDERMODE_UNKNOWN,
-            FPDFText_GetTextRenderMode(text_page, 314));
+    ASSERT_FALSE(FPDFText_GetTextObject(nullptr, 0));
+    ASSERT_FALSE(FPDFText_GetTextObject(text_page.get(), -1));
+    ASSERT_FALSE(FPDFText_GetTextObject(text_page.get(), 314));
 
-  ASSERT_EQ(FPDF_TEXTRENDERMODE_FILL, FPDFText_GetTextRenderMode(text_page, 0));
+    FPDF_PAGEOBJECT text_object = FPDFText_GetTextObject(text_page.get(), 0);
+    ASSERT_TRUE(text_object);
+    ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object));
+    EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL,
+              FPDFTextObj_GetTextRenderMode(text_object));
 
-  ASSERT_EQ(FPDF_TEXTRENDERMODE_STROKE,
-            FPDFText_GetTextRenderMode(text_page, 7));
+    text_object = FPDFText_GetTextObject(text_page.get(), 7);
+    ASSERT_TRUE(text_object);
+    ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object));
+    EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE,
+              FPDFTextObj_GetTextRenderMode(text_object));
+  }
 
-  FPDFText_ClosePage(text_page);
   UnloadPage(page);
 }
 
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index 5042fcf..6ccea4e 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -439,7 +439,7 @@
     CHK(FPDFText_GetSchResultIndex);
     CHK(FPDFText_GetStrokeColor);
     CHK(FPDFText_GetText);
-    CHK(FPDFText_GetTextRenderMode);
+    CHK(FPDFText_GetTextObject);
     CHK(FPDFText_GetUnicode);
     CHK(FPDFText_HasUnicodeMapError);
     CHK(FPDFText_IsGenerated);
diff --git a/public/fpdf_text.h b/public/fpdf_text.h
index a3d666b..fe96ccd 100644
--- a/public/fpdf_text.h
+++ b/public/fpdf_text.h
@@ -75,6 +75,21 @@
 FPDFText_GetUnicode(FPDF_TEXTPAGE text_page, int index);
 
 // Experimental API.
+// Function: FPDFText_GetTextObject
+//          Get the FPDF_PAGEOBJECT associated with a given character.
+// Parameters:
+//          text_page   -   Handle to a text page information structure.
+//                          Returned by FPDFText_LoadPage function.
+//          index       -   Zero-based index of the character.
+// Return value:
+//          The associated text object for the character at |index|, or NULL on
+//          error. The returned text object, if non-null, is of type
+//          |FPDF_PAGEOBJ_TEXT|. The caller does not own the returned object.
+//
+FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
+FPDFText_GetTextObject(FPDF_TEXTPAGE text_page, int index);
+
+// Experimental API.
 // Function: FPDFText_IsGenerated
 //          Get if a character in a page is generated by PDFium.
 // Parameters:
@@ -175,22 +190,6 @@
                                                      int index);
 
 // Experimental API.
-// Function: FPDFText_GetTextRenderMode
-//          Get text rendering mode of character.
-// Parameters:
-//          text_page   -   Handle to a text page information structure.
-//                          Returned by FPDFText_LoadPage function.
-//          index       -   Zero-based index of the character.
-// Return Value:
-//          On success, return the render mode value. A valid value is of type
-//          FPDF_TEXT_RENDERMODE. If |text_page| is invalid, if |index| is out
-//          of bounds, or if the text object is undefined, then return
-//          FPDF_TEXTRENDERMODE_UNKNOWN.
-//
-FPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV
-FPDFText_GetTextRenderMode(FPDF_TEXTPAGE text_page, int index);
-
-// Experimental API.
 // Function: FPDFText_GetFillColor
 //          Get the fill color of a particular character.
 // Parameters: