blob: 265d0db76955d04174201cce60502a3e5f43a262 [file] [log] [blame]
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/dom/window_timers.h"
#include <limits>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/debug/trace_event.h"
#include "cobalt/dom/global_stats.h"
#include "nb/memory_scope.h"
namespace cobalt {
namespace dom {
int WindowTimers::SetTimeout(const TimerCallbackArg& handler, int timeout) {
TRACK_MEMORY_SCOPE("DOM");
int handle = GetFreeTimerHandle();
DCHECK(handle);
if (handle == 0) { // unable to get a free timer handle
// avoid accidentally overwriting existing timers
return 0;
}
scoped_ptr<base::Timer> timer(new base::OneShotTimer<TimerInfo>());
timer->Start(FROM_HERE, base::TimeDelta::FromMilliseconds(timeout),
base::Bind(&WindowTimers::RunTimerCallback,
base::Unretained(this), handle));
timers_[handle] = new TimerInfo(owner_, timer.Pass(), handler);
return handle;
}
void WindowTimers::ClearTimeout(int handle) { timers_.erase(handle); }
int WindowTimers::SetInterval(const TimerCallbackArg& handler, int timeout) {
int handle = GetFreeTimerHandle();
DCHECK(handle);
if (handle == 0) { // unable to get a free timer handle
// avoid accidentally overwriting existing timers
return 0;
}
scoped_ptr<base::Timer> timer(new base::RepeatingTimer<TimerInfo>());
timer->Start(FROM_HERE, base::TimeDelta::FromMilliseconds(timeout),
base::Bind(&WindowTimers::RunTimerCallback,
base::Unretained(this), handle));
timers_[handle] = new TimerInfo(owner_, timer.Pass(), handler);
return handle;
}
void WindowTimers::ClearInterval(int handle) { timers_.erase(handle); }
void WindowTimers::ClearAllIntervalsAndTimeouts() { timers_.clear(); }
int WindowTimers::GetFreeTimerHandle() {
int next_timer_index = current_timer_index_;
while (true) {
if (next_timer_index == std::numeric_limits<int>::max()) {
next_timer_index = 1;
} else {
++next_timer_index;
}
if (timers_.find(next_timer_index) == timers_.end()) {
current_timer_index_ = next_timer_index;
return current_timer_index_;
}
if (next_timer_index == current_timer_index_) {
break;
}
}
DLOG(INFO) << "No available timer handle.";
return 0;
}
void WindowTimers::RunTimerCallback(int handle) {
TRACE_EVENT0("cobalt::dom", "WindowTimers::RunTimerCallback");
Timers::iterator timer = timers_.find(handle);
DCHECK(timer != timers_.end());
// The callback is now being run. Track it in the global stats.
GlobalStats::GetInstance()->StartJavaScriptEvent();
// Keep a |TimerInfo| reference, so it won't be released when running the
// callback.
scoped_refptr<TimerInfo> timer_info = timer->second;
timer_info->callback_reference().value().Run();
// After running the callback, double check whether the timer is still there
// since it might be deleted inside the callback.
timer = timers_.find(handle);
// If the timer is not deleted and is not running, it means it is an oneshot
// timer and has just fired the shot, and it should be deleted now.
if (timer != timers_.end() && !timer->second->timer()->IsRunning()) {
timers_.erase(timer);
}
// The callback has finished running. Stop tracking it in the global stats.
GlobalStats::GetInstance()->StopJavaScriptEvent();
}
} // namespace dom
} // namespace cobalt