Home | History | Annotate | Download | only in animation
      1 // Copyright (c) 2011 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 "ui/gfx/animation/animation_container.h"
      6 
      7 #include "ui/gfx/animation/animation_container_element.h"
      8 #include "ui/gfx/animation/animation_container_observer.h"
      9 #include "ui/gfx/frame_time.h"
     10 
     11 using base::TimeDelta;
     12 using base::TimeTicks;
     13 
     14 namespace gfx {
     15 
     16 AnimationContainer::AnimationContainer()
     17     : last_tick_time_(gfx::FrameTime::Now()),
     18       observer_(NULL) {
     19 }
     20 
     21 AnimationContainer::~AnimationContainer() {
     22   // The animations own us and stop themselves before being deleted. If
     23   // elements_ is not empty, something is wrong.
     24   DCHECK(elements_.empty());
     25 }
     26 
     27 void AnimationContainer::Start(AnimationContainerElement* element) {
     28   DCHECK(elements_.count(element) == 0);  // Start should only be invoked if the
     29                                           // element isn't running.
     30 
     31   if (elements_.empty()) {
     32     last_tick_time_ = gfx::FrameTime::Now();
     33     SetMinTimerInterval(element->GetTimerInterval());
     34   } else if (element->GetTimerInterval() < min_timer_interval_) {
     35     SetMinTimerInterval(element->GetTimerInterval());
     36   }
     37 
     38   element->SetStartTime(last_tick_time_);
     39   elements_.insert(element);
     40 }
     41 
     42 void AnimationContainer::Stop(AnimationContainerElement* element) {
     43   DCHECK(elements_.count(element) > 0);  // The element must be running.
     44 
     45   elements_.erase(element);
     46 
     47   if (elements_.empty()) {
     48     timer_.Stop();
     49     if (observer_)
     50       observer_->AnimationContainerEmpty(this);
     51   } else {
     52     TimeDelta min_timer_interval = GetMinInterval();
     53     if (min_timer_interval > min_timer_interval_)
     54       SetMinTimerInterval(min_timer_interval);
     55   }
     56 }
     57 
     58 void AnimationContainer::Run() {
     59   // We notify the observer after updating all the elements. If all the elements
     60   // are deleted as a result of updating then our ref count would go to zero and
     61   // we would be deleted before we notify our observer. We add a reference to
     62   // ourself here to make sure we're still valid after running all the elements.
     63   scoped_refptr<AnimationContainer> this_ref(this);
     64 
     65   TimeTicks current_time = gfx::FrameTime::Now();
     66 
     67   last_tick_time_ = current_time;
     68 
     69   // Make a copy of the elements to iterate over so that if any elements are
     70   // removed as part of invoking Step there aren't any problems.
     71   Elements elements = elements_;
     72 
     73   for (Elements::const_iterator i = elements.begin();
     74        i != elements.end(); ++i) {
     75     // Make sure the element is still valid.
     76     if (elements_.find(*i) != elements_.end())
     77       (*i)->Step(current_time);
     78   }
     79 
     80   if (observer_)
     81     observer_->AnimationContainerProgressed(this);
     82 }
     83 
     84 void AnimationContainer::SetMinTimerInterval(base::TimeDelta delta) {
     85   // This doesn't take into account how far along the current element is, but
     86   // that shouldn't be a problem for uses of Animation/AnimationContainer.
     87   timer_.Stop();
     88   min_timer_interval_ = delta;
     89   timer_.Start(FROM_HERE, min_timer_interval_, this, &AnimationContainer::Run);
     90 }
     91 
     92 TimeDelta AnimationContainer::GetMinInterval() {
     93   DCHECK(!elements_.empty());
     94 
     95   TimeDelta min;
     96   Elements::const_iterator i = elements_.begin();
     97   min = (*i)->GetTimerInterval();
     98   for (++i; i != elements_.end(); ++i) {
     99     if ((*i)->GetTimerInterval() < min)
    100       min = (*i)->GetTimerInterval();
    101   }
    102   return min;
    103 }
    104 
    105 }  // namespace gfx
    106