OLD | NEW |
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 14 matching lines...) Expand all Loading... |
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 "core/animation/KeyframeEffect.h" | 31 #include "core/animation/KeyframeEffect.h" |
32 | 32 |
33 #include "bindings/core/v8/Dictionary.h" | 33 #include "bindings/core/v8/Dictionary.h" |
34 #include "bindings/core/v8/ExceptionState.h" | 34 #include "bindings/core/v8/ExceptionState.h" |
35 #include "core/animation/Animation.h" | |
36 #include "core/animation/AnimationEffectTiming.h" | 35 #include "core/animation/AnimationEffectTiming.h" |
37 #include "core/animation/AnimationTimeline.h" | 36 #include "core/animation/EffectInput.h" |
38 #include "core/animation/CompositorAnimations.h" | |
39 #include "core/animation/ElementAnimations.h" | |
40 #include "core/animation/Interpolation.h" | |
41 #include "core/animation/KeyframeEffectModel.h" | |
42 #include "core/animation/KeyframeEffectOptions.h" | 37 #include "core/animation/KeyframeEffectOptions.h" |
43 #include "core/animation/KeyframeEffectReadOnly.h" | 38 #include "core/animation/KeyframeEffectReadOnly.h" |
44 #include "core/animation/PropertyHandle.h" | 39 #include "core/animation/TimingInput.h" |
45 #include "core/dom/Element.h" | 40 #include "core/dom/Element.h" |
46 #include "core/dom/NodeComputedStyle.h" | |
47 #include "core/frame/UseCounter.h" | 41 #include "core/frame/UseCounter.h" |
48 #include "core/paint/PaintLayer.h" | |
49 #include "core/svg/SVGElement.h" | |
50 | 42 |
51 namespace blink { | 43 namespace blink { |
52 | 44 |
53 KeyframeEffect* KeyframeEffect::create( | 45 KeyframeEffect* KeyframeEffect::create( |
54 Element* target, | 46 Element* target, |
55 EffectModel* model, | 47 EffectModel* model, |
56 const Timing& timing, | 48 const Timing& timing, |
57 KeyframeEffectReadOnly::Priority priority, | 49 KeyframeEffectReadOnly::Priority priority, |
58 EventDelegate* eventDelegate) { | 50 EventDelegate* eventDelegate) { |
59 return new KeyframeEffect(target, model, timing, priority, eventDelegate); | 51 return new KeyframeEffect(target, model, timing, priority, eventDelegate); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 | 107 |
116 KeyframeEffect::KeyframeEffect(Element* target, | 108 KeyframeEffect::KeyframeEffect(Element* target, |
117 EffectModel* model, | 109 EffectModel* model, |
118 const Timing& timing, | 110 const Timing& timing, |
119 KeyframeEffectReadOnly::Priority priority, | 111 KeyframeEffectReadOnly::Priority priority, |
120 EventDelegate* eventDelegate) | 112 EventDelegate* eventDelegate) |
121 : KeyframeEffectReadOnly(target, model, timing, priority, eventDelegate) {} | 113 : KeyframeEffectReadOnly(target, model, timing, priority, eventDelegate) {} |
122 | 114 |
123 KeyframeEffect::~KeyframeEffect() {} | 115 KeyframeEffect::~KeyframeEffect() {} |
124 | 116 |
125 void KeyframeEffect::attach(Animation* animation) { | |
126 if (m_target) { | |
127 m_target->ensureElementAnimations().animations().add(animation); | |
128 m_target->setNeedsAnimationStyleRecalc(); | |
129 if (RuntimeEnabledFeatures::webAnimationsSVGEnabled() && | |
130 m_target->isSVGElement()) | |
131 toSVGElement(m_target)->setWebAnimationsPending(); | |
132 } | |
133 AnimationEffectReadOnly::attach(animation); | |
134 } | |
135 | |
136 void KeyframeEffect::detach() { | |
137 if (m_target) | |
138 m_target->elementAnimations()->animations().remove(animation()); | |
139 if (m_sampledEffect) | |
140 clearEffects(); | |
141 AnimationEffectReadOnly::detach(); | |
142 } | |
143 | |
144 void KeyframeEffect::specifiedTimingChanged() { | |
145 if (animation()) { | |
146 // FIXME: Needs to consider groups when added. | |
147 DCHECK_EQ(animation()->effect(), this); | |
148 animation()->setCompositorPending(true); | |
149 } | |
150 } | |
151 | |
152 static AnimationStack& ensureAnimationStack(Element* element) { | |
153 return element->ensureElementAnimations().animationStack(); | |
154 } | |
155 | |
156 bool KeyframeEffect::hasMultipleTransformProperties() const { | |
157 if (!m_target->computedStyle()) | |
158 return false; | |
159 | |
160 unsigned transformPropertyCount = 0; | |
161 if (m_target->computedStyle()->hasTransformOperations()) | |
162 transformPropertyCount++; | |
163 if (m_target->computedStyle()->rotate()) | |
164 transformPropertyCount++; | |
165 if (m_target->computedStyle()->scale()) | |
166 transformPropertyCount++; | |
167 if (m_target->computedStyle()->translate()) | |
168 transformPropertyCount++; | |
169 return transformPropertyCount > 1; | |
170 } | |
171 | |
172 // Returns true if transform, translate, rotate or scale is composited | |
173 // and a motion path or other transform properties | |
174 // has been introduced on the element | |
175 bool KeyframeEffect::hasIncompatibleStyle() { | |
176 if (!m_target->computedStyle()) | |
177 return false; | |
178 | |
179 bool affectsTransform = | |
180 animation()->affects(*m_target, CSSPropertyTransform) || | |
181 animation()->affects(*m_target, CSSPropertyScale) || | |
182 animation()->affects(*m_target, CSSPropertyRotate) || | |
183 animation()->affects(*m_target, CSSPropertyTranslate); | |
184 | |
185 if (animation()->hasActiveAnimationsOnCompositor()) { | |
186 if (m_target->computedStyle()->hasOffset() && affectsTransform) | |
187 return true; | |
188 return hasMultipleTransformProperties(); | |
189 } | |
190 | |
191 return false; | |
192 } | |
193 | |
194 void KeyframeEffect::applyEffects() { | |
195 DCHECK(isInEffect()); | |
196 DCHECK(animation()); | |
197 if (!m_target || !m_model) | |
198 return; | |
199 | |
200 if (hasIncompatibleStyle()) | |
201 animation()->cancelAnimationOnCompositor(); | |
202 | |
203 double iteration = currentIteration(); | |
204 DCHECK_GE(iteration, 0); | |
205 bool changed = false; | |
206 if (m_sampledEffect) { | |
207 changed = m_model->sample(clampTo<int>(iteration, 0), progress(), | |
208 iterationDuration(), | |
209 m_sampledEffect->mutableInterpolations()); | |
210 } else { | |
211 Vector<RefPtr<Interpolation>> interpolations; | |
212 m_model->sample(clampTo<int>(iteration, 0), progress(), iterationDuration(), | |
213 interpolations); | |
214 if (!interpolations.isEmpty()) { | |
215 SampledEffect* sampledEffect = SampledEffect::create(this); | |
216 sampledEffect->mutableInterpolations().swap(interpolations); | |
217 m_sampledEffect = sampledEffect; | |
218 ensureAnimationStack(m_target).add(sampledEffect); | |
219 changed = true; | |
220 } else { | |
221 return; | |
222 } | |
223 } | |
224 | |
225 if (changed) { | |
226 m_target->setNeedsAnimationStyleRecalc(); | |
227 if (RuntimeEnabledFeatures::webAnimationsSVGEnabled() && | |
228 m_target->isSVGElement()) | |
229 toSVGElement(*m_target).setWebAnimationsPending(); | |
230 } | |
231 } | |
232 | |
233 void KeyframeEffect::clearEffects() { | |
234 DCHECK(animation()); | |
235 DCHECK(m_sampledEffect); | |
236 | |
237 m_sampledEffect->clear(); | |
238 m_sampledEffect = nullptr; | |
239 restartAnimationOnCompositor(); | |
240 m_target->setNeedsAnimationStyleRecalc(); | |
241 if (RuntimeEnabledFeatures::webAnimationsSVGEnabled() && | |
242 m_target->isSVGElement()) | |
243 toSVGElement(*m_target).clearWebAnimatedAttributes(); | |
244 invalidate(); | |
245 } | |
246 | |
247 void KeyframeEffect::updateChildrenAndEffects() const { | |
248 if (!m_model) | |
249 return; | |
250 DCHECK(animation()); | |
251 if (isInEffect() && !animation()->effectSuppressed()) | |
252 const_cast<KeyframeEffect*>(this)->applyEffects(); | |
253 else if (m_sampledEffect) | |
254 const_cast<KeyframeEffect*>(this)->clearEffects(); | |
255 } | |
256 | |
257 double KeyframeEffect::calculateTimeToEffectChange( | |
258 bool forwards, | |
259 double localTime, | |
260 double timeToNextIteration) const { | |
261 const double startTime = specifiedTiming().startDelay; | |
262 const double endTimeMinusEndDelay = startTime + activeDurationInternal(); | |
263 const double endTime = endTimeMinusEndDelay + specifiedTiming().endDelay; | |
264 const double afterTime = std::min(endTimeMinusEndDelay, endTime); | |
265 | |
266 switch (getPhase()) { | |
267 case PhaseNone: | |
268 return std::numeric_limits<double>::infinity(); | |
269 case PhaseBefore: | |
270 DCHECK_GE(startTime, localTime); | |
271 return forwards ? startTime - localTime | |
272 : std::numeric_limits<double>::infinity(); | |
273 case PhaseActive: | |
274 if (forwards) { | |
275 // Need service to apply fill / fire events. | |
276 const double timeToEnd = afterTime - localTime; | |
277 if (requiresIterationEvents()) { | |
278 return std::min(timeToEnd, timeToNextIteration); | |
279 } | |
280 return timeToEnd; | |
281 } | |
282 return 0; | |
283 case PhaseAfter: | |
284 DCHECK_GE(localTime, afterTime); | |
285 // If this KeyframeEffect is still in effect then it will need to update | |
286 // when its parent goes out of effect. We have no way of knowing when | |
287 // that will be, however, so the parent will need to supply it. | |
288 return forwards ? std::numeric_limits<double>::infinity() | |
289 : localTime - afterTime; | |
290 default: | |
291 NOTREACHED(); | |
292 return std::numeric_limits<double>::infinity(); | |
293 } | |
294 } | |
295 | |
296 void KeyframeEffect::notifySampledEffectRemovedFromAnimationStack() { | |
297 m_sampledEffect = nullptr; | |
298 } | |
299 | |
300 bool KeyframeEffect::isCandidateForAnimationOnCompositor( | |
301 double animationPlaybackRate) const { | |
302 // Do not put transforms on compositor if more than one of them are defined | |
303 // in computed style because they need to be explicitly ordered | |
304 if (!model() || !m_target || | |
305 (m_target->computedStyle() && m_target->computedStyle()->hasOffset()) || | |
306 hasMultipleTransformProperties()) | |
307 return false; | |
308 | |
309 return CompositorAnimations::isCandidateForAnimationOnCompositor( | |
310 specifiedTiming(), *m_target, animation(), *model(), | |
311 animationPlaybackRate); | |
312 } | |
313 | |
314 bool KeyframeEffect::maybeStartAnimationOnCompositor( | |
315 int group, | |
316 double startTime, | |
317 double currentTime, | |
318 double animationPlaybackRate) { | |
319 DCHECK(!hasActiveAnimationsOnCompositor()); | |
320 if (!isCandidateForAnimationOnCompositor(animationPlaybackRate)) | |
321 return false; | |
322 if (!CompositorAnimations::canStartAnimationOnCompositor(*m_target)) | |
323 return false; | |
324 CompositorAnimations::startAnimationOnCompositor( | |
325 *m_target, group, startTime, currentTime, specifiedTiming(), *animation(), | |
326 *model(), m_compositorAnimationIds, animationPlaybackRate); | |
327 DCHECK(!m_compositorAnimationIds.isEmpty()); | |
328 return true; | |
329 } | |
330 | |
331 bool KeyframeEffect::hasActiveAnimationsOnCompositor() const { | |
332 return !m_compositorAnimationIds.isEmpty(); | |
333 } | |
334 | |
335 bool KeyframeEffect::hasActiveAnimationsOnCompositor( | |
336 CSSPropertyID property) const { | |
337 return hasActiveAnimationsOnCompositor() && affects(PropertyHandle(property)); | |
338 } | |
339 | |
340 bool KeyframeEffect::affects(PropertyHandle property) const { | |
341 return m_model && m_model->affects(property); | |
342 } | |
343 | |
344 bool KeyframeEffect::cancelAnimationOnCompositor() { | |
345 // FIXME: cancelAnimationOnCompositor is called from withins style recalc. | |
346 // This queries compositingState, which is not necessarily up to date. | |
347 // https://code.google.com/p/chromium/issues/detail?id=339847 | |
348 DisableCompositingQueryAsserts disabler; | |
349 if (!hasActiveAnimationsOnCompositor()) | |
350 return false; | |
351 if (!m_target || !m_target->layoutObject()) | |
352 return false; | |
353 DCHECK(animation()); | |
354 for (const auto& compositorAnimationId : m_compositorAnimationIds) | |
355 CompositorAnimations::cancelAnimationOnCompositor(*m_target, *animation(), | |
356 compositorAnimationId); | |
357 m_compositorAnimationIds.clear(); | |
358 return true; | |
359 } | |
360 | |
361 void KeyframeEffect::restartAnimationOnCompositor() { | |
362 if (cancelAnimationOnCompositor()) | |
363 animation()->setCompositorPending(true); | |
364 } | |
365 | |
366 void KeyframeEffect::cancelIncompatibleAnimationsOnCompositor() { | |
367 if (m_target && animation() && model()) | |
368 CompositorAnimations::cancelIncompatibleAnimationsOnCompositor( | |
369 *m_target, *animation(), *model()); | |
370 } | |
371 | |
372 void KeyframeEffect::pauseAnimationForTestingOnCompositor(double pauseTime) { | |
373 DCHECK(hasActiveAnimationsOnCompositor()); | |
374 if (!m_target || !m_target->layoutObject()) | |
375 return; | |
376 DCHECK(animation()); | |
377 for (const auto& compositorAnimationId : m_compositorAnimationIds) | |
378 CompositorAnimations::pauseAnimationForTestingOnCompositor( | |
379 *m_target, *animation(), compositorAnimationId, pauseTime); | |
380 } | |
381 | |
382 void KeyframeEffect::attachCompositedLayers() { | |
383 DCHECK(m_target); | |
384 DCHECK(animation()); | |
385 CompositorAnimations::attachCompositedLayers(*m_target, *animation()); | |
386 } | |
387 | |
388 AnimationEffectTiming* KeyframeEffect::timing() { | 117 AnimationEffectTiming* KeyframeEffect::timing() { |
389 return AnimationEffectTiming::create(this); | 118 return AnimationEffectTiming::create(this); |
390 } | 119 } |
391 | 120 |
392 DEFINE_TRACE(KeyframeEffect) { | |
393 KeyframeEffectReadOnly::trace(visitor); | |
394 } | |
395 | |
396 } // namespace blink | 121 } // namespace blink |
OLD | NEW |