diff options
Diffstat (limited to 'ui/base/animation/animation_container.cc')
-rw-r--r-- | ui/base/animation/animation_container.cc | 104 |
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 |