layer_animation_sequence.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1// Copyright (c) 2012 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/compositor/layer_animation_sequence.h" 6 7#include <algorithm> 8#include <iterator> 9 10#include "base/debug/trace_event.h" 11#include "cc/animation/animation_id_provider.h" 12#include "ui/compositor/layer_animation_delegate.h" 13#include "ui/compositor/layer_animation_element.h" 14#include "ui/compositor/layer_animation_observer.h" 15 16namespace ui { 17 18LayerAnimationSequence::LayerAnimationSequence() 19 : is_cyclic_(false), 20 last_element_(0), 21 waiting_for_group_start_(false), 22 animation_group_id_(0), 23 last_progressed_fraction_(0.0), 24 weak_ptr_factory_(this) { 25} 26 27LayerAnimationSequence::LayerAnimationSequence(LayerAnimationElement* element) 28 : is_cyclic_(false), 29 last_element_(0), 30 waiting_for_group_start_(false), 31 animation_group_id_(0), 32 last_progressed_fraction_(0.0), 33 weak_ptr_factory_(this) { 34 AddElement(element); 35} 36 37LayerAnimationSequence::~LayerAnimationSequence() { 38 FOR_EACH_OBSERVER(LayerAnimationObserver, 39 observers_, 40 DetachedFromSequence(this, true)); 41} 42 43void LayerAnimationSequence::Start(LayerAnimationDelegate* delegate) { 44 DCHECK(start_time_ != base::TimeTicks()); 45 last_progressed_fraction_ = 0.0; 46 if (elements_.empty()) 47 return; 48 49 elements_[0]->set_requested_start_time(start_time_); 50 elements_[0]->Start(delegate, animation_group_id_); 51} 52 53void LayerAnimationSequence::Progress(base::TimeTicks now, 54 LayerAnimationDelegate* delegate) { 55 DCHECK(start_time_ != base::TimeTicks()); 56 bool redraw_required = false; 57 58 if (elements_.empty()) 59 return; 60 61 if (last_element_ == 0) 62 last_start_ = start_time_; 63 64 size_t current_index = last_element_ % elements_.size(); 65 base::TimeDelta element_duration; 66 while (is_cyclic_ || last_element_ < elements_.size()) { 67 elements_[current_index]->set_requested_start_time(last_start_); 68 if (!elements_[current_index]->IsFinished(now, &element_duration)) 69 break; 70 71 // Let the element we're passing finish. 72 if (elements_[current_index]->ProgressToEnd(delegate)) 73 redraw_required = true; 74 last_start_ += element_duration; 75 ++last_element_; 76 last_progressed_fraction_ = 77 elements_[current_index]->last_progressed_fraction(); 78 current_index = last_element_ % elements_.size(); 79 } 80 81 if (is_cyclic_ || last_element_ < elements_.size()) { 82 if (!elements_[current_index]->Started()) { 83 animation_group_id_ = cc::AnimationIdProvider::NextGroupId(); 84 elements_[current_index]->Start(delegate, animation_group_id_); 85 } 86 base::WeakPtr<LayerAnimationSequence> alive(weak_ptr_factory_.GetWeakPtr()); 87 if (elements_[current_index]->Progress(now, delegate)) 88 redraw_required = true; 89 if (!alive) 90 return; 91 last_progressed_fraction_ = 92 elements_[current_index]->last_progressed_fraction(); 93 } 94 95 // Since the delegate may be deleted due to the notifications below, it is 96 // important that we schedule a draw before sending them. 97 if (redraw_required) 98 delegate->ScheduleDrawForAnimation(); 99 100 if (!is_cyclic_ && last_element_ == elements_.size()) { 101 last_element_ = 0; 102 waiting_for_group_start_ = false; 103 animation_group_id_ = 0; 104 NotifyEnded(); 105 } 106} 107 108bool LayerAnimationSequence::IsFinished(base::TimeTicks time) { 109 if (is_cyclic_ || waiting_for_group_start_) 110 return false; 111 112 if (elements_.empty()) 113 return true; 114 115 if (last_element_ == 0) 116 last_start_ = start_time_; 117 118 base::TimeTicks current_start = last_start_; 119 size_t current_index = last_element_; 120 base::TimeDelta element_duration; 121 while (current_index < elements_.size()) { 122 elements_[current_index]->set_requested_start_time(current_start); 123 if (!elements_[current_index]->IsFinished(time, &element_duration)) 124 break; 125 126 current_start += element_duration; 127 ++current_index; 128 } 129 130 return (current_index == elements_.size()); 131} 132 133void LayerAnimationSequence::ProgressToEnd(LayerAnimationDelegate* delegate) { 134 bool redraw_required = false; 135 136 if (elements_.empty()) 137 return; 138 139 size_t current_index = last_element_ % elements_.size(); 140 while (current_index < elements_.size()) { 141 if (elements_[current_index]->ProgressToEnd(delegate)) 142 redraw_required = true; 143 last_progressed_fraction_ = 144 elements_[current_index]->last_progressed_fraction(); 145 ++current_index; 146 ++last_element_; 147 } 148 149 if (redraw_required) 150 delegate->ScheduleDrawForAnimation(); 151 152 if (!is_cyclic_) { 153 last_element_ = 0; 154 waiting_for_group_start_ = false; 155 animation_group_id_ = 0; 156 NotifyEnded(); 157 } 158} 159 160void LayerAnimationSequence::GetTargetValue( 161 LayerAnimationElement::TargetValue* target) const { 162 if (is_cyclic_) 163 return; 164 165 for (size_t i = last_element_; i < elements_.size(); ++i) 166 elements_[i]->GetTargetValue(target); 167} 168 169void LayerAnimationSequence::Abort(LayerAnimationDelegate* delegate) { 170 size_t current_index = last_element_ % elements_.size(); 171 while (current_index < elements_.size()) { 172 elements_[current_index]->Abort(delegate); 173 ++current_index; 174 } 175 last_element_ = 0; 176 waiting_for_group_start_ = false; 177 NotifyAborted(); 178} 179 180void LayerAnimationSequence::AddElement(LayerAnimationElement* element) { 181 properties_.insert(element->properties().begin(), 182 element->properties().end()); 183 elements_.push_back(make_linked_ptr(element)); 184} 185 186bool LayerAnimationSequence::HasConflictingProperty( 187 const LayerAnimationElement::AnimatableProperties& other) const { 188 LayerAnimationElement::AnimatableProperties intersection; 189 std::insert_iterator<LayerAnimationElement::AnimatableProperties> ii( 190 intersection, intersection.begin()); 191 std::set_intersection(properties_.begin(), properties_.end(), 192 other.begin(), other.end(), 193 ii); 194 return (intersection.size() > 0); 195} 196 197bool LayerAnimationSequence::IsFirstElementThreaded() const { 198 if (!elements_.empty()) 199 return elements_[0]->IsThreaded(); 200 201 return false; 202} 203 204void LayerAnimationSequence::AddObserver(LayerAnimationObserver* observer) { 205 if (!observers_.HasObserver(observer)) { 206 observers_.AddObserver(observer); 207 observer->AttachedToSequence(this); 208 } 209} 210 211void LayerAnimationSequence::RemoveObserver(LayerAnimationObserver* observer) { 212 observers_.RemoveObserver(observer); 213 observer->DetachedFromSequence(this, true); 214} 215 216void LayerAnimationSequence::OnThreadedAnimationStarted( 217 const cc::AnimationEvent& event) { 218 if (elements_.empty() || event.group_id != animation_group_id_) 219 return; 220 221 size_t current_index = last_element_ % elements_.size(); 222 const LayerAnimationElement::AnimatableProperties& element_properties = 223 elements_[current_index]->properties(); 224 LayerAnimationElement::AnimatableProperty event_property = 225 LayerAnimationElement::ToAnimatableProperty(event.target_property); 226 DCHECK(element_properties.find(event_property) != element_properties.end()); 227 elements_[current_index]->set_effective_start_time( 228 base::TimeTicks::FromInternalValue( 229 event.monotonic_time * base::Time::kMicrosecondsPerSecond)); 230} 231 232void LayerAnimationSequence::OnScheduled() { 233 NotifyScheduled(); 234} 235 236void LayerAnimationSequence::OnAnimatorDestroyed() { 237 if (observers_.might_have_observers()) { 238 ObserverListBase<LayerAnimationObserver>::Iterator it(observers_); 239 LayerAnimationObserver* obs; 240 while ((obs = it.GetNext()) != NULL) { 241 if (!obs->RequiresNotificationWhenAnimatorDestroyed()) { 242 // Remove the observer, but do not allow notifications to be sent. 243 observers_.RemoveObserver(obs); 244 obs->DetachedFromSequence(this, false); 245 } 246 } 247 } 248} 249 250size_t LayerAnimationSequence::size() const { 251 return elements_.size(); 252} 253 254LayerAnimationElement* LayerAnimationSequence::FirstElement() const { 255 if (elements_.empty()) { 256 return NULL; 257 } 258 259 return elements_[0].get(); 260} 261 262void LayerAnimationSequence::NotifyScheduled() { 263 FOR_EACH_OBSERVER(LayerAnimationObserver, 264 observers_, 265 OnLayerAnimationScheduled(this)); 266} 267 268void LayerAnimationSequence::NotifyEnded() { 269 FOR_EACH_OBSERVER(LayerAnimationObserver, 270 observers_, 271 OnLayerAnimationEnded(this)); 272} 273 274void LayerAnimationSequence::NotifyAborted() { 275 FOR_EACH_OBSERVER(LayerAnimationObserver, 276 observers_, 277 OnLayerAnimationAborted(this)); 278} 279 280LayerAnimationElement* LayerAnimationSequence::CurrentElement() const { 281 if (elements_.empty()) 282 return NULL; 283 284 size_t current_index = last_element_ % elements_.size(); 285 return elements_[current_index].get(); 286} 287 288} // namespace ui 289