Merge to XFA: CJS_Timer should observe CJS_Runtime destruction.

Also remove dead CJS_EmbedObj::{Begin,End}Timer code.

BUG=539107
R=tsepez@chromium.org

Review URL: https://codereview.chromium.org/1384883002 .

(cherry picked from commit 794c9b67d3d519342aa7e15052766f7d4a99f551)

Review URL: https://codereview.chromium.org/1386053002 .
diff --git a/fpdfsdk/src/javascript/JS_Object.cpp b/fpdfsdk/src/javascript/JS_Object.cpp
index 429d268..a3f972c 100644
--- a/fpdfsdk/src/javascript/JS_Object.cpp
+++ b/fpdfsdk/src/javascript/JS_Object.cpp
@@ -55,20 +55,6 @@
   CJS_Object::Alert(pContext, swMsg);
 }
 
-CJS_Timer* CJS_EmbedObj::BeginTimer(CPDFDoc_Environment* pApp,
-                                    FX_UINT nElapse) {
-  CJS_Timer* pTimer = new CJS_Timer(this, pApp);
-  pTimer->SetJSTimer(nElapse);
-
-  return pTimer;
-}
-
-void CJS_EmbedObj::EndTimer(CJS_Timer* pTimer) {
-  ASSERT(pTimer != NULL);
-  pTimer->KillJSTimer();
-  delete pTimer;
-}
-
 void FreeObject(const v8::WeakCallbackInfo<CJS_Object>& data) {
   CJS_Object* pJSObj = data.GetParameter();
   pJSObj->ExitInstance();
@@ -122,20 +108,40 @@
   }
 }
 
-FX_UINT CJS_Timer::SetJSTimer(FX_UINT nElapse) {
-  if (m_nTimerID)
-    KillJSTimer();
+CJS_Timer::CJS_Timer(CJS_EmbedObj* pObj,
+                     CPDFDoc_Environment* pApp,
+                     CJS_Runtime* pRuntime,
+                     int nType,
+                     const CFX_WideString& script,
+                     FX_DWORD dwElapse,
+                     FX_DWORD dwTimeOut)
+    : m_nTimerID(0),
+      m_pEmbedObj(pObj),
+      m_bProcessing(false),
+      m_bValid(true),
+      m_nType(nType),
+      m_dwTimeOut(dwTimeOut),
+      m_pRuntime(pRuntime),
+      m_pApp(pApp) {
   IFX_SystemHandler* pHandler = m_pApp->GetSysHandler();
-  m_nTimerID = pHandler->SetTimer(nElapse, TimerProc);
+  m_nTimerID = pHandler->SetTimer(dwElapse, TimerProc);
   (*GetGlobalTimerMap())[m_nTimerID] = this;
-  m_dwElapse = nElapse;
-  return m_nTimerID;
+  m_pRuntime->AddObserver(this);
+}
+
+CJS_Timer::~CJS_Timer() {
+  CJS_Runtime* pRuntime = GetRuntime();
+  if (pRuntime)
+    pRuntime->RemoveObserver(this);
+  KillJSTimer();
 }
 
 void CJS_Timer::KillJSTimer() {
   if (m_nTimerID) {
-    IFX_SystemHandler* pHandler = m_pApp->GetSysHandler();
-    pHandler->KillTimer(m_nTimerID);
+    if (m_bValid) {
+      IFX_SystemHandler* pHandler = m_pApp->GetSysHandler();
+      pHandler->KillTimer(m_nTimerID);
+    }
     GetGlobalTimerMap()->erase(m_nTimerID);
     m_nTimerID = 0;
   }
@@ -147,10 +153,10 @@
   if (it != GetGlobalTimerMap()->end()) {
     CJS_Timer* pTimer = it->second;
     if (!pTimer->m_bProcessing) {
-      pTimer->m_bProcessing = TRUE;
+      CFX_AutoRestorer<bool> scoped_processing(&pTimer->m_bProcessing);
+      pTimer->m_bProcessing = true;
       if (pTimer->m_pEmbedObj)
         pTimer->m_pEmbedObj->TimerProc(pTimer);
-      pTimer->m_bProcessing = FALSE;
     }
   }
 }
@@ -161,3 +167,7 @@
   static auto* s_TimerMap = new TimerMap;
   return s_TimerMap;
 }
+
+void CJS_Timer::OnDestroyed() {
+  m_bValid = false;
+}
diff --git a/fpdfsdk/src/javascript/JS_Runtime.cpp b/fpdfsdk/src/javascript/JS_Runtime.cpp
index 998f45f..49d235c 100644
--- a/fpdfsdk/src/javascript/JS_Runtime.cpp
+++ b/fpdfsdk/src/javascript/JS_Runtime.cpp
@@ -11,7 +11,6 @@
 #include "../../include/javascript/JS_Define.h"
 #include "../../include/javascript/JS_Object.h"
 #include "../../include/javascript/JS_Value.h"
-#include "../../include/javascript/Document.h"
 #include "../../include/javascript/app.h"
 #include "../../include/javascript/color.h"
 #include "../../include/javascript/Consts.h"
@@ -77,6 +76,9 @@
 }
 
 CJS_Runtime::~CJS_Runtime() {
+  for (auto* obs : m_observers)
+    obs->OnDestroyed();
+
   int size = m_ContextArray.GetSize();
   for (int i = 0; i < size; i++)
     delete m_ContextArray.GetAt(i);
@@ -256,3 +258,13 @@
 
   return TRUE;
 }
+
+void CJS_Runtime::AddObserver(Observer* observer) {
+  ASSERT(m_observers.find(observer) == m_observers.end());
+  m_observers.insert(observer);
+}
+
+void CJS_Runtime::RemoveObserver(Observer* observer) {
+  ASSERT(m_observers.find(observer) != m_observers.end());
+  m_observers.erase(observer);
+}
diff --git a/fpdfsdk/src/javascript/app.cpp b/fpdfsdk/src/javascript/app.cpp
index 248e50e..1466dc1 100644
--- a/fpdfsdk/src/javascript/app.cpp
+++ b/fpdfsdk/src/javascript/app.cpp
@@ -414,16 +414,10 @@
 
   CPDFDoc_Environment* pApp = pRuntime->GetReaderApp();
   ASSERT(pApp);
-  CJS_Timer* pTimer = new CJS_Timer(this, pApp);
+  CJS_Timer* pTimer =
+      new CJS_Timer(this, pApp, pRuntime, 0, script, dwInterval, 0);
   m_aTimer.Add(pTimer);
 
-  pTimer->SetType(0);
-  pTimer->SetRuntime(pRuntime);
-  pTimer->SetJScript(script);
-  pTimer->SetTimeOut(0);
-  //	pTimer->SetStartTime(GetTickCount());
-  pTimer->SetJSTimer(dwInterval);
-
   v8::Local<v8::Object> pRetObj = FXJS_NewFxDynamicObj(
       pRuntime->GetIsolate(), pContext,
       FXJS_GetObjDefnID(pRuntime->GetIsolate(), L"TimerObj"));
@@ -468,15 +462,10 @@
   CPDFDoc_Environment* pApp = pRuntime->GetReaderApp();
   ASSERT(pApp);
 
-  CJS_Timer* pTimer = new CJS_Timer(this, pApp);
+  CJS_Timer* pTimer =
+      new CJS_Timer(this, pApp, pRuntime, 1, script, dwTimeOut, dwTimeOut);
   m_aTimer.Add(pTimer);
 
-  pTimer->SetType(1);
-  pTimer->SetRuntime(pRuntime);
-  pTimer->SetJScript(script);
-  pTimer->SetTimeOut(dwTimeOut);
-  pTimer->SetJSTimer(dwTimeOut);
-
   v8::Local<v8::Object> pRetObj = FXJS_NewFxDynamicObj(
       pRuntime->GetIsolate(), pContext,
       FXJS_GetObjDefnID(pRuntime->GetIsolate(), L"TimerObj"));
@@ -591,13 +580,17 @@
 void app::TimerProc(CJS_Timer* pTimer) {
   ASSERT(pTimer != NULL);
 
+  CJS_Runtime* pRuntime = pTimer->GetRuntime();
+
   switch (pTimer->GetType()) {
     case 0:  // interval
-      RunJsScript(pTimer->GetRuntime(), pTimer->GetJScript());
+      if (pRuntime)
+        RunJsScript(pRuntime, pTimer->GetJScript());
       break;
     case 1:
       if (pTimer->GetTimeOut() > 0) {
-        RunJsScript(pTimer->GetRuntime(), pTimer->GetJScript());
+        if (pRuntime)
+          RunJsScript(pRuntime, pTimer->GetJScript());
         pTimer->KillJSTimer();
       }
       break;