CJS_Timer should observe CJS_Runtime destruction.
[pdfium.git] / fpdfsdk / src / javascript / JS_Object.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../include/javascript/JavaScript.h"
8 #include "../../include/javascript/IJavaScript.h"
9 #include "../../include/javascript/JS_Define.h"
10 #include "../../include/javascript/JS_Object.h"
11 #include "../../include/javascript/JS_Context.h"
12
13 int FXJS_MsgBox(CPDFDoc_Environment* pApp,
14                 CPDFSDK_PageView* pPageView,
15                 const FX_WCHAR* swMsg,
16                 const FX_WCHAR* swTitle,
17                 FX_UINT nType,
18                 FX_UINT nIcon) {
19   if (!pApp)
20     return 0;
21
22   if (CPDFSDK_Document* pDoc = pApp->GetSDKDocument())
23     pDoc->KillFocusAnnot();
24
25   return pApp->JS_appAlert(swMsg, swTitle, nType, nIcon);
26 }
27
28 CPDFSDK_PageView* FXJS_GetPageView(IFXJS_Context* cc) {
29   if (CJS_Context* pContext = (CJS_Context*)cc) {
30     if (pContext->GetReaderDocument())
31       return NULL;
32   }
33   return NULL;
34 }
35
36 CJS_EmbedObj::CJS_EmbedObj(CJS_Object* pJSObject) : m_pJSObject(pJSObject) {}
37
38 CJS_EmbedObj::~CJS_EmbedObj() {
39   m_pJSObject = NULL;
40 }
41
42 CPDFSDK_PageView* CJS_EmbedObj::JSGetPageView(IFXJS_Context* cc) {
43   return FXJS_GetPageView(cc);
44 }
45
46 int CJS_EmbedObj::MsgBox(CPDFDoc_Environment* pApp,
47                          CPDFSDK_PageView* pPageView,
48                          const FX_WCHAR* swMsg,
49                          const FX_WCHAR* swTitle,
50                          FX_UINT nType,
51                          FX_UINT nIcon) {
52   return FXJS_MsgBox(pApp, pPageView, swMsg, swTitle, nType, nIcon);
53 }
54
55 void CJS_EmbedObj::Alert(CJS_Context* pContext, const FX_WCHAR* swMsg) {
56   CJS_Object::Alert(pContext, swMsg);
57 }
58
59 void FreeObject(const v8::WeakCallbackInfo<CJS_Object>& data) {
60   CJS_Object* pJSObj = data.GetParameter();
61   pJSObj->ExitInstance();
62   delete pJSObj;
63   FXJS_FreePrivate(data.GetInternalField(0));
64 }
65
66 void DisposeObject(const v8::WeakCallbackInfo<CJS_Object>& data) {
67   CJS_Object* pJSObj = data.GetParameter();
68   pJSObj->Dispose();
69   data.SetSecondPassCallback(FreeObject);
70 }
71
72 CJS_Object::CJS_Object(v8::Local<v8::Object> pObject) {
73   m_pIsolate = pObject->CreationContext()->GetIsolate();
74   m_pV8Object.Reset(m_pIsolate, pObject);
75 }
76
77 CJS_Object::~CJS_Object() {
78 }
79
80 void CJS_Object::MakeWeak() {
81   m_pV8Object.SetWeak(this, DisposeObject,
82                       v8::WeakCallbackType::kInternalFields);
83 }
84
85 void CJS_Object::Dispose() {
86   m_pV8Object.Reset();
87 }
88
89 CPDFSDK_PageView* CJS_Object::JSGetPageView(IFXJS_Context* cc) {
90   return FXJS_GetPageView(cc);
91 }
92
93 int CJS_Object::MsgBox(CPDFDoc_Environment* pApp,
94                        CPDFSDK_PageView* pPageView,
95                        const FX_WCHAR* swMsg,
96                        const FX_WCHAR* swTitle,
97                        FX_UINT nType,
98                        FX_UINT nIcon) {
99   return FXJS_MsgBox(pApp, pPageView, swMsg, swTitle, nType, nIcon);
100 }
101
102 void CJS_Object::Alert(CJS_Context* pContext, const FX_WCHAR* swMsg) {
103   ASSERT(pContext != NULL);
104
105   if (pContext->IsMsgBoxEnabled()) {
106     CPDFDoc_Environment* pApp = pContext->GetReaderApp();
107     if (pApp)
108       pApp->JS_appAlert(swMsg, NULL, 0, 3);
109   }
110 }
111
112 CJS_Timer::CJS_Timer(CJS_EmbedObj* pObj,
113                      CPDFDoc_Environment* pApp,
114                      CJS_Runtime* pRuntime,
115                      int nType,
116                      const CFX_WideString& script,
117                      FX_DWORD dwElapse,
118                      FX_DWORD dwTimeOut)
119     : m_nTimerID(0),
120       m_pEmbedObj(pObj),
121       m_bProcessing(false),
122       m_bValid(true),
123       m_nType(nType),
124       m_dwTimeOut(dwTimeOut),
125       m_pRuntime(pRuntime),
126       m_pApp(pApp) {
127   IFX_SystemHandler* pHandler = m_pApp->GetSysHandler();
128   m_nTimerID = pHandler->SetTimer(dwElapse, TimerProc);
129   (*GetGlobalTimerMap())[m_nTimerID] = this;
130   m_pRuntime->AddObserver(this);
131 }
132
133 CJS_Timer::~CJS_Timer() {
134   CJS_Runtime* pRuntime = GetRuntime();
135   if (pRuntime)
136     pRuntime->RemoveObserver(this);
137   KillJSTimer();
138 }
139
140 void CJS_Timer::KillJSTimer() {
141   if (m_nTimerID) {
142     if (m_bValid) {
143       IFX_SystemHandler* pHandler = m_pApp->GetSysHandler();
144       pHandler->KillTimer(m_nTimerID);
145     }
146     GetGlobalTimerMap()->erase(m_nTimerID);
147     m_nTimerID = 0;
148   }
149 }
150
151 // static
152 void CJS_Timer::TimerProc(int idEvent) {
153   const auto it = GetGlobalTimerMap()->find(idEvent);
154   if (it != GetGlobalTimerMap()->end()) {
155     CJS_Timer* pTimer = it->second;
156     if (!pTimer->m_bProcessing) {
157       CFX_AutoRestorer<bool> scoped_processing(&pTimer->m_bProcessing);
158       pTimer->m_bProcessing = true;
159       if (pTimer->m_pEmbedObj)
160         pTimer->m_pEmbedObj->TimerProc(pTimer);
161     }
162   }
163 }
164
165 // static
166 CJS_Timer::TimerMap* CJS_Timer::GetGlobalTimerMap() {
167   // Leak the timer array at shutdown.
168   static auto* s_TimerMap = new TimerMap;
169   return s_TimerMap;
170 }
171
172 void CJS_Timer::OnDestroyed() {
173   m_bValid = false;
174 }