summaryrefslogtreecommitdiff
path: root/fpdfsdk
diff options
context:
space:
mode:
Diffstat (limited to 'fpdfsdk')
-rw-r--r--fpdfsdk/fpdfformfill_embeddertest.cpp22
-rw-r--r--fpdfsdk/javascript/JS_Object.cpp38
-rw-r--r--fpdfsdk/javascript/JS_Object.h10
-rw-r--r--fpdfsdk/javascript/app.cpp47
-rw-r--r--fpdfsdk/javascript/app.h6
5 files changed, 68 insertions, 55 deletions
diff --git a/fpdfsdk/fpdfformfill_embeddertest.cpp b/fpdfsdk/fpdfformfill_embeddertest.cpp
index a1425153a1..3a6a7448e5 100644
--- a/fpdfsdk/fpdfformfill_embeddertest.cpp
+++ b/fpdfsdk/fpdfformfill_embeddertest.cpp
@@ -157,4 +157,26 @@ TEST_F(FPDFFormFillEmbeddertest, BUG_634394) {
EXPECT_EQ(2U, alerts.size());
}
+TEST_F(FPDFFormFillEmbeddertest, BUG_634716) {
+ EmbedderTestTimerHandlingDelegate delegate;
+ SetDelegate(&delegate);
+
+ EXPECT_TRUE(OpenDocument("bug_634716.pdf"));
+ FPDF_PAGE page = LoadPage(0);
+ EXPECT_TRUE(page);
+ DoOpenActions();
+
+ // Timers fire at most once per AdvanceTime(), allow intervals
+ // to fire several times if possible.
+ delegate.AdvanceTime(1000);
+ delegate.AdvanceTime(1000);
+ delegate.AdvanceTime(1000);
+ delegate.AdvanceTime(1000);
+ delegate.AdvanceTime(1000);
+ UnloadPage(page);
+
+ const auto& alerts = delegate.GetAlerts();
+ EXPECT_EQ(2U, alerts.size());
+}
+
#endif // PDF_ENABLE_V8
diff --git a/fpdfsdk/javascript/JS_Object.cpp b/fpdfsdk/javascript/JS_Object.cpp
index 9ec316303d..b65699a18b 100644
--- a/fpdfsdk/javascript/JS_Object.cpp
+++ b/fpdfsdk/javascript/JS_Object.cpp
@@ -90,7 +90,7 @@ CJS_Timer::CJS_Timer(CJS_EmbedObj* pObj,
m_pRuntime(pRuntime),
m_pApp(pApp) {
CFX_SystemHandler* pHandler = m_pApp->GetSysHandler();
- m_nTimerID = pHandler->SetTimer(dwElapse, TimerProc);
+ m_nTimerID = pHandler->SetTimer(dwElapse, Trigger);
(*GetGlobalTimerMap())[m_nTimerID] = this;
m_pRuntime->AddObserver(this);
}
@@ -99,23 +99,19 @@ CJS_Timer::~CJS_Timer() {
CJS_Runtime* pRuntime = GetRuntime();
if (pRuntime)
pRuntime->RemoveObserver(this);
- KillJSTimer();
-}
-void CJS_Timer::KillJSTimer() {
- if (m_nTimerID) {
- if (m_bValid) {
- CFX_SystemHandler* pHandler = m_pApp->GetSysHandler();
- pHandler->KillTimer(m_nTimerID);
- }
- GetGlobalTimerMap()->erase(m_nTimerID);
- m_nTimerID = 0;
- }
+ if (!m_nTimerID)
+ return;
+
+ if (m_bValid)
+ m_pApp->GetSysHandler()->KillTimer(m_nTimerID);
+
+ GetGlobalTimerMap()->erase(m_nTimerID);
}
// static
-void CJS_Timer::TimerProc(int idEvent) {
- auto it = GetGlobalTimerMap()->find(idEvent);
+void CJS_Timer::Trigger(int nTimerID) {
+ auto it = GetGlobalTimerMap()->find(nTimerID);
if (it == GetGlobalTimerMap()->end())
return;
@@ -128,12 +124,24 @@ void CJS_Timer::TimerProc(int idEvent) {
pTimer->m_pEmbedObj->TimerProc(pTimer);
// Timer proc may have destroyed timer, find it again.
- it = GetGlobalTimerMap()->find(idEvent);
+ it = GetGlobalTimerMap()->find(nTimerID);
if (it == GetGlobalTimerMap()->end())
return;
pTimer = it->second;
pTimer->m_bProcessing = false;
+ if (pTimer->IsOneShot())
+ pTimer->m_pEmbedObj->CancelProc(pTimer);
+}
+
+// static
+void CJS_Timer::Cancel(int nTimerID) {
+ auto it = GetGlobalTimerMap()->find(nTimerID);
+ if (it == GetGlobalTimerMap()->end())
+ return;
+
+ CJS_Timer* pTimer = it->second;
+ pTimer->m_pEmbedObj->CancelProc(pTimer);
}
// static
diff --git a/fpdfsdk/javascript/JS_Object.h b/fpdfsdk/javascript/JS_Object.h
index 146a7c93b5..aec94c0362 100644
--- a/fpdfsdk/javascript/JS_Object.h
+++ b/fpdfsdk/javascript/JS_Object.h
@@ -18,12 +18,14 @@ class CJS_Context;
class CJS_Object;
class CJS_Timer;
class CPDFDoc_Environment;
+
class CJS_EmbedObj {
public:
explicit CJS_EmbedObj(CJS_Object* pJSObject);
virtual ~CJS_EmbedObj();
virtual void TimerProc(CJS_Timer* pTimer) {}
+ virtual void CancelProc(CJS_Timer* pTimer) {}
CJS_Object* GetJSObject() const { return m_pJSObject; }
@@ -76,15 +78,15 @@ class CJS_Timer : public CJS_Runtime::Observer {
uint32_t dwTimeOut);
~CJS_Timer() override;
- void KillJSTimer();
+ static void Trigger(int nTimerID);
+ static void Cancel(int nTimerID);
- int GetType() const { return m_nType; }
+ bool IsOneShot() const { return m_nType == 1; }
uint32_t GetTimeOut() const { return m_dwTimeOut; }
+ int GetTimerID() const { return m_nTimerID; }
CJS_Runtime* GetRuntime() const { return m_bValid ? m_pRuntime : nullptr; }
CFX_WideString GetJScript() const { return m_swJScript; }
- static void TimerProc(int idEvent);
-
private:
using TimerMap = std::map<FX_UINT, CJS_Timer*>;
static TimerMap* GetGlobalTimerMap();
diff --git a/fpdfsdk/javascript/app.cpp b/fpdfsdk/javascript/app.cpp
index 1077629244..329b625545 100644
--- a/fpdfsdk/javascript/app.cpp
+++ b/fpdfsdk/javascript/app.cpp
@@ -31,16 +31,12 @@ END_JS_STATIC_METHOD()
IMPLEMENT_JS_CLASS(CJS_TimerObj, TimerObj)
TimerObj::TimerObj(CJS_Object* pJSObject)
- : CJS_EmbedObj(pJSObject), m_pTimer(nullptr) {}
+ : CJS_EmbedObj(pJSObject), m_nTimerID(0) {}
TimerObj::~TimerObj() {}
void TimerObj::SetTimer(CJS_Timer* pTimer) {
- m_pTimer = pTimer;
-}
-
-CJS_Timer* TimerObj::GetTimer() const {
- return m_pTimer;
+ m_nTimerID = pTimer->GetTimerID();
}
#define JS_STR_VIEWERTYPE L"pdfium"
@@ -473,20 +469,7 @@ void app::ClearTimerCommon(const CJS_Value& param) {
if (!pTimerObj)
return;
- CJS_Timer* pTimer = pTimerObj->GetTimer();
- if (!pTimer)
- return;
-
- pTimer->KillJSTimer();
- auto iter = std::find_if(m_Timers.begin(), m_Timers.end(),
- [pTimer](const std::unique_ptr<CJS_Timer>& that) {
- return pTimer == that.get();
- });
-
- if (iter != m_Timers.end())
- m_Timers.erase(iter);
-
- pTimerObj->SetTimer(nullptr);
+ CJS_Timer::Cancel(pTimerObj->GetTimerID());
}
FX_BOOL app::execMenuItem(IJS_Context* cc,
@@ -498,20 +481,18 @@ FX_BOOL app::execMenuItem(IJS_Context* cc,
void app::TimerProc(CJS_Timer* pTimer) {
CJS_Runtime* pRuntime = pTimer->GetRuntime();
+ if (pRuntime && (!pTimer->IsOneShot() || pTimer->GetTimeOut() > 0))
+ RunJsScript(pRuntime, pTimer->GetJScript());
+}
- switch (pTimer->GetType()) {
- case 0: // interval
- if (pRuntime)
- RunJsScript(pRuntime, pTimer->GetJScript());
- break;
- case 1:
- if (pTimer->GetTimeOut() > 0) {
- if (pRuntime)
- RunJsScript(pRuntime, pTimer->GetJScript());
- pTimer->KillJSTimer();
- }
- break;
- }
+void app::CancelProc(CJS_Timer* pTimer) {
+ auto iter = std::find_if(m_Timers.begin(), m_Timers.end(),
+ [pTimer](const std::unique_ptr<CJS_Timer>& that) {
+ return pTimer == that.get();
+ });
+
+ if (iter != m_Timers.end())
+ m_Timers.erase(iter);
}
void app::RunJsScript(CJS_Runtime* pRuntime, const CFX_WideString& wsScript) {
diff --git a/fpdfsdk/javascript/app.h b/fpdfsdk/javascript/app.h
index c6cda555d9..bb083cedb4 100644
--- a/fpdfsdk/javascript/app.h
+++ b/fpdfsdk/javascript/app.h
@@ -20,12 +20,11 @@ class TimerObj : public CJS_EmbedObj {
TimerObj(CJS_Object* pJSObject);
~TimerObj() override;
- public:
void SetTimer(CJS_Timer* pTimer);
- CJS_Timer* GetTimer() const;
+ int GetTimerID() const { return m_nTimerID; }
private:
- CJS_Timer* m_pTimer;
+ int m_nTimerID; // Weak reference to timer through global map.
};
class CJS_TimerObj : public CJS_Object {
@@ -158,6 +157,7 @@ class app : public CJS_EmbedObj {
private:
// CJS_EmbedObj
void TimerProc(CJS_Timer* pTimer) override;
+ void CancelProc(CJS_Timer* pTimer) override;
void RunJsScript(CJS_Runtime* pRuntime, const CFX_WideString& wsScript);
void ClearTimerCommon(const CJS_Value& param);