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 "JS_Object.h"
8
9#include "JS_Context.h"
10#include "JS_Define.h"
11#include "fpdfsdk/include/fsdk_mgr.h"  // For CPDFDoc_Environment.
12#include "fpdfsdk/include/javascript/IJavaScript.h"
13
14namespace {
15
16int FXJS_MsgBox(CPDFDoc_Environment* pApp,
17                const FX_WCHAR* swMsg,
18                const FX_WCHAR* swTitle,
19                FX_UINT nType,
20                FX_UINT nIcon) {
21  if (!pApp)
22    return 0;
23
24  if (CPDFSDK_Document* pDoc = pApp->GetSDKDocument())
25    pDoc->KillFocusAnnot();
26
27  return pApp->JS_appAlert(swMsg, swTitle, nType, nIcon);
28}
29
30}  // namespace
31
32CJS_EmbedObj::CJS_EmbedObj(CJS_Object* pJSObject) : m_pJSObject(pJSObject) {}
33
34CJS_EmbedObj::~CJS_EmbedObj() {
35  m_pJSObject = NULL;
36}
37
38int CJS_EmbedObj::MsgBox(CPDFDoc_Environment* pApp,
39                         const FX_WCHAR* swMsg,
40                         const FX_WCHAR* swTitle,
41                         FX_UINT nType,
42                         FX_UINT nIcon) {
43  return FXJS_MsgBox(pApp, swMsg, swTitle, nType, nIcon);
44}
45
46void CJS_EmbedObj::Alert(CJS_Context* pContext, const FX_WCHAR* swMsg) {
47  CJS_Object::Alert(pContext, swMsg);
48}
49
50void FreeObject(const v8::WeakCallbackInfo<CJS_Object>& data) {
51  CJS_Object* pJSObj = data.GetParameter();
52  pJSObj->ExitInstance();
53  delete pJSObj;
54  FXJS_FreePrivate(data.GetInternalField(0));
55}
56
57void DisposeObject(const v8::WeakCallbackInfo<CJS_Object>& data) {
58  CJS_Object* pJSObj = data.GetParameter();
59  pJSObj->Dispose();
60  data.SetSecondPassCallback(FreeObject);
61}
62
63CJS_Object::CJS_Object(v8::Local<v8::Object> pObject) {
64  m_pIsolate = pObject->GetIsolate();
65  m_pV8Object.Reset(m_pIsolate, pObject);
66}
67
68CJS_Object::~CJS_Object() {
69}
70
71void CJS_Object::MakeWeak() {
72  m_pV8Object.SetWeak(this, DisposeObject,
73                      v8::WeakCallbackType::kInternalFields);
74}
75
76void CJS_Object::Dispose() {
77  m_pV8Object.Reset();
78}
79
80int CJS_Object::MsgBox(CPDFDoc_Environment* pApp,
81                       const FX_WCHAR* swMsg,
82                       const FX_WCHAR* swTitle,
83                       FX_UINT nType,
84                       FX_UINT nIcon) {
85  return FXJS_MsgBox(pApp, swMsg, swTitle, nType, nIcon);
86}
87
88void CJS_Object::Alert(CJS_Context* pContext, const FX_WCHAR* swMsg) {
89  if (pContext->IsMsgBoxEnabled()) {
90    CPDFDoc_Environment* pApp = pContext->GetReaderApp();
91    if (pApp)
92      pApp->JS_appAlert(swMsg, NULL, 0, 3);
93  }
94}
95
96CJS_Timer::CJS_Timer(CJS_EmbedObj* pObj,
97                     CPDFDoc_Environment* pApp,
98                     CJS_Runtime* pRuntime,
99                     int nType,
100                     const CFX_WideString& script,
101                     FX_DWORD dwElapse,
102                     FX_DWORD dwTimeOut)
103    : m_nTimerID(0),
104      m_pEmbedObj(pObj),
105      m_bProcessing(false),
106      m_bValid(true),
107      m_nType(nType),
108      m_dwTimeOut(dwTimeOut),
109      m_swJScript(script),
110      m_pRuntime(pRuntime),
111      m_pApp(pApp) {
112  IFX_SystemHandler* pHandler = m_pApp->GetSysHandler();
113  m_nTimerID = pHandler->SetTimer(dwElapse, TimerProc);
114  (*GetGlobalTimerMap())[m_nTimerID] = this;
115  m_pRuntime->AddObserver(this);
116}
117
118CJS_Timer::~CJS_Timer() {
119  CJS_Runtime* pRuntime = GetRuntime();
120  if (pRuntime)
121    pRuntime->RemoveObserver(this);
122  KillJSTimer();
123}
124
125void CJS_Timer::KillJSTimer() {
126  if (m_nTimerID) {
127    if (m_bValid) {
128      IFX_SystemHandler* pHandler = m_pApp->GetSysHandler();
129      pHandler->KillTimer(m_nTimerID);
130    }
131    GetGlobalTimerMap()->erase(m_nTimerID);
132    m_nTimerID = 0;
133  }
134}
135
136// static
137void CJS_Timer::TimerProc(int idEvent) {
138  const auto it = GetGlobalTimerMap()->find(idEvent);
139  if (it != GetGlobalTimerMap()->end()) {
140    CJS_Timer* pTimer = it->second;
141    if (!pTimer->m_bProcessing) {
142      CFX_AutoRestorer<bool> scoped_processing(&pTimer->m_bProcessing);
143      pTimer->m_bProcessing = true;
144      if (pTimer->m_pEmbedObj)
145        pTimer->m_pEmbedObj->TimerProc(pTimer);
146    }
147  }
148}
149
150// static
151CJS_Timer::TimerMap* CJS_Timer::GetGlobalTimerMap() {
152  // Leak the timer array at shutdown.
153  static auto* s_TimerMap = new TimerMap;
154  return s_TimerMap;
155}
156
157void CJS_Timer::OnDestroyed() {
158  m_bValid = false;
159}
160