Index: webkit/glue/plugins/plugin_instance.cc |
=================================================================== |
--- webkit/glue/plugins/plugin_instance.cc (revision 29899) |
+++ webkit/glue/plugins/plugin_instance.cc (working copy) |
@@ -38,7 +38,8 @@ |
#endif |
message_loop_(MessageLoop::current()), |
load_manually_(false), |
- in_close_streams_(false) { |
+ in_close_streams_(false), |
+ next_timer_id_(1) { |
npp_ = new NPP_t(); |
npp_->ndata = 0; |
npp_->pdata = 0; |
@@ -156,7 +157,7 @@ |
void PluginInstance::NPP_Destroy() { |
DCHECK(npp_functions_ != 0); |
- DCHECK(npp_functions_->newp != 0); |
+ DCHECK(npp_functions_->destroy != 0); |
if (npp_functions_->destroy != 0) { |
NPSavedData *savedData = 0; |
@@ -175,6 +176,9 @@ |
file_index++) { |
file_util::Delete(files_created_[file_index], false); |
} |
+ |
+ // Ensure that no timer callbacks are invoked after NPP_Destroy. |
+ timers_.clear(); |
} |
NPError PluginInstance::NPP_SetWindow(NPWindow *window) { |
@@ -361,21 +365,76 @@ |
void PluginInstance::OnPluginThreadAsyncCall(void (*func)(void *), |
void *user_data) { |
-#if defined(OS_WIN) |
- // We are invoking an arbitrary callback provided by a third |
- // party plugin. It's better to wrap this into an exception |
- // block to protect us from crashes. |
- __try { |
- func(user_data); |
- } __except(EXCEPTION_EXECUTE_HANDLER) { |
- // Maybe we can disable a crashing plugin. |
- // But for now, just continue. |
- } |
-#else |
func(user_data); |
-#endif |
} |
+uint32 PluginInstance::ScheduleTimer(uint32 interval, |
+ NPBool repeat, |
+ void (*func)(NPP id, uint32 timer_id)) { |
+ // Use next timer id. |
+ uint32 timer_id; |
+ timer_id = next_timer_id_; |
+ ++next_timer_id_; |
+ DCHECK(next_timer_id_ != 0); |
+ |
+ // Record timer interval and repeat. |
+ TimerInfo info; |
+ info.interval = interval; |
+ info.repeat = repeat; |
+ timers_[timer_id] = info; |
+ |
+ // Schedule the callback. |
+ message_loop_->PostDelayedTask(FROM_HERE, |
+ NewRunnableMethod(this, |
+ &PluginInstance::OnTimerCall, |
+ func, |
+ npp_, |
+ timer_id), |
+ interval); |
+ return timer_id; |
+} |
+ |
+void PluginInstance::UnscheduleTimer(uint32 timer_id) { |
+ // Remove info about the timer. |
+ TimerMap::iterator it = timers_.find(timer_id); |
+ if (it != timers_.end()) |
+ timers_.erase(it); |
+} |
+ |
+void PluginInstance::OnTimerCall(void (*func)(NPP id, uint32 timer_id), |
+ NPP id, |
+ uint32 timer_id) { |
+ // Do not invoke callback if the timer has been unscheduled. |
+ TimerMap::iterator it = timers_.find(timer_id); |
+ if (it == timers_.end()) |
+ return; |
+ |
+ // Get all information about the timer before invoking the callback. The |
+ // callback might unschedule the timer. |
+ TimerInfo info = it->second; |
+ |
+ func(id, timer_id); |
+ |
+ // If the timer was unscheduled by the callback, just free up the timer id. |
+ if (timers_.find(timer_id) == timers_.end()) |
+ return; |
+ |
+ // Reschedule repeating timers after invoking the callback so callback is not |
+ // re-entered if it pumps the messager loop. |
+ if (info.repeat) { |
+ message_loop_->PostDelayedTask(FROM_HERE, |
+ NewRunnableMethod( |
+ this, |
+ &PluginInstance::OnTimerCall, |
+ func, |
+ npp_, |
+ timer_id), |
+ info.interval); |
+ } else { |
+ timers_.erase(it); |
+ } |
+} |
+ |
void PluginInstance::PushPopupsEnabledState(bool enabled) { |
popups_enabled_stack_.push(enabled); |
} |