Chromium Code Reviews| Index: components/mus/ws/animation_runner.cc |
| diff --git a/components/mus/ws/animation_runner.cc b/components/mus/ws/animation_runner.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..af5ac952a6b7b5034c9c108dbffd3bf5671c4be6 |
| --- /dev/null |
| +++ b/components/mus/ws/animation_runner.cc |
| @@ -0,0 +1,164 @@ |
| +// 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 "components/mus/ws/animation_runner.h" |
| + |
| +#include "base/memory/scoped_vector.h" |
| +#include "components/mus/ws/animation_runner_observer.h" |
| +#include "components/mus/ws/scheduled_animation_group.h" |
| +#include "components/mus/ws/server_window.h" |
| + |
| +namespace mus { |
| +namespace ws { |
| +namespace { |
| + |
| +bool ConvertWindowAndAnimationPairsToScheduledAnimationGroups( |
| + const std::vector<AnimationRunner::WindowAndAnimationPair>& pairs, |
| + AnimationRunner::AnimationId id, |
| + base::TimeTicks now, |
| + ScopedVector<ScheduledAnimationGroup>* groups) { |
| + for (const auto& window_animation_pair : pairs) { |
| + DCHECK(window_animation_pair.first); |
| + DCHECK(window_animation_pair.second); |
| + std::unique_ptr<ScheduledAnimationGroup> group( |
| + ScheduledAnimationGroup::Create(window_animation_pair.first, now, id, |
| + *(window_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<WindowAndAnimationPair>& pairs, |
| + base::TimeTicks now) { |
| + DCHECK_GE(now, last_tick_time_); |
| + |
| + const AnimationId animation_id = next_id_++; |
| + ScopedVector<ScheduledAnimationGroup> groups; |
|
sky
2016/06/16 16:36:33
ScopedVector is deprecated.
mfomitchev
2016/06/22 21:59:35
Done.
|
| + if (!ConvertWindowAndAnimationPairsToScheduledAnimationGroups( |
| + pairs, animation_id, now, &groups)) { |
| + return 0; |
| + } |
| + |
| + // Cancel any animations for the affected windows. If the cancelled animations |
| + // also animated properties that are not animated by the new group - instantly |
| + // set those to the target value. |
| + for (auto* group : groups) { |
| + ScheduledAnimationGroup* current_group = |
| + window_to_animation_map_.get(group->window()); |
| + if (current_group) |
| + current_group->SetValuesToTargetValuesForPropertiesNotIn(*group); |
| + |
| + CancelAnimationForWindowImpl(group->window(), CANCEL_SOURCE_SCHEDULE); |
| + } |
| + |
| + // Update internal maps |
| + for (auto* group : groups) { |
| + group->ObtainStartValues(); |
| + window_to_animation_map_.set(group->window(), base::WrapUnique(group)); |
| + DCHECK(!id_to_windows_map_[animation_id].count(group->window())); |
| + id_to_windows_map_[animation_id].insert(group->window()); |
| + } |
| + // |window_to_animation_map_| owns the individual group objects. |
| + groups.weak_clear(); |
| + |
| + FOR_EACH_OBSERVER(AnimationRunnerObserver, observers_, |
| + OnAnimationScheduled(animation_id)); |
| + return animation_id; |
| +} |
| + |
| +void AnimationRunner::CancelAnimation(AnimationId id) { |
| + if (id_to_windows_map_.count(id) == 0) |
| + return; |
| + |
| + std::set<ServerWindow*> windows(id_to_windows_map_[id]); |
| + for (ServerWindow* window : windows) |
| + CancelAnimationForWindow(window); |
| +} |
| + |
| +void AnimationRunner::CancelAnimationForWindow(ServerWindow* window) { |
| + CancelAnimationForWindowImpl(window, CANCEL_SOURCE_CANCEL); |
| +} |
| + |
| +void AnimationRunner::Tick(base::TimeTicks time) { |
| + DCHECK(time >= last_tick_time_); |
| + last_tick_time_ = time; |
| + if (window_to_animation_map_.empty()) |
| + return; |
| + |
| + // The animation ids of any windows whose animation completes are added here. |
| + // We notify after processing all windows 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 (WindowToAnimationMap::iterator i = window_to_animation_map_.begin(); |
| + i != window_to_animation_map_.end();) { |
| + bool animation_done = i->second->Tick(time); |
| + if (animation_done) { |
| + const AnimationId animation_id = i->second->id(); |
| + ServerWindow* window = i->first; |
| + ++i; |
| + bool animation_completed = RemoveWindowFromMaps(window); |
| + if (animation_completed) |
| + animations_completed.insert(animation_id); |
| + } else { |
| + ++i; |
| + } |
| + } |
| + for (const AnimationId& id : animations_completed) { |
| + FOR_EACH_OBSERVER(AnimationRunnerObserver, observers_, OnAnimationDone(id)); |
| + } |
| +} |
| + |
| +void AnimationRunner::CancelAnimationForWindowImpl(ServerWindow* window, |
| + CancelSource source) { |
| + if (!window_to_animation_map_.contains(window)) |
| + return; |
| + |
| + const AnimationId animation_id = window_to_animation_map_.get(window)->id(); |
| + if (RemoveWindowFromMaps(window)) { |
| + // This was the last window 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::RemoveWindowFromMaps(ServerWindow* window) { |
| + DCHECK(window_to_animation_map_.contains(window)); |
| + |
| + const AnimationId animation_id = window_to_animation_map_.get(window)->id(); |
| + window_to_animation_map_.erase(window); |
| + |
| + DCHECK(id_to_windows_map_.count(animation_id)); |
| + id_to_windows_map_[animation_id].erase(window); |
| + if (!id_to_windows_map_[animation_id].empty()) |
| + return false; |
| + |
| + id_to_windows_map_.erase(animation_id); |
| + return true; |
| +} |
| + |
| +} // namespace ws |
| +} // namespace mus |