summaryrefslogtreecommitdiffstats
path: root/ui/base/animation/animation_container.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ui/base/animation/animation_container.cc')
-rw-r--r--ui/base/animation/animation_container.cc104
1 files changed, 104 insertions, 0 deletions
diff --git a/ui/base/animation/animation_container.cc b/ui/base/animation/animation_container.cc
new file mode 100644
index 0000000..1e316cd
--- /dev/null
+++ b/ui/base/animation/animation_container.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/animation/animation_container.h"
+
+#include "ui/base/animation/animation_container_element.h"
+#include "ui/base/animation/animation_container_observer.h"
+
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace ui {
+
+AnimationContainer::AnimationContainer()
+ : last_tick_time_(TimeTicks::Now()),
+ observer_(NULL) {
+}
+
+AnimationContainer::~AnimationContainer() {
+ // The animations own us and stop themselves before being deleted. If
+ // elements_ is not empty, something is wrong.
+ DCHECK(elements_.empty());
+}
+
+void AnimationContainer::Start(AnimationContainerElement* element) {
+ DCHECK(elements_.count(element) == 0); // Start should only be invoked if the
+ // element isn't running.
+
+ if (elements_.empty()) {
+ last_tick_time_ = TimeTicks::Now();
+ SetMinTimerInterval(element->GetTimerInterval());
+ } else if (element->GetTimerInterval() < min_timer_interval_) {
+ SetMinTimerInterval(element->GetTimerInterval());
+ }
+
+ element->SetStartTime(last_tick_time_);
+ elements_.insert(element);
+}
+
+void AnimationContainer::Stop(AnimationContainerElement* element) {
+ DCHECK(elements_.count(element) > 0); // The element must be running.
+
+ elements_.erase(element);
+
+ if (elements_.empty()) {
+ timer_.Stop();
+ if (observer_)
+ observer_->AnimationContainerEmpty(this);
+ } else {
+ TimeDelta min_timer_interval = GetMinInterval();
+ if (min_timer_interval > min_timer_interval_)
+ SetMinTimerInterval(min_timer_interval);
+ }
+}
+
+void AnimationContainer::Run() {
+ // We notify the observer after updating all the elements. If all the elements
+ // are deleted as a result of updating then our ref count would go to zero and
+ // we would be deleted before we notify our observer. We add a reference to
+ // ourself here to make sure we're still valid after running all the elements.
+ scoped_refptr<AnimationContainer> this_ref(this);
+
+ TimeTicks current_time = TimeTicks::Now();
+
+ last_tick_time_ = current_time;
+
+ // Make a copy of the elements to iterate over so that if any elements are
+ // removed as part of invoking Step there aren't any problems.
+ Elements elements = elements_;
+
+ for (Elements::const_iterator i = elements.begin();
+ i != elements.end(); ++i) {
+ // Make sure the element is still valid.
+ if (elements_.find(*i) != elements_.end())
+ (*i)->Step(current_time);
+ }
+
+ if (observer_)
+ observer_->AnimationContainerProgressed(this);
+}
+
+void AnimationContainer::SetMinTimerInterval(base::TimeDelta delta) {
+ // This doesn't take into account how far along the current element is, but
+ // that shouldn't be a problem for uses of Animation/AnimationContainer.
+ timer_.Stop();
+ min_timer_interval_ = delta;
+ timer_.Start(min_timer_interval_, this, &AnimationContainer::Run);
+}
+
+TimeDelta AnimationContainer::GetMinInterval() {
+ DCHECK(!elements_.empty());
+
+ TimeDelta min;
+ Elements::const_iterator i = elements_.begin();
+ min = (*i)->GetTimerInterval();
+ for (++i; i != elements_.end(); ++i) {
+ if ((*i)->GetTimerInterval() < min)
+ min = (*i)->GetTimerInterval();
+ }
+ return min;
+}
+
+} // namespace ui