Add a FXGC heap to the CPDFXFA_Context.

Checks that an Oilpan heap for XFA can be created and live
for the proper duration under each of test harnesses (and
chrome when build with XFA after this rolls forward).

Change-Id: I39886cc191038eb014aa232752680c61a86aa329
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/70550
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/fpdfsdk/fpdfxfa/BUILD.gn b/fpdfsdk/fpdfxfa/BUILD.gn
index 4e88c4c..658f050 100644
--- a/fpdfsdk/fpdfxfa/BUILD.gn
+++ b/fpdfsdk/fpdfxfa/BUILD.gn
@@ -37,8 +37,15 @@
 }
 
 pdfium_embeddertest_source_set("embeddertests") {
-  sources = [ "cpdfxfa_docenvironment_embeddertest.cpp" ]
+  sources = [
+    "cpdfxfa_context_embeddertest.cpp",
+    "cpdfxfa_docenvironment_embeddertest.cpp",
+  ]
   configs = [ "//v8:external_startup_data" ]
-  deps = [ "../../fxjs" ]
+  deps = [
+    ":fpdfxfa",
+    "../:fpdfsdk",
+    "../../fxjs",
+  ]
   pdfium_root_dir = "../../"
 }
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp
index e6cfdfb..620016e 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp
@@ -81,6 +81,7 @@
 
 CPDFXFA_Context::CPDFXFA_Context(CPDF_Document* pPDFDoc)
     : m_pPDFDoc(pPDFDoc),
+      m_pGCHeap(FXGC_CreateHeap()),
       m_pXFAApp(std::make_unique<CXFA_FFApp>(this)),
       m_DocEnv(this) {
   ASSERT(m_pPDFDoc);
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_context.h b/fpdfsdk/fpdfxfa/cpdfxfa_context.h
index 0f6a14b..017545e 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_context.h
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_context.h
@@ -18,6 +18,7 @@
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h"
 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
+#include "fxjs/gc/heap.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
 
 class CJS_Runtime;
@@ -42,12 +43,12 @@
   bool LoadXFADoc();
   CXFA_FFDoc* GetXFADoc() { return m_pXFADoc.get(); }
   CXFA_FFDocView* GetXFADocView() const { return m_pXFADocView.Get(); }
+  cppgc::Heap* GetGCHeap() { return m_pGCHeap.get(); }
   FormType GetFormType() const { return m_FormType; }
   CPDFSDK_FormFillEnvironment* GetFormFillEnv() const {
     return m_pFormFillEnv.Get();
   }
   void SetFormFillEnv(CPDFSDK_FormFillEnvironment* pFormFillEnv);
-
   RetainPtr<CPDFXFA_Page> GetXFAPage(int page_index);
   RetainPtr<CPDFXFA_Page> GetXFAPage(CXFA_FFPageView* pPage) const;
   void ClearChangeMark();
@@ -115,6 +116,7 @@
 
   FormType m_FormType = FormType::kNone;
   UnownedPtr<CPDF_Document> const m_pPDFDoc;
+  FXGCScopedHeap m_pGCHeap;
   std::unique_ptr<CXFA_FFDoc> m_pXFADoc;
   ObservedPtr<CPDFSDK_FormFillEnvironment> m_pFormFillEnv;
   UnownedPtr<CXFA_FFDocView> m_pXFADocView;
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_context_embeddertest.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_context_embeddertest.cpp
new file mode 100644
index 0000000..b7eed28
--- /dev/null
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_context_embeddertest.cpp
@@ -0,0 +1,20 @@
+// Copyright 2020 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
+
+#include "fpdfsdk/cpdfsdk_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/xfa_js_embedder_test.h"
+
+class CPDFXFAContextEmbedderTest : public XFAJSEmbedderTest {};
+
+// Should not crash.
+TEST_F(CPDFXFAContextEmbedderTest, HasHeap) {
+  ASSERT_TRUE(OpenDocument("simple_xfa.pdf"));
+
+  CPDF_Document* pDocument = CPDFDocumentFromFPDFDocument(document());
+  auto* pContext = static_cast<CPDFXFA_Context*>(pDocument->GetExtension());
+  EXPECT_TRUE(pContext->GetGCHeap());
+}
diff --git a/fxjs/gc/heap.cpp b/fxjs/gc/heap.cpp
index 757d932..d75c675 100644
--- a/fxjs/gc/heap.cpp
+++ b/fxjs/gc/heap.cpp
@@ -55,12 +55,22 @@
 }
 
 FXGCScopedHeap FXGC_CreateHeap() {
+  // If XFA is included at compile-time, but JS is disabled at run-time,
+  // we may still attempt to build a CPDFXFA_Context which will want a
+  // heap. But we can't make one because JS is disabled.
+  // TODO(tsepez): Stop the context from even being created.
+  if (!g_platform)
+    return nullptr;
+
   ++g_platform_ref_count;
   auto heap = cppgc::Heap::Create(std::make_shared<CFXGC_Platform>());
   return FXGCScopedHeap(heap.release());
 }
 
 void FXGCHeapDeleter::operator()(cppgc::Heap* heap) {
+  if (!heap)
+    return;
+
   --g_platform_ref_count;
   delete heap;
 }
diff --git a/fxjs/gc/heap_embeddertest.cpp b/fxjs/gc/heap_embeddertest.cpp
index 77dc90b..2696a91 100644
--- a/fxjs/gc/heap_embeddertest.cpp
+++ b/fxjs/gc/heap_embeddertest.cpp
@@ -9,20 +9,7 @@
 #include "testing/embedder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-class HeapEmbedderTest : public EmbedderTest {
- public:
-  void SetUp() override {
-    EmbedderTest::SetUp();
-    FXGC_Initialize(EmbedderTestEnvironment::GetInstance()->platform());
-  }
-
-  void TearDown() override {
-    FXGC_Release();
-    EmbedderTest::TearDown();
-  }
-};
-
-TEST_F(HeapEmbedderTest, SeveralHeaps) {
+TEST_F(EmbedderTest, SeveralHeaps) {
   FXGCScopedHeap heap1 = FXGC_CreateHeap();
   EXPECT_TRUE(heap1);
 
diff --git a/testing/embedder_test.cpp b/testing/embedder_test.cpp
index c3e7192..ae09cf9 100644
--- a/testing/embedder_test.cpp
+++ b/testing/embedder_test.cpp
@@ -114,10 +114,16 @@
 
 void EmbedderTest::SetUp() {
   FPDF_LIBRARY_CONFIG config;
-  config.version = 2;
+  config.version = 3;
   config.m_pUserFontPaths = nullptr;
   config.m_v8EmbedderSlot = 0;
   config.m_pIsolate = external_isolate_;
+#ifdef PDF_ENABLE_V8
+  config.m_pPlatform = EmbedderTestEnvironment::GetInstance()->platform();
+#else   // PDF_ENABLE_V8
+  config.m_pPlatform = nullptr;
+#endif  // PDF_ENABLE_V8
+
   FPDF_InitLibraryWithConfig(&config);
 
   UNSUPPORT_INFO* info = static_cast<UNSUPPORT_INFO*>(this);