1// Copyright 2014 The Chromium 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#include "cc/base/delayed_unique_notifier.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/location.h"
10#include "base/sequenced_task_runner.h"
11
12namespace cc {
13
14DelayedUniqueNotifier::DelayedUniqueNotifier(
15    base::SequencedTaskRunner* task_runner,
16    const base::Closure& closure,
17    const base::TimeDelta& delay)
18    : task_runner_(task_runner),
19      closure_(closure),
20      delay_(delay),
21      notification_pending_(false),
22      weak_ptr_factory_(this) {
23}
24
25DelayedUniqueNotifier::~DelayedUniqueNotifier() {
26}
27
28void DelayedUniqueNotifier::Schedule() {
29  if (notification_pending_) {
30    next_notification_time_ = Now() + delay_;
31    return;
32  }
33
34  next_notification_time_ = Now() + delay_;
35  task_runner_->PostDelayedTask(FROM_HERE,
36                                base::Bind(&DelayedUniqueNotifier::NotifyIfTime,
37                                           weak_ptr_factory_.GetWeakPtr()),
38                                delay_);
39  notification_pending_ = true;
40}
41
42void DelayedUniqueNotifier::Cancel() {
43  next_notification_time_ = base::TimeTicks();
44}
45
46bool DelayedUniqueNotifier::HasPendingNotification() const {
47  return notification_pending_ && !next_notification_time_.is_null();
48}
49
50base::TimeTicks DelayedUniqueNotifier::Now() const {
51  return base::TimeTicks::Now();
52}
53
54void DelayedUniqueNotifier::NotifyIfTime() {
55  // If next notifiaction time is not valid, then this schedule was canceled.
56  if (next_notification_time_.is_null()) {
57    notification_pending_ = false;
58    return;
59  }
60
61  // If the notification was rescheduled or arrived too early for any other
62  // reason, then post another task instead of running the callback.
63  base::TimeTicks now = Now();
64  if (next_notification_time_ > now) {
65    task_runner_->PostDelayedTask(
66        FROM_HERE,
67        base::Bind(&DelayedUniqueNotifier::NotifyIfTime,
68                   weak_ptr_factory_.GetWeakPtr()),
69        next_notification_time_ - now);
70    return;
71  }
72
73  // Note the order here is important since closure might schedule another run.
74  notification_pending_ = false;
75  closure_.Run();
76}
77
78}  // namespace cc
79