Introduce IJS_Runtime::ScopedEventContext helper class.

This proves that m_EventContextArray is, in fact, a stack.
Tidy one function by using AutoRestorer while at it.

Change-Id: I319538b4eadcd9ce83319aa73861635dd5eb8c36
Reviewed-on: https://pdfium-review.googlesource.com/33970
Reviewed-by: dsinclair <dsinclair@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/fpdfsdk/cpdfsdk_actionhandler.cpp b/fpdfsdk/cpdfsdk_actionhandler.cpp
index d7bcd7f..5b72082 100644
--- a/fpdfsdk/cpdfsdk_actionhandler.cpp
+++ b/fpdfsdk/cpdfsdk_actionhandler.cpp
@@ -539,12 +539,8 @@
 void CPDFSDK_ActionHandler::RunScript(CPDFSDK_FormFillEnvironment* pFormFillEnv,
                                       const WideString& script,
                                       const RunScriptCallback& cb) {
-  IJS_Runtime* pRuntime = pFormFillEnv->GetIJSRuntime();
-  IJS_EventContext* pContext = pRuntime->NewEventContext();
-
-  cb(pContext);
-
+  IJS_Runtime::ScopedEventContext pContext(pFormFillEnv->GetIJSRuntime());
+  cb(pContext.Get());
   pContext->RunScript(script);
-  pRuntime->ReleaseEventContext(pContext);
   // TODO(dsinclair): Return error if RunScript returns a IJS_Runtime::JS_Error.
 }
diff --git a/fpdfsdk/cpdfsdk_interform.cpp b/fpdfsdk/cpdfsdk_interform.cpp
index 638b4df..1d8002a 100644
--- a/fpdfsdk/cpdfsdk_interform.cpp
+++ b/fpdfsdk/cpdfsdk_interform.cpp
@@ -19,6 +19,7 @@
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fpdfdoc/cpdf_actionfields.h"
 #include "core/fpdfdoc/cpdf_interform.h"
+#include "core/fxcrt/autorestorer.h"
 #include "core/fxge/cfx_graphstatedata.h"
 #include "core/fxge/cfx_pathdata.h"
 #include "fpdfsdk/cpdfsdk_actionhandler.h"
@@ -255,12 +256,11 @@
   if (m_bBusy)
     return;
 
+  AutoRestorer<bool> restorer(&m_bBusy);
   m_bBusy = true;
 
-  if (!IsCalculateEnabled()) {
-    m_bBusy = false;
+  if (!IsCalculateEnabled())
     return;
-  }
 
   IJS_Runtime* pRuntime = m_pFormFillEnv->GetIJSRuntime();
   int nSize = m_pInterForm->CountFieldsInCalculationOrder();
@@ -285,18 +285,16 @@
     if (csJS.IsEmpty())
       continue;
 
-    IJS_EventContext* pContext = pRuntime->NewEventContext();
     WideString sOldValue = pField->GetValue();
     WideString sValue = sOldValue;
     bool bRC = true;
+    IJS_Runtime::ScopedEventContext pContext(pRuntime);
     pContext->OnField_Calculate(pFormField, pField, sValue, bRC);
 
     Optional<IJS_Runtime::JS_Error> err = pContext->RunScript(csJS);
-    pRuntime->ReleaseEventContext(pContext);
     if (!err && bRC && sValue.Compare(sOldValue) != 0)
       pField->SetValue(sValue, true);
   }
-  m_bBusy = false;
 }
 
 WideString CPDFSDK_InterForm::OnFormat(CPDF_FormField* pFormField,
@@ -325,11 +323,10 @@
       if (!script.IsEmpty()) {
         WideString Value = sValue;
 
-        IJS_EventContext* pContext = pRuntime->NewEventContext();
+        IJS_Runtime::ScopedEventContext pContext(pRuntime);
         pContext->OnField_Format(pFormField, Value, true);
 
         Optional<IJS_Runtime::JS_Error> err = pContext->RunScript(script);
-        pRuntime->ReleaseEventContext(pContext);
         if (!err) {
           sValue = Value;
           bFormatted = true;
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp
index f9f5981..81e5fd0 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.cpp
@@ -994,10 +994,8 @@
   if (!pIJSRuntime)
     return false;
 
-  IJS_EventContext* pContext = pIJSRuntime->NewEventContext();
-  bool bRet = pIJSRuntime->SetValueByNameInGlobalObject(szPropName, pValue);
-  pIJSRuntime->ReleaseEventContext(pContext);
-  return bRet;
+  IJS_Runtime::ScopedEventContext pContext(pIJSRuntime);
+  return pIJSRuntime->SetValueByNameInGlobalObject(szPropName, pValue);
 }
 
 bool CPDFXFA_DocEnvironment::GetPropertyFromNonXFAGlobalObject(
@@ -1015,8 +1013,6 @@
   if (!pIJSRuntime)
     return false;
 
-  IJS_EventContext* pContext = pIJSRuntime->NewEventContext();
-  bool bRet = pIJSRuntime->GetValueByNameFromGlobalObject(szPropName, pValue);
-  pIJSRuntime->ReleaseEventContext(pContext);
-  return bRet;
+  IJS_Runtime::ScopedEventContext pContext(pIJSRuntime);
+  return pIJSRuntime->GetValueByNameFromGlobalObject(szPropName, pValue);
 }
diff --git a/fxjs/cfxjse_engine.cpp b/fxjs/cfxjse_engine.cpp
index 90fcc31..2361a64 100644
--- a/fxjs/cfxjse_engine.cpp
+++ b/fxjs/cfxjse_engine.cpp
@@ -145,13 +145,10 @@
   }
   AutoRestorer<CXFA_Object*> nodeRestorer(&m_pThisObject);
   m_pThisObject = pThisObject;
+
   CFXJSE_Value* pValue = pThisObject ? GetJSValueFromMap(pThisObject) : nullptr;
-
-  IJS_EventContext* ctx = m_pSubordinateRuntime->NewEventContext();
-  bool ret = m_JsContext->ExecuteScript(btScript.c_str(), hRetValue, pValue);
-  m_pSubordinateRuntime->ReleaseEventContext(ctx);
-
-  return ret;
+  IJS_Runtime::ScopedEventContext ctx(m_pSubordinateRuntime.Get());
+  return m_JsContext->ExecuteScript(btScript.c_str(), hRetValue, pValue);
 }
 
 bool CFXJSE_Engine::QueryNodeByFlag(CXFA_Node* refNode,
diff --git a/fxjs/cjs_app.cpp b/fxjs/cjs_app.cpp
index 9ce8dc3..3f9244c 100644
--- a/fxjs/cjs_app.cpp
+++ b/fxjs/cjs_app.cpp
@@ -414,12 +414,12 @@
 }
 
 void CJS_App::RunJsScript(CJS_Runtime* pRuntime, const WideString& wsScript) {
-  if (!pRuntime->IsBlocking()) {
-    IJS_EventContext* pContext = pRuntime->NewEventContext();
-    pContext->OnExternal_Exec();
-    pContext->RunScript(wsScript);
-    pRuntime->ReleaseEventContext(pContext);
-  }
+  if (pRuntime->IsBlocking())
+    return;
+
+  IJS_Runtime::ScopedEventContext pContext(pRuntime);
+  pContext->OnExternal_Exec();
+  pContext->RunScript(wsScript);
 }
 
 CJS_Return CJS_App::goBack(CJS_Runtime* pRuntime,
diff --git a/fxjs/cjs_runtime.cpp b/fxjs/cjs_runtime.cpp
index 22dc904..a8640ea 100644
--- a/fxjs/cjs_runtime.cpp
+++ b/fxjs/cjs_runtime.cpp
@@ -80,9 +80,8 @@
   if (m_isolateManaged || FXJS_GlobalIsolateRefCount() == 0)
     DefineJSObjects();
 
-  IJS_EventContext* pContext = NewEventContext();
+  ScopedEventContext pContext(this);
   InitializeEngine();
-  ReleaseEventContext(pContext);
   SetFormFillEnvToDocument();
 }
 
@@ -153,11 +152,8 @@
 }
 
 void CJS_Runtime::ReleaseEventContext(IJS_EventContext* pContext) {
-  auto it = std::find(m_EventContextArray.begin(), m_EventContextArray.end(),
-                      pdfium::FakeUniquePtr<CJS_EventContext>(
-                          static_cast<CJS_EventContext*>(pContext)));
-  if (it != m_EventContextArray.end())
-    m_EventContextArray.erase(it);
+  ASSERT(pContext == m_EventContextArray.back().get());
+  m_EventContextArray.pop_back();
 }
 
 CJS_EventContext* CJS_Runtime::GetCurrentEventContext() const {
diff --git a/fxjs/ijs_runtime.h b/fxjs/ijs_runtime.h
index a21aae8..9f15aba 100644
--- a/fxjs/ijs_runtime.h
+++ b/fxjs/ijs_runtime.h
@@ -34,10 +34,26 @@
     JS_Error(int line, int column, const WideString& exception);
   };
 
+  class ScopedEventContext {
+   public:
+    explicit ScopedEventContext(IJS_Runtime* pRuntime)
+        : m_pRuntime(pRuntime), m_pContext(pRuntime->NewEventContext()) {}
+
+    ~ScopedEventContext() { m_pRuntime->ReleaseEventContext(m_pContext); }
+
+    IJS_EventContext* Get() const { return m_pContext; }
+    IJS_EventContext* operator->() const { return m_pContext; }
+
+   private:
+    IJS_Runtime* m_pRuntime;
+    IJS_EventContext* m_pContext;
+  };
+
   static void Initialize(unsigned int slot, void* isolate);
   static void Destroy();
   static std::unique_ptr<IJS_Runtime> Create(
       CPDFSDK_FormFillEnvironment* pFormFillEnv);
+
   virtual ~IJS_Runtime();
 
   virtual CJS_Runtime* AsCJSRuntime() = 0;