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

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

Issue 2397113002: Move content up to KeyframeEffectReadOnly (Closed)
Patch Set: Created 4 years, 2 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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698