[xfa] Make the event context available when calling back in XFA

When calling into the XFA JS engine with a request for a non-XFA JS
call which accesses the EventContext we would get a crash in XFA as we
never set the context. This CL changes the XFA code to accept the
CJS_Runtime instead of the CFXJS_Engine and then calls NewEventContext
before executing JS scripts. This will correctly setup the event context
as needed for any JS callbacks.

Bug: pdfium:1003
Change-Id: Icf202252b2e6e56afdf0d1766a32a893935a2fd3
Reviewed-on: https://pdfium-review.googlesource.com/33930
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: dsinclair <dsinclair@chromium.org>
diff --git a/fxjs/cfxjse_engine.cpp b/fxjs/cfxjse_engine.cpp
index e894d51..90fcc31 100644
--- a/fxjs/cfxjse_engine.cpp
+++ b/fxjs/cfxjse_engine.cpp
@@ -11,10 +11,10 @@
 #include "core/fxcrt/autorestorer.h"
 #include "core/fxcrt/cfx_widetextbuf.h"
 #include "core/fxcrt/fx_extension.h"
-#include "fxjs/cfxjs_engine.h"
 #include "fxjs/cfxjse_class.h"
 #include "fxjs/cfxjse_resolveprocessor.h"
 #include "fxjs/cfxjse_value.h"
+#include "fxjs/cjs_runtime.h"
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
 #include "xfa/fxfa/cxfa_eventparam.h"
@@ -94,12 +94,12 @@
 }
 
 CFXJSE_Engine::CFXJSE_Engine(CXFA_Document* pDocument,
-                             CFXJS_Engine* fxjs_engine)
-    : CFX_V8(fxjs_engine->GetIsolate()),
-      m_pSubordinateEngine(fxjs_engine),
+                             CJS_Runtime* fxjs_runtime)
+    : CFX_V8(fxjs_runtime->GetIsolate()),
+      m_pSubordinateRuntime(fxjs_runtime),
       m_pDocument(pDocument),
-      m_JsContext(CFXJSE_Context::Create(fxjs_engine->GetIsolate(),
-                                         fxjs_engine,
+      m_JsContext(CFXJSE_Context::Create(fxjs_runtime->GetIsolate(),
+                                         fxjs_runtime,
                                          &GlobalClassDescriptor,
                                          pDocument->GetRoot())),
       m_pJsClass(nullptr),
@@ -146,7 +146,12 @@
   AutoRestorer<CXFA_Object*> nodeRestorer(&m_pThisObject);
   m_pThisObject = pThisObject;
   CFXJSE_Value* pValue = pThisObject ? GetJSValueFromMap(pThisObject) : nullptr;
-  return m_JsContext->ExecuteScript(btScript.c_str(), hRetValue, pValue);
+
+  IJS_EventContext* ctx = m_pSubordinateRuntime->NewEventContext();
+  bool ret = m_JsContext->ExecuteScript(btScript.c_str(), hRetValue, pValue);
+  m_pSubordinateRuntime->ReleaseEventContext(ctx);
+
+  return ret;
 }
 
 bool CFXJSE_Engine::QueryNodeByFlag(CXFA_Node* refNode,
@@ -463,7 +468,7 @@
     return nullptr;
 
   auto pNewContext = CFXJSE_Context::Create(
-      GetIsolate(), m_pSubordinateEngine.Get(), &VariablesClassDescriptor,
+      GetIsolate(), m_pSubordinateRuntime.Get(), &VariablesClassDescriptor,
       new CXFA_ThisProxy(pSubform, pScriptNode));
   RemoveBuiltInObjs(pNewContext.get());
   pNewContext->EnableCompatibleMode();
diff --git a/fxjs/cfxjse_engine.h b/fxjs/cfxjse_engine.h
index dc05f0d..62de061 100644
--- a/fxjs/cfxjse_engine.h
+++ b/fxjs/cfxjse_engine.h
@@ -23,7 +23,7 @@
 #define XFA_RESOLVENODE_TagName 0x0002
 
 class CFXJSE_ResolveProcessor;
-class CFXJS_Engine;
+class CJS_Runtime;
 class CXFA_List;
 
 class CFXJSE_Engine : public CFX_V8 {
@@ -52,7 +52,7 @@
                                       const ByteStringView& szPropName,
                                       bool bQueryIn);
 
-  CFXJSE_Engine(CXFA_Document* pDocument, CFXJS_Engine* fxjs_engine);
+  CFXJSE_Engine(CXFA_Document* pDocument, CJS_Runtime* fxjs_runtime);
   ~CFXJSE_Engine() override;
 
   void SetEventParam(CXFA_EventParam* param) { m_eventParam = param; }
@@ -107,7 +107,7 @@
                           bool bGetter);
   bool RunVariablesScript(CXFA_Node* pScriptNode);
 
-  UnownedPtr<CFXJS_Engine> const m_pSubordinateEngine;
+  UnownedPtr<CJS_Runtime> const m_pSubordinateRuntime;
   UnownedPtr<CXFA_Document> const m_pDocument;
   std::unique_ptr<CFXJSE_Context> m_JsContext;
   CFXJSE_Class* m_pJsClass;
diff --git a/fxjs/cjs_event.cpp b/fxjs/cjs_event.cpp
index ca0671d..de22ab8 100644
--- a/fxjs/cjs_event.cpp
+++ b/fxjs/cjs_event.cpp
@@ -50,6 +50,8 @@
 CJS_Event::~CJS_Event() = default;
 
 CJS_Return CJS_Event::get_change(CJS_Runtime* pRuntime) {
+  ASSERT(pRuntime->GetCurrentEventContext());
+
   CJS_EventHandler* pEvent =
       pRuntime->GetCurrentEventContext()->GetEventHandler();
   return CJS_Return(pRuntime->NewString(pEvent->Change().c_str()));
@@ -57,6 +59,8 @@
 
 CJS_Return CJS_Event::set_change(CJS_Runtime* pRuntime,
                                  v8::Local<v8::Value> vp) {
+  ASSERT(pRuntime->GetCurrentEventContext());
+
   CJS_EventHandler* pEvent =
       pRuntime->GetCurrentEventContext()->GetEventHandler();
 
@@ -68,6 +72,8 @@
 }
 
 CJS_Return CJS_Event::get_change_ex(CJS_Runtime* pRuntime) {
+  ASSERT(pRuntime->GetCurrentEventContext());
+
   CJS_EventHandler* pEvent =
       pRuntime->GetCurrentEventContext()->GetEventHandler();
 
@@ -80,6 +86,8 @@
 }
 
 CJS_Return CJS_Event::get_commit_key(CJS_Runtime* pRuntime) {
+  ASSERT(pRuntime->GetCurrentEventContext());
+
   CJS_EventHandler* pEvent =
       pRuntime->GetCurrentEventContext()->GetEventHandler();
 
@@ -92,6 +100,8 @@
 }
 
 CJS_Return CJS_Event::get_field_full(CJS_Runtime* pRuntime) {
+  ASSERT(pRuntime->GetCurrentEventContext());
+
   CJS_EventHandler* pEvent =
       pRuntime->GetCurrentEventContext()->GetEventHandler();
 
@@ -245,6 +255,8 @@
 }
 
 CJS_Return CJS_Event::get_target(CJS_Runtime* pRuntime) {
+  ASSERT(pRuntime->GetCurrentEventContext());
+
   CJS_EventHandler* pEvent =
       pRuntime->GetCurrentEventContext()->GetEventHandler();
   return CJS_Return(pEvent->Target_Field()->ToV8Object());
@@ -256,6 +268,8 @@
 }
 
 CJS_Return CJS_Event::get_target_name(CJS_Runtime* pRuntime) {
+  ASSERT(pRuntime->GetCurrentEventContext());
+
   CJS_EventHandler* pEvent =
       pRuntime->GetCurrentEventContext()->GetEventHandler();
   return CJS_Return(pRuntime->NewString(pEvent->TargetName().c_str()));
@@ -267,6 +281,8 @@
 }
 
 CJS_Return CJS_Event::get_type(CJS_Runtime* pRuntime) {
+  ASSERT(pRuntime->GetCurrentEventContext());
+
   CJS_EventHandler* pEvent =
       pRuntime->GetCurrentEventContext()->GetEventHandler();
   return CJS_Return(pRuntime->NewString(pEvent->Type()));
@@ -277,6 +293,8 @@
 }
 
 CJS_Return CJS_Event::get_value(CJS_Runtime* pRuntime) {
+  ASSERT(pRuntime->GetCurrentEventContext());
+
   CJS_EventHandler* pEvent =
       pRuntime->GetCurrentEventContext()->GetEventHandler();
 
@@ -291,6 +309,8 @@
 
 CJS_Return CJS_Event::set_value(CJS_Runtime* pRuntime,
                                 v8::Local<v8::Value> vp) {
+  ASSERT(pRuntime->GetCurrentEventContext());
+
   CJS_EventHandler* pEvent =
       pRuntime->GetCurrentEventContext()->GetEventHandler();
 
@@ -305,6 +325,8 @@
 }
 
 CJS_Return CJS_Event::get_will_commit(CJS_Runtime* pRuntime) {
+  ASSERT(pRuntime->GetCurrentEventContext());
+
   CJS_EventHandler* pEvent =
       pRuntime->GetCurrentEventContext()->GetEventHandler();
   return CJS_Return(pRuntime->NewBoolean(pEvent->WillCommit()));
diff --git a/xfa/fxfa/parser/cxfa_document.cpp b/xfa/fxfa/parser/cxfa_document.cpp
index 5c4b557..a24bf20 100644
--- a/xfa/fxfa/parser/cxfa_document.cpp
+++ b/xfa/fxfa/parser/cxfa_document.cpp
@@ -1435,9 +1435,9 @@
   return m_pLocalMgr.get();
 }
 
-CFXJSE_Engine* CXFA_Document::InitScriptContext(CFXJS_Engine* fxjs_engine) {
+CFXJSE_Engine* CXFA_Document::InitScriptContext(CJS_Runtime* fxjs_runtime) {
   ASSERT(!m_pScriptContext);
-  m_pScriptContext = pdfium::MakeUnique<CFXJSE_Engine>(this, fxjs_engine);
+  m_pScriptContext = pdfium::MakeUnique<CFXJSE_Engine>(this, fxjs_runtime);
   return m_pScriptContext.get();
 }
 
diff --git a/xfa/fxfa/parser/cxfa_document.h b/xfa/fxfa/parser/cxfa_document.h
index f924abb..795da00 100644
--- a/xfa/fxfa/parser/cxfa_document.h
+++ b/xfa/fxfa/parser/cxfa_document.h
@@ -41,7 +41,7 @@
 };
 
 class CFXJSE_Engine;
-class CFXJS_Engine;
+class CJS_Runtime;
 class CScript_DataWindow;
 class CScript_EventPseudoModel;
 class CScript_HostPseudoModel;
@@ -58,7 +58,7 @@
   explicit CXFA_Document(CXFA_FFNotify* notify);
   ~CXFA_Document() override;
 
-  CFXJSE_Engine* InitScriptContext(CFXJS_Engine* fxjs_engine);
+  CFXJSE_Engine* InitScriptContext(CJS_Runtime* fxjs_runtime);
 
   CXFA_Node* GetRoot() const { return m_pRootNode; }
   CXFA_FFNotify* GetNotify() const { return notify_.Get(); }