Push some page object logic back into appropriate files.

Avoids having the font/ layer do too much work itself.

- Rename LoadBitmap() to indicate it only covers a special case.
- Use incomplete type for CPDF_Image in header file.

Change-Id: I2d7c7547fd659b6da72a449997dd141eb8118426
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/57690
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/font/cpdf_type3char.cpp b/core/fpdfapi/font/cpdf_type3char.cpp
index 1e3ff65..96c9b30 100644
--- a/core/fpdfapi/font/cpdf_type3char.cpp
+++ b/core/fpdfapi/font/cpdf_type3char.cpp
@@ -36,33 +36,19 @@
   pRect->Scale(kTextUnitInGlyphUnit);
 }
 
-bool CPDF_Type3Char::LoadBitmap() {
+bool CPDF_Type3Char::LoadBitmapFromSoleImageOfForm() {
   if (m_pBitmap || !m_pForm)
     return true;
 
-  if (m_pForm->GetPageObjectCount() != 1 || m_bColored)
+  if (m_bColored)
     return false;
 
-  auto& pPageObj = *m_pForm->begin();
-  if (!pPageObj->IsImage())
+  const CPDF_ImageObject* pImageObject = m_pForm->GetSoleImageOfForm();
+  if (!pImageObject)
     return false;
 
-  m_ImageMatrix = pPageObj->AsImage()->matrix();
-  {
-    // |pSource| actually gets assigned a CPDF_DIBBase, which has pointers
-    // into objects owned by |m_pForm|. Make sure it is out of scope before
-    // clearing the form.
-    RetainPtr<CFX_DIBBase> pSource =
-        pPageObj->AsImage()->GetImage()->LoadDIBBase();
-
-    // Clone() is non-virtual, and can't be overloaded by CPDF_DIBBase to
-    // return a clone of the subclass as one would typically expect from a
-    // such a method. Instead, it only clones the CFX_DIBBase, none of whose
-    // members point to objects owned by the form. As a result, |m_pBitmap|
-    // may outlive |m_pForm|.
-    if (pSource)
-      m_pBitmap = pSource->Clone(nullptr);
-  }
+  m_ImageMatrix = pImageObject->matrix();
+  m_pBitmap = pImageObject->GetIndependentBitmap();
   m_pForm.reset();
   return true;
 }
diff --git a/core/fpdfapi/font/cpdf_type3char.h b/core/fpdfapi/font/cpdf_type3char.h
index 784332d..bcf94da 100644
--- a/core/fpdfapi/font/cpdf_type3char.h
+++ b/core/fpdfapi/font/cpdf_type3char.h
@@ -24,7 +24,7 @@
   static float TextUnitToGlyphUnit(float fTextUnit);
   static void TextUnitRectToGlyphUnitRect(CFX_FloatRect* pRect);
 
-  bool LoadBitmap();
+  bool LoadBitmapFromSoleImageOfForm();
   void InitializeFromStreamData(bool bColored, const float* pData);
   void Transform(CPDF_Form* pForm, const CFX_Matrix& matrix);
 
diff --git a/core/fpdfapi/page/cpdf_form.cpp b/core/fpdfapi/page/cpdf_form.cpp
index 31b4133..a30087a 100644
--- a/core/fpdfapi/page/cpdf_form.cpp
+++ b/core/fpdfapi/page/cpdf_form.cpp
@@ -7,6 +7,7 @@
 #include "core/fpdfapi/page/cpdf_form.h"
 
 #include "core/fpdfapi/page/cpdf_contentparser.h"
+#include "core/fpdfapi/page/cpdf_imageobject.h"
 #include "core/fpdfapi/page/cpdf_pageobject.h"
 #include "core/fpdfapi/page/cpdf_pageobjectholder.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
@@ -69,3 +70,7 @@
 const CPDF_Stream* CPDF_Form::GetStream() const {
   return m_pFormStream.Get();
 }
+
+const CPDF_ImageObject* CPDF_Form::GetSoleImageOfForm() const {
+  return GetPageObjectCount() == 1 ? (*begin())->AsImage() : nullptr;
+}
diff --git a/core/fpdfapi/page/cpdf_form.h b/core/fpdfapi/page/cpdf_form.h
index 1fe0ae2..9719476 100644
--- a/core/fpdfapi/page/cpdf_form.h
+++ b/core/fpdfapi/page/cpdf_form.h
@@ -16,6 +16,7 @@
 class CPDF_AllStates;
 class CPDF_Dictionary;
 class CPDF_Document;
+class CPDF_ImageObject;
 class CPDF_Stream;
 class CPDF_Type3Char;
 
@@ -42,9 +43,11 @@
 
   const CPDF_Stream* GetStream() const;
 
+  // Fast path helper for avoiding a full rendering of form.
+  const CPDF_ImageObject* GetSoleImageOfForm() const;
+
  private:
   std::unique_ptr<std::set<const uint8_t*>> m_ParsedSet;
-
   RetainPtr<CPDF_Stream> const m_pFormStream;
 };
 
diff --git a/core/fpdfapi/page/cpdf_imageobject.cpp b/core/fpdfapi/page/cpdf_imageobject.cpp
index ed12465..e1c8520 100644
--- a/core/fpdfapi/page/cpdf_imageobject.cpp
+++ b/core/fpdfapi/page/cpdf_imageobject.cpp
@@ -12,6 +12,8 @@
 #include "core/fpdfapi/page/cpdf_image.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
+#include "core/fxge/dib/cfx_dibbase.h"
+#include "core/fxge/dib/cfx_dibitmap.h"
 
 CPDF_ImageObject::CPDF_ImageObject(int32_t content_stream)
     : CPDF_PageObject(content_stream) {}
@@ -54,6 +56,21 @@
   m_pImage = pImage;
 }
 
+RetainPtr<CPDF_Image> CPDF_ImageObject::GetImage() const {
+  return m_pImage;
+}
+
+RetainPtr<CFX_DIBitmap> CPDF_ImageObject::GetIndependentBitmap() const {
+  RetainPtr<CFX_DIBBase> pSource = GetImage()->LoadDIBBase();
+
+  // Clone() is non-virtual, and can't be overloaded by CPDF_DIBBase to
+  // return a clone of the subclass as one would typically expect from a
+  // such a method. Instead, it only clones the CFX_DIBBase, none of whose
+  // members point to objects owned by |this| or the form containing |this|.
+  // As a result, the clone may outlive them.
+  return pSource ? pSource->Clone(nullptr) : nullptr;
+}
+
 void CPDF_ImageObject::MaybePurgeCache() {
   if (!m_pImage)
     return;
diff --git a/core/fpdfapi/page/cpdf_imageobject.h b/core/fpdfapi/page/cpdf_imageobject.h
index b28e733..f221a98 100644
--- a/core/fpdfapi/page/cpdf_imageobject.h
+++ b/core/fpdfapi/page/cpdf_imageobject.h
@@ -7,9 +7,12 @@
 #ifndef CORE_FPDFAPI_PAGE_CPDF_IMAGEOBJECT_H_
 #define CORE_FPDFAPI_PAGE_CPDF_IMAGEOBJECT_H_
 
-#include "core/fpdfapi/page/cpdf_image.h"
 #include "core/fpdfapi/page/cpdf_pageobject.h"
 #include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/retain_ptr.h"
+
+class CFX_DIBitmap;
+class CPDF_Image;
 
 class CPDF_ImageObject final : public CPDF_PageObject {
  public:
@@ -25,8 +28,10 @@
   const CPDF_ImageObject* AsImage() const override;
 
   void CalcBoundingBox();
-  RetainPtr<CPDF_Image> GetImage() const { return m_pImage; }
   void SetImage(const RetainPtr<CPDF_Image>& pImage);
+  RetainPtr<CPDF_Image> GetImage() const;
+  RetainPtr<CFX_DIBitmap> GetIndependentBitmap() const;
+
   void set_matrix(const CFX_Matrix& matrix) { m_Matrix = matrix; }
   const CFX_Matrix& matrix() const { return m_Matrix; }
 
diff --git a/core/fpdfapi/render/cpdf_renderstatus.cpp b/core/fpdfapi/render/cpdf_renderstatus.cpp
index 95ad758..55b959d 100644
--- a/core/fpdfapi/render/cpdf_renderstatus.cpp
+++ b/core/fpdfapi/render/cpdf_renderstatus.cpp
@@ -1825,7 +1825,7 @@
     matrix.e += iChar > 0 ? textobj->GetCharPositions()[iChar - 1] : 0;
     matrix.Concat(text_matrix);
     matrix.Concat(mtObj2Device);
-    if (!pType3Char->LoadBitmap()) {
+    if (!pType3Char->LoadBitmapFromSoleImageOfForm()) {
       if (!glyphs.empty()) {
         for (size_t i = 0; i < iChar; ++i) {
           const TextGlyphPos& glyph = glyphs[i];