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