| Index: mojo/services/view_manager/animation_runner.cc
 | 
| diff --git a/mojo/services/view_manager/animation_runner.cc b/mojo/services/view_manager/animation_runner.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..dc910a112e9a37917848c269b0850d89e8605a71
 | 
| --- /dev/null
 | 
| +++ b/mojo/services/view_manager/animation_runner.cc
 | 
| @@ -0,0 +1,157 @@
 | 
| +// Copyright 2014 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 "mojo/services/view_manager/animation_runner.h"
 | 
| +
 | 
| +#include "base/memory/scoped_vector.h"
 | 
| +#include "mojo/services/view_manager/animation_runner_observer.h"
 | 
| +#include "mojo/services/view_manager/scheduled_animation_group.h"
 | 
| +#include "mojo/services/view_manager/server_view.h"
 | 
| +
 | 
| +namespace view_manager {
 | 
| +namespace {
 | 
| +
 | 
| +bool ConvertViewAndAnimationPairToScheduledAnimationGroup(
 | 
| +    const std::vector<AnimationRunner::ViewAndAnimationPair>& views,
 | 
| +    AnimationRunner::AnimationId id,
 | 
| +    base::TimeTicks now,
 | 
| +    ScopedVector<ScheduledAnimationGroup>* groups) {
 | 
| +  for (const auto& view_animation_pair : views) {
 | 
| +    DCHECK(view_animation_pair.second);
 | 
| +    scoped_ptr<ScheduledAnimationGroup> group(ScheduledAnimationGroup::Create(
 | 
| +        view_animation_pair.first, now, id, *(view_animation_pair.second)));
 | 
| +    if (!group.get())
 | 
| +      return false;
 | 
| +    groups->push_back(group.release());
 | 
| +  }
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +}  // namespace
 | 
| +
 | 
| +AnimationRunner::AnimationRunner(base::TimeTicks now)
 | 
| +    : next_id_(1), last_tick_time_(now) {
 | 
| +}
 | 
| +
 | 
| +AnimationRunner::~AnimationRunner() {
 | 
| +}
 | 
| +
 | 
| +void AnimationRunner::AddObserver(AnimationRunnerObserver* observer) {
 | 
| +  observers_.AddObserver(observer);
 | 
| +}
 | 
| +
 | 
| +void AnimationRunner::RemoveObserver(AnimationRunnerObserver* observer) {
 | 
| +  observers_.RemoveObserver(observer);
 | 
| +}
 | 
| +
 | 
| +AnimationRunner::AnimationId AnimationRunner::Schedule(
 | 
| +    const std::vector<ViewAndAnimationPair>& views,
 | 
| +    base::TimeTicks now) {
 | 
| +  DCHECK_GE(now, last_tick_time_);
 | 
| +
 | 
| +  const AnimationId animation_id = next_id_++;
 | 
| +  ScopedVector<ScheduledAnimationGroup> groups;
 | 
| +  if (!ConvertViewAndAnimationPairToScheduledAnimationGroup(views, animation_id,
 | 
| +                                                            now, &groups)) {
 | 
| +    return 0;
 | 
| +  }
 | 
| +
 | 
| +  // Cancel any animations for the views.
 | 
| +  for (auto* group : groups) {
 | 
| +    ScheduledAnimationGroup* current_group =
 | 
| +        view_to_animation_map_.get(group->view());
 | 
| +    if (current_group)
 | 
| +      current_group->SetValuesToTargetValuesForPropertiesNotIn(*group);
 | 
| +
 | 
| +    CancelAnimationForViewImpl(group->view(), CANCEL_SOURCE_SCHEDULE);
 | 
| +  }
 | 
| +
 | 
| +  for (auto* group : groups) {
 | 
| +    group->ObtainStartValues();
 | 
| +    view_to_animation_map_.set(group->view(), make_scoped_ptr(group));
 | 
| +    DCHECK(!id_to_views_map_[animation_id].count(group->view()));
 | 
| +    id_to_views_map_[animation_id].insert(group->view());
 | 
| +  }
 | 
| +  // |view_to_animation_map_| owns the groups.
 | 
| +  groups.weak_clear();
 | 
| +
 | 
| +  FOR_EACH_OBSERVER(AnimationRunnerObserver, observers_,
 | 
| +                    OnAnimationScheduled(animation_id));
 | 
| +  return animation_id;
 | 
| +}
 | 
| +
 | 
| +void AnimationRunner::CancelAnimation(AnimationId id) {
 | 
| +  if (id_to_views_map_.count(id) == 0)
 | 
| +    return;
 | 
| +
 | 
| +  std::set<ServerView*> views(id_to_views_map_[id]);
 | 
| +  for (ServerView* view : views)
 | 
| +    CancelAnimationForView(view);
 | 
| +}
 | 
| +
 | 
| +void AnimationRunner::CancelAnimationForView(ServerView* view) {
 | 
| +  CancelAnimationForViewImpl(view, CANCEL_SOURCE_CANCEL);
 | 
| +}
 | 
| +
 | 
| +void AnimationRunner::Tick(base::TimeTicks time) {
 | 
| +  DCHECK(time >= last_tick_time_);
 | 
| +  last_tick_time_ = time;
 | 
| +  if (view_to_animation_map_.empty())
 | 
| +    return;
 | 
| +
 | 
| +  // The animation ids of any views whose animation completes are added here. We
 | 
| +  // notify after processing all views so that if an observer mutates us in some
 | 
| +  // way we're aren't left in a weird state.
 | 
| +  std::set<AnimationId> animations_completed;
 | 
| +  for (ViewToAnimationMap::iterator i = view_to_animation_map_.begin();
 | 
| +       i != view_to_animation_map_.end();) {
 | 
| +    if (i->second->Tick(time)) {
 | 
| +      const AnimationId animation_id = i->second->id();
 | 
| +      ServerView* view = i->first;
 | 
| +      ++i;
 | 
| +      if (RemoveViewFromMaps(view))
 | 
| +        animations_completed.insert(animation_id);
 | 
| +    } else {
 | 
| +      ++i;
 | 
| +    }
 | 
| +  }
 | 
| +  for (const AnimationId& id : animations_completed) {
 | 
| +    FOR_EACH_OBSERVER(AnimationRunnerObserver, observers_, OnAnimationDone(id));
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void AnimationRunner::CancelAnimationForViewImpl(ServerView* view,
 | 
| +                                                 CancelSource source) {
 | 
| +  if (!view_to_animation_map_.contains(view))
 | 
| +    return;
 | 
| +
 | 
| +  const AnimationId animation_id = view_to_animation_map_.get(view)->id();
 | 
| +  if (RemoveViewFromMaps(view)) {
 | 
| +    // This was the last view in the group.
 | 
| +    if (source == CANCEL_SOURCE_CANCEL) {
 | 
| +      FOR_EACH_OBSERVER(AnimationRunnerObserver, observers_,
 | 
| +                        OnAnimationCanceled(animation_id));
 | 
| +    } else {
 | 
| +      FOR_EACH_OBSERVER(AnimationRunnerObserver, observers_,
 | 
| +                        OnAnimationInterrupted(animation_id));
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +bool AnimationRunner::RemoveViewFromMaps(ServerView* view) {
 | 
| +  DCHECK(view_to_animation_map_.contains(view));
 | 
| +
 | 
| +  const AnimationId animation_id = view_to_animation_map_.get(view)->id();
 | 
| +  view_to_animation_map_.erase(view);
 | 
| +
 | 
| +  DCHECK(id_to_views_map_.count(animation_id));
 | 
| +  id_to_views_map_[animation_id].erase(view);
 | 
| +  if (!id_to_views_map_[animation_id].empty())
 | 
| +    return false;
 | 
| +
 | 
| +  id_to_views_map_.erase(animation_id);
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +}  // namespace view_manager
 | 
| 
 |