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

Side by Side Diff: Source/core/animation/Animation.cpp

Issue 1113173003: Web Animations: Update naming to reflect spec changes (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: No, really. Created 5 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « Source/core/animation/Animation.h ('k') | Source/core/animation/Animation.idl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 13 matching lines...) Expand all
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31 #include "config.h" 31 #include "config.h"
32 #include "core/animation/Animation.h" 32 #include "core/animation/Animation.h"
33 33
34 #include "bindings/core/v8/Dictionary.h"
35 #include "bindings/core/v8/ExceptionState.h"
36 #include "core/animation/AnimationPlayer.h"
37 #include "core/animation/AnimationTimeline.h" 34 #include "core/animation/AnimationTimeline.h"
38 #include "core/animation/AnimationTimingProperties.h" 35 #include "core/animation/KeyframeEffect.h"
39 #include "core/animation/CompositorAnimations.h" 36 #include "core/dom/Document.h"
40 #include "core/animation/ElementAnimations.h" 37 #include "core/dom/ExceptionCode.h"
41 #include "core/animation/Interpolation.h" 38 #include "core/events/AnimationPlayerEvent.h"
42 #include "core/animation/KeyframeEffectModel.h"
43 #include "core/animation/PropertyHandle.h"
44 #include "core/dom/Element.h"
45 #include "core/dom/NodeComputedStyle.h"
46 #include "core/frame/UseCounter.h" 39 #include "core/frame/UseCounter.h"
47 #include "core/paint/DeprecatedPaintLayer.h" 40 #include "core/inspector/InspectorInstrumentation.h"
48 #include "core/svg/SVGElement.h" 41 #include "core/inspector/InspectorTraceEvents.h"
42 #include "platform/RuntimeEnabledFeatures.h"
43 #include "platform/TraceEvent.h"
44 #include "public/platform/Platform.h"
45 #include "public/platform/WebCompositorAnimationPlayer.h"
46 #include "public/platform/WebCompositorSupport.h"
47 #include "wtf/MathExtras.h"
49 48
50 namespace blink { 49 namespace blink {
51 50
52 PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* target, PassRefPtrW illBeRawPtr<AnimationEffect> effect, const Timing& timing, Priority priority, Pa ssOwnPtrWillBeRawPtr<EventDelegate> eventDelegate) 51 namespace {
53 { 52
54 return adoptRefWillBeNoop(new Animation(target, effect, timing, priority, ev entDelegate)); 53 static unsigned nextSequenceNumber()
55 } 54 {
56 55 static unsigned next = 0;
57 PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, const Vect or<Dictionary>& keyframeDictionaryVector, double duration, ExceptionState& excep tionState) 56 return ++next;
58 { 57 }
59 ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled()); 58
60 if (element) 59 }
61 UseCounter::count(element->document(), UseCounter::AnimationConstructorK eyframeListEffectObjectTiming); 60
62 return create(element, EffectInput::convert(element, keyframeDictionaryVecto r, exceptionState), TimingInput::convert(duration)); 61 PassRefPtrWillBeRawPtr<Animation> Animation::create(AnimationEffect* source, Ani mationTimeline* timeline)
63 } 62 {
64 PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, const Vect or<Dictionary>& keyframeDictionaryVector, const AnimationTimingProperties& timin gInput, ExceptionState& exceptionState) 63 if (!timeline) {
65 { 64 // FIXME: Support creating animations without a timeline.
66 ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled()); 65 return nullptr;
67 if (element) 66 }
68 UseCounter::count(element->document(), UseCounter::AnimationConstructorK eyframeListEffectObjectTiming); 67
69 return create(element, EffectInput::convert(element, keyframeDictionaryVecto r, exceptionState), TimingInput::convert(timingInput)); 68 RefPtrWillBeRawPtr<Animation> animation = adoptRefWillBeNoop(new Animation(t imeline->document()->contextDocument().get(), *timeline, source));
70 } 69 animation->suspendIfNeeded();
71 PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, const Vect or<Dictionary>& keyframeDictionaryVector, ExceptionState& exceptionState) 70
72 { 71 if (timeline) {
73 ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled()); 72 timeline->animationAttached(*animation);
74 if (element) 73 animation->attachCompositorTimeline();
75 UseCounter::count(element->document(), UseCounter::AnimationConstructorK eyframeListEffectNoTiming); 74 }
76 return create(element, EffectInput::convert(element, keyframeDictionaryVecto r, exceptionState), Timing()); 75
77 } 76 return animation.release();
78 77 }
79 Animation::Animation(Element* target, PassRefPtrWillBeRawPtr<AnimationEffect> ef fect, const Timing& timing, Priority priority, PassOwnPtrWillBeRawPtr<EventDeleg ate> eventDelegate) 78
80 : AnimationNode(timing, eventDelegate) 79 Animation::Animation(ExecutionContext* executionContext, AnimationTimeline& time line, AnimationEffect* content)
81 , m_target(target) 80 : ActiveDOMObject(executionContext)
82 , m_effect(effect) 81 , m_playState(Idle)
83 , m_sampledEffect(nullptr) 82 , m_playbackRate(1)
84 , m_priority(priority) 83 , m_startTime(nullValue())
84 , m_holdTime(0)
85 , m_sequenceNumber(nextSequenceNumber())
86 , m_content(content)
87 , m_timeline(&timeline)
88 , m_paused(false)
89 , m_held(true)
90 , m_isPausedForTesting(false)
91 , m_outdated(false)
92 , m_finished(true)
93 , m_compositorState(nullptr)
94 , m_compositorPending(false)
95 , m_compositorGroup(0)
96 , m_currentTimePending(false)
97 , m_stateIsBeingUpdated(false)
98 {
99 if (m_content) {
100 if (m_content->animation()) {
101 m_content->animation()->cancel();
102 m_content->animation()->setSource(0);
103 }
104 m_content->attach(this);
105 }
106 }
107
108 Animation::~Animation()
85 { 109 {
86 #if !ENABLE(OILPAN) 110 #if !ENABLE(OILPAN)
87 if (m_target) 111 if (m_content)
88 m_target->ensureElementAnimations().addAnimation(this); 112 m_content->detach();
113 if (m_timeline)
114 m_timeline->animationDestroyed(this);
89 #endif 115 #endif
90 } 116
91 117 destroyCompositorPlayer();
92 Animation::~Animation() 118 }
93 { 119
94 #if !ENABLE(OILPAN) 120 #if !ENABLE(OILPAN)
95 if (m_target) 121 void Animation::detachFromTimeline()
96 m_target->elementAnimations()->notifyAnimationDestroyed(this); 122 {
123 dispose();
124 m_timeline = nullptr;
125 }
97 #endif 126 #endif
98 } 127
99 128 double Animation::sourceEnd() const
100 void Animation::attach(AnimationPlayer* player) 129 {
101 { 130 return m_content ? m_content->endTimeInternal() : 0;
102 if (m_target) { 131 }
103 m_target->ensureElementAnimations().players().add(player); 132
104 m_target->setNeedsAnimationStyleRecalc(); 133 bool Animation::limited(double currentTime) const
105 } 134 {
106 AnimationNode::attach(player); 135 return (m_playbackRate < 0 && currentTime <= 0) || (m_playbackRate > 0 && cu rrentTime >= sourceEnd());
107 } 136 }
108 137
109 void Animation::detach() 138 void Animation::setCurrentTime(double newCurrentTime)
110 { 139 {
111 if (m_target) 140 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
112 m_target->elementAnimations()->players().remove(player()); 141
113 if (m_sampledEffect) 142 m_currentTimePending = false;
114 clearEffects(); 143 setCurrentTimeInternal(newCurrentTime / 1000, TimingUpdateOnDemand);
115 AnimationNode::detach(); 144
116 } 145 if (calculatePlayState() == Finished)
117 146 m_startTime = calculateStartTime(newCurrentTime);
118 void Animation::specifiedTimingChanged() 147 }
119 { 148
120 if (player()) { 149 void Animation::setCurrentTimeInternal(double newCurrentTime, TimingUpdateReason reason)
121 // FIXME: Needs to consider groups when added. 150 {
122 ASSERT(player()->source() == this); 151 ASSERT(std::isfinite(newCurrentTime));
123 player()->setCompositorPending(true); 152
124 } 153 bool oldHeld = m_held;
125 } 154 bool outdated = false;
126 155 bool isLimited = limited(newCurrentTime);
127 static AnimationStack& ensureAnimationStack(Element* element) 156 m_held = m_paused || !m_playbackRate || isLimited || std::isnan(m_startTime) ;
128 { 157 if (m_held) {
129 return element->ensureElementAnimations().defaultStack(); 158 if (!oldHeld || m_holdTime != newCurrentTime)
130 } 159 outdated = true;
131 160 m_holdTime = newCurrentTime;
132 void Animation::applyEffects() 161 if (m_paused || !m_playbackRate) {
133 { 162 m_startTime = nullValue();
134 ASSERT(isInEffect()); 163 } else if (isLimited && std::isnan(m_startTime) && reason == TimingUpdat eForAnimationFrame) {
135 ASSERT(player()); 164 m_startTime = calculateStartTime(newCurrentTime);
136 if (!m_target || !m_effect) 165 }
137 return;
138
139 // Cancel composited animation of transform if a motion path has been introd uced on the element.
140 if (m_target->computedStyle()
141 && m_target->computedStyle()->hasMotionPath()
142 && player()->hasActiveAnimationsOnCompositor()
143 && player()->affects(*m_target, CSSPropertyTransform)) {
144 player()->cancelAnimationOnCompositor();
145 }
146
147 double iteration = currentIteration();
148 ASSERT(iteration >= 0);
149 OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation>>> inte rpolations = m_sampledEffect ? m_sampledEffect->mutableInterpolations() : nullpt r;
150 // FIXME: Handle iteration values which overflow int.
151 m_effect->sample(static_cast<int>(iteration), timeFraction(), iterationDurat ion(), interpolations);
152 if (m_sampledEffect) {
153 m_sampledEffect->setInterpolations(interpolations.release());
154 } else if (interpolations && !interpolations->isEmpty()) {
155 OwnPtrWillBeRawPtr<SampledEffect> sampledEffect = SampledEffect::create( this, interpolations.release());
156 m_sampledEffect = sampledEffect.get();
157 ensureAnimationStack(m_target).add(sampledEffect.release());
158 } else { 166 } else {
159 return; 167 m_holdTime = nullValue();
160 } 168 m_startTime = calculateStartTime(newCurrentTime);
161 169 m_finished = false;
162 m_target->setNeedsAnimationStyleRecalc(); 170 outdated = true;
163 if (m_target->isSVGElement()) 171 }
164 m_sampledEffect->applySVGUpdate(toSVGElement(*m_target)); 172
165 } 173 if (outdated) {
166 174 setOutdated();
167 void Animation::clearEffects() 175 }
168 { 176 }
169 ASSERT(player()); 177
170 ASSERT(m_sampledEffect); 178 // Update timing to reflect updated animation clock due to tick
171 179 void Animation::updateCurrentTimingState(TimingUpdateReason reason)
172 m_sampledEffect->clear(); 180 {
173 m_sampledEffect = nullptr; 181 if (m_held) {
174 restartAnimationOnCompositor(); 182 double newCurrentTime = m_holdTime;
175 m_target->setNeedsAnimationStyleRecalc(); 183 if (playStateInternal() == Finished && !isNull(m_startTime) && m_timelin e) {
176 invalidate(); 184 // Add hystersis due to floating point error accumulation
177 } 185 if (!limited(calculateCurrentTime() + 0.001 * m_playbackRate)) {
178 186 // The current time became unlimited, eg. due to a backwards
179 void Animation::updateChildrenAndEffects() const 187 // seek of the timeline.
180 { 188 newCurrentTime = calculateCurrentTime();
181 if (!m_effect) 189 } else if (!limited(m_holdTime)) {
182 return; 190 // The hold time became unlimited, eg. due to the source content
183 if (isInEffect()) 191 // becoming longer.
184 const_cast<Animation*>(this)->applyEffects(); 192 newCurrentTime = clampTo<double>(calculateCurrentTime(), 0, sour ceEnd());
185 else if (m_sampledEffect)
186 const_cast<Animation*>(this)->clearEffects();
187 }
188
189 double Animation::calculateTimeToEffectChange(bool forwards, double localTime, d ouble timeToNextIteration) const
190 {
191 const double start = startTimeInternal() + specifiedTiming().startDelay;
192 const double end = start + activeDurationInternal();
193
194 switch (phase()) {
195 case PhaseNone:
196 return std::numeric_limits<double>::infinity();
197 case PhaseBefore:
198 ASSERT(start >= localTime);
199 return forwards
200 ? start - localTime
201 : std::numeric_limits<double>::infinity();
202 case PhaseActive:
203 if (forwards) {
204 // Need service to apply fill / fire events.
205 const double timeToEnd = end - localTime;
206 if (requiresIterationEvents()) {
207 return std::min(timeToEnd, timeToNextIteration);
208 } 193 }
209 return timeToEnd; 194 }
210 } 195 setCurrentTimeInternal(newCurrentTime, reason);
211 return 0; 196 } else if (limited(calculateCurrentTime())) {
212 case PhaseAfter: 197 m_held = true;
213 ASSERT(localTime >= end); 198 m_holdTime = m_playbackRate < 0 ? 0 : sourceEnd();
214 // If this Animation is still in effect then it will need to update 199 }
215 // when its parent goes out of effect. We have no way of knowing when 200 }
216 // that will be, however, so the parent will need to supply it. 201
217 return forwards 202 double Animation::startTime(bool& isNull) const
218 ? std::numeric_limits<double>::infinity() 203 {
219 : localTime - end; 204 double result = startTime();
205 isNull = std::isnan(result);
206 return result;
207 }
208
209 double Animation::startTime() const
210 {
211 return m_startTime * 1000;
212 }
213
214 double Animation::currentTime(bool& isNull)
215 {
216 double result = currentTime();
217 isNull = std::isnan(result);
218 return result;
219 }
220
221 double Animation::currentTime()
222 {
223 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
224
225 if (m_currentTimePending || playStateInternal() == Idle)
226 return std::numeric_limits<double>::quiet_NaN();
227
228 return currentTimeInternal() * 1000;
229 }
230
231 double Animation::currentTimeInternal() const
232 {
233 double result = m_held ? m_holdTime : calculateCurrentTime();
234 #if ENABLE(ASSERT)
235 const_cast<Animation*>(this)->updateCurrentTimingState(TimingUpdateOnDemand) ;
236 ASSERT(result == (m_held ? m_holdTime : calculateCurrentTime()));
237 #endif
238 return result;
239 }
240
241 double Animation::unlimitedCurrentTimeInternal() const
242 {
243 #if ENABLE(ASSERT)
244 currentTimeInternal();
245 #endif
246 return playStateInternal() == Paused || isNull(m_startTime)
247 ? currentTimeInternal()
248 : calculateCurrentTime();
249 }
250
251 void Animation::preCommit(int compositorGroup, bool startOnCompositor)
252 {
253 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, DoNotSetCompos itorPending);
254
255 bool softChange = m_compositorState && (paused() || m_compositorState->playb ackRate != m_playbackRate);
256 bool hardChange = m_compositorState && (m_compositorState->sourceChanged || m_compositorState->startTime != m_startTime);
257
258 // FIXME: softChange && !hardChange should generate a Pause/ThenStart,
259 // not a Cancel, but we can't communicate these to the compositor yet.
260
261 bool changed = softChange || hardChange;
262 bool shouldCancel = (!playing() && m_compositorState) || changed;
263 bool shouldStart = playing() && (!m_compositorState || changed);
264
265 if (shouldCancel) {
266 cancelAnimationOnCompositor();
267 m_compositorState = nullptr;
268 }
269
270 if (m_compositorState && m_compositorState->pendingAction == Start) {
271 // Still waiting for a start time.
272 return;
273 }
274
275 ASSERT(!m_compositorState || !std::isnan(m_compositorState->startTime));
276
277 if (!shouldStart) {
278 m_currentTimePending = false;
279 }
280
281 if (shouldStart) {
282 m_compositorGroup = compositorGroup;
283 if (startOnCompositor) {
284 if (isCandidateForAnimationOnCompositor())
285 createCompositorPlayer();
286
287 if (maybeStartAnimationOnCompositor())
288 m_compositorState = adoptPtr(new CompositorState(*this));
289 else
290 cancelIncompatibleAnimationsOnCompositor();
291 }
292 }
293 }
294
295 void Animation::postCommit(double timelineTime)
296 {
297 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, DoNotSetCompos itorPending);
298
299 m_compositorPending = false;
300
301 if (!m_compositorState || m_compositorState->pendingAction == None)
302 return;
303
304 switch (m_compositorState->pendingAction) {
305 case Start:
306 if (!std::isnan(m_compositorState->startTime)) {
307 ASSERT(m_startTime == m_compositorState->startTime);
308 m_compositorState->pendingAction = None;
309 }
310 break;
311 case Pause:
312 case PauseThenStart:
313 ASSERT(std::isnan(m_startTime));
314 m_compositorState->pendingAction = None;
315 setCurrentTimeInternal((timelineTime - m_compositorState->startTime) * m _playbackRate, TimingUpdateForAnimationFrame);
316 m_currentTimePending = false;
317 break;
220 default: 318 default:
221 ASSERT_NOT_REACHED(); 319 ASSERT_NOT_REACHED();
320 }
321 }
322
323 void Animation::notifyCompositorStartTime(double timelineTime)
324 {
325 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, DoNotSetCompos itorPending);
326
327 if (m_compositorState) {
328 ASSERT(m_compositorState->pendingAction == Start);
329 ASSERT(std::isnan(m_compositorState->startTime));
330
331 double initialCompositorHoldTime = m_compositorState->holdTime;
332 m_compositorState->pendingAction = None;
333 m_compositorState->startTime = timelineTime + currentTimeInternal() / -m _playbackRate;
334
335 if (m_startTime == timelineTime) {
336 // The start time was set to the incoming compositor start time.
337 // Unlikely, but possible.
338 // FIXME: Depending on what changed above this might still be pendin g.
339 // Maybe...
340 m_currentTimePending = false;
341 return;
342 }
343
344 if (!std::isnan(m_startTime) || currentTimeInternal() != initialComposit orHoldTime) {
345 // A new start time or current time was set while starting.
346 setCompositorPending(true);
347 return;
348 }
349 }
350
351 notifyStartTime(timelineTime);
352 }
353
354 void Animation::notifyStartTime(double timelineTime)
355 {
356 if (playing()) {
357 ASSERT(std::isnan(m_startTime));
358 ASSERT(m_held);
359
360 if (m_playbackRate == 0) {
361 setStartTimeInternal(timelineTime);
362 } else {
363 setStartTimeInternal(timelineTime + currentTimeInternal() / -m_playb ackRate);
364 }
365
366 // FIXME: This avoids marking this animation as outdated needlessly when a start time
367 // is notified, but we should refactor how outdating works to avoid this .
368 m_outdated = false;
369
370 m_currentTimePending = false;
371 }
372 }
373
374 bool Animation::affects(const Element& element, CSSPropertyID property) const
375 {
376 if (!m_content || !m_content->isAnimation())
377 return false;
378
379 const KeyframeEffect* effect = toKeyframeEffect(m_content.get());
380 return (effect->target() == &element) && effect->affects(PropertyHandle(prop erty));
381 }
382
383 double Animation::calculateStartTime(double currentTime) const
384 {
385 return m_timeline->effectiveTime() - currentTime / m_playbackRate;
386 }
387
388 double Animation::calculateCurrentTime() const
389 {
390 if (isNull(m_startTime) || !m_timeline)
391 return 0;
392 return (m_timeline->effectiveTime() - m_startTime) * m_playbackRate;
393 }
394
395 void Animation::setStartTime(double startTime)
396 {
397 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
398
399 if (m_paused || playStateInternal() == Idle)
400 return;
401 if (startTime == m_startTime)
402 return;
403
404 m_currentTimePending = false;
405 setStartTimeInternal(startTime / 1000);
406 }
407
408 void Animation::setStartTimeInternal(double newStartTime)
409 {
410 ASSERT(!m_paused);
411 ASSERT(std::isfinite(newStartTime));
412 ASSERT(newStartTime != m_startTime);
413
414 bool hadStartTime = hasStartTime();
415 double previousCurrentTime = currentTimeInternal();
416 m_startTime = newStartTime;
417 if (m_held && m_playbackRate) {
418 // If held, the start time would still be derrived from the hold time.
419 // Force a new, limited, current time.
420 m_held = false;
421 double currentTime = calculateCurrentTime();
422 if (m_playbackRate > 0 && currentTime > sourceEnd()) {
423 currentTime = sourceEnd();
424 } else if (m_playbackRate < 0 && currentTime < 0) {
425 currentTime = 0;
426 }
427 setCurrentTimeInternal(currentTime, TimingUpdateOnDemand);
428 }
429 updateCurrentTimingState(TimingUpdateOnDemand);
430 double newCurrentTime = currentTimeInternal();
431
432 if (previousCurrentTime != newCurrentTime) {
433 setOutdated();
434 } else if (!hadStartTime && m_timeline) {
435 // Even though this animation is not outdated, time to effect change is
436 // infinity until start time is set.
437 m_timeline->wake();
438 }
439 }
440
441 void Animation::setSource(AnimationEffect* newSource)
442 {
443 if (m_content == newSource)
444 return;
445 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, SetCompositorP endingWithSourceChanged);
446
447 double storedCurrentTime = currentTimeInternal();
448 if (m_content)
449 m_content->detach();
450 m_content = newSource;
451 if (newSource) {
452 // FIXME: This logic needs to be updated once groups are implemented
453 if (newSource->animation()) {
454 newSource->animation()->cancel();
455 newSource->animation()->setSource(0);
456 }
457 newSource->attach(this);
458 setOutdated();
459 }
460 setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand);
461 }
462
463 const char* Animation::playStateString(AnimationPlayState playState)
464 {
465 switch (playState) {
466 case Idle:
467 return "idle";
468 case Pending:
469 return "pending";
470 case Running:
471 return "running";
472 case Paused:
473 return "paused";
474 case Finished:
475 return "finished";
476 default:
477 ASSERT_NOT_REACHED();
478 return "";
479 }
480 }
481
482 Animation::AnimationPlayState Animation::playStateInternal() const
483 {
484 return m_playState;
485 }
486
487 Animation::AnimationPlayState Animation::calculatePlayState()
488 {
489 if (m_playState == Idle)
490 return Idle;
491 if (m_currentTimePending || (isNull(m_startTime) && !m_paused && m_playbackR ate != 0))
492 return Pending;
493 if (m_paused)
494 return Paused;
495 if (limited())
496 return Finished;
497 return Running;
498 }
499
500 void Animation::pause()
501 {
502 if (m_paused)
503 return;
504
505 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
506
507 if (playing()) {
508 m_currentTimePending = true;
509 }
510 m_paused = true;
511 setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand);
512 }
513
514 void Animation::unpause()
515 {
516 if (!m_paused)
517 return;
518
519 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
520
521 m_currentTimePending = true;
522 unpauseInternal();
523 }
524
525 void Animation::unpauseInternal()
526 {
527 if (!m_paused)
528 return;
529 m_paused = false;
530 setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand);
531 }
532
533 void Animation::play()
534 {
535 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
536
537 if (!playing())
538 m_startTime = nullValue();
539
540 if (playStateInternal() == Idle) {
541 // We may not go into the pending state, but setting it to something oth er
542 // than Idle here will force an update.
543 ASSERT(isNull(m_startTime));
544 m_playState = Pending;
545 m_held = true;
546 m_holdTime = 0;
547 }
548
549 m_finished = false;
550 unpauseInternal();
551 if (!m_content)
552 return;
553 double currentTime = this->currentTimeInternal();
554 if (m_playbackRate > 0 && (currentTime < 0 || currentTime >= sourceEnd())) {
555 m_startTime = nullValue();
556 setCurrentTimeInternal(0, TimingUpdateOnDemand);
557 } else if (m_playbackRate < 0 && (currentTime <= 0 || currentTime > sourceEn d())) {
558 m_startTime = nullValue();
559 setCurrentTimeInternal(sourceEnd(), TimingUpdateOnDemand);
560 }
561 }
562
563 void Animation::reverse()
564 {
565 if (!m_playbackRate) {
566 return;
567 }
568
569 setPlaybackRateInternal(-m_playbackRate);
570 play();
571 }
572
573 void Animation::finish(ExceptionState& exceptionState)
574 {
575 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
576
577 if (!m_playbackRate || playStateInternal() == Idle) {
578 return;
579 }
580 if (m_playbackRate > 0 && sourceEnd() == std::numeric_limits<double>::infini ty()) {
581 exceptionState.throwDOMException(InvalidStateError, "Animation has sourc e content whose end time is infinity.");
582 return;
583 }
584
585 double newCurrentTime = m_playbackRate < 0 ? 0 : sourceEnd();
586 setCurrentTimeInternal(newCurrentTime, TimingUpdateOnDemand);
587 if (!paused()) {
588 m_startTime = calculateStartTime(newCurrentTime);
589 }
590
591 m_currentTimePending = false;
592 ASSERT(playStateInternal() != Idle);
593 ASSERT(limited());
594 }
595
596 ScriptPromise Animation::finished(ScriptState* scriptState)
597 {
598 if (!m_finishedPromise) {
599 m_finishedPromise = new AnimationPromise(scriptState->executionContext() , this, AnimationPromise::Finished);
600 if (playStateInternal() == Finished)
601 m_finishedPromise->resolve(this);
602 }
603 return m_finishedPromise->promise(scriptState->world());
604 }
605
606 ScriptPromise Animation::ready(ScriptState* scriptState)
607 {
608 if (!m_readyPromise) {
609 m_readyPromise = new AnimationPromise(scriptState->executionContext(), t his, AnimationPromise::Ready);
610 if (playStateInternal() != Pending)
611 m_readyPromise->resolve(this);
612 }
613 return m_readyPromise->promise(scriptState->world());
614 }
615
616 const AtomicString& Animation::interfaceName() const
617 {
618 return EventTargetNames::AnimationPlayer;
619 }
620
621 ExecutionContext* Animation::executionContext() const
622 {
623 return ActiveDOMObject::executionContext();
624 }
625
626 bool Animation::hasPendingActivity() const
627 {
628 return m_pendingFinishedEvent || (!m_finished && hasEventListeners(EventType Names::finish));
629 }
630
631 void Animation::stop()
632 {
633 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
634
635 m_finished = true;
636 m_pendingFinishedEvent = nullptr;
637 }
638
639 bool Animation::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
640 {
641 if (m_pendingFinishedEvent == event)
642 m_pendingFinishedEvent = nullptr;
643 return EventTargetWithInlineData::dispatchEvent(event);
644 }
645
646 double Animation::playbackRate() const
647 {
648 return m_playbackRate;
649 }
650
651 void Animation::setPlaybackRate(double playbackRate)
652 {
653 if (playbackRate == m_playbackRate)
654 return;
655
656 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
657
658 setPlaybackRateInternal(playbackRate);
659 }
660
661 void Animation::setPlaybackRateInternal(double playbackRate)
662 {
663 ASSERT(std::isfinite(playbackRate));
664 ASSERT(playbackRate != m_playbackRate);
665
666 if (!limited() && !paused() && hasStartTime())
667 m_currentTimePending = true;
668
669 double storedCurrentTime = currentTimeInternal();
670 if ((m_playbackRate < 0 && playbackRate >= 0) || (m_playbackRate > 0 && play backRate <= 0))
671 m_finished = false;
672
673 m_playbackRate = playbackRate;
674 m_startTime = std::numeric_limits<double>::quiet_NaN();
675 setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand);
676 }
677
678 void Animation::setOutdated()
679 {
680 m_outdated = true;
681 if (m_timeline)
682 m_timeline->setOutdatedAnimation(this);
683 }
684
685 bool Animation::canStartAnimationOnCompositor() const
686 {
687 // FIXME: Timeline playback rates should be compositable
688 if (m_playbackRate == 0 || (std::isinf(sourceEnd()) && m_playbackRate < 0) | | (timeline() && timeline()->playbackRate() != 1))
689 return false;
690
691 return m_timeline && m_content && m_content->isAnimation() && playing();
692 }
693
694 bool Animation::isCandidateForAnimationOnCompositor() const
695 {
696 if (!canStartAnimationOnCompositor())
697 return false;
698
699 return toKeyframeEffect(m_content.get())->isCandidateForAnimationOnComposito r(m_playbackRate);
700 }
701
702 bool Animation::maybeStartAnimationOnCompositor()
703 {
704 if (!canStartAnimationOnCompositor())
705 return false;
706
707 bool reversed = m_playbackRate < 0;
708
709 double startTime = timeline()->zeroTime() + startTimeInternal();
710 if (reversed) {
711 startTime -= sourceEnd() / fabs(m_playbackRate);
712 }
713
714 double timeOffset = 0;
715 if (std::isnan(startTime)) {
716 timeOffset = reversed ? sourceEnd() - currentTimeInternal() : currentTim eInternal();
717 timeOffset = timeOffset / fabs(m_playbackRate);
718 }
719 ASSERT(m_compositorGroup != 0);
720 return toKeyframeEffect(m_content.get())->maybeStartAnimationOnCompositor(m_ compositorGroup, startTime, timeOffset, m_playbackRate);
721 }
722
723 void Animation::setCompositorPending(bool sourceChanged)
724 {
725 // FIXME: KeyframeEffect could notify this directly?
726 if (!hasActiveAnimationsOnCompositor()) {
727 destroyCompositorPlayer();
728 m_compositorState.release();
729 }
730 if (sourceChanged && m_compositorState) {
731 m_compositorState->sourceChanged = true;
732 }
733 if (m_compositorPending || m_isPausedForTesting) {
734 return;
735 }
736
737 if (sourceChanged || !m_compositorState
738 || !playing() || m_compositorState->playbackRate != m_playbackRate
739 || m_compositorState->startTime != m_startTime) {
740 m_compositorPending = true;
741 ASSERT(timeline());
742 ASSERT(timeline()->document());
743 timeline()->document()->compositorPendingAnimations().add(this);
744 }
745 }
746
747 void Animation::cancelAnimationOnCompositor()
748 {
749 if (hasActiveAnimationsOnCompositor())
750 toKeyframeEffect(m_content.get())->cancelAnimationOnCompositor();
751
752 destroyCompositorPlayer();
753 }
754
755 void Animation::restartAnimationOnCompositor()
756 {
757 if (hasActiveAnimationsOnCompositor())
758 toKeyframeEffect(m_content.get())->restartAnimationOnCompositor();
759 }
760
761 void Animation::cancelIncompatibleAnimationsOnCompositor()
762 {
763 if (m_content && m_content->isAnimation())
764 toKeyframeEffect(m_content.get())->cancelIncompatibleAnimationsOnComposi tor();
765 }
766
767 bool Animation::hasActiveAnimationsOnCompositor()
768 {
769 if (!m_content || !m_content->isAnimation())
770 return false;
771
772 return toKeyframeEffect(m_content.get())->hasActiveAnimationsOnCompositor();
773 }
774
775 bool Animation::update(TimingUpdateReason reason)
776 {
777 if (!m_timeline)
778 return false;
779
780 PlayStateUpdateScope updateScope(*this, reason, DoNotSetCompositorPending);
781
782 m_outdated = false;
783 bool idle = playStateInternal() == Idle;
784
785 if (m_content) {
786 double inheritedTime = idle || isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal();
787 // Special case for end-exclusivity when playing backwards.
788 if (inheritedTime == 0 && m_playbackRate < 0)
789 inheritedTime = -1;
790 m_content->updateInheritedTime(inheritedTime, reason);
791 }
792
793 if ((idle || limited()) && !m_finished) {
794 if (reason == TimingUpdateForAnimationFrame && (idle || hasStartTime())) {
795 const AtomicString& eventType = EventTypeNames::finish;
796 if (executionContext() && hasEventListeners(eventType)) {
797 double eventCurrentTime = currentTimeInternal() * 1000;
798 m_pendingFinishedEvent = AnimationPlayerEvent::create(eventType, eventCurrentTime, timeline()->currentTime());
799 m_pendingFinishedEvent->setTarget(this);
800 m_pendingFinishedEvent->setCurrentTarget(this);
801 m_timeline->document()->enqueueAnimationFrameEvent(m_pendingFini shedEvent);
802 }
803 m_finished = true;
804 }
805 }
806 ASSERT(!m_outdated);
807 return !m_finished;
808 }
809
810 double Animation::timeToEffectChange()
811 {
812 ASSERT(!m_outdated);
813 if (m_held || !hasStartTime())
222 return std::numeric_limits<double>::infinity(); 814 return std::numeric_limits<double>::infinity();
223 } 815 if (!m_content)
224 } 816 return -currentTimeInternal() / m_playbackRate;
225 817 double result = m_playbackRate > 0
226 #if !ENABLE(OILPAN) 818 ? m_content->timeToForwardsEffectChange() / m_playbackRate
227 void Animation::notifyElementDestroyed() 819 : m_content->timeToReverseEffectChange() / -m_playbackRate;
228 { 820 return !hasActiveAnimationsOnCompositor() && m_content->phase() == Animation Effect::PhaseActive
229 // If our player is kept alive just by the sampledEffect, we might get our 821 ? 0
230 // destructor called when we call SampledEffect::clear(), so we need to 822 : result;
231 // clear m_sampledEffect first. 823 }
232 m_target = nullptr; 824
233 clearEventDelegate(); 825 void Animation::cancel()
234 SampledEffect* sampledEffect = m_sampledEffect; 826 {
235 m_sampledEffect = nullptr; 827 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
236 if (sampledEffect) 828
237 sampledEffect->clear(); 829 if (playStateInternal() == Idle)
238 } 830 return;
831
832 m_holdTime = currentTimeInternal();
833 m_held = true;
834 // TODO
835 m_playState = Idle;
836 m_startTime = nullValue();
837 m_currentTimePending = false;
838
839 InspectorInstrumentation::didCancelAnimation(timeline()->document(), this);
840 }
841
842 void Animation::beginUpdatingState()
843 {
844 // Nested calls are not allowed!
845 ASSERT(!m_stateIsBeingUpdated);
846 m_stateIsBeingUpdated = true;
847 }
848
849 void Animation::endUpdatingState()
850 {
851 ASSERT(m_stateIsBeingUpdated);
852 m_stateIsBeingUpdated = false;
853 }
854
855 void Animation::createCompositorPlayer()
856 {
857 if (RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled() && !m_comp ositorPlayer && Platform::current()->compositorSupport()) {
858 m_compositorPlayer = adoptPtr(Platform::current()->compositorSupport()-> createAnimationPlayer());
859 ASSERT(m_compositorPlayer);
860 m_compositorPlayer->setAnimationDelegate(this);
861 attachCompositorTimeline();
862 }
863
864 attachCompositedLayers();
865 }
866
867 void Animation::destroyCompositorPlayer()
868 {
869 detachCompositedLayers();
870
871 if (m_compositorPlayer) {
872 detachCompositorTimeline();
873 m_compositorPlayer->setAnimationDelegate(nullptr);
874 }
875 m_compositorPlayer.clear();
876 }
877
878 void Animation::attachCompositorTimeline()
879 {
880 if (m_compositorPlayer) {
881 WebCompositorAnimationTimeline* timeline = m_timeline ? m_timeline->comp ositorTimeline() : nullptr;
882 if (timeline)
883 timeline->playerAttached(*this);
884 }
885 }
886
887 void Animation::detachCompositorTimeline()
888 {
889 if (m_compositorPlayer) {
890 WebCompositorAnimationTimeline* timeline = m_timeline ? m_timeline->comp ositorTimeline() : nullptr;
891 if (timeline)
892 timeline->playerDestroyed(*this);
893 }
894 }
895
896 void Animation::attachCompositedLayers()
897 {
898 if (!RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled() || !m_com positorPlayer)
899 return;
900
901 ASSERT(m_content);
902 ASSERT(m_content->isAnimation());
903
904 if (toKeyframeEffect(m_content.get())->canAttachCompositedLayers())
905 toKeyframeEffect(m_content.get())->attachCompositedLayers();
906 }
907
908 void Animation::detachCompositedLayers()
909 {
910 if (m_compositorPlayer && m_compositorPlayer->isLayerAttached())
911 m_compositorPlayer->detachLayer();
912 }
913
914 void Animation::notifyAnimationStarted(double monotonicTime, int group)
915 {
916 ASSERT(RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled());
917 timeline()->document()->compositorPendingAnimations().notifyCompositorAnimat ionStarted(monotonicTime, group);
918 }
919
920 Animation::PlayStateUpdateScope::PlayStateUpdateScope(Animation& animation, Timi ngUpdateReason reason, CompositorPendingChange compositorPendingChange)
921 : m_animation(animation)
922 , m_initialPlayState(m_animation->playStateInternal())
923 , m_compositorPendingChange(compositorPendingChange)
924 {
925 m_animation->beginUpdatingState();
926 m_animation->updateCurrentTimingState(reason);
927 }
928
929 Animation::PlayStateUpdateScope::~PlayStateUpdateScope()
930 {
931 AnimationPlayState oldPlayState = m_initialPlayState;
932 AnimationPlayState newPlayState = m_animation->calculatePlayState();
933
934 m_animation->m_playState = newPlayState;
935 if (oldPlayState != newPlayState) {
936 bool wasActive = oldPlayState == Pending || oldPlayState == Running;
937 bool isActive = newPlayState == Pending || newPlayState == Running;
938 if (!wasActive && isActive)
939 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("blink.animations," TRACE_DISABLED _BY_DEFAULT("devtools.timeline"), "KeyframeEffect", m_animation, "data", Inspect orAnimationEvent::data(*m_animation));
940 else if (wasActive && !isActive)
941 TRACE_EVENT_NESTABLE_ASYNC_END1("blink.animations," TRACE_DISABLED_B Y_DEFAULT("devtools.timeline"), "KeyframeEffect", m_animation, "endData", Inspec torAnimationStateEvent::data(*m_animation));
942 else
943 TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("blink.animations," TRACE_DISABL ED_BY_DEFAULT("devtools.timeline"), "KeyframeEffect", m_animation, "data", Inspe ctorAnimationStateEvent::data(*m_animation));
944 }
945
946 // Ordering is important, the ready promise should resolve/reject before
947 // the finished promise.
948 if (m_animation->m_readyPromise && newPlayState != oldPlayState) {
949 if (newPlayState == Idle) {
950 if (m_animation->m_readyPromise->state() == AnimationPromise::Pendin g) {
951 m_animation->m_readyPromise->reject(DOMException::create(AbortEr ror));
952 }
953 m_animation->m_readyPromise->reset();
954 m_animation->m_readyPromise->resolve(m_animation);
955 } else if (oldPlayState == Pending) {
956 m_animation->m_readyPromise->resolve(m_animation);
957 } else if (newPlayState == Pending) {
958 ASSERT(m_animation->m_readyPromise->state() != AnimationPromise::Pen ding);
959 m_animation->m_readyPromise->reset();
960 }
961 }
962
963 if (m_animation->m_finishedPromise && newPlayState != oldPlayState) {
964 if (newPlayState == Idle) {
965 if (m_animation->m_finishedPromise->state() == AnimationPromise::Pen ding) {
966 m_animation->m_finishedPromise->reject(DOMException::create(Abor tError));
967 }
968 m_animation->m_finishedPromise->reset();
969 } else if (newPlayState == Finished) {
970 m_animation->m_finishedPromise->resolve(m_animation);
971 } else if (oldPlayState == Finished) {
972 m_animation->m_finishedPromise->reset();
973 }
974 }
975
976 if (oldPlayState != newPlayState && (oldPlayState == Idle || newPlayState == Idle)) {
977 m_animation->setOutdated();
978 }
979
980 #if ENABLE(ASSERT)
981 // Verify that current time is up to date.
982 m_animation->currentTimeInternal();
239 #endif 983 #endif
240 984
241 bool Animation::isCandidateForAnimationOnCompositor(double playerPlaybackRate) c onst 985 switch (m_compositorPendingChange) {
242 { 986 case SetCompositorPending:
243 if (!effect() 987 m_animation->setCompositorPending();
244 || !m_target 988 break;
245 || (m_target->computedStyle() && m_target->computedStyle()->hasMotionPat h())) 989 case SetCompositorPendingWithSourceChanged:
246 return false; 990 m_animation->setCompositorPending(true);
247 991 break;
248 return CompositorAnimations::instance()->isCandidateForAnimationOnCompositor (specifiedTiming(), *m_target, player(), *effect(), playerPlaybackRate); 992 case DoNotSetCompositorPending:
249 } 993 break;
250 994 default:
251 bool Animation::maybeStartAnimationOnCompositor(int group, double startTime, dou ble currentTime, double playerPlaybackRate) 995 ASSERT_NOT_REACHED();
252 { 996 break;
253 ASSERT(!hasActiveAnimationsOnCompositor()); 997 }
254 if (!isCandidateForAnimationOnCompositor(playerPlaybackRate)) 998 m_animation->endUpdatingState();
255 return false; 999
256 if (!CompositorAnimations::instance()->canStartAnimationOnCompositor(*m_targ et)) 1000 if (oldPlayState != newPlayState && newPlayState == Running)
257 return false; 1001 InspectorInstrumentation::didCreateAnimation(m_animation->timeline()->do cument(), m_animation);
258 if (!CompositorAnimations::instance()->startAnimationOnCompositor(*m_target, group, startTime, currentTime, specifiedTiming(), *player(), *effect(), m_compo sitorAnimationIds, playerPlaybackRate)) 1002 }
259 return false; 1003
260 ASSERT(!m_compositorAnimationIds.isEmpty()); 1004 bool Animation::addEventListener(const AtomicString& eventType, PassRefPtr<Event Listener> listener, bool useCapture)
261 return true; 1005 {
262 } 1006 if (eventType == EventTypeNames::finish)
263 1007 UseCounter::count(executionContext(), UseCounter::AnimationFinishEvent);
264 bool Animation::hasActiveAnimationsOnCompositor() const 1008 return EventTargetWithInlineData::addEventListener(eventType, listener, useC apture);
265 { 1009 }
266 return !m_compositorAnimationIds.isEmpty(); 1010
267 } 1011 void Animation::pauseForTesting(double pauseTime)
268 1012 {
269 bool Animation::hasActiveAnimationsOnCompositor(CSSPropertyID property) const 1013 RELEASE_ASSERT(!paused());
270 { 1014 setCurrentTimeInternal(pauseTime, TimingUpdateOnDemand);
271 return hasActiveAnimationsOnCompositor() && affects(PropertyHandle(property) ); 1015 if (hasActiveAnimationsOnCompositor())
272 } 1016 toKeyframeEffect(m_content.get())->pauseAnimationForTestingOnCompositor( currentTimeInternal());
273 1017 m_isPausedForTesting = true;
274 bool Animation::affects(PropertyHandle property) const 1018 pause();
275 {
276 return m_effect && m_effect->affects(property);
277 }
278
279 bool Animation::cancelAnimationOnCompositor()
280 {
281 // FIXME: cancelAnimationOnCompositor is called from withins style recalc.
282 // This queries compositingState, which is not necessarily up to date.
283 // https://code.google.com/p/chromium/issues/detail?id=339847
284 DisableCompositingQueryAsserts disabler;
285 if (!hasActiveAnimationsOnCompositor())
286 return false;
287 if (!m_target || !m_target->layoutObject())
288 return false;
289 ASSERT(player());
290 for (const auto& compositorAnimationId : m_compositorAnimationIds)
291 CompositorAnimations::instance()->cancelAnimationOnCompositor(*m_target, *player(), compositorAnimationId);
292 m_compositorAnimationIds.clear();
293 return true;
294 }
295
296 void Animation::restartAnimationOnCompositor()
297 {
298 if (cancelAnimationOnCompositor())
299 player()->setCompositorPending(true);
300 }
301
302 void Animation::cancelIncompatibleAnimationsOnCompositor()
303 {
304 if (m_target && player() && effect())
305 CompositorAnimations::instance()->cancelIncompatibleAnimationsOnComposit or(*m_target, *player(), *effect());
306 }
307
308 void Animation::pauseAnimationForTestingOnCompositor(double pauseTime)
309 {
310 ASSERT(hasActiveAnimationsOnCompositor());
311 if (!m_target || !m_target->layoutObject())
312 return;
313 ASSERT(player());
314 for (const auto& compositorAnimationId : m_compositorAnimationIds)
315 CompositorAnimations::instance()->pauseAnimationForTestingOnCompositor(* m_target, *player(), compositorAnimationId, pauseTime);
316 }
317
318 bool Animation::canAttachCompositedLayers() const
319 {
320 if (!m_target || !player())
321 return false;
322
323 return CompositorAnimations::instance()->canAttachCompositedLayers(*m_target , *player());
324 }
325
326 void Animation::attachCompositedLayers()
327 {
328 ASSERT(m_target);
329 ASSERT(player());
330 CompositorAnimations::instance()->attachCompositedLayers(*m_target, *player( ));
331 } 1019 }
332 1020
333 DEFINE_TRACE(Animation) 1021 DEFINE_TRACE(Animation)
334 { 1022 {
335 visitor->trace(m_target); 1023 visitor->trace(m_content);
336 visitor->trace(m_effect); 1024 visitor->trace(m_timeline);
337 visitor->trace(m_sampledEffect); 1025 visitor->trace(m_pendingFinishedEvent);
338 AnimationNode::trace(visitor); 1026 visitor->trace(m_finishedPromise);
339 } 1027 visitor->trace(m_readyPromise);
340 1028 EventTargetWithInlineData::trace(visitor);
341 } // namespace blink 1029 ActiveDOMObject::trace(visitor);
1030 }
1031
1032 } // namespace
OLDNEW
« no previous file with comments | « Source/core/animation/Animation.h ('k') | Source/core/animation/Animation.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698