| // 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 |