Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Side by Side Diff: third_party/WebKit/Source/core/animation/AnimationTimeline.cpp

Issue 2948193002: Merge AnimationTimeline and DocumentTimeline (Closed)
Patch Set: Fix rebase error Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "core/animation/AnimationTimeline.h"
32
33 #include <algorithm>
34 #include "core/animation/AnimationClock.h"
35 #include "core/animation/ElementAnimations.h"
36 #include "core/dom/Document.h"
37 #include "core/frame/LocalFrameView.h"
38 #include "core/loader/DocumentLoader.h"
39 #include "core/page/Page.h"
40 #include "platform/RuntimeEnabledFeatures.h"
41 #include "platform/animation/CompositorAnimationTimeline.h"
42 #include "platform/instrumentation/tracing/TraceEvent.h"
43 #include "platform/wtf/PtrUtil.h"
44 #include "public/platform/Platform.h"
45 #include "public/platform/WebCompositorSupport.h"
46
47 namespace blink {
48
49 namespace {
50
51 bool CompareAnimations(const Member<Animation>& left,
52 const Member<Animation>& right) {
53 return Animation::HasLowerPriority(left.Get(), right.Get());
54 }
55 }
56
57 // This value represents 1 frame at 30Hz plus a little bit of wiggle room.
58 // TODO: Plumb a nominal framerate through and derive this value from that.
59 const double AnimationTimeline::kMinimumDelay = 0.04;
60
61 AnimationTimeline* AnimationTimeline::Create(Document* document,
62 PlatformTiming* timing) {
63 return new AnimationTimeline(document, timing);
64 }
65
66 AnimationTimeline::AnimationTimeline(Document* document, PlatformTiming* timing)
67 : document_(document),
68 // 0 is used by unit tests which cannot initialize from the loader
69 zero_time_(0),
70 zero_time_initialized_(false),
71 outdated_animation_count_(0),
72 playback_rate_(1),
73 last_current_time_internal_(0) {
74 if (!timing)
75 timing_ = new AnimationTimelineTiming(this);
76 else
77 timing_ = timing;
78
79 if (Platform::Current()->IsThreadedAnimationEnabled())
80 compositor_timeline_ = CompositorAnimationTimeline::Create();
81
82 DCHECK(document);
83 }
84
85 bool AnimationTimeline::IsActive() {
86 return document_ && document_->GetPage();
87 }
88
89 void AnimationTimeline::AnimationAttached(Animation& animation) {
90 DCHECK_EQ(animation.TimelineInternal(), this);
91 DCHECK(!animations_.Contains(&animation));
92 animations_.insert(&animation);
93 }
94
95 Animation* AnimationTimeline::Play(AnimationEffectReadOnly* child) {
96 if (!document_)
97 return nullptr;
98
99 Animation* animation = Animation::Create(child, this);
100 DCHECK(animations_.Contains(animation));
101
102 animation->play();
103 DCHECK(animations_needing_update_.Contains(animation));
104
105 return animation;
106 }
107
108 HeapVector<Member<Animation>> AnimationTimeline::getAnimations() {
109 HeapVector<Member<Animation>> animations;
110 for (const auto& animation : animations_) {
111 if (animation->effect() &&
112 (animation->effect()->IsCurrent() || animation->effect()->IsInEffect()))
113 animations.push_back(animation);
114 }
115 std::sort(animations.begin(), animations.end(), CompareAnimations);
116 return animations;
117 }
118
119 void AnimationTimeline::Wake() {
120 timing_->ServiceOnNextFrame();
121 }
122
123 void AnimationTimeline::ServiceAnimations(TimingUpdateReason reason) {
124 TRACE_EVENT0("blink", "AnimationTimeline::serviceAnimations");
125
126 last_current_time_internal_ = CurrentTimeInternal();
127
128 HeapVector<Member<Animation>> animations;
129 animations.ReserveInitialCapacity(animations_needing_update_.size());
130 for (Animation* animation : animations_needing_update_)
131 animations.push_back(animation);
132
133 std::sort(animations.begin(), animations.end(), Animation::HasLowerPriority);
134
135 for (Animation* animation : animations) {
136 if (!animation->Update(reason))
137 animations_needing_update_.erase(animation);
138 }
139
140 DCHECK_EQ(outdated_animation_count_, 0U);
141 DCHECK(last_current_time_internal_ == CurrentTimeInternal() ||
142 (std::isnan(CurrentTimeInternal()) &&
143 std::isnan(last_current_time_internal_)));
144
145 #if DCHECK_IS_ON()
146 for (const auto& animation : animations_needing_update_)
147 DCHECK(!animation->Outdated());
148 #endif
149 }
150
151 void AnimationTimeline::ScheduleNextService() {
152 DCHECK_EQ(outdated_animation_count_, 0U);
153
154 double time_to_next_effect = std::numeric_limits<double>::infinity();
155 for (const auto& animation : animations_needing_update_) {
156 time_to_next_effect =
157 std::min(time_to_next_effect, animation->TimeToEffectChange());
158 }
159
160 if (time_to_next_effect < kMinimumDelay) {
161 timing_->ServiceOnNextFrame();
162 } else if (time_to_next_effect != std::numeric_limits<double>::infinity()) {
163 timing_->WakeAfter(time_to_next_effect - kMinimumDelay);
164 }
165 }
166
167 void AnimationTimeline::AnimationTimelineTiming::WakeAfter(double duration) {
168 if (timer_.IsActive() && timer_.NextFireInterval() < duration)
169 return;
170 timer_.StartOneShot(duration, BLINK_FROM_HERE);
171 }
172
173 void AnimationTimeline::AnimationTimelineTiming::ServiceOnNextFrame() {
174 if (timeline_->document_ && timeline_->document_->View())
175 timeline_->document_->View()->ScheduleAnimation();
176 }
177
178 DEFINE_TRACE(AnimationTimeline::AnimationTimelineTiming) {
179 visitor->Trace(timeline_);
180 AnimationTimeline::PlatformTiming::Trace(visitor);
181 }
182
183 double AnimationTimeline::ZeroTime() {
184 if (!zero_time_initialized_ && document_ && document_->Loader()) {
185 zero_time_ = document_->Loader()->GetTiming().ReferenceMonotonicTime();
186 zero_time_initialized_ = true;
187 }
188 return zero_time_;
189 }
190
191 void AnimationTimeline::ResetForTesting() {
192 zero_time_ = 0;
193 zero_time_initialized_ = true;
194 playback_rate_ = 1;
195 last_current_time_internal_ = 0;
196 }
197
198 double AnimationTimeline::currentTime(bool& is_null) {
199 return CurrentTimeInternal(is_null) * 1000;
200 }
201
202 double AnimationTimeline::CurrentTimeInternal(bool& is_null) {
203 if (!IsActive()) {
204 is_null = true;
205 return std::numeric_limits<double>::quiet_NaN();
206 }
207 double result =
208 playback_rate_ == 0
209 ? ZeroTime()
210 : (GetDocument()->GetAnimationClock().CurrentTime() - ZeroTime()) *
211 playback_rate_;
212 is_null = std::isnan(result);
213 return result;
214 }
215
216 double AnimationTimeline::currentTime() {
217 return CurrentTimeInternal() * 1000;
218 }
219
220 double AnimationTimeline::CurrentTimeInternal() {
221 bool is_null;
222 return CurrentTimeInternal(is_null);
223 }
224
225 double AnimationTimeline::EffectiveTime() {
226 double time = CurrentTimeInternal();
227 return std::isnan(time) ? 0 : time;
228 }
229
230 void AnimationTimeline::PauseAnimationsForTesting(double pause_time) {
231 for (const auto& animation : animations_needing_update_)
232 animation->PauseForTesting(pause_time);
233 ServiceAnimations(kTimingUpdateOnDemand);
234 }
235
236 bool AnimationTimeline::NeedsAnimationTimingUpdate() {
237 if (CurrentTimeInternal() == last_current_time_internal_)
238 return false;
239
240 if (std::isnan(CurrentTimeInternal()) &&
241 std::isnan(last_current_time_internal_))
242 return false;
243
244 // We allow m_lastCurrentTimeInternal to advance here when there
245 // are no animations to allow animations spawned during style
246 // recalc to not invalidate this flag.
247 if (animations_needing_update_.IsEmpty())
248 last_current_time_internal_ = CurrentTimeInternal();
249
250 return !animations_needing_update_.IsEmpty();
251 }
252
253 void AnimationTimeline::ClearOutdatedAnimation(Animation* animation) {
254 DCHECK(!animation->Outdated());
255 outdated_animation_count_--;
256 }
257
258 void AnimationTimeline::SetOutdatedAnimation(Animation* animation) {
259 DCHECK(animation->Outdated());
260 outdated_animation_count_++;
261 animations_needing_update_.insert(animation);
262 if (IsActive() && !document_->GetPage()->Animator().IsServicingAnimations())
263 timing_->ServiceOnNextFrame();
264 }
265
266 void AnimationTimeline::SetPlaybackRate(double playback_rate) {
267 if (!IsActive())
268 return;
269 double current_time = CurrentTimeInternal();
270 playback_rate_ = playback_rate;
271 zero_time_ = playback_rate == 0
272 ? current_time
273 : GetDocument()->GetAnimationClock().CurrentTime() -
274 current_time / playback_rate;
275 zero_time_initialized_ = true;
276
277 // Corresponding compositor animation may need to be restarted to pick up
278 // the new playback rate. Marking the effect changed forces this.
279 SetAllCompositorPending(true);
280 }
281
282 void AnimationTimeline::SetAllCompositorPending(bool source_changed) {
283 for (const auto& animation : animations_) {
284 animation->SetCompositorPending(source_changed);
285 }
286 }
287
288 double AnimationTimeline::PlaybackRate() const {
289 return playback_rate_;
290 }
291
292 void AnimationTimeline::InvalidateKeyframeEffects(const TreeScope& tree_scope) {
293 for (const auto& animation : animations_)
294 animation->InvalidateKeyframeEffect(tree_scope);
295 }
296
297 DEFINE_TRACE(AnimationTimeline) {
298 visitor->Trace(document_);
299 visitor->Trace(timing_);
300 visitor->Trace(animations_needing_update_);
301 visitor->Trace(animations_);
302 SuperAnimationTimeline::Trace(visitor);
303 }
304
305 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698