Rename fxjse/ to fxjs/ update files to match class names.

This Cl moves the fxjse/ directory to fxjs/ in anticipation of merging in
fpdfsdk/jsapi. In the process the filenames are updated to better match the
class contents. Static methods are moved to anonymous namespaces as possible.

Review-Url: https://codereview.chromium.org/2136213002
diff --git a/fxjs/DEPS b/fxjs/DEPS
new file mode 100644
index 0000000..18698e4
--- /dev/null
+++ b/fxjs/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+  '+core/fxcrt/include',
+  # TODO(dsinclair): Layering violation. FXJSE can't include FPDFSDK.
+  '+fpdfsdk/jsapi/include',
+  '+v8/include',
+]
diff --git a/fxjs/cfxjse_arguments.cpp b/fxjs/cfxjse_arguments.cpp
new file mode 100644
index 0000000..1ff425d
--- /dev/null
+++ b/fxjs/cfxjse_arguments.cpp
@@ -0,0 +1,56 @@
+// Copyright 2016 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "fxjs/include/cfxjse_arguments.h"
+
+#include "fxjs/include/cfxjse_context.h"
+#include "fxjs/include/cfxjse_value.h"
+
+v8::Isolate* CFXJSE_Arguments::GetRuntime() const {
+  return m_pRetValue->GetIsolate();
+}
+
+int32_t CFXJSE_Arguments::GetLength() const {
+  return m_pInfo->Length();
+}
+
+std::unique_ptr<CFXJSE_Value> CFXJSE_Arguments::GetValue(int32_t index) const {
+  std::unique_ptr<CFXJSE_Value> lpArgValue(
+      new CFXJSE_Value(v8::Isolate::GetCurrent()));
+  lpArgValue->ForceSetValue((*m_pInfo)[index]);
+  return lpArgValue;
+}
+
+FX_BOOL CFXJSE_Arguments::GetBoolean(int32_t index) const {
+  return (*m_pInfo)[index]->BooleanValue();
+}
+
+int32_t CFXJSE_Arguments::GetInt32(int32_t index) const {
+  return static_cast<int32_t>((*m_pInfo)[index]->NumberValue());
+}
+
+FX_FLOAT CFXJSE_Arguments::GetFloat(int32_t index) const {
+  return static_cast<FX_FLOAT>((*m_pInfo)[index]->NumberValue());
+}
+
+CFX_ByteString CFXJSE_Arguments::GetUTF8String(int32_t index) const {
+  v8::Local<v8::String> hString = (*m_pInfo)[index]->ToString();
+  v8::String::Utf8Value szStringVal(hString);
+  return CFX_ByteString(*szStringVal);
+}
+
+CFXJSE_HostObject* CFXJSE_Arguments::GetObject(int32_t index,
+                                               CFXJSE_Class* pClass) const {
+  v8::Local<v8::Value> hValue = (*m_pInfo)[index];
+  ASSERT(!hValue.IsEmpty());
+  if (!hValue->IsObject())
+    return nullptr;
+  return FXJSE_RetrieveObjectBinding(hValue.As<v8::Object>(), pClass);
+}
+
+CFXJSE_Value* CFXJSE_Arguments::GetReturnValue() {
+  return m_pRetValue;
+}
diff --git a/fxjs/cfxjse_class.cpp b/fxjs/cfxjse_class.cpp
new file mode 100644
index 0000000..de22af7
--- /dev/null
+++ b/fxjs/cfxjse_class.cpp
@@ -0,0 +1,433 @@
+// Copyright 2016 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "fxjs/include/cfxjse_class.h"
+
+#include "fxjs/include/cfxjse_context.h"
+#include "fxjs/include/cfxjse_value.h"
+
+namespace {
+
+void V8FunctionCallback_Wrapper(
+    const v8::FunctionCallbackInfo<v8::Value>& info) {
+  const FXJSE_FUNCTION_DESCRIPTOR* lpFunctionInfo =
+      static_cast<FXJSE_FUNCTION_DESCRIPTOR*>(
+          info.Data().As<v8::External>()->Value());
+  if (!lpFunctionInfo)
+    return;
+
+  CFX_ByteStringC szFunctionName(lpFunctionInfo->name);
+  std::unique_ptr<CFXJSE_Value> lpThisValue(
+      new CFXJSE_Value(info.GetIsolate()));
+  lpThisValue->ForceSetValue(info.This());
+  std::unique_ptr<CFXJSE_Value> lpRetValue(new CFXJSE_Value(info.GetIsolate()));
+  CFXJSE_Arguments impl(&info, lpRetValue.get());
+  lpFunctionInfo->callbackProc(lpThisValue.get(), szFunctionName, impl);
+  if (!lpRetValue->DirectGetValue().IsEmpty())
+    info.GetReturnValue().Set(lpRetValue->DirectGetValue());
+}
+
+void V8ClassGlobalConstructorCallback_Wrapper(
+    const v8::FunctionCallbackInfo<v8::Value>& info) {
+  const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition =
+      static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+          info.Data().As<v8::External>()->Value());
+  if (!lpClassDefinition)
+    return;
+
+  CFX_ByteStringC szFunctionName(lpClassDefinition->name);
+  std::unique_ptr<CFXJSE_Value> lpThisValue(
+      new CFXJSE_Value(info.GetIsolate()));
+  lpThisValue->ForceSetValue(info.This());
+  std::unique_ptr<CFXJSE_Value> lpRetValue(new CFXJSE_Value(info.GetIsolate()));
+  CFXJSE_Arguments impl(&info, lpRetValue.get());
+  lpClassDefinition->constructor(lpThisValue.get(), szFunctionName, impl);
+  if (!lpRetValue->DirectGetValue().IsEmpty())
+    info.GetReturnValue().Set(lpRetValue->DirectGetValue());
+}
+
+void V8GetterCallback_Wrapper(v8::Local<v8::String> property,
+                              const v8::PropertyCallbackInfo<v8::Value>& info) {
+  const FXJSE_PROPERTY_DESCRIPTOR* lpPropertyInfo =
+      static_cast<FXJSE_PROPERTY_DESCRIPTOR*>(
+          info.Data().As<v8::External>()->Value());
+  if (!lpPropertyInfo)
+    return;
+
+  CFX_ByteStringC szPropertyName(lpPropertyInfo->name);
+  std::unique_ptr<CFXJSE_Value> lpThisValue(
+      new CFXJSE_Value(info.GetIsolate()));
+  std::unique_ptr<CFXJSE_Value> lpPropValue(
+      new CFXJSE_Value(info.GetIsolate()));
+  lpThisValue->ForceSetValue(info.This());
+  lpPropertyInfo->getProc(lpThisValue.get(), szPropertyName, lpPropValue.get());
+  info.GetReturnValue().Set(lpPropValue->DirectGetValue());
+}
+
+void V8SetterCallback_Wrapper(v8::Local<v8::String> property,
+                              v8::Local<v8::Value> value,
+                              const v8::PropertyCallbackInfo<void>& info) {
+  const FXJSE_PROPERTY_DESCRIPTOR* lpPropertyInfo =
+      static_cast<FXJSE_PROPERTY_DESCRIPTOR*>(
+          info.Data().As<v8::External>()->Value());
+  if (!lpPropertyInfo)
+    return;
+
+  CFX_ByteStringC szPropertyName(lpPropertyInfo->name);
+  std::unique_ptr<CFXJSE_Value> lpThisValue(
+      new CFXJSE_Value(info.GetIsolate()));
+  std::unique_ptr<CFXJSE_Value> lpPropValue(
+      new CFXJSE_Value(info.GetIsolate()));
+  lpThisValue->ForceSetValue(info.This());
+  lpPropValue->ForceSetValue(value);
+  lpPropertyInfo->setProc(lpThisValue.get(), szPropertyName, lpPropValue.get());
+}
+
+void V8ConstructorCallback_Wrapper(
+    const v8::FunctionCallbackInfo<v8::Value>& info) {
+  if (!info.IsConstructCall())
+    return;
+
+  const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition =
+      static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+          info.Data().As<v8::External>()->Value());
+  if (!lpClassDefinition)
+    return;
+
+  ASSERT(info.This()->InternalFieldCount());
+  info.This()->SetAlignedPointerInInternalField(0, nullptr);
+}
+
+void Context_GlobalObjToString(
+    const v8::FunctionCallbackInfo<v8::Value>& info) {
+  const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+      info.Data().As<v8::External>()->Value());
+  if (!lpClass)
+    return;
+
+  if (info.This() == info.Holder() && lpClass->name) {
+    CFX_ByteString szStringVal;
+    szStringVal.Format("[object %s]", lpClass->name);
+    info.GetReturnValue().Set(v8::String::NewFromUtf8(
+        info.GetIsolate(), szStringVal.c_str(), v8::String::kNormalString,
+        szStringVal.GetLength()));
+    return;
+  }
+  v8::Local<v8::String> local_str =
+      info.This()
+          ->ObjectProtoToString(info.GetIsolate()->GetCurrentContext())
+          .FromMaybe(v8::Local<v8::String>());
+  info.GetReturnValue().Set(local_str);
+}
+
+void DynPropGetterAdapter_MethodCallback(
+    const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Local<v8::Object> hCallBackInfo = info.Data().As<v8::Object>();
+  FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+      hCallBackInfo->GetAlignedPointerFromInternalField(0));
+  v8::Local<v8::String> hPropName =
+      hCallBackInfo->GetInternalField(1).As<v8::String>();
+  ASSERT(lpClass && !hPropName.IsEmpty());
+  v8::String::Utf8Value szPropName(hPropName);
+  CFX_ByteStringC szFxPropName = *szPropName;
+  std::unique_ptr<CFXJSE_Value> lpThisValue(
+      new CFXJSE_Value(info.GetIsolate()));
+  lpThisValue->ForceSetValue(info.This());
+  std::unique_ptr<CFXJSE_Value> lpRetValue(new CFXJSE_Value(info.GetIsolate()));
+  CFXJSE_Arguments impl(&info, lpRetValue.get());
+  lpClass->dynMethodCall(lpThisValue.get(), szFxPropName, impl);
+  if (!lpRetValue->DirectGetValue().IsEmpty())
+    info.GetReturnValue().Set(lpRetValue->DirectGetValue());
+}
+
+void DynPropGetterAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
+                          CFXJSE_Value* pObject,
+                          const CFX_ByteStringC& szPropName,
+                          CFXJSE_Value* pValue) {
+  ASSERT(lpClass);
+  int32_t nPropType =
+      lpClass->dynPropTypeGetter == nullptr
+          ? FXJSE_ClassPropType_Property
+          : lpClass->dynPropTypeGetter(pObject, szPropName, FALSE);
+  if (nPropType == FXJSE_ClassPropType_Property) {
+    if (lpClass->dynPropGetter)
+      lpClass->dynPropGetter(pObject, szPropName, pValue);
+  } else if (nPropType == FXJSE_ClassPropType_Method) {
+    if (lpClass->dynMethodCall && pValue) {
+      v8::Isolate* pIsolate = pValue->GetIsolate();
+      v8::HandleScope hscope(pIsolate);
+      v8::Local<v8::ObjectTemplate> hCallBackInfoTemplate =
+          v8::ObjectTemplate::New(pIsolate);
+      hCallBackInfoTemplate->SetInternalFieldCount(2);
+      v8::Local<v8::Object> hCallBackInfo =
+          hCallBackInfoTemplate->NewInstance();
+      hCallBackInfo->SetAlignedPointerInInternalField(
+          0, const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClass));
+      hCallBackInfo->SetInternalField(
+          1, v8::String::NewFromUtf8(
+                 pIsolate, reinterpret_cast<const char*>(szPropName.raw_str()),
+                 v8::String::kNormalString, szPropName.GetLength()));
+      pValue->ForceSetValue(
+          v8::Function::New(pValue->GetIsolate()->GetCurrentContext(),
+                            DynPropGetterAdapter_MethodCallback, hCallBackInfo,
+                            0, v8::ConstructorBehavior::kThrow)
+              .ToLocalChecked());
+    }
+  }
+}
+
+void DynPropSetterAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
+                          CFXJSE_Value* pObject,
+                          const CFX_ByteStringC& szPropName,
+                          CFXJSE_Value* pValue) {
+  ASSERT(lpClass);
+  int32_t nPropType =
+      lpClass->dynPropTypeGetter == nullptr
+          ? FXJSE_ClassPropType_Property
+          : lpClass->dynPropTypeGetter(pObject, szPropName, FALSE);
+  if (nPropType != FXJSE_ClassPropType_Method) {
+    if (lpClass->dynPropSetter)
+      lpClass->dynPropSetter(pObject, szPropName, pValue);
+  }
+}
+
+FX_BOOL DynPropQueryAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
+                            CFXJSE_Value* pObject,
+                            const CFX_ByteStringC& szPropName) {
+  ASSERT(lpClass);
+  int32_t nPropType =
+      lpClass->dynPropTypeGetter == nullptr
+          ? FXJSE_ClassPropType_Property
+          : lpClass->dynPropTypeGetter(pObject, szPropName, TRUE);
+  return nPropType != FXJSE_ClassPropType_None;
+}
+
+FX_BOOL DynPropDeleterAdapter(const FXJSE_CLASS_DESCRIPTOR* lpClass,
+                              CFXJSE_Value* pObject,
+                              const CFX_ByteStringC& szPropName) {
+  ASSERT(lpClass);
+  int32_t nPropType =
+      lpClass->dynPropTypeGetter == nullptr
+          ? FXJSE_ClassPropType_Property
+          : lpClass->dynPropTypeGetter(pObject, szPropName, FALSE);
+  if (nPropType != FXJSE_ClassPropType_Method) {
+    if (lpClass->dynPropDeleter)
+      return lpClass->dynPropDeleter(pObject, szPropName);
+    return nPropType == FXJSE_ClassPropType_Property ? FALSE : TRUE;
+  }
+  return FALSE;
+}
+
+void NamedPropertyQueryCallback(
+    v8::Local<v8::Name> property,
+    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+  v8::Local<v8::Object> thisObject = info.This();
+  const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+      info.Data().As<v8::External>()->Value());
+  v8::Isolate* pIsolate = info.GetIsolate();
+  v8::HandleScope scope(pIsolate);
+  v8::String::Utf8Value szPropName(property);
+  CFX_ByteStringC szFxPropName(*szPropName, szPropName.length());
+  std::unique_ptr<CFXJSE_Value> lpThisValue(
+      new CFXJSE_Value(info.GetIsolate()));
+  lpThisValue->ForceSetValue(thisObject);
+  if (DynPropQueryAdapter(lpClass, lpThisValue.get(), szFxPropName)) {
+    info.GetReturnValue().Set(v8::DontDelete);
+    return;
+  }
+  const int32_t iV8Absent = 64;
+  info.GetReturnValue().Set(iV8Absent);
+}
+
+void NamedPropertyDeleterCallback(
+    v8::Local<v8::Name> property,
+    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
+  v8::Local<v8::Object> thisObject = info.This();
+  const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+      info.Data().As<v8::External>()->Value());
+  v8::Isolate* pIsolate = info.GetIsolate();
+  v8::HandleScope scope(pIsolate);
+  v8::String::Utf8Value szPropName(property);
+  CFX_ByteStringC szFxPropName(*szPropName, szPropName.length());
+  std::unique_ptr<CFXJSE_Value> lpThisValue(
+      new CFXJSE_Value(info.GetIsolate()));
+  lpThisValue->ForceSetValue(thisObject);
+  info.GetReturnValue().Set(
+      !!DynPropDeleterAdapter(lpClass, lpThisValue.get(), szFxPropName));
+}
+
+void NamedPropertyGetterCallback(
+    v8::Local<v8::Name> property,
+    const v8::PropertyCallbackInfo<v8::Value>& info) {
+  v8::Local<v8::Object> thisObject = info.This();
+  const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+      info.Data().As<v8::External>()->Value());
+  v8::String::Utf8Value szPropName(property);
+  CFX_ByteStringC szFxPropName(*szPropName, szPropName.length());
+  std::unique_ptr<CFXJSE_Value> lpThisValue(
+      new CFXJSE_Value(info.GetIsolate()));
+  lpThisValue->ForceSetValue(thisObject);
+  std::unique_ptr<CFXJSE_Value> lpNewValue(new CFXJSE_Value(info.GetIsolate()));
+  DynPropGetterAdapter(lpClass, lpThisValue.get(), szFxPropName,
+                       lpNewValue.get());
+  info.GetReturnValue().Set(lpNewValue->DirectGetValue());
+}
+
+void NamedPropertySetterCallback(
+    v8::Local<v8::Name> property,
+    v8::Local<v8::Value> value,
+    const v8::PropertyCallbackInfo<v8::Value>& info) {
+  v8::Local<v8::Object> thisObject = info.This();
+  const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+      info.Data().As<v8::External>()->Value());
+  v8::String::Utf8Value szPropName(property);
+  CFX_ByteStringC szFxPropName(*szPropName, szPropName.length());
+  std::unique_ptr<CFXJSE_Value> lpThisValue(
+      new CFXJSE_Value(info.GetIsolate()));
+  lpThisValue->ForceSetValue(thisObject);
+
+  CFXJSE_Value* lpNewValue = new CFXJSE_Value(info.GetIsolate());
+  lpNewValue->ForceSetValue(value);
+  DynPropSetterAdapter(lpClass, lpThisValue.get(), szFxPropName, lpNewValue);
+  info.GetReturnValue().Set(value);
+}
+
+void NamedPropertyEnumeratorCallback(
+    const v8::PropertyCallbackInfo<v8::Array>& info) {
+  const FXJSE_CLASS_DESCRIPTOR* lpClass = static_cast<FXJSE_CLASS_DESCRIPTOR*>(
+      info.Data().As<v8::External>()->Value());
+  v8::Isolate* pIsolate = info.GetIsolate();
+  v8::Local<v8::Array> newArray = v8::Array::New(pIsolate, lpClass->propNum);
+  for (int i = 0; i < lpClass->propNum; i++) {
+    newArray->Set(
+        i, v8::String::NewFromUtf8(pIsolate, lpClass->properties[i].name));
+  }
+  info.GetReturnValue().Set(newArray);
+}
+
+}  // namespace
+
+// static
+CFXJSE_Class* CFXJSE_Class::Create(
+    CFXJSE_Context* lpContext,
+    const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition,
+    FX_BOOL bIsJSGlobal) {
+  if (!lpContext || !lpClassDefinition)
+    return nullptr;
+
+  CFXJSE_Class* pClass =
+      GetClassFromContext(lpContext, lpClassDefinition->name);
+  if (pClass)
+    return pClass;
+
+  v8::Isolate* pIsolate = lpContext->m_pIsolate;
+  pClass = new CFXJSE_Class(lpContext);
+  pClass->m_szClassName = lpClassDefinition->name;
+  pClass->m_lpClassDefinition = lpClassDefinition;
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
+  v8::Local<v8::FunctionTemplate> hFunctionTemplate = v8::FunctionTemplate::New(
+      pIsolate, bIsJSGlobal ? 0 : V8ConstructorCallback_Wrapper,
+      v8::External::New(
+          pIsolate, const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClassDefinition)));
+  hFunctionTemplate->SetClassName(
+      v8::String::NewFromUtf8(pIsolate, lpClassDefinition->name));
+  hFunctionTemplate->InstanceTemplate()->SetInternalFieldCount(1);
+  v8::Local<v8::ObjectTemplate> hObjectTemplate =
+      hFunctionTemplate->InstanceTemplate();
+  SetUpNamedPropHandler(pIsolate, hObjectTemplate, lpClassDefinition);
+
+  if (lpClassDefinition->propNum) {
+    for (int32_t i = 0; i < lpClassDefinition->propNum; i++) {
+      hObjectTemplate->SetNativeDataProperty(
+          v8::String::NewFromUtf8(pIsolate,
+                                  lpClassDefinition->properties[i].name),
+          lpClassDefinition->properties[i].getProc ? V8GetterCallback_Wrapper
+                                                   : nullptr,
+          lpClassDefinition->properties[i].setProc ? V8SetterCallback_Wrapper
+                                                   : nullptr,
+          v8::External::New(pIsolate, const_cast<FXJSE_PROPERTY_DESCRIPTOR*>(
+                                          lpClassDefinition->properties + i)),
+          static_cast<v8::PropertyAttribute>(v8::DontDelete));
+    }
+  }
+  if (lpClassDefinition->methNum) {
+    for (int32_t i = 0; i < lpClassDefinition->methNum; i++) {
+      v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(
+          pIsolate, V8FunctionCallback_Wrapper,
+          v8::External::New(pIsolate, const_cast<FXJSE_FUNCTION_DESCRIPTOR*>(
+                                          lpClassDefinition->methods + i)));
+      fun->RemovePrototype();
+      hObjectTemplate->Set(
+          v8::String::NewFromUtf8(pIsolate, lpClassDefinition->methods[i].name),
+          fun,
+          static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
+    }
+  }
+  if (lpClassDefinition->constructor) {
+    if (bIsJSGlobal) {
+      hObjectTemplate->Set(
+          v8::String::NewFromUtf8(pIsolate, lpClassDefinition->name),
+          v8::FunctionTemplate::New(
+              pIsolate, V8ClassGlobalConstructorCallback_Wrapper,
+              v8::External::New(pIsolate, const_cast<FXJSE_CLASS_DESCRIPTOR*>(
+                                              lpClassDefinition))),
+          static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
+    } else {
+      v8::Local<v8::Context> hLocalContext =
+          v8::Local<v8::Context>::New(pIsolate, lpContext->m_hContext);
+      FXJSE_GetGlobalObjectFromContext(hLocalContext)
+          ->Set(v8::String::NewFromUtf8(pIsolate, lpClassDefinition->name),
+                v8::Function::New(
+                    pIsolate, V8ClassGlobalConstructorCallback_Wrapper,
+                    v8::External::New(pIsolate,
+                                      const_cast<FXJSE_CLASS_DESCRIPTOR*>(
+                                          lpClassDefinition))));
+    }
+  }
+  if (bIsJSGlobal) {
+    v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(
+        pIsolate, Context_GlobalObjToString,
+        v8::External::New(
+            pIsolate, const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClassDefinition)));
+    fun->RemovePrototype();
+    hObjectTemplate->Set(v8::String::NewFromUtf8(pIsolate, "toString"), fun);
+  }
+  pClass->m_hTemplate.Reset(lpContext->m_pIsolate, hFunctionTemplate);
+  lpContext->m_rgClasses.push_back(std::unique_ptr<CFXJSE_Class>(pClass));
+  return pClass;
+}
+
+// static
+CFXJSE_Class* CFXJSE_Class::GetClassFromContext(CFXJSE_Context* pContext,
+                                                const CFX_ByteStringC& szName) {
+  for (const auto& pClass : pContext->m_rgClasses) {
+    if (pClass->m_szClassName == szName)
+      return pClass.get();
+  }
+  return nullptr;
+}
+
+// static
+void CFXJSE_Class::SetUpNamedPropHandler(
+    v8::Isolate* pIsolate,
+    v8::Local<v8::ObjectTemplate>& hObjectTemplate,
+    const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition) {
+  v8::NamedPropertyHandlerConfiguration configuration(
+      lpClassDefinition->dynPropGetter ? NamedPropertyGetterCallback : 0,
+      lpClassDefinition->dynPropSetter ? NamedPropertySetterCallback : 0,
+      lpClassDefinition->dynPropTypeGetter ? NamedPropertyQueryCallback : 0,
+      lpClassDefinition->dynPropDeleter ? NamedPropertyDeleterCallback : 0,
+      NamedPropertyEnumeratorCallback,
+      v8::External::New(pIsolate,
+                        const_cast<FXJSE_CLASS_DESCRIPTOR*>(lpClassDefinition)),
+      v8::PropertyHandlerFlags::kNonMasking);
+  hObjectTemplate->SetHandler(configuration);
+}
+
+CFXJSE_Class::CFXJSE_Class(CFXJSE_Context* lpContext)
+    : m_lpClassDefinition(nullptr), m_pContext(lpContext) {}
+
+CFXJSE_Class::~CFXJSE_Class() {}
diff --git a/fxjs/cfxjse_context.cpp b/fxjs/cfxjse_context.cpp
new file mode 100644
index 0000000..4b0d0f6
--- /dev/null
+++ b/fxjs/cfxjse_context.cpp
@@ -0,0 +1,255 @@
+// Copyright 2016 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "fxjs/include/cfxjse_context.h"
+
+#include "fxjs/include/cfxjse_class.h"
+#include "fxjs/include/cfxjse_value.h"
+
+namespace {
+
+const FX_CHAR szCompatibleModeScript[] =
+    "(function(global, list) {\n"
+    "  'use strict';\n"
+    "  var objname;\n"
+    "  for (objname in list) {\n"
+    "    var globalobj = global[objname];\n"
+    "    if (globalobj) {\n"
+    "      list[objname].forEach(function(name) {\n"
+    "        if (!globalobj[name]) {\n"
+    "          Object.defineProperty(globalobj, name, {\n"
+    "            writable: true,\n"
+    "            enumerable: false,\n"
+    "            value: (function(obj) {\n"
+    "              if (arguments.length === 0) {\n"
+    "                throw new TypeError('missing argument 0 when calling "
+    "                    function ' + objname + '.' + name);\n"
+    "              }\n"
+    "              return globalobj.prototype[name].apply(obj, "
+    "                  Array.prototype.slice.call(arguments, 1));\n"
+    "            })\n"
+    "          });\n"
+    "        }\n"
+    "      });\n"
+    "    }\n"
+    "  }\n"
+    "}(this, {String: ['substr', 'toUpperCase']}));";
+
+}  // namespace
+
+// Note, not in the anonymous namespace due to the friend call
+// in cfxjse_context.h
+// TODO(dsinclair): Remove the friending, use public methods.
+class CFXJSE_ScopeUtil_IsolateHandleContext {
+ public:
+  explicit CFXJSE_ScopeUtil_IsolateHandleContext(CFXJSE_Context* pContext)
+      : m_context(pContext),
+        m_parent(pContext->m_pIsolate),
+        m_cscope(v8::Local<v8::Context>::New(pContext->m_pIsolate,
+                                             pContext->m_hContext)) {}
+  v8::Isolate* GetIsolate() { return m_context->m_pIsolate; }
+  v8::Local<v8::Context> GetLocalContext() {
+    return v8::Local<v8::Context>::New(m_context->m_pIsolate,
+                                       m_context->m_hContext);
+  }
+
+ private:
+  CFXJSE_ScopeUtil_IsolateHandleContext(
+      const CFXJSE_ScopeUtil_IsolateHandleContext&) = delete;
+  void operator=(const CFXJSE_ScopeUtil_IsolateHandleContext&) = delete;
+  void* operator new(size_t size) = delete;
+  void operator delete(void*, size_t) = delete;
+
+  CFXJSE_Context* m_context;
+  CFXJSE_ScopeUtil_IsolateHandle m_parent;
+  v8::Context::Scope m_cscope;
+};
+
+v8::Local<v8::Object> FXJSE_GetGlobalObjectFromContext(
+    const v8::Local<v8::Context>& hContext) {
+  return hContext->Global()->GetPrototype().As<v8::Object>();
+}
+
+void FXJSE_UpdateObjectBinding(v8::Local<v8::Object>& hObject,
+                               CFXJSE_HostObject* lpNewBinding) {
+  ASSERT(!hObject.IsEmpty());
+  ASSERT(hObject->InternalFieldCount() > 0);
+  hObject->SetAlignedPointerInInternalField(0,
+                                            static_cast<void*>(lpNewBinding));
+}
+
+CFXJSE_HostObject* FXJSE_RetrieveObjectBinding(
+    const v8::Local<v8::Object>& hJSObject,
+    CFXJSE_Class* lpClass) {
+  ASSERT(!hJSObject.IsEmpty());
+  if (!hJSObject->IsObject())
+    return nullptr;
+
+  v8::Local<v8::Object> hObject = hJSObject;
+  if (hObject->InternalFieldCount() == 0) {
+    v8::Local<v8::Value> hProtoObject = hObject->GetPrototype();
+    if (hProtoObject.IsEmpty() || !hProtoObject->IsObject())
+      return nullptr;
+
+    hObject = hProtoObject.As<v8::Object>();
+    if (hObject->InternalFieldCount() == 0)
+      return nullptr;
+  }
+  if (lpClass) {
+    v8::Local<v8::FunctionTemplate> hClass =
+        v8::Local<v8::FunctionTemplate>::New(
+            lpClass->GetContext()->GetRuntime(), lpClass->GetTemplate());
+    if (!hClass->HasInstance(hObject))
+      return nullptr;
+  }
+  return static_cast<CFXJSE_HostObject*>(
+      hObject->GetAlignedPointerFromInternalField(0));
+}
+
+v8::Local<v8::Object> FXJSE_CreateReturnValue(v8::Isolate* pIsolate,
+                                              v8::TryCatch& trycatch) {
+  v8::Local<v8::Object> hReturnValue = v8::Object::New(pIsolate);
+  if (trycatch.HasCaught()) {
+    v8::Local<v8::Value> hException = trycatch.Exception();
+    v8::Local<v8::Message> hMessage = trycatch.Message();
+    if (hException->IsObject()) {
+      v8::Local<v8::Value> hValue;
+      hValue = hException.As<v8::Object>()->Get(
+          v8::String::NewFromUtf8(pIsolate, "name"));
+      if (hValue->IsString() || hValue->IsStringObject())
+        hReturnValue->Set(0, hValue);
+      else
+        hReturnValue->Set(0, v8::String::NewFromUtf8(pIsolate, "Error"));
+
+      hValue = hException.As<v8::Object>()->Get(
+          v8::String::NewFromUtf8(pIsolate, "message"));
+      if (hValue->IsString() || hValue->IsStringObject())
+        hReturnValue->Set(1, hValue);
+      else
+        hReturnValue->Set(1, hMessage->Get());
+    } else {
+      hReturnValue->Set(0, v8::String::NewFromUtf8(pIsolate, "Error"));
+      hReturnValue->Set(1, hMessage->Get());
+    }
+    hReturnValue->Set(2, hException);
+    hReturnValue->Set(3, v8::Integer::New(pIsolate, hMessage->GetLineNumber()));
+    hReturnValue->Set(4, hMessage->GetSourceLine());
+    v8::Maybe<int32_t> maybe_int =
+        hMessage->GetStartColumn(pIsolate->GetCurrentContext());
+    hReturnValue->Set(5, v8::Integer::New(pIsolate, maybe_int.FromMaybe(0)));
+    maybe_int = hMessage->GetEndColumn(pIsolate->GetCurrentContext());
+    hReturnValue->Set(6, v8::Integer::New(pIsolate, maybe_int.FromMaybe(0)));
+  }
+  return hReturnValue;
+}
+
+// static
+CFXJSE_Context* CFXJSE_Context::Create(
+    v8::Isolate* pIsolate,
+    const FXJSE_CLASS_DESCRIPTOR* lpGlobalClass,
+    CFXJSE_HostObject* lpGlobalObject) {
+  CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
+  CFXJSE_Context* pContext = new CFXJSE_Context(pIsolate);
+  CFXJSE_Class* lpGlobalClassObj = nullptr;
+  v8::Local<v8::ObjectTemplate> hObjectTemplate;
+  if (lpGlobalClass) {
+    lpGlobalClassObj = CFXJSE_Class::Create(pContext, lpGlobalClass, TRUE);
+    ASSERT(lpGlobalClassObj);
+    v8::Local<v8::FunctionTemplate> hFunctionTemplate =
+        v8::Local<v8::FunctionTemplate>::New(pIsolate,
+                                             lpGlobalClassObj->m_hTemplate);
+    hObjectTemplate = hFunctionTemplate->InstanceTemplate();
+  } else {
+    hObjectTemplate = v8::ObjectTemplate::New(pIsolate);
+    hObjectTemplate->SetInternalFieldCount(1);
+  }
+  hObjectTemplate->Set(
+      v8::Symbol::GetToStringTag(pIsolate),
+      v8::String::NewFromUtf8(pIsolate, "global", v8::NewStringType::kNormal)
+          .ToLocalChecked());
+  v8::Local<v8::Context> hNewContext =
+      v8::Context::New(pIsolate, nullptr, hObjectTemplate);
+  v8::Local<v8::Context> hRootContext = v8::Local<v8::Context>::New(
+      pIsolate, CFXJSE_RuntimeData::Get(pIsolate)->m_hRootContext);
+  hNewContext->SetSecurityToken(hRootContext->GetSecurityToken());
+  v8::Local<v8::Object> hGlobalObject =
+      FXJSE_GetGlobalObjectFromContext(hNewContext);
+  FXJSE_UpdateObjectBinding(hGlobalObject, lpGlobalObject);
+  pContext->m_hContext.Reset(pIsolate, hNewContext);
+  return pContext;
+}
+
+CFXJSE_Context::CFXJSE_Context(v8::Isolate* pIsolate) : m_pIsolate(pIsolate) {}
+
+CFXJSE_Context::~CFXJSE_Context() {}
+
+std::unique_ptr<CFXJSE_Value> CFXJSE_Context::GetGlobalObject() {
+  std::unique_ptr<CFXJSE_Value> pValue(new CFXJSE_Value(m_pIsolate));
+
+  CFXJSE_ScopeUtil_IsolateHandleContext scope(this);
+  v8::Local<v8::Context> hContext =
+      v8::Local<v8::Context>::New(m_pIsolate, m_hContext);
+  v8::Local<v8::Object> hGlobalObject = hContext->Global();
+  pValue->ForceSetValue(hGlobalObject);
+
+  return pValue;
+}
+
+void CFXJSE_Context::EnableCompatibleMode() {
+  ExecuteScript(szCompatibleModeScript, nullptr, nullptr);
+}
+
+FX_BOOL CFXJSE_Context::ExecuteScript(const FX_CHAR* szScript,
+                                      CFXJSE_Value* lpRetValue,
+                                      CFXJSE_Value* lpNewThisObject) {
+  CFXJSE_ScopeUtil_IsolateHandleContext scope(this);
+  v8::TryCatch trycatch(m_pIsolate);
+  v8::Local<v8::String> hScriptString =
+      v8::String::NewFromUtf8(m_pIsolate, szScript);
+  if (!lpNewThisObject) {
+    v8::Local<v8::Script> hScript = v8::Script::Compile(hScriptString);
+    if (!trycatch.HasCaught()) {
+      v8::Local<v8::Value> hValue = hScript->Run();
+      if (!trycatch.HasCaught()) {
+        if (lpRetValue) {
+          lpRetValue->m_hValue.Reset(m_pIsolate, hValue);
+        }
+        return TRUE;
+      }
+    }
+    if (lpRetValue) {
+      lpRetValue->m_hValue.Reset(m_pIsolate,
+                                 FXJSE_CreateReturnValue(m_pIsolate, trycatch));
+    }
+    return FALSE;
+  } else {
+    v8::Local<v8::Value> hNewThis =
+        v8::Local<v8::Value>::New(m_pIsolate, lpNewThisObject->m_hValue);
+    ASSERT(!hNewThis.IsEmpty());
+    v8::Local<v8::Script> hWrapper =
+        v8::Script::Compile(v8::String::NewFromUtf8(
+            m_pIsolate, "(function () { return eval(arguments[0]); })"));
+    v8::Local<v8::Value> hWrapperValue = hWrapper->Run();
+    ASSERT(hWrapperValue->IsFunction());
+    v8::Local<v8::Function> hWrapperFn = hWrapperValue.As<v8::Function>();
+    if (!trycatch.HasCaught()) {
+      v8::Local<v8::Value> rgArgs[] = {hScriptString};
+      v8::Local<v8::Value> hValue =
+          hWrapperFn->Call(hNewThis.As<v8::Object>(), 1, rgArgs);
+      if (!trycatch.HasCaught()) {
+        if (lpRetValue) {
+          lpRetValue->m_hValue.Reset(m_pIsolate, hValue);
+        }
+        return TRUE;
+      }
+    }
+    if (lpRetValue) {
+      lpRetValue->m_hValue.Reset(m_pIsolate,
+                                 FXJSE_CreateReturnValue(m_pIsolate, trycatch));
+    }
+    return FALSE;
+  }
+}
diff --git a/fxjs/cfxjse_isolatetracker.cpp b/fxjs/cfxjse_isolatetracker.cpp
new file mode 100644
index 0000000..9594df3
--- /dev/null
+++ b/fxjs/cfxjse_isolatetracker.cpp
@@ -0,0 +1,35 @@
+// Copyright 2016 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "fxjs/cfxjse_isolatetracker.h"
+
+#include <algorithm>
+
+CFXJSE_IsolateTracker::CFXJSE_IsolateTracker() {}
+
+CFXJSE_IsolateTracker::~CFXJSE_IsolateTracker() {}
+
+void CFXJSE_IsolateTracker::Append(v8::Isolate* pIsolate) {
+  m_OwnedIsolates.push_back(pIsolate);
+}
+
+void CFXJSE_IsolateTracker::Remove(
+    v8::Isolate* pIsolate,
+    CFXJSE_IsolateTracker::DisposeCallback lpfnDisposeCallback) {
+  auto it = std::find(m_OwnedIsolates.begin(), m_OwnedIsolates.end(), pIsolate);
+  bool bFound = it != m_OwnedIsolates.end();
+  if (bFound)
+    m_OwnedIsolates.erase(it);
+  lpfnDisposeCallback(pIsolate, bFound);
+}
+
+void CFXJSE_IsolateTracker::RemoveAll(
+    CFXJSE_IsolateTracker::DisposeCallback lpfnDisposeCallback) {
+  for (v8::Isolate* pIsolate : m_OwnedIsolates)
+    lpfnDisposeCallback(pIsolate, true);
+
+  m_OwnedIsolates.clear();
+}
diff --git a/fxjs/cfxjse_isolatetracker.h b/fxjs/cfxjse_isolatetracker.h
new file mode 100644
index 0000000..7558416
--- /dev/null
+++ b/fxjs/cfxjse_isolatetracker.h
@@ -0,0 +1,70 @@
+// Copyright 2016 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJS_CFXJSE_ISOLATETRACKER_H_
+#define FXJS_CFXJSE_ISOLATETRACKER_H_
+
+#include <vector>
+
+#include "v8/include/v8.h"
+
+#include "fxjs/cfxjse_runtimedata.h"
+
+class CFXJSE_ScopeUtil_IsolateHandle {
+ public:
+  explicit CFXJSE_ScopeUtil_IsolateHandle(v8::Isolate* pIsolate)
+      : m_isolate(pIsolate), m_iscope(pIsolate), m_hscope(pIsolate) {}
+  v8::Isolate* GetIsolate() { return m_isolate; }
+
+ private:
+  CFXJSE_ScopeUtil_IsolateHandle(const CFXJSE_ScopeUtil_IsolateHandle&) =
+      delete;
+  void operator=(const CFXJSE_ScopeUtil_IsolateHandle&) = delete;
+  void* operator new(size_t size) = delete;
+  void operator delete(void*, size_t) = delete;
+
+  v8::Isolate* m_isolate;
+  v8::Isolate::Scope m_iscope;
+  v8::HandleScope m_hscope;
+};
+
+class CFXJSE_ScopeUtil_IsolateHandleRootContext {
+ public:
+  explicit CFXJSE_ScopeUtil_IsolateHandleRootContext(v8::Isolate* pIsolate)
+      : m_parent(pIsolate),
+        m_cscope(v8::Local<v8::Context>::New(
+            pIsolate,
+            CFXJSE_RuntimeData::Get(pIsolate)->m_hRootContext)) {}
+
+ private:
+  CFXJSE_ScopeUtil_IsolateHandleRootContext(
+      const CFXJSE_ScopeUtil_IsolateHandleRootContext&) = delete;
+  void operator=(const CFXJSE_ScopeUtil_IsolateHandleRootContext&) = delete;
+  void* operator new(size_t size) = delete;
+  void operator delete(void*, size_t) = delete;
+
+  CFXJSE_ScopeUtil_IsolateHandle m_parent;
+  v8::Context::Scope m_cscope;
+};
+
+class CFXJSE_IsolateTracker {
+ public:
+  typedef void (*DisposeCallback)(v8::Isolate*, bool bOwnedIsolate);
+
+  CFXJSE_IsolateTracker();
+  ~CFXJSE_IsolateTracker();
+
+  void Append(v8::Isolate* pIsolate);
+  void Remove(v8::Isolate* pIsolate, DisposeCallback lpfnDisposeCallback);
+  void RemoveAll(DisposeCallback lpfnDisposeCallback);
+
+  static CFXJSE_IsolateTracker* g_pInstance;
+
+ protected:
+  std::vector<v8::Isolate*> m_OwnedIsolates;
+};
+
+#endif  // FXJS_CFXJSE_ISOLATETRACKER_H_
diff --git a/fxjs/cfxjse_runtimedata.cpp b/fxjs/cfxjse_runtimedata.cpp
new file mode 100644
index 0000000..f58f5f8
--- /dev/null
+++ b/fxjs/cfxjse_runtimedata.cpp
@@ -0,0 +1,105 @@
+// Copyright 2016 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "fxjs/cfxjse_runtimedata.h"
+
+#include "fpdfsdk/jsapi/include/fxjs_v8.h"
+#include "fxjs/cfxjse_isolatetracker.h"
+
+namespace {
+
+// Duplicates fpdfsdk's cjs_runtime.h, but keeps XFA from depending on it.
+// TODO(tsepez): make a single version of this.
+class FXJSE_ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
+  void* Allocate(size_t length) override { return calloc(1, length); }
+  void* AllocateUninitialized(size_t length) override { return malloc(length); }
+  void Free(void* data, size_t length) override { free(data); }
+};
+
+void Runtime_DisposeCallback(v8::Isolate* pIsolate, bool bOwned) {
+  if (FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate)) {
+    delete pData->m_pFXJSERuntimeData;
+    pData->m_pFXJSERuntimeData = nullptr;
+  }
+  if (bOwned)
+    pIsolate->Dispose();
+}
+
+void KillV8() {
+  v8::V8::Dispose();
+}
+
+}  // namespace
+
+void FXJSE_Initialize() {
+  if (!CFXJSE_IsolateTracker::g_pInstance)
+    CFXJSE_IsolateTracker::g_pInstance = new CFXJSE_IsolateTracker;
+
+  static FX_BOOL bV8Initialized = FALSE;
+  if (bV8Initialized)
+    return;
+
+  bV8Initialized = TRUE;
+  atexit(KillV8);
+}
+
+void FXJSE_Finalize() {
+  if (!CFXJSE_IsolateTracker::g_pInstance)
+    return;
+
+  CFXJSE_IsolateTracker::g_pInstance->RemoveAll(Runtime_DisposeCallback);
+  delete CFXJSE_IsolateTracker::g_pInstance;
+  CFXJSE_IsolateTracker::g_pInstance = nullptr;
+}
+
+v8::Isolate* FXJSE_Runtime_Create_Own() {
+  v8::Isolate::CreateParams params;
+  params.array_buffer_allocator = new FXJSE_ArrayBufferAllocator();
+  v8::Isolate* pIsolate = v8::Isolate::New(params);
+  ASSERT(pIsolate && CFXJSE_IsolateTracker::g_pInstance);
+  CFXJSE_IsolateTracker::g_pInstance->Append(pIsolate);
+  return pIsolate;
+}
+
+void FXJSE_Runtime_Release(v8::Isolate* pIsolate) {
+  if (!pIsolate)
+    return;
+  CFXJSE_IsolateTracker::g_pInstance->Remove(pIsolate, Runtime_DisposeCallback);
+}
+
+CFXJSE_RuntimeData::CFXJSE_RuntimeData(v8::Isolate* pIsolate)
+    : m_pIsolate(pIsolate) {}
+
+CFXJSE_RuntimeData::~CFXJSE_RuntimeData() {}
+
+CFXJSE_RuntimeData* CFXJSE_RuntimeData::Create(v8::Isolate* pIsolate) {
+  CFXJSE_RuntimeData* pRuntimeData = new CFXJSE_RuntimeData(pIsolate);
+  CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
+  v8::Local<v8::FunctionTemplate> hFuncTemplate =
+      v8::FunctionTemplate::New(pIsolate);
+  v8::Local<v8::ObjectTemplate> hGlobalTemplate =
+      hFuncTemplate->InstanceTemplate();
+  hGlobalTemplate->Set(
+      v8::Symbol::GetToStringTag(pIsolate),
+      v8::String::NewFromUtf8(pIsolate, "global", v8::NewStringType::kNormal)
+          .ToLocalChecked());
+  v8::Local<v8::Context> hContext =
+      v8::Context::New(pIsolate, 0, hGlobalTemplate);
+  hContext->SetSecurityToken(v8::External::New(pIsolate, pIsolate));
+  pRuntimeData->m_hRootContextGlobalTemplate.Reset(pIsolate, hFuncTemplate);
+  pRuntimeData->m_hRootContext.Reset(pIsolate, hContext);
+  return pRuntimeData;
+}
+
+CFXJSE_RuntimeData* CFXJSE_RuntimeData::Get(v8::Isolate* pIsolate) {
+  FXJS_PerIsolateData::SetUp(pIsolate);
+  FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate);
+  if (!pData->m_pFXJSERuntimeData)
+    pData->m_pFXJSERuntimeData = CFXJSE_RuntimeData::Create(pIsolate);
+  return pData->m_pFXJSERuntimeData;
+}
+
+CFXJSE_IsolateTracker* CFXJSE_IsolateTracker::g_pInstance = nullptr;
diff --git a/fxjs/cfxjse_runtimedata.h b/fxjs/cfxjse_runtimedata.h
new file mode 100644
index 0000000..34f8f32
--- /dev/null
+++ b/fxjs/cfxjse_runtimedata.h
@@ -0,0 +1,34 @@
+// Copyright 2016 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJS_CFXJSE_RUNTIMEDATA_H_
+#define FXJS_CFXJSE_RUNTIMEDATA_H_
+
+#include "v8/include/v8.h"
+
+class CFXJSE_RuntimeList;
+
+class CFXJSE_RuntimeData {
+ public:
+  ~CFXJSE_RuntimeData();
+
+  static CFXJSE_RuntimeData* Get(v8::Isolate* pIsolate);
+
+  v8::Isolate* m_pIsolate;
+  v8::Global<v8::FunctionTemplate> m_hRootContextGlobalTemplate;
+  v8::Global<v8::Context> m_hRootContext;
+
+ protected:
+  explicit CFXJSE_RuntimeData(v8::Isolate* pIsolate);
+
+  static CFXJSE_RuntimeData* Create(v8::Isolate* pIsolate);
+
+ private:
+  CFXJSE_RuntimeData(const CFXJSE_RuntimeData&) = delete;
+  CFXJSE_RuntimeData& operator=(const CFXJSE_RuntimeData&) = delete;
+};
+
+#endif  // FXJS_CFXJSE_RUNTIMEDATA_H_
diff --git a/fxjs/cfxjse_value.cpp b/fxjs/cfxjse_value.cpp
new file mode 100644
index 0000000..b1fc078
--- /dev/null
+++ b/fxjs/cfxjse_value.cpp
@@ -0,0 +1,519 @@
+// Copyright 2014 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "fxjs/include/cfxjse_value.h"
+
+#include <math.h>
+
+#include "fxjs/include/cfxjse_class.h"
+#include "fxjs/include/cfxjse_context.h"
+
+namespace {
+
+double ftod(FX_FLOAT fNumber) {
+  static_assert(sizeof(FX_FLOAT) == 4, "FX_FLOAT of incorrect size");
+
+  uint32_t nFloatBits = (uint32_t&)fNumber;
+  uint8_t nExponent = (uint8_t)(nFloatBits >> 23);
+  if (nExponent == 0 || nExponent == 255)
+    return fNumber;
+
+  int8_t nErrExp = nExponent - 150;
+  if (nErrExp >= 0)
+    return fNumber;
+
+  double dwError = pow(2.0, nErrExp), dwErrorHalf = dwError / 2;
+  double dNumber = fNumber, dNumberAbs = fabs(fNumber);
+  double dNumberAbsMin = dNumberAbs - dwErrorHalf,
+         dNumberAbsMax = dNumberAbs + dwErrorHalf;
+  int32_t iErrPos = 0;
+  if (floor(dNumberAbsMin) == floor(dNumberAbsMax)) {
+    dNumberAbsMin = fmod(dNumberAbsMin, 1.0);
+    dNumberAbsMax = fmod(dNumberAbsMax, 1.0);
+    int32_t iErrPosMin = 1, iErrPosMax = 38;
+    do {
+      int32_t iMid = (iErrPosMin + iErrPosMax) / 2;
+      double dPow = pow(10.0, iMid);
+      if (floor(dNumberAbsMin * dPow) == floor(dNumberAbsMax * dPow)) {
+        iErrPosMin = iMid + 1;
+      } else {
+        iErrPosMax = iMid;
+      }
+    } while (iErrPosMin < iErrPosMax);
+    iErrPos = iErrPosMax;
+  }
+  double dPow = pow(10.0, iErrPos);
+  return fNumber < 0 ? ceil(dNumber * dPow - 0.5) / dPow
+                     : floor(dNumber * dPow + 0.5) / dPow;
+}
+
+}  // namespace
+
+void FXJSE_ThrowMessage(const CFX_ByteStringC& utf8Message) {
+  v8::Isolate* pIsolate = v8::Isolate::GetCurrent();
+  ASSERT(pIsolate);
+
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
+  v8::Local<v8::String> hMessage = v8::String::NewFromUtf8(
+      pIsolate, utf8Message.c_str(), v8::String::kNormalString,
+      utf8Message.GetLength());
+  v8::Local<v8::Value> hError = v8::Exception::Error(hMessage);
+  pIsolate->ThrowException(hError);
+}
+
+CFXJSE_Value::CFXJSE_Value(v8::Isolate* pIsolate) : m_pIsolate(pIsolate) {}
+
+CFXJSE_Value::~CFXJSE_Value() {}
+
+CFXJSE_HostObject* CFXJSE_Value::ToHostObject(CFXJSE_Class* lpClass) const {
+  ASSERT(!m_hValue.IsEmpty());
+
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> pValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  ASSERT(!pValue.IsEmpty());
+
+  if (!pValue->IsObject())
+    return nullptr;
+
+  return FXJSE_RetrieveObjectBinding(pValue.As<v8::Object>(), lpClass);
+}
+
+void CFXJSE_Value::SetObject(CFXJSE_HostObject* lpObject,
+                             CFXJSE_Class* pClass) {
+  if (!pClass) {
+    ASSERT(!lpObject);
+    SetJSObject();
+    return;
+  }
+  SetHostObject(lpObject, pClass);
+}
+
+void CFXJSE_Value::SetHostObject(CFXJSE_HostObject* lpObject,
+                                 CFXJSE_Class* lpClass) {
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  ASSERT(lpClass);
+  v8::Local<v8::FunctionTemplate> hClass =
+      v8::Local<v8::FunctionTemplate>::New(m_pIsolate, lpClass->m_hTemplate);
+  v8::Local<v8::Object> hObject = hClass->InstanceTemplate()->NewInstance();
+  FXJSE_UpdateObjectBinding(hObject, lpObject);
+  m_hValue.Reset(m_pIsolate, hObject);
+}
+
+void CFXJSE_Value::SetArray(uint32_t uValueCount, CFXJSE_Value** rgValues) {
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Array> hArrayObject = v8::Array::New(m_pIsolate, uValueCount);
+  if (rgValues) {
+    for (uint32_t i = 0; i < uValueCount; i++) {
+      if (rgValues[i]) {
+        hArrayObject->Set(i, v8::Local<v8::Value>::New(
+                                 m_pIsolate, rgValues[i]->DirectGetValue()));
+      }
+    }
+  }
+  m_hValue.Reset(m_pIsolate, hArrayObject);
+}
+
+void CFXJSE_Value::SetDate(double dDouble) {
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hDate = v8::Date::New(m_pIsolate, dDouble);
+  m_hValue.Reset(m_pIsolate, hDate);
+}
+
+void CFXJSE_Value::SetFloat(FX_FLOAT fFloat) {
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> pValue = v8::Number::New(m_pIsolate, ftod(fFloat));
+  m_hValue.Reset(m_pIsolate, pValue);
+}
+
+FX_BOOL CFXJSE_Value::SetObjectProperty(const CFX_ByteStringC& szPropName,
+                                        CFXJSE_Value* lpPropValue) {
+  ASSERT(lpPropValue);
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hObject =
+      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  if (!hObject->IsObject())
+    return FALSE;
+
+  v8::Local<v8::Value> hPropValue =
+      v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->DirectGetValue());
+  return (FX_BOOL)hObject.As<v8::Object>()->Set(
+      v8::String::NewFromUtf8(m_pIsolate, szPropName.c_str(),
+                              v8::String::kNormalString,
+                              szPropName.GetLength()),
+      hPropValue);
+}
+
+FX_BOOL CFXJSE_Value::GetObjectProperty(const CFX_ByteStringC& szPropName,
+                                        CFXJSE_Value* lpPropValue) {
+  ASSERT(lpPropValue);
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hObject =
+      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  if (!hObject->IsObject())
+    return FALSE;
+
+  v8::Local<v8::Value> hPropValue =
+      hObject.As<v8::Object>()->Get(v8::String::NewFromUtf8(
+          m_pIsolate, szPropName.c_str(), v8::String::kNormalString,
+          szPropName.GetLength()));
+  lpPropValue->ForceSetValue(hPropValue);
+  return TRUE;
+}
+
+FX_BOOL CFXJSE_Value::SetObjectProperty(uint32_t uPropIdx,
+                                        CFXJSE_Value* lpPropValue) {
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hObject =
+      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  if (!hObject->IsObject())
+    return FALSE;
+
+  v8::Local<v8::Value> hPropValue =
+      v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->DirectGetValue());
+  return (FX_BOOL)hObject.As<v8::Object>()->Set(uPropIdx, hPropValue);
+}
+
+FX_BOOL CFXJSE_Value::GetObjectPropertyByIdx(uint32_t uPropIdx,
+                                             CFXJSE_Value* lpPropValue) {
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hObject =
+      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  if (!hObject->IsObject())
+    return FALSE;
+
+  v8::Local<v8::Value> hPropValue = hObject.As<v8::Object>()->Get(uPropIdx);
+  lpPropValue->ForceSetValue(hPropValue);
+  return TRUE;
+}
+
+FX_BOOL CFXJSE_Value::DeleteObjectProperty(const CFX_ByteStringC& szPropName) {
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hObject =
+      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  if (!hObject->IsObject())
+    return FALSE;
+
+  hObject.As<v8::Object>()->Delete(v8::String::NewFromUtf8(
+      m_pIsolate, szPropName.c_str(), v8::String::kNormalString,
+      szPropName.GetLength()));
+  return TRUE;
+}
+
+FX_BOOL CFXJSE_Value::HasObjectOwnProperty(const CFX_ByteStringC& szPropName,
+                                           FX_BOOL bUseTypeGetter) {
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hObject =
+      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  if (!hObject->IsObject())
+    return FALSE;
+
+  v8::Local<v8::String> hKey = v8::String::NewFromUtf8(
+      m_pIsolate, szPropName.c_str(), v8::String::kNormalString,
+      szPropName.GetLength());
+  return hObject.As<v8::Object>()->HasRealNamedProperty(hKey) ||
+         (bUseTypeGetter &&
+          hObject.As<v8::Object>()
+              ->HasOwnProperty(m_pIsolate->GetCurrentContext(), hKey)
+              .FromMaybe(false));
+}
+
+FX_BOOL CFXJSE_Value::SetObjectOwnProperty(const CFX_ByteStringC& szPropName,
+                                           CFXJSE_Value* lpPropValue) {
+  ASSERT(lpPropValue);
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hObject =
+      v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  if (!hObject->IsObject())
+    return FALSE;
+
+  v8::Local<v8::Value> pValue =
+      v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->m_hValue);
+  return hObject.As<v8::Object>()
+      ->DefineOwnProperty(
+          m_pIsolate->GetCurrentContext(),
+          v8::String::NewFromUtf8(m_pIsolate, szPropName.c_str(),
+                                  v8::String::kNormalString,
+                                  szPropName.GetLength()),
+          pValue)
+      .FromMaybe(false);
+}
+
+FX_BOOL CFXJSE_Value::SetFunctionBind(CFXJSE_Value* lpOldFunction,
+                                      CFXJSE_Value* lpNewThis) {
+  ASSERT(lpOldFunction && lpNewThis);
+
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> rgArgs[2];
+  v8::Local<v8::Value> hOldFunction =
+      v8::Local<v8::Value>::New(m_pIsolate, lpOldFunction->DirectGetValue());
+  if (hOldFunction.IsEmpty() || !hOldFunction->IsFunction())
+    return FALSE;
+
+  rgArgs[0] = hOldFunction;
+  v8::Local<v8::Value> hNewThis =
+      v8::Local<v8::Value>::New(m_pIsolate, lpNewThis->DirectGetValue());
+  if (hNewThis.IsEmpty())
+    return FALSE;
+
+  rgArgs[1] = hNewThis;
+  v8::Local<v8::String> hBinderFuncSource =
+      v8::String::NewFromUtf8(m_pIsolate,
+                              "(function (oldfunction, newthis) { return "
+                              "oldfunction.bind(newthis); })");
+  v8::Local<v8::Function> hBinderFunc =
+      v8::Script::Compile(hBinderFuncSource)->Run().As<v8::Function>();
+  v8::Local<v8::Value> hBoundFunction =
+      hBinderFunc->Call(m_pIsolate->GetCurrentContext()->Global(), 2, rgArgs);
+  if (hBoundFunction.IsEmpty() || !hBoundFunction->IsFunction())
+    return FALSE;
+
+  m_hValue.Reset(m_pIsolate, hBoundFunction);
+  return TRUE;
+}
+
+#define FXJSE_INVALID_PTR ((void*)(intptr_t)-1)
+FX_BOOL CFXJSE_Value::Call(CFXJSE_Value* lpReceiver,
+                           CFXJSE_Value* lpRetValue,
+                           uint32_t nArgCount,
+                           CFXJSE_Value** lpArgs) {
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hFunctionValue =
+      v8::Local<v8::Value>::New(m_pIsolate, DirectGetValue());
+  v8::Local<v8::Object> hFunctionObject =
+      !hFunctionValue.IsEmpty() && hFunctionValue->IsObject()
+          ? hFunctionValue.As<v8::Object>()
+          : v8::Local<v8::Object>();
+
+  v8::TryCatch trycatch(m_pIsolate);
+  if (hFunctionObject.IsEmpty() || !hFunctionObject->IsCallable()) {
+    if (lpRetValue)
+      lpRetValue->ForceSetValue(FXJSE_CreateReturnValue(m_pIsolate, trycatch));
+    return FALSE;
+  }
+
+  v8::Local<v8::Value> hReturnValue;
+  v8::Local<v8::Value>* lpLocalArgs = NULL;
+  if (nArgCount) {
+    lpLocalArgs = FX_Alloc(v8::Local<v8::Value>, nArgCount);
+    for (uint32_t i = 0; i < nArgCount; i++) {
+      new (lpLocalArgs + i) v8::Local<v8::Value>;
+      CFXJSE_Value* lpArg = lpArgs[i];
+      if (lpArg) {
+        lpLocalArgs[i] =
+            v8::Local<v8::Value>::New(m_pIsolate, lpArg->DirectGetValue());
+      }
+      if (lpLocalArgs[i].IsEmpty()) {
+        lpLocalArgs[i] = v8::Undefined(m_pIsolate);
+      }
+    }
+  }
+
+  FX_BOOL bRetValue = TRUE;
+  if (lpReceiver == FXJSE_INVALID_PTR) {
+    v8::MaybeLocal<v8::Value> maybe_retvalue =
+        hFunctionObject->CallAsConstructor(m_pIsolate->GetCurrentContext(),
+                                           nArgCount, lpLocalArgs);
+    hReturnValue = maybe_retvalue.FromMaybe(v8::Local<v8::Value>());
+  } else {
+    v8::Local<v8::Value> hReceiver;
+    if (lpReceiver) {
+      hReceiver =
+          v8::Local<v8::Value>::New(m_pIsolate, lpReceiver->DirectGetValue());
+    }
+    if (hReceiver.IsEmpty() || !hReceiver->IsObject())
+      hReceiver = v8::Object::New(m_pIsolate);
+
+    v8::MaybeLocal<v8::Value> maybe_retvalue = hFunctionObject->CallAsFunction(
+        m_pIsolate->GetCurrentContext(), hReceiver, nArgCount, lpLocalArgs);
+    hReturnValue = maybe_retvalue.FromMaybe(v8::Local<v8::Value>());
+  }
+
+  if (trycatch.HasCaught()) {
+    hReturnValue = FXJSE_CreateReturnValue(m_pIsolate, trycatch);
+    bRetValue = FALSE;
+  }
+
+  if (lpRetValue)
+    lpRetValue->ForceSetValue(hReturnValue);
+
+  if (lpLocalArgs) {
+    for (uint32_t i = 0; i < nArgCount; i++)
+      lpLocalArgs[i].~Local();
+    FX_Free(lpLocalArgs);
+  }
+  return bRetValue;
+}
+
+FX_BOOL CFXJSE_Value::IsUndefined() const {
+  if (m_hValue.IsEmpty())
+    return FALSE;
+
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return hValue->IsUndefined();
+}
+
+FX_BOOL CFXJSE_Value::IsNull() const {
+  if (m_hValue.IsEmpty())
+    return FALSE;
+
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return hValue->IsNull();
+}
+
+FX_BOOL CFXJSE_Value::IsBoolean() const {
+  if (m_hValue.IsEmpty())
+    return FALSE;
+
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return hValue->IsBoolean();
+}
+
+FX_BOOL CFXJSE_Value::IsString() const {
+  if (m_hValue.IsEmpty())
+    return FALSE;
+
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return hValue->IsString();
+}
+
+FX_BOOL CFXJSE_Value::IsNumber() const {
+  if (m_hValue.IsEmpty())
+    return FALSE;
+
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return hValue->IsNumber();
+}
+
+FX_BOOL CFXJSE_Value::IsInteger() const {
+  if (m_hValue.IsEmpty())
+    return FALSE;
+
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return hValue->IsInt32();
+}
+
+FX_BOOL CFXJSE_Value::IsObject() const {
+  if (m_hValue.IsEmpty())
+    return FALSE;
+
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return hValue->IsObject();
+}
+
+FX_BOOL CFXJSE_Value::IsArray() const {
+  if (m_hValue.IsEmpty())
+    return FALSE;
+
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return hValue->IsArray();
+}
+
+FX_BOOL CFXJSE_Value::IsFunction() const {
+  if (m_hValue.IsEmpty())
+    return FALSE;
+
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return hValue->IsFunction();
+}
+
+FX_BOOL CFXJSE_Value::IsDate() const {
+  if (m_hValue.IsEmpty())
+    return FALSE;
+
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return hValue->IsDate();
+}
+
+FX_BOOL CFXJSE_Value::ToBoolean() const {
+  ASSERT(!m_hValue.IsEmpty());
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return static_cast<FX_BOOL>(hValue->BooleanValue());
+}
+
+FX_FLOAT CFXJSE_Value::ToFloat() const {
+  ASSERT(!m_hValue.IsEmpty());
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return static_cast<FX_FLOAT>(hValue->NumberValue());
+}
+
+double CFXJSE_Value::ToDouble() const {
+  ASSERT(!m_hValue.IsEmpty());
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return static_cast<double>(hValue->NumberValue());
+}
+
+int32_t CFXJSE_Value::ToInteger() const {
+  ASSERT(!m_hValue.IsEmpty());
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  return static_cast<int32_t>(hValue->NumberValue());
+}
+
+CFX_ByteString CFXJSE_Value::ToString() const {
+  ASSERT(!m_hValue.IsEmpty());
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue);
+  v8::Local<v8::String> hString = hValue->ToString();
+  v8::String::Utf8Value hStringVal(hString);
+  return CFX_ByteString(*hStringVal);
+}
+
+void CFXJSE_Value::SetUndefined() {
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Undefined(m_pIsolate);
+  m_hValue.Reset(m_pIsolate, hValue);
+}
+
+void CFXJSE_Value::SetNull() {
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Null(m_pIsolate);
+  m_hValue.Reset(m_pIsolate, hValue);
+}
+
+void CFXJSE_Value::SetBoolean(FX_BOOL bBoolean) {
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Boolean::New(m_pIsolate, bBoolean != FALSE);
+  m_hValue.Reset(m_pIsolate, hValue);
+}
+
+void CFXJSE_Value::SetInteger(int32_t nInteger) {
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Integer::New(m_pIsolate, nInteger);
+  m_hValue.Reset(m_pIsolate, hValue);
+}
+
+void CFXJSE_Value::SetDouble(double dDouble) {
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Number::New(m_pIsolate, dDouble);
+  m_hValue.Reset(m_pIsolate, hValue);
+}
+
+void CFXJSE_Value::SetString(const CFX_ByteStringC& szString) {
+  CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::String::NewFromUtf8(
+      m_pIsolate, reinterpret_cast<const char*>(szString.raw_str()),
+      v8::String::kNormalString, szString.GetLength());
+  m_hValue.Reset(m_pIsolate, hValue);
+}
+
+void CFXJSE_Value::SetJSObject() {
+  CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate);
+  v8::Local<v8::Value> hValue = v8::Object::New(m_pIsolate);
+  m_hValue.Reset(m_pIsolate, hValue);
+}
diff --git a/fxjs/include/cfxjse_arguments.h b/fxjs/include/cfxjse_arguments.h
new file mode 100644
index 0000000..e6c8659
--- /dev/null
+++ b/fxjs/include/cfxjse_arguments.h
@@ -0,0 +1,38 @@
+// Copyright 2016 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJS_INCLUDE_CFXJSE_ARGUMENTS_H_
+#define FXJS_INCLUDE_CFXJSE_ARGUMENTS_H_
+
+#include <memory>
+
+#include "fxjs/include/fxjse.h"
+
+class CFXJSE_Class;
+
+class CFXJSE_Arguments {
+ public:
+  CFXJSE_Arguments(const v8::FunctionCallbackInfo<v8::Value>* pInfo,
+                   CFXJSE_Value* pRetValue)
+      : m_pInfo(pInfo), m_pRetValue(pRetValue) {}
+
+  v8::Isolate* GetRuntime() const;
+  int32_t GetLength() const;
+  std::unique_ptr<CFXJSE_Value> GetValue(int32_t index) const;
+  FX_BOOL GetBoolean(int32_t index) const;
+  int32_t GetInt32(int32_t index) const;
+  FX_FLOAT GetFloat(int32_t index) const;
+  CFX_ByteString GetUTF8String(int32_t index) const;
+  CFXJSE_HostObject* GetObject(int32_t index,
+                               CFXJSE_Class* pClass = nullptr) const;
+  CFXJSE_Value* GetReturnValue();
+
+ private:
+  const v8::FunctionCallbackInfo<v8::Value>* m_pInfo;
+  CFXJSE_Value* m_pRetValue;
+};
+
+#endif  // FXJS_INCLUDE_CFXJSE_ARGUMENTS_H_
diff --git a/fxjs/include/cfxjse_class.h b/fxjs/include/cfxjse_class.h
new file mode 100644
index 0000000..13eb1ad
--- /dev/null
+++ b/fxjs/include/cfxjse_class.h
@@ -0,0 +1,45 @@
+// Copyright 2014 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJS_INCLUDE_CFXJSE_CLASS_H_
+#define FXJS_INCLUDE_CFXJSE_CLASS_H_
+
+#include "fxjs/include/cfxjse_arguments.h"
+#include "fxjs/include/fxjse.h"
+#include "v8/include/v8.h"
+
+class CFXJSE_Context;
+class CFXJSE_Value;
+
+class CFXJSE_Class {
+ public:
+  static CFXJSE_Class* Create(CFXJSE_Context* pContext,
+                              const FXJSE_CLASS_DESCRIPTOR* lpClassDefintion,
+                              FX_BOOL bIsJSGlobal = FALSE);
+  static CFXJSE_Class* GetClassFromContext(CFXJSE_Context* pContext,
+                                           const CFX_ByteStringC& szName);
+  static void SetUpNamedPropHandler(
+      v8::Isolate* pIsolate,
+      v8::Local<v8::ObjectTemplate>& hObjectTemplate,
+      const FXJSE_CLASS_DESCRIPTOR* lpClassDefinition);
+
+  ~CFXJSE_Class();
+
+  CFXJSE_Context* GetContext() { return m_pContext; }
+  v8::Global<v8::FunctionTemplate>& GetTemplate() { return m_hTemplate; }
+
+ protected:
+  explicit CFXJSE_Class(CFXJSE_Context* lpContext);
+
+  CFX_ByteString m_szClassName;
+  const FXJSE_CLASS_DESCRIPTOR* m_lpClassDefinition;
+  CFXJSE_Context* m_pContext;
+  v8::Global<v8::FunctionTemplate> m_hTemplate;
+  friend class CFXJSE_Context;
+  friend class CFXJSE_Value;
+};
+
+#endif  // FXJS_INCLUDE_CFXJSE_CLASS_H_
diff --git a/fxjs/include/cfxjse_context.h b/fxjs/include/cfxjse_context.h
new file mode 100644
index 0000000..882258f
--- /dev/null
+++ b/fxjs/include/cfxjse_context.h
@@ -0,0 +1,65 @@
+// Copyright 2016 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJS_INCLUDE_CFXJSE_CONTEXT_H_
+#define FXJS_INCLUDE_CFXJSE_CONTEXT_H_
+
+#include <memory>
+#include <vector>
+
+#include "core/fxcrt/include/fx_basic.h"
+#include "fxjs/include/fxjse.h"
+#include "v8/include/v8.h"
+
+class CFXJSE_Class;
+class CFXJSE_Value;
+struct FXJSE_CLASS_DESCRIPTOR;
+
+class CFXJSE_Context {
+ public:
+  static CFXJSE_Context* Create(
+      v8::Isolate* pIsolate,
+      const FXJSE_CLASS_DESCRIPTOR* lpGlobalClass = nullptr,
+      CFXJSE_HostObject* lpGlobalObject = nullptr);
+
+  ~CFXJSE_Context();
+
+  v8::Isolate* GetRuntime() { return m_pIsolate; }
+  std::unique_ptr<CFXJSE_Value> GetGlobalObject();
+  void EnableCompatibleMode();
+  FX_BOOL ExecuteScript(const FX_CHAR* szScript,
+                        CFXJSE_Value* lpRetValue,
+                        CFXJSE_Value* lpNewThisObject = nullptr);
+
+ protected:
+  friend class CFXJSE_Class;
+  friend class CFXJSE_ScopeUtil_IsolateHandleContext;
+
+  CFXJSE_Context();
+  CFXJSE_Context(const CFXJSE_Context&);
+  explicit CFXJSE_Context(v8::Isolate* pIsolate);
+
+  CFXJSE_Context& operator=(const CFXJSE_Context&);
+
+  v8::Global<v8::Context> m_hContext;
+  v8::Isolate* m_pIsolate;
+  std::vector<std::unique_ptr<CFXJSE_Class>> m_rgClasses;
+};
+
+v8::Local<v8::Object> FXJSE_CreateReturnValue(v8::Isolate* pIsolate,
+                                              v8::TryCatch& trycatch);
+
+v8::Local<v8::Object> FXJSE_GetGlobalObjectFromContext(
+    const v8::Local<v8::Context>& hContext);
+
+void FXJSE_UpdateObjectBinding(v8::Local<v8::Object>& hObject,
+                               CFXJSE_HostObject* lpNewBinding = nullptr);
+
+CFXJSE_HostObject* FXJSE_RetrieveObjectBinding(
+    const v8::Local<v8::Object>& hJSObject,
+    CFXJSE_Class* lpClass = nullptr);
+
+#endif  // FXJS_INCLUDE_CFXJSE_CONTEXT_H_
diff --git a/fxjs/include/cfxjse_value.h b/fxjs/include/cfxjse_value.h
new file mode 100644
index 0000000..7bb2c2d
--- /dev/null
+++ b/fxjs/include/cfxjse_value.h
@@ -0,0 +1,102 @@
+// Copyright 2014 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJS_INCLUDE_CFXJSE_VALUE_H_
+#define FXJS_INCLUDE_CFXJSE_VALUE_H_
+
+#include "v8/include/v8.h"
+
+#include "core/fxcrt/include/fx_string.h"
+#include "core/fxcrt/include/fx_system.h"
+#include "fxjs/cfxjse_isolatetracker.h"
+#include "fxjs/cfxjse_runtimedata.h"
+
+class CFXJSE_Class;
+class CFXJSE_HostObject;
+
+class CFXJSE_Value {
+ public:
+  explicit CFXJSE_Value(v8::Isolate* pIsolate);
+  ~CFXJSE_Value();
+
+  FX_BOOL IsUndefined() const;
+  FX_BOOL IsNull() const;
+  FX_BOOL IsBoolean() const;
+  FX_BOOL IsString() const;
+  FX_BOOL IsNumber() const;
+  FX_BOOL IsInteger() const;
+  FX_BOOL IsObject() const;
+  FX_BOOL IsArray() const;
+  FX_BOOL IsFunction() const;
+  FX_BOOL IsDate() const;
+  FX_BOOL ToBoolean() const;
+  FX_FLOAT ToFloat() const;
+  double ToDouble() const;
+  int32_t ToInteger() const;
+  CFX_ByteString ToString() const;
+  CFX_WideString ToWideString() const {
+    return CFX_WideString::FromUTF8(ToString().AsStringC());
+  }
+  CFXJSE_HostObject* ToHostObject(CFXJSE_Class* lpClass) const;
+
+  void SetUndefined();
+  void SetNull();
+  void SetBoolean(FX_BOOL bBoolean);
+  void SetInteger(int32_t nInteger);
+  void SetDouble(double dDouble);
+  void SetString(const CFX_ByteStringC& szString);
+  void SetFloat(FX_FLOAT fFloat);
+  void SetJSObject();
+
+  void SetObject(CFXJSE_HostObject* lpObject, CFXJSE_Class* pClass);
+  void SetHostObject(CFXJSE_HostObject* lpObject, CFXJSE_Class* lpClass);
+  void SetArray(uint32_t uValueCount, CFXJSE_Value** rgValues);
+  void SetDate(double dDouble);
+
+  FX_BOOL GetObjectProperty(const CFX_ByteStringC& szPropName,
+                            CFXJSE_Value* lpPropValue);
+  FX_BOOL SetObjectProperty(const CFX_ByteStringC& szPropName,
+                            CFXJSE_Value* lpPropValue);
+  FX_BOOL GetObjectPropertyByIdx(uint32_t uPropIdx, CFXJSE_Value* lpPropValue);
+  FX_BOOL SetObjectProperty(uint32_t uPropIdx, CFXJSE_Value* lpPropValue);
+  FX_BOOL DeleteObjectProperty(const CFX_ByteStringC& szPropName);
+  FX_BOOL HasObjectOwnProperty(const CFX_ByteStringC& szPropName,
+                               FX_BOOL bUseTypeGetter);
+  FX_BOOL SetObjectOwnProperty(const CFX_ByteStringC& szPropName,
+                               CFXJSE_Value* lpPropValue);
+  FX_BOOL SetFunctionBind(CFXJSE_Value* lpOldFunction, CFXJSE_Value* lpNewThis);
+  FX_BOOL Call(CFXJSE_Value* lpReceiver,
+               CFXJSE_Value* lpRetValue,
+               uint32_t nArgCount,
+               CFXJSE_Value** lpArgs);
+
+  v8::Isolate* GetIsolate() const { return m_pIsolate; }
+  const v8::Global<v8::Value>& DirectGetValue() const { return m_hValue; }
+  void ForceSetValue(v8::Local<v8::Value> hValue) {
+    m_hValue.Reset(m_pIsolate, hValue);
+  }
+  void Assign(const CFXJSE_Value* lpValue) {
+    ASSERT(lpValue);
+    if (lpValue) {
+      m_hValue.Reset(m_pIsolate, lpValue->m_hValue);
+    } else {
+      m_hValue.Reset();
+    }
+  }
+
+ private:
+  friend class CFXJSE_Class;
+  friend class CFXJSE_Context;
+
+  CFXJSE_Value();
+  CFXJSE_Value(const CFXJSE_Value&);
+  CFXJSE_Value& operator=(const CFXJSE_Value&);
+
+  v8::Isolate* m_pIsolate;
+  v8::Global<v8::Value> m_hValue;
+};
+
+#endif  // FXJS_INCLUDE_CFXJSE_VALUE_H_
diff --git a/fxjs/include/fxjse.h b/fxjs/include/fxjse.h
new file mode 100644
index 0000000..79c32b0
--- /dev/null
+++ b/fxjs/include/fxjse.h
@@ -0,0 +1,74 @@
+// Copyright 2014 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXJS_INCLUDE_FXJSE_H_
+#define FXJS_INCLUDE_FXJSE_H_
+
+#include "core/fxcrt/include/fx_string.h"
+#include "core/fxcrt/include/fx_system.h"
+#include "v8/include/v8.h"
+
+class CFXJSE_Arguments;
+class CFXJSE_Value;
+
+// C++ object which can be wrapped by CFXJSE_value.
+class CFXJSE_HostObject {
+ public:
+  virtual ~CFXJSE_HostObject() {}
+};
+
+typedef void (*FXJSE_FuncCallback)(CFXJSE_Value* pThis,
+                                   const CFX_ByteStringC& szFuncName,
+                                   CFXJSE_Arguments& args);
+typedef void (*FXJSE_PropAccessor)(CFXJSE_Value* pObject,
+                                   const CFX_ByteStringC& szPropName,
+                                   CFXJSE_Value* pValue);
+typedef int32_t (*FXJSE_PropTypeGetter)(CFXJSE_Value* pObject,
+                                        const CFX_ByteStringC& szPropName,
+                                        FX_BOOL bQueryIn);
+typedef FX_BOOL (*FXJSE_PropDeleter)(CFXJSE_Value* pObject,
+                                     const CFX_ByteStringC& szPropName);
+
+enum FXJSE_ClassPropTypes {
+  FXJSE_ClassPropType_None,
+  FXJSE_ClassPropType_Property,
+  FXJSE_ClassPropType_Method
+};
+
+struct FXJSE_FUNCTION_DESCRIPTOR {
+  const FX_CHAR* name;
+  FXJSE_FuncCallback callbackProc;
+};
+
+struct FXJSE_PROPERTY_DESCRIPTOR {
+  const FX_CHAR* name;
+  FXJSE_PropAccessor getProc;
+  FXJSE_PropAccessor setProc;
+};
+
+struct FXJSE_CLASS_DESCRIPTOR {
+  const FX_CHAR* name;
+  FXJSE_FuncCallback constructor;
+  const FXJSE_PROPERTY_DESCRIPTOR* properties;
+  const FXJSE_FUNCTION_DESCRIPTOR* methods;
+  int32_t propNum;
+  int32_t methNum;
+  FXJSE_PropTypeGetter dynPropTypeGetter;
+  FXJSE_PropAccessor dynPropGetter;
+  FXJSE_PropAccessor dynPropSetter;
+  FXJSE_PropDeleter dynPropDeleter;
+  FXJSE_FuncCallback dynMethodCall;
+};
+
+void FXJSE_Initialize();
+void FXJSE_Finalize();
+
+v8::Isolate* FXJSE_Runtime_Create_Own();
+void FXJSE_Runtime_Release(v8::Isolate* pIsolate);
+
+void FXJSE_ThrowMessage(const CFX_ByteStringC& utf8Message);
+
+#endif  // FXJS_INCLUDE_FXJSE_H_