| Index: fpdfsdk/src/javascript/JS_Object.cpp
 | 
| diff --git a/fpdfsdk/src/javascript/JS_Object.cpp b/fpdfsdk/src/javascript/JS_Object.cpp
 | 
| index 429d2682d85026f8123f4c0537fdcc8d8922bfcb..a3f972c1cd3f175350b774a712bccb1e3ed00097 100644
 | 
| --- a/fpdfsdk/src/javascript/JS_Object.cpp
 | 
| +++ b/fpdfsdk/src/javascript/JS_Object.cpp
 | 
| @@ -55,20 +55,6 @@ void CJS_EmbedObj::Alert(CJS_Context* pContext, const FX_WCHAR* swMsg) {
 | 
|    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 @@ void CJS_Object::Alert(CJS_Context* pContext, const FX_WCHAR* swMsg) {
 | 
|    }
 | 
|  }
 | 
|  
 | 
| -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 @@ void CJS_Timer::TimerProc(int idEvent) {
 | 
|    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 @@ CJS_Timer::TimerMap* CJS_Timer::GetGlobalTimerMap() {
 | 
|    static auto* s_TimerMap = new TimerMap;
 | 
|    return s_TimerMap;
 | 
|  }
 | 
| +
 | 
| +void CJS_Timer::OnDestroyed() {
 | 
| +  m_bValid = false;
 | 
| +}
 | 
| 
 |