Split V8 initialization code into testing/v8_initializer.h.

Change-Id: Icb63d0e50717261667aa657deab38927f96495f0
Reviewed-on: https://pdfium-review.googlesource.com/c/49892
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/testing/v8_initializer.cpp b/testing/v8_initializer.cpp
new file mode 100644
index 0000000..548be03
--- /dev/null
+++ b/testing/v8_initializer.cpp
@@ -0,0 +1,98 @@
+// Copyright 2019 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 "testing/v8_initializer.h"
+
+#include "testing/test_support.h"
+#include "testing/utils/path_service.h"
+#include "v8/include/libplatform/libplatform.h"
+#include "v8/include/v8.h"
+
+namespace {
+
+#ifdef V8_USE_EXTERNAL_STARTUP_DATA
+// Returns the full path for an external V8 data file based on either
+// the currect exectuable path or an explicit override.
+std::string GetFullPathForSnapshotFile(const std::string& exe_path,
+                                       const std::string& bin_dir,
+                                       const std::string& filename) {
+  std::string result;
+  if (!bin_dir.empty()) {
+    result = bin_dir;
+    if (*bin_dir.rbegin() != PATH_SEPARATOR) {
+      result += PATH_SEPARATOR;
+    }
+  } else if (!exe_path.empty()) {
+    size_t last_separator = exe_path.rfind(PATH_SEPARATOR);
+    if (last_separator != std::string::npos) {
+      result = exe_path.substr(0, last_separator + 1);
+    }
+  }
+  result += filename;
+  return result;
+}
+
+bool GetExternalData(const std::string& exe_path,
+                     const std::string& bin_dir,
+                     const std::string& filename,
+                     v8::StartupData* result_data) {
+  std::string full_path =
+      GetFullPathForSnapshotFile(exe_path, bin_dir, filename);
+  size_t data_length = 0;
+  std::unique_ptr<char, pdfium::FreeDeleter> data_buffer =
+      GetFileContents(full_path.c_str(), &data_length);
+  if (!data_buffer)
+    return false;
+
+  result_data->data = data_buffer.release();
+  result_data->raw_size = data_length;
+  return true;
+}
+#endif  // V8_USE_EXTERNAL_STARTUP_DATA
+
+std::unique_ptr<v8::Platform> InitializeV8Common(const std::string& exe_path) {
+  v8::V8::InitializeICUDefaultLocation(exe_path.c_str());
+
+  std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
+  v8::V8::InitializePlatform(platform.get());
+
+  const char* recommended_v8_flags = FPDF_GetRecommendedV8Flags();
+  v8::V8::SetFlagsFromString(recommended_v8_flags,
+                             static_cast<int>(strlen(recommended_v8_flags)));
+
+  // By enabling predictable mode, V8 won't post any background tasks.
+  // By enabling GC, it makes it easier to chase use-after-free.
+  static const char kAdditionalV8Flags[] = "--predictable --expose-gc";
+  v8::V8::SetFlagsFromString(kAdditionalV8Flags,
+                             static_cast<int>(strlen(kAdditionalV8Flags)));
+
+  v8::V8::Initialize();
+  return platform;
+}
+
+}  // namespace
+
+#ifdef V8_USE_EXTERNAL_STARTUP_DATA
+std::unique_ptr<v8::Platform> InitializeV8ForPDFiumWithStartupData(
+    const std::string& exe_path,
+    const std::string& bin_dir,
+    v8::StartupData* natives_blob,
+    v8::StartupData* snapshot_blob) {
+  std::unique_ptr<v8::Platform> platform = InitializeV8Common(exe_path);
+  if (natives_blob && snapshot_blob) {
+    if (!GetExternalData(exe_path, bin_dir, "natives_blob.bin", natives_blob))
+      return nullptr;
+    if (!GetExternalData(exe_path, bin_dir, "snapshot_blob.bin", snapshot_blob))
+      return nullptr;
+    v8::V8::SetNativesDataBlob(natives_blob);
+    v8::V8::SetSnapshotDataBlob(snapshot_blob);
+  }
+  return platform;
+}
+#else   // V8_USE_EXTERNAL_STARTUP_DATA
+std::unique_ptr<v8::Platform> InitializeV8ForPDFium(
+    const std::string& exe_path) {
+  return InitializeV8Common(exe_path);
+}
+#endif  // V8_USE_EXTERNAL_STARTUP_DATA